# 'AILPAY_SUPPORT',
# 'SUPPORT_FACTORY_SERVICE',
# 'MEMORY_CORRUPTION',
+ 'SUPPORT_AI_SERVICE',
'SAP_EFFECT_SWS_SUPPORT',
'AUDIO_SMARTPA_AW88082',
'LCD_JD9885',
${CMAKE_CURRENT_SOURCE_DIR}/example/ppp_example.c
# ${CMAKE_CURRENT_SOURCE_DIR}/example/ppp_power_example.c
${CMAKE_CURRENT_SOURCE_DIR}/example/api_shell.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/example/ppp_tcp_test.c
)
# 源文件列表
set(SOURCES
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
src/ppp_stub_functions.c
# PPP_OPTIONS=1
SUPPORT_PPP_SERVICE
SUPPORT_AT_PPP
+ SUPPORT_TCP_TEST
)
set(PRIVATE_DEFINES
--- /dev/null
+
\ No newline at end of file
--- /dev/null
+# Makefile for PPP TCP Test Client
+# 基于Python版本tcp_test_client.py实现的C语言版本
+
+# 编译器设置
+CC = gcc
+CFLAGS = -Wall -Wextra -std=c99 -O2 -g
+LDFLAGS = -pthread
+
+# 目录设置
+SRC_DIR = .
+INC_DIR = ../include
+BUILD_DIR = build
+
+# 目标程序
+TARGET = ppp_tcp_test
+
+# 源文件
+SRCS = ppp_tcp_test.c ppp_tcp_test_main.c
+
+# 目标文件
+OBJS = $(SRCS:%.c=$(BUILD_DIR)/%.o)
+
+# 头文件依赖
+INCLUDES = -I$(INC_DIR) -I.
+
+# 默认目标
+all: $(BUILD_DIR)/$(TARGET)
+
+# 创建构建目录
+$(BUILD_DIR):
+ mkdir -p $(BUILD_DIR)
+
+# 编译目标程序
+$(BUILD_DIR)/$(TARGET): $(BUILD_DIR) $(OBJS)
+ $(CC) $(OBJS) -o $@ $(LDFLAGS)
+ @echo "Build complete: $@"
+
+# 编译源文件
+$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
+ $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+
+# 清理
+clean:
+ rm -rf $(BUILD_DIR)
+
+# 安装
+install: $(BUILD_DIR)/$(TARGET)
+ cp $(BUILD_DIR)/$(TARGET) /usr/local/bin/$(TARGET)
+ @echo "Installed to /usr/local/bin/$(TARGET)"
+
+# 卸载
+uninstall:
+ rm -f /usr/local/bin/$(TARGET)
+ @echo "Uninstalled $(TARGET)"
+
+# 测试运行
+test: $(BUILD_DIR)/$(TARGET)
+ @echo "Running basic test..."
+ $(BUILD_DIR)/$(TARGET) --help
+
+# 示例运行
+example: $(BUILD_DIR)/$(TARGET)
+ @echo "Running example test (需要服务器支持)..."
+ $(BUILD_DIR)/$(TARGET) --host 127.0.0.1 --port 8910 --connections 2 --time 10 --verbose
+
+# 显示帮助
+help:
+ @echo "Available targets:"
+ @echo " all - Build the TCP test client"
+ @echo " clean - Remove build files"
+ @echo " install - Install to /usr/local/bin"
+ @echo " uninstall - Remove from /usr/local/bin"
+ @echo " test - Run basic functionality test"
+ @echo " example - Run example test (needs server)"
+ @echo " help - Show this help"
+ @echo ""
+ @echo "Usage examples:"
+ @echo " make"
+ @echo " make test"
+ @echo " make example"
+ @echo " ./build/$(TARGET) --host 192.168.1.100 --port 8080 --connections 5 --time 30"
+
+.PHONY: all clean install uninstall test example help
\ No newline at end of file
--- /dev/null
+
\ No newline at end of file
#include "ppp_types.h"
#include "ppp_api.h"
#include "ppp_at_handler.h"
+#include "ppp_debug_manager.h"
+#include "ppp_tcp_test.h"
#include "ppp_example.h"
return ERRCODE_SUCC;
}
+/**
+ * @brief AT^PPPDEBUGSET - 设置PPP调试级别
+ * @param para 参数: 调试级别 (0=NONE, 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG) 或级别名称
+ * @param paraLen 参数长度
+ */
+static errcode_t at_ppp_debug_set_level(uint8_t *para, uint32_t paraLen)
+{
+ if (!para || paraLen == 0) {
+ PRINT("[PPP_ERR]PPP DEBUG SET: Missing debug level parameter\r\n");
+ PRINT("[PPP_INFO]Usage: AT^PPPDEBUGSET=<level>\r\n");
+ PRINT("[PPP_INFO]Levels: 0=NONE, 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG\r\n");
+ PRINT("[PPP_INFO]Or use names: NONE, ERROR, WARN, INFO, DEBUG\r\n");
+ return ERRCODE_FAIL;
+ }
+
+ // 将参数转换为字符串
+ char level_str[16] = {0};
+ uint32_t copy_len = (paraLen < sizeof(level_str) - 1) ? paraLen : sizeof(level_str) - 1;
+ memcpy(level_str, para, copy_len);
+ level_str[copy_len] = '\0';
+
+ PRINT("[PPP_INFO]PPP DEBUG SET: Setting debug level to '%s'...\r\n", level_str);
+
+ ppp_error_t ret = PPP_ERR_OK;
+
+ // 尝试按数字设置
+ if (level_str[0] >= '0' && level_str[0] <= '4' && level_str[1] == '\0') {
+ int level = level_str[0] - '0';
+ ret = ppp_debug_set_level(level);
+ if (ret == PPP_ERR_OK) {
+ PRINT("[PPP_INFO]PPP DEBUG SET: Debug level set to %d (%s)\r\n",
+ level, ppp_debug_get_level_name(level));
+ }
+ } else {
+ // 尝试按名称设置
+ ret = ppp_debug_set_level_by_name(level_str);
+ if (ret == PPP_ERR_OK) {
+ int current_level = ppp_debug_get_level();
+ PRINT("[PPP_INFO]PPP DEBUG SET: Debug level set to %s (%d)\r\n",
+ ppp_debug_get_level_name(current_level), current_level);
+ }
+ }
+
+ if (ret != PPP_ERR_OK) {
+ PRINT("[PPP_ERR]PPP DEBUG SET: Invalid debug level '%s'\r\n", level_str);
+ PRINT("[PPP_INFO]Valid levels: 0=NONE, 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG\r\n");
+ return ERRCODE_FAIL;
+ }
+
+ return ERRCODE_SUCC;
+}
+
+/**
+ * @brief AT^PPPDEBUGGET - 获取当前PPP调试级别
+ */
+static errcode_t at_ppp_debug_get_level(uint8_t *para, uint32_t paraLen)
+{
+ (void)para;
+ (void)paraLen;
+
+ int current_level = ppp_debug_get_level();
+ const char *level_name = ppp_debug_get_level_name(current_level);
+
+ PRINT("[PPP_INFO]PPP DEBUG GET: Current debug level is %d (%s)\r\n",
+ current_level, level_name);
+
+ // 显示各级别的含义
+ PRINT("[PPP_INFO]Debug levels:\r\n");
+ PRINT("[PPP_INFO] 0=NONE - No debug output\r\n");
+ PRINT("[PPP_INFO] 1=ERROR - Error messages only\r\n");
+ PRINT("[PPP_INFO] 2=WARN - Warnings and errors\r\n");
+ PRINT("[PPP_INFO] 3=INFO - Info, warnings and errors\r\n");
+ PRINT("[PPP_INFO] 4=DEBUG - All debug messages\r\n");
+
+ return ERRCODE_SUCC;
+}
+#include "ppp_debug.h"
+/**
+ * @brief AT^PPPDEBUGTEST - 测试各级别调试输出
+ */
+static errcode_t at_ppp_debug_test_output(uint8_t *para, uint32_t paraLen)
+{
+ (void)para;
+ (void)paraLen;
+
+ int current_level = ppp_debug_get_level();
+
+ PRINT("[PPP_INFO]PPP DEBUG TEST: Testing debug output at level %d (%s)\r\n",
+ current_level, ppp_debug_get_level_name(current_level));
+
+ // 测试各级别输出
+ PPP_DEBUG_ERROR("This is an ERROR message (level 1)");
+ PPP_DEBUG_WARN("This is a WARN message (level 2)");
+ PPP_DEBUG_INFO("This is an INFO message (level 3)");
+ PPP_DEBUG_DEBUG("This is a DEBUG message (level 4)");
+ PPP_DEBUG_CRITICAL("This is a CRITICAL message (always shown)");
+
+ PRINT("[PPP_INFO]PPP DEBUG TEST: Test completed\r\n");
+
+ return ERRCODE_SUCC;
+}
+
+/**
+ * @brief AT^PPPDEBUGDEFAULT - 重置调试级别为默认值
+ */
+static errcode_t at_ppp_debug_reset_level(uint8_t *para, uint32_t paraLen)
+{
+ (void)para;
+ (void)paraLen;
+
+ ppp_error_t ret = ppp_debug_reset_level();
+ if (ret == PPP_ERR_OK) {
+ int current_level = ppp_debug_get_level();
+ PRINT("[PPP_INFO]PPP DEBUG RESET: Debug level reset to default %d (%s)\r\n",
+ current_level, ppp_debug_get_level_name(current_level));
+ return ERRCODE_SUCC;
+ } else {
+ PRINT("[PPP_ERR]PPP DEBUG RESET: Failed to reset debug level\r\n");
+ return ERRCODE_FAIL;
+ }
+}
+
+/**
+ * @brief AT^PPPTCPPERF - PPP TCP性能测试
+ * @param para 参数: 服务器地址,端口,连接数,测试时间
+ * @param paraLen 参数长度
+ */
+static errcode_t at_ppp_tcp_performance_test(uint8_t *para, uint32_t paraLen)
+{
+ if (!para || paraLen == 0) {
+ PRINT("[PPP_ERR]PPP TCP PERF: Missing parameters\r\n");
+ PRINT("[PPP_INFO]Usage: AT^PPPTCPPERF=<host>,<port>,<connections>,<time>\r\n");
+ PRINT("[PPP_INFO]Example: AT^PPPTCPPERF=110.42.224.129,8910,5,30\r\n");
+ return ERRCODE_FAIL;
+ }
+
+ uint8_t argv[CUSTOM_UTILS_MAX_ARGC][CUSTOM_UTILS_MAX_ARGV_LEN];
+ uint32_t argc;
+
+ if (ConvertCmdToParam(para, paraLen, argv, &argc) != CUSTOM_UTILS_SUCCESS || argc != 4) {
+ PRINT("[PPP_ERR]PPP TCP PERF: Invalid parameters, need 4 parameters, got %d\r\n", argc);
+ PRINT("[PPP_INFO]Usage: AT^PPPTCPPERF=<host>,<port>,<connections>,<time>\r\n");
+ return ERRCODE_FAIL;
+ }
+
+ // 解析参数
+ char *server_host = (char*)argv[0];
+ int port = atoi((char*)argv[1]);
+ int connections = atoi((char*)argv[2]);
+ int test_time = atoi((char*)argv[3]);
+
+ // 参数验证
+ if (port < 1 || port > 65535) {
+ PRINT("[PPP_ERR]PPP TCP PERF: Invalid port %d (must be 1-65535)\r\n", port);
+ return ERRCODE_FAIL;
+ }
+
+ if (connections < 1 || connections > TCP_TEST_MAX_CONNECTIONS) {
+ PRINT("[PPP_ERR]PPP TCP PERF: Invalid connections %d (must be 1-%d)\r\n",
+ connections, TCP_TEST_MAX_CONNECTIONS);
+ return ERRCODE_FAIL;
+ }
+
+ if (test_time < 1 || test_time > 3600) {
+ PRINT("[PPP_ERR]PPP TCP PERF: Invalid test time %d (must be 1-3600 seconds)\r\n", test_time);
+ return ERRCODE_FAIL;
+ }
+
+ PRINT("[PPP_INFO]PPP TCP PERF: Starting TCP performance test\r\n");
+ PRINT("[PPP_INFO]Target: %s:%d\r\n", server_host, port);
+ PRINT("[PPP_INFO]Connections: %d\r\n", connections);
+ PRINT("[PPP_INFO]Duration: %d seconds\r\n", test_time);
+
+#ifdef SUPPORT_TCP_TEST
+ // 初始化TCP测试配置
+ tcp_test_config_t config;
+ strncpy(config.server_host, server_host, sizeof(config.server_host) - 1);
+ config.server_host[sizeof(config.server_host) - 1] = '\0';
+ config.server_port = (uint16_t)port;
+ config.test_duration = (uint32_t)test_time;
+ config.connection_count = (uint16_t)connections;
+ config.verbose = false; // AT命令模式不使用详细输出
+ config.send_interval_ms = 10; // 10ms间隔,适合AT命令模式
+ config.data_min_size = 64; // 较小的数据包
+ config.data_max_size = 1024; // 适中的最大包
+
+ // 初始化TCP测试
+ ppp_error_t ret = tcp_test_init();
+ if (ret != PPP_ERR_OK) {
+ PRINT("[PPP_ERR]PPP TCP PERF: Failed to initialize TCP test: %d\r\n", ret);
+ return ERRCODE_FAIL;
+ }
+
+ // 启动测试
+ ret = tcp_test_start(&config);
+ if (ret != PPP_ERR_OK) {
+ PRINT("[PPP_ERR]PPP TCP PERF: Failed to start TCP test: %d\r\n", ret);
+ tcp_test_deinit();
+ return ERRCODE_FAIL;
+ }
+
+ PRINT("[PPP_INFO]PPP TCP PERF: Test started successfully\r\n");
+ PRINT("[PPP_INFO]PPP TCP PERF: Use AT^PPPTCPSTOP to stop early\r\n");
+ PRINT("[PPP_INFO]PPP TCP PERF: Use AT^PPPTCPSTATS to check status\r\n");
+
+ return ERRCODE_SUCC;
+
+#else
+ PRINT("[PPP_ERR]PPP TCP PERF: TCP test not supported in this build\r\n");
+ PRINT("[PPP_INFO]PPP TCP PERF: Enable SUPPORT_TCP_TEST to use this feature\r\n");
+ return ERRCODE_FAIL;
+#endif
+}
+
+/**
+ * @brief AT^PPPTCPSTOP - 停止TCP性能测试
+ */
+static errcode_t at_ppp_tcp_test_stop(uint8_t *para, uint32_t paraLen)
+{
+ (void)para;
+ (void)paraLen;
+
+#ifdef SUPPORT_TCP_TEST
+ if (!tcp_test_is_running()) {
+ PRINT("[PPP_INFO]PPP TCP STOP: No TCP test is currently running\r\n");
+ return ERRCODE_SUCC;
+ }
+
+ PRINT("[PPP_INFO]PPP TCP STOP: Stopping TCP performance test...\r\n");
+
+ ppp_error_t ret = tcp_test_stop();
+ if (ret != PPP_ERR_OK) {
+ PRINT("[PPP_ERR]PPP TCP STOP: Failed to stop TCP test: %d\r\n", ret);
+ return ERRCODE_FAIL;
+ }
+
+ // 清理资源
+ tcp_test_deinit();
+
+ PRINT("[PPP_INFO]PPP TCP STOP: TCP test stopped successfully\r\n");
+ return ERRCODE_SUCC;
+
+#else
+ PRINT("[PPP_ERR]PPP TCP STOP: TCP test not supported in this build\r\n");
+ return ERRCODE_FAIL;
+#endif
+}
+
+/**
+ * @brief AT^PPPTCPSTATS - 获取TCP测试统计信息
+ */
+static errcode_t at_ppp_tcp_test_stats(uint8_t *para, uint32_t paraLen)
+{
+ (void)para;
+ (void)paraLen;
+
+#ifdef SUPPORT_TCP_TEST
+ if (!tcp_test_is_running()) {
+ PRINT("[PPP_INFO]PPP TCP STATS: No TCP test is currently running\r\n");
+ return ERRCODE_SUCC;
+ }
+
+ // 获取全局统计信息
+ tcp_global_stats_t stats;
+ ppp_error_t ret = tcp_test_get_stats(&stats);
+ if (ret != PPP_ERR_OK) {
+ PRINT("[PPP_ERR]PPP TCP STATS: Failed to get TCP test stats: %d\r\n", ret);
+ return ERRCODE_FAIL;
+ }
+
+ // 计算运行时间
+ uint32_t current_time = tcp_test_get_time_ms();
+ uint32_t elapsed_ms = current_time - stats.start_time;
+ uint32_t elapsed_sec = elapsed_ms / 1000;
+
+ // 显示统计信息
+ PRINT("[PPP_INFO]=== TCP Performance Test Statistics ===\r\n");
+ PRINT("[PPP_INFO]Test Status: %s\r\n", stats.test_running ? "RUNNING" : "STOPPED");
+ PRINT("[PPP_INFO]Elapsed Time: %d seconds\r\n", elapsed_sec);
+ PRINT("[PPP_INFO]Successful Connections: %d\r\n", stats.successful_connections);
+ PRINT("[PPP_INFO]Failed Connections: %d\r\n", stats.failed_connections);
+ PRINT("[PPP_INFO]Packets Sent: %llu\r\n", stats.total_packets_sent);
+ PRINT("[PPP_INFO]Packets Received: %llu\r\n", stats.total_packets_received);
+ PRINT("[PPP_INFO]Bytes Sent: %llu\r\n", stats.total_bytes_sent);
+ PRINT("[PPP_INFO]Bytes Received: %llu\r\n", stats.total_bytes_received);
+ PRINT("[PPP_INFO]Total Errors: %d\r\n", stats.total_errors);
+ PRINT("[PPP_INFO]Data Verification Errors: %d\r\n", stats.data_verification_errors);
+
+ // 计算传输速率
+ if (elapsed_ms > 0) {
+ uint64_t throughput_bps = (stats.total_bytes_sent * 1000) / elapsed_ms;
+ char bytes_buf[64];
+ PRINT("[PPP_INFO]Average Throughput: %s/s\r\n",
+ tcp_test_format_bytes(throughput_bps, bytes_buf, sizeof(bytes_buf)));
+
+ float packet_rate = (float)stats.total_packets_sent * 1000 / elapsed_ms;
+ PRINT("[PPP_INFO]Average Packet Rate: %.1f packets/s\r\n", packet_rate);
+ }
+
+ // 计算成功率
+ if (stats.total_packets_sent > 0) {
+ float success_rate = (float)stats.total_packets_received / stats.total_packets_sent * 100;
+ PRINT("[PPP_INFO]Packet Success Rate: %.1f%%\r\n", success_rate);
+ }
+
+ PRINT("[PPP_INFO]========================================\r\n");
+
+ return ERRCODE_SUCC;
+
+#else
+ PRINT("[PPP_ERR]PPP TCP STATS: TCP test not supported in this build\r\n");
+ return ERRCODE_FAIL;
+#endif
+}
+
static const at_cmd_table_t g_ppp_cmd[] = {
{ (char *)"AT^CAT1POWER", cat1_power, (char *)"1" },
{ (char *)"AT^CAT1GETSIGNAL", at_cat1_getsignal, (char *)"1" },
{ (char *)"AT^WSMULTISTATUS", at_ws_multi_test_status, (char *)" " },
#endif
{ (char *)"AT^PPPSIGNALINFO", at_ppp_get_signal_info, (char *)" " },
+ { (char *)"AT^PPPDEBUGSET", at_ppp_debug_set_level, (char *)"level" },
+ { (char *)"AT^PPPDEBUGGET", at_ppp_debug_get_level, (char *)" " },
+ { (char *)"AT^PPPDEBUGTEST", at_ppp_debug_test_output, (char *)" " },
+ { (char *)"AT^PPPDEBUGDEFAULT", at_ppp_debug_reset_level, (char *)" " },
+ { (char *)"AT^PPPTCPPERF", at_ppp_tcp_performance_test, (char *)"host,port,connections,time" },
+ { (char *)"AT^PPPTCPSTOP", at_ppp_tcp_test_stop, (char *)" " },
+ { (char *)"AT^PPPTCPSTATS", at_ppp_tcp_test_stats, (char *)" " },
};
at_cmd_table_t *get_ppp_cmd_table(uint32_t *cmd_count)
PRINT("Sim Status: %d\r\n", cat1_api_runtime_get_cat1_simstat());
PRINT("Network Type: %d\r\n", cat1_api_runtime_get_cat1_networktype());
+ // 这些接口已移至ppp_lwip.c实现
+ PRINT("ip: %s\r\n", ppp_lwip_get_ip_address());
+ PRINT("netmask: %s\r\n", ppp_lwip_get_netmask());
+ PRINT("gateway: %s\r\n", ppp_lwip_get_gateway());
+ PRINT("dns: %s\r\n", ppp_lwip_get_dns());
+
ppp_state_t state = ppp_get_state();
switch (state) {
case PPP_STATE_IDLE:
--- /dev/null
+/**
+ * @file ppp_tcp_test.c
+ * @brief PPP TCP性能测试客户端实现
+ *
+ * 基于Python版本tcp_test_client.py实现的C语言版本
+ * 支持多连接并发测试、性能统计和数据验证
+ * 使用lwIP socket接口兼容嵌入式环境
+ */
+
+#include "ppp_tcp_test.h"
+#include "ppp_debug.h"
+#include "ppp_tcp_lwip_compat.h" /* lwIP兼容性定义 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+
+/* 时间相关头文件 */
+#ifndef USE_LWIP_SOCKET
+#include <sys/time.h>
+#endif
+
+/* 系统相关头文件 */
+#ifdef USE_LWIP_SOCKET
+ /* 使用嵌入式环境的简化定义 */
+ #include "osal_mutex.h"
+ #include "osal_task.h"
+
+ /* 简化的兼容性定义 */
+ #define TCP_MUTEX_INIT(mutex) osal_mutex_init(&(mutex))
+ #define TCP_MUTEX_DESTROY(mutex) osal_mutex_destroy(&(mutex))
+ #define TCP_MUTEX_LOCK(mutex) osal_mutex_lock(&(mutex))
+ #define TCP_MUTEX_UNLOCK(mutex) osal_mutex_unlock(&(mutex))
+ #define TCP_TIMER_CREATE(id, cb, arg, period, cycle) (*(id) = 0) /* 简化实现 */
+ #define TCP_TIMER_DELETE(id) /* 简化实现 */
+ #define TCP_TASK_CREATE(func, arg, name, size) \
+ do { \
+ osal_kthread_create((osal_kthread_handler)func, arg, name, size); \
+ } while(0)
+ #define TCP_SLEEP_MS(ms) osal_msleep(ms)
+ #define TCP_STRERROR(err) "socket error"
+
+ typedef osal_mutex tcp_mutex_t;
+ typedef int tcp_timer_id_t;
+
+#else
+ /* 使用标准POSIX环境 */
+ #include <pthread.h>
+ #include <unistd.h>
+ #include <sys/time.h>
+
+ /* POSIX兼容性定义 */
+ #define TCP_MUTEX_INIT(mutex) pthread_mutex_init(&(mutex), NULL)
+ #define TCP_MUTEX_DESTROY(mutex) pthread_mutex_destroy(&(mutex))
+ #define TCP_MUTEX_LOCK(mutex) pthread_mutex_lock(&(mutex))
+ #define TCP_MUTEX_UNLOCK(mutex) pthread_mutex_unlock(&(mutex))
+ #define TCP_TIMER_CREATE(id, cb, arg, period, cycle) (*(id) = 0) /* 简化实现 */
+ #define TCP_TIMER_DELETE(id) /* 简化实现 */
+ #define TCP_TASK_CREATE(func, arg, name, size) \
+ do { \
+ pthread_t thread_id; \
+ pthread_create(&thread_id, NULL, func, arg); \
+ pthread_detach(thread_id); \
+ } while(0)
+ #define TCP_SLEEP_MS(ms) usleep((ms) * 1000)
+ #define TCP_STRERROR(err) strerror(err)
+
+ typedef pthread_mutex_t tcp_mutex_t;
+ typedef int tcp_timer_id_t;
+
+
+#endif
+
+/* 全局测试管理器 */
+static tcp_test_manager_t g_tcp_test_manager = {0};
+static tcp_mutex_t g_tcp_stats_mutex;
+static bool g_tcp_test_initialized = false;
+
+/* 内部函数声明 */
+static ppp_error_t tcp_test_create_connection_thread(uint16_t conn_id);
+static void* tcp_test_connection_worker(void *arg);
+static ppp_error_t tcp_test_generate_data(uint16_t conn_id, uint32_t packet_id,
+ uint8_t *buffer, uint32_t size);
+static uint32_t tcp_test_calculate_checksum(const uint8_t *data, uint32_t size);
+static bool tcp_test_verify_data(const uint8_t *sent_data, const uint8_t *recv_data, uint32_t size);
+static void tcp_test_stats_timer_callback(void *arg);
+static void tcp_test_signal_handler(int signum);
+static ppp_error_t tcp_test_connect_socket(int *sock_fd, const char *host, uint16_t port);
+
+/**
+ * @brief 初始化TCP测试
+ */
+ppp_error_t tcp_test_init(void)
+{
+ if (g_tcp_test_initialized) {
+ return PPP_ERR_OK;
+ }
+
+ // 初始化互斥锁
+ if (TCP_MUTEX_INIT(g_tcp_stats_mutex) != 0) {
+ PPP_DEBUG_ERROR("Failed to initialize TCP test mutex");
+ return PPP_ERR_MEMORY;
+ }
+
+ // 清零管理器
+ memset(&g_tcp_test_manager, 0, sizeof(g_tcp_test_manager));
+
+ // 设置信号处理 (仅在POSIX环境下)
+#ifndef USE_LWIP_SOCKET
+ signal(SIGINT, tcp_test_signal_handler);
+ signal(SIGTERM, tcp_test_signal_handler);
+#endif
+
+ g_tcp_test_initialized = true;
+ PPP_DEBUG_INFO("TCP test initialized successfully");
+
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 反初始化TCP测试
+ */
+ppp_error_t tcp_test_deinit(void)
+{
+ if (!g_tcp_test_initialized) {
+ return PPP_ERR_OK;
+ }
+
+ // 停止测试
+ tcp_test_stop();
+
+ // 销毁互斥锁
+ TCP_MUTEX_DESTROY(g_tcp_stats_mutex);
+
+ g_tcp_test_initialized = false;
+ PPP_DEBUG_INFO("TCP test deinitialized");
+
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 启动TCP测试
+ */
+ppp_error_t tcp_test_start(const tcp_test_config_t *config)
+{
+ if (!g_tcp_test_initialized) {
+ PPP_DEBUG_ERROR("TCP test not initialized");
+ return PPP_ERR_INVALID_STATE;
+ }
+
+ if (!config) {
+ PPP_DEBUG_ERROR("Invalid config parameter");
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ if (g_tcp_test_manager.global_stats.test_running) {
+ PPP_DEBUG_ERROR("TCP test already running");
+ return PPP_ERR_INVALID_STATE;
+ }
+
+ // 复制配置
+ memcpy(&g_tcp_test_manager.config, config, sizeof(tcp_test_config_t));
+
+ // 初始化全局统计
+ memset(&g_tcp_test_manager.global_stats, 0, sizeof(tcp_global_stats_t));
+ g_tcp_test_manager.global_stats.start_time = tcp_test_get_time_ms();
+ g_tcp_test_manager.global_stats.test_running = true;
+ g_tcp_test_manager.stop_flag = false;
+
+ // 初始化连接统计
+ for (int i = 0; i < config->connection_count; i++) {
+ memset(&g_tcp_test_manager.connections[i], 0, sizeof(tcp_connection_stats_t));
+ g_tcp_test_manager.connections[i].conn_id = i;
+ g_tcp_test_manager.connections[i].socket_fd = -1;
+ }
+
+ printf("TCP性能测试客户端\n");
+ printf("目标服务器: %s:%d\n", config->server_host, config->server_port);
+ printf("测试时间: %d 秒\n", config->test_duration);
+ printf("并发连接: %d\n", config->connection_count);
+ printf("数据包大小: %d-%d 字节\n", config->data_min_size, config->data_max_size);
+ printf("========================================\n");
+
+ // 启动统计定时器
+ TCP_TIMER_CREATE(&g_tcp_test_manager.stats_timer_id,
+ tcp_test_stats_timer_callback, NULL,
+ TCP_TEST_STATS_INTERVAL * 1000,
+ TCP_TEST_STATS_INTERVAL * 1000);
+
+ // 创建连接线程
+ for (int i = 0; i < config->connection_count; i++) {
+ ppp_error_t ret = tcp_test_create_connection_thread(i);
+ if (ret != PPP_ERR_OK) {
+ PPP_DEBUG_ERROR("Failed to create connection thread %d", i);
+ tcp_test_stop();
+ return ret;
+ }
+
+ // 错开连接启动时间
+ TCP_SLEEP_MS(100); // 100ms
+ }
+
+ PPP_DEBUG_INFO("TCP test started with %d connections", config->connection_count);
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 停止TCP测试
+ */
+ppp_error_t tcp_test_stop(void)
+{
+ if (!g_tcp_test_manager.global_stats.test_running) {
+ return PPP_ERR_OK;
+ }
+
+ printf("\n正在停止TCP测试...\n");
+
+ // 设置停止标志
+ g_tcp_test_manager.stop_flag = true;
+ g_tcp_test_manager.global_stats.test_running = false;
+ g_tcp_test_manager.global_stats.end_time = tcp_test_get_time_ms();
+
+ // 停止统计定时器
+ if (g_tcp_test_manager.stats_timer_id != 0) {
+ TCP_TIMER_DELETE(g_tcp_test_manager.stats_timer_id);
+ g_tcp_test_manager.stats_timer_id = 0;
+ }
+
+ // 等待所有连接线程结束
+ printf("等待所有连接关闭...\n");
+ TCP_SLEEP_MS(2000); // 给线程时间退出
+
+ // 强制关闭所有socket
+ for (int i = 0; i < g_tcp_test_manager.config.connection_count; i++) {
+ tcp_connection_stats_t *conn = &g_tcp_test_manager.connections[i];
+ if (conn->socket_fd >= 0) {
+ TCP_CLOSE(conn->socket_fd);
+ conn->socket_fd = -1;
+ conn->connected = false;
+ }
+ }
+
+ // 打印最终报告
+ tcp_test_print_report();
+
+ PPP_DEBUG_INFO("TCP test stopped");
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 获取测试状态
+ */
+bool tcp_test_is_running(void)
+{
+ return g_tcp_test_manager.global_stats.test_running;
+}
+
+/**
+ * @brief 获取全局统计信息
+ */
+ppp_error_t tcp_test_get_stats(tcp_global_stats_t *stats)
+{
+ if (!stats) {
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ TCP_MUTEX_LOCK(g_tcp_stats_mutex);
+ memcpy(stats, &g_tcp_test_manager.global_stats, sizeof(tcp_global_stats_t));
+ TCP_MUTEX_UNLOCK(g_tcp_stats_mutex);
+
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 创建连接线程
+ */
+static ppp_error_t tcp_test_create_connection_thread(uint16_t conn_id)
+{
+ uint16_t *arg = malloc(sizeof(uint16_t));
+ if (!arg) {
+ return PPP_ERR_MEMORY;
+ }
+
+ *arg = conn_id;
+
+ TCP_TASK_CREATE(tcp_test_connection_worker, arg, "tcp_test_conn", 8192);
+
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 连接工作线程
+ */
+static void* tcp_test_connection_worker(void *arg)
+{
+ uint16_t conn_id = *(uint16_t*)arg;
+ free(arg);
+
+ tcp_connection_stats_t *conn = &g_tcp_test_manager.connections[conn_id];
+ tcp_test_config_t *config = &g_tcp_test_manager.config;
+
+ conn->thread_running = true;
+
+ uint32_t connect_start = tcp_test_get_time_ms();
+
+ // 建立连接
+ ppp_error_t ret = tcp_test_connect_socket(&conn->socket_fd,
+ config->server_host,
+ config->server_port);
+
+ if (ret != PPP_ERR_OK) {
+ PPP_DEBUG_ERROR("[连接 %03d] 连接失败", conn_id);
+ TCP_MUTEX_LOCK(g_tcp_stats_mutex);
+ g_tcp_test_manager.global_stats.failed_connections++;
+ TCP_MUTEX_UNLOCK(g_tcp_stats_mutex);
+ conn->thread_running = false;
+ return NULL;
+ }
+
+ conn->connected = true;
+ conn->connect_time_ms = tcp_test_get_time_ms() - connect_start;
+
+ TCP_MUTEX_LOCK(g_tcp_stats_mutex);
+ g_tcp_test_manager.global_stats.successful_connections++;
+ TCP_MUTEX_UNLOCK(g_tcp_stats_mutex);
+
+ printf("[连接 %03d] 连接成功,耗时 %d ms\n", conn_id, conn->connect_time_ms);
+
+ // 数据传输循环
+ uint32_t packet_counter = 0;
+ uint8_t send_buffer[TCP_TEST_MAX_DATA_SIZE];
+ uint8_t recv_buffer[TCP_TEST_MAX_DATA_SIZE];
+
+ uint32_t test_end_time = g_tcp_test_manager.global_stats.start_time +
+ (config->test_duration * 1000);
+
+ while (!g_tcp_test_manager.stop_flag &&
+ tcp_test_get_time_ms() < test_end_time) {
+
+ // 生成随机大小的测试数据
+ uint32_t data_size = config->data_min_size +
+ (rand() % (config->data_max_size - config->data_min_size + 1));
+
+ // 生成测试数据
+ ret = tcp_test_generate_data(conn_id, packet_counter, send_buffer, data_size);
+ if (ret != PPP_ERR_OK) {
+ conn->errors++;
+ continue;
+ }
+
+ // 发送数据
+ ssize_t bytes_sent = TCP_SEND(conn->socket_fd, send_buffer, data_size, 0);
+ if (bytes_sent != (ssize_t)data_size) {
+ if (bytes_sent < 0) {
+ PPP_DEBUG_ERROR("[连接 %03d] 发送失败: %s", conn_id, TCP_STRERROR(TCP_GET_ERRNO()));
+ conn->errors++;
+ break;
+ } else {
+ PPP_DEBUG_WARN("[连接 %03d] 发送不完整 (%ld/%d 字节)",
+ conn_id, bytes_sent, data_size);
+ }
+ }
+
+ conn->packets_sent++;
+ conn->bytes_sent += bytes_sent;
+
+ // 接收回显数据
+ ssize_t total_received = 0;
+ uint32_t recv_start = tcp_test_get_time_ms();
+
+ while (total_received < data_size &&
+ (tcp_test_get_time_ms() - recv_start) < (TCP_TEST_RECV_TIMEOUT * 1000)) {
+
+ ssize_t bytes_recv = TCP_RECV(conn->socket_fd,
+ recv_buffer + total_received,
+ data_size - total_received,
+ 0);
+
+ if (bytes_recv > 0) {
+ total_received += bytes_recv;
+ } else if (bytes_recv == 0) {
+ PPP_DEBUG_WARN("[连接 %03d] 连接关闭", conn_id);
+ goto thread_exit;
+ } else {
+ int err = TCP_GET_ERRNO();
+ if (err != TCP_EAGAIN && err != TCP_EWOULDBLOCK) {
+ PPP_DEBUG_ERROR("[连接 %03d] 接收失败: %s", conn_id, TCP_STRERROR(err));
+ conn->errors++;
+ goto thread_exit;
+ }
+ }
+
+ TCP_SLEEP_MS(1); // 1ms延迟
+ }
+
+ if (total_received == data_size) {
+ conn->packets_received++;
+ conn->bytes_received += total_received;
+
+ // 验证数据完整性
+ if (!tcp_test_verify_data(send_buffer, recv_buffer, data_size)) {
+ conn->data_errors++;
+ TCP_MUTEX_LOCK(g_tcp_stats_mutex);
+ g_tcp_test_manager.global_stats.data_verification_errors++;
+ TCP_MUTEX_UNLOCK(g_tcp_stats_mutex);
+ }
+ } else {
+ PPP_DEBUG_WARN("[连接 %03d] 接收数据不完整: %ld/%d 字节",
+ conn_id, total_received, data_size);
+ conn->errors++;
+ }
+
+ // 更新全局统计
+ TCP_MUTEX_LOCK(g_tcp_stats_mutex);
+ g_tcp_test_manager.global_stats.total_packets_sent++;
+ g_tcp_test_manager.global_stats.total_bytes_sent += bytes_sent;
+ if (total_received == data_size) {
+ g_tcp_test_manager.global_stats.total_packets_received++;
+ g_tcp_test_manager.global_stats.total_bytes_received += total_received;
+ } else {
+ g_tcp_test_manager.global_stats.total_errors++;
+ }
+ TCP_MUTEX_UNLOCK(g_tcp_stats_mutex);
+
+ conn->last_activity_time = tcp_test_get_time_ms();
+ packet_counter++;
+
+ // 控制发送频率
+ if (config->send_interval_ms > 0) {
+ TCP_SLEEP_MS(config->send_interval_ms);
+ } else {
+ TCP_SLEEP_MS((rand() % 10 + 1)); // 1-10ms随机延迟
+ }
+ }
+
+thread_exit:
+ // 关闭连接
+ if (conn->socket_fd >= 0) {
+ TCP_CLOSE(conn->socket_fd);
+ conn->socket_fd = -1;
+ }
+
+ conn->connected = false;
+ conn->thread_running = false;
+
+ return NULL;
+}
+
+/**
+ * @brief 建立Socket连接
+ */
+static ppp_error_t tcp_test_connect_socket(int *sock_fd, const char *host, uint16_t port)
+{
+ int fd = TCP_SOCKET(TCP_AF_INET, TCP_SOCK_STREAM, 0);
+ if (fd < 0) {
+ PPP_DEBUG_ERROR("Failed to create socket: %s", TCP_STRERROR(TCP_GET_ERRNO()));
+ return PPP_ERR_UNKNOWN;
+ }
+
+#ifndef USE_LWIP_SOCKET
+ // 设置连接超时 (仅在POSIX环境下)
+ struct timeval timeout;
+ timeout.tv_sec = TCP_TEST_CONNECT_TIMEOUT;
+ timeout.tv_usec = 0;
+
+ if (TCP_SETSOCKOPT(fd, TCP_SOL_SOCKET, TCP_SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0 ||
+ TCP_SETSOCKOPT(fd, TCP_SOL_SOCKET, TCP_SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
+ PPP_DEBUG_WARN("Failed to set socket timeout");
+ }
+#else
+ // 在lwIP环境下设置超时 (使用简化方式)
+ int timeout_ms = TCP_TEST_CONNECT_TIMEOUT * 1000;
+ if (TCP_SETSOCKOPT(fd, TCP_SOL_SOCKET, TCP_SO_RCVTIMEO, &timeout_ms, sizeof(timeout_ms)) < 0 ||
+ TCP_SETSOCKOPT(fd, TCP_SOL_SOCKET, TCP_SO_SNDTIMEO, &timeout_ms, sizeof(timeout_ms)) < 0) {
+ PPP_DEBUG_WARN("Failed to set socket timeout in lwIP");
+ }
+#endif
+
+ struct sockaddr_in server_addr;
+ memset(&server_addr, 0, sizeof(server_addr));
+ server_addr.sin_family = TCP_AF_INET;
+ server_addr.sin_port = TCP_HTONS(port);
+
+ if (TCP_INET_PTON(TCP_AF_INET, host, &server_addr.sin_addr) <= 0) {
+ PPP_DEBUG_ERROR("Invalid server address: %s", host);
+ TCP_CLOSE(fd);
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ if (TCP_CONNECT(fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
+ PPP_DEBUG_ERROR("Failed to connect to %s:%d: %s", host, port, TCP_STRERROR(TCP_GET_ERRNO()));
+ TCP_CLOSE(fd);
+ return PPP_ERR_UNKNOWN;
+ }
+
+ *sock_fd = fd;
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 生成测试数据
+ */
+static ppp_error_t tcp_test_generate_data(uint16_t conn_id, uint32_t packet_id,
+ uint8_t *buffer, uint32_t size)
+{
+ if (!buffer || size < sizeof(tcp_test_packet_header_t)) {
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ tcp_test_packet_header_t *header = (tcp_test_packet_header_t*)buffer;
+ header->conn_id = TCP_HTONS(conn_id);
+ header->packet_id = TCP_HTONL(packet_id);
+ header->data_size = TCP_HTONS(size);
+ header->timestamp = TCP_HTONL(tcp_test_get_time_ms());
+
+ // 填充随机数据
+ for (uint32_t i = sizeof(tcp_test_packet_header_t); i < size - sizeof(uint32_t); i++) {
+ buffer[i] = rand() & 0xFF;
+ }
+
+ // 计算校验和
+ header->checksum = TCP_HTONL(tcp_test_calculate_checksum(buffer, size - sizeof(uint32_t)));
+
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 计算校验和
+ */
+static uint32_t tcp_test_calculate_checksum(const uint8_t *data, uint32_t size)
+{
+ uint32_t checksum = 0;
+ for (uint32_t i = 0; i < size; i++) {
+ checksum += data[i];
+ }
+ return checksum;
+}
+
+/**
+ * @brief 验证数据完整性
+ */
+static bool tcp_test_verify_data(const uint8_t *sent_data, const uint8_t *recv_data, uint32_t size)
+{
+ return memcmp(sent_data, recv_data, size) == 0;
+}
+
+/**
+ * @brief 统计定时器回调
+ */
+static void tcp_test_stats_timer_callback(void *arg)
+{
+ (void)arg;
+
+ if (!g_tcp_test_manager.global_stats.test_running) {
+ return;
+ }
+
+ uint32_t current_time = tcp_test_get_time_ms();
+ uint32_t elapsed = current_time - g_tcp_test_manager.global_stats.start_time;
+ uint32_t remaining = 0;
+
+ if (elapsed < g_tcp_test_manager.config.test_duration * 1000) {
+ remaining = (g_tcp_test_manager.config.test_duration * 1000 - elapsed) / 1000;
+ }
+
+ // 统计活跃连接
+ int active_connections = 0;
+ for (int i = 0; i < g_tcp_test_manager.config.connection_count; i++) {
+ if (g_tcp_test_manager.connections[i].connected) {
+ active_connections++;
+ }
+ }
+
+ TCP_MUTEX_LOCK(g_tcp_stats_mutex);
+
+ char bytes_buf[64];
+ printf("\n=== 实时统计 (已运行: %ds, 剩余: %ds) ===\n", elapsed/1000, remaining);
+ printf("活跃连接: %d\n", active_connections);
+ printf("成功连接: %d\n", g_tcp_test_manager.global_stats.successful_connections);
+ printf("失败连接: %d\n", g_tcp_test_manager.global_stats.failed_connections);
+ printf("发送包数: %llu\n", g_tcp_test_manager.global_stats.total_packets_sent);
+ printf("接收包数: %llu\n", g_tcp_test_manager.global_stats.total_packets_received);
+ printf("发送数据: %s\n", tcp_test_format_bytes(g_tcp_test_manager.global_stats.total_bytes_sent,
+ bytes_buf, sizeof(bytes_buf)));
+
+ // 计算当前吞吐量
+ if (elapsed > 0) {
+ uint64_t throughput = (g_tcp_test_manager.global_stats.total_bytes_sent * 1000) / elapsed;
+ printf("平均吞吐量: %s/s\n", tcp_test_format_bytes(throughput, bytes_buf, sizeof(bytes_buf)));
+ }
+
+ printf("错误总数: %d\n", g_tcp_test_manager.global_stats.total_errors);
+ printf("==========================================\n");
+
+ TCP_MUTEX_UNLOCK(g_tcp_stats_mutex);
+}
+
+/**
+ * @brief 获取当前时间(毫秒) - 导出函数
+ */
+uint32_t tcp_test_get_time_ms(void)
+{
+#ifdef USE_LWIP_SOCKET
+ /* 在lwIP环境中尝试使用真实的时间函数 */
+ #ifdef OSAL_TIME_AVAILABLE
+ /* 如果OSAL时间函数可用,使用它 */
+ return osal_get_time_ms();
+ #else
+ /* 否则使用简化的时间模拟 */
+ static uint32_t start_time = 0;
+ static uint32_t last_time = 0;
+
+ if (start_time == 0) {
+ start_time = 1000; /* 从1秒开始 */
+ last_time = start_time;
+ }
+
+ /* 每次调用增加约1-10ms的随机时间 */
+ last_time += (rand() % 10 + 1);
+ return last_time;
+ #endif
+#else
+ /* 在POSIX环境中使用标准gettimeofday */
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+#endif
+}
+
+/**
+ * @brief 信号处理函数
+ */
+static void tcp_test_signal_handler(int signum)
+{
+ printf("\n收到信号 %d,正在停止测试...\n", signum);
+ tcp_test_stop();
+}
+
+/**
+ * @brief 格式化字节数显示
+ */
+const char* tcp_test_format_bytes(uint64_t bytes, char *buffer, size_t buffer_size)
+{
+ if (!buffer || buffer_size == 0) {
+ return "N/A";
+ }
+
+ if (bytes < 1024) {
+ snprintf(buffer, buffer_size, "%llu B", bytes);
+ } else if (bytes < 1024 * 1024) {
+ snprintf(buffer, buffer_size, "%.1f KB", bytes / 1024.0);
+ } else if (bytes < 1024ULL * 1024 * 1024) {
+ snprintf(buffer, buffer_size, "%.1f MB", bytes / (1024.0 * 1024));
+ } else {
+ snprintf(buffer, buffer_size, "%.1f GB", bytes / (1024.0 * 1024 * 1024));
+ }
+
+ return buffer;
+}
+
+/**
+ * @brief 打印测试报告
+ */
+ppp_error_t tcp_test_print_report(void)
+{
+ uint32_t total_duration = g_tcp_test_manager.global_stats.end_time -
+ g_tcp_test_manager.global_stats.start_time;
+
+ printf("\n========================================\n");
+ printf(" 最终测试报告\n");
+ printf("========================================\n");
+
+ printf("测试配置:\n");
+ printf(" 服务器地址: %s:%d\n", g_tcp_test_manager.config.server_host,
+ g_tcp_test_manager.config.server_port);
+ printf(" 测试时长: %d 秒 (实际: %.2f 秒)\n",
+ g_tcp_test_manager.config.test_duration, total_duration / 1000.0);
+ printf(" 并发连接数: %d\n", g_tcp_test_manager.config.connection_count);
+
+ printf("\n连接统计:\n");
+ printf(" 成功连接: %d\n", g_tcp_test_manager.global_stats.successful_connections);
+ printf(" 失败连接: %d\n", g_tcp_test_manager.global_stats.failed_connections);
+
+ if (g_tcp_test_manager.config.connection_count > 0) {
+ printf(" 连接成功率: %.1f%%\n",
+ (float)g_tcp_test_manager.global_stats.successful_connections /
+ g_tcp_test_manager.config.connection_count * 100);
+ }
+
+ printf("\n数据传输统计:\n");
+ printf(" 发送包数: %llu\n", g_tcp_test_manager.global_stats.total_packets_sent);
+ printf(" 接收包数: %llu\n", g_tcp_test_manager.global_stats.total_packets_received);
+
+ if (g_tcp_test_manager.global_stats.total_packets_sent > 0) {
+ printf(" 包传输成功率: %.1f%%\n",
+ (float)g_tcp_test_manager.global_stats.total_packets_received /
+ g_tcp_test_manager.global_stats.total_packets_sent * 100);
+ }
+
+ char bytes_buf[64];
+ printf(" 发送数据总量: %s\n",
+ tcp_test_format_bytes(g_tcp_test_manager.global_stats.total_bytes_sent,
+ bytes_buf, sizeof(bytes_buf)));
+ printf(" 接收数据总量: %s\n",
+ tcp_test_format_bytes(g_tcp_test_manager.global_stats.total_bytes_received,
+ bytes_buf, sizeof(bytes_buf)));
+
+ if (total_duration > 0) {
+ uint64_t avg_throughput = (g_tcp_test_manager.global_stats.total_bytes_sent * 1000) / total_duration;
+ float avg_pps = (float)g_tcp_test_manager.global_stats.total_packets_sent * 1000 / total_duration;
+
+ printf("\n性能统计:\n");
+ printf(" 平均吞吐量: %s/s\n", tcp_test_format_bytes(avg_throughput, bytes_buf, sizeof(bytes_buf)));
+ printf(" 平均包速率: %.1f 包/秒\n", avg_pps);
+
+ if (g_tcp_test_manager.global_stats.total_packets_sent > 0) {
+ printf(" 平均包大小: %.1f 字节\n",
+ (float)g_tcp_test_manager.global_stats.total_bytes_sent /
+ g_tcp_test_manager.global_stats.total_packets_sent);
+ }
+ }
+
+ printf("\n错误统计:\n");
+ printf(" 传输错误: %d\n", g_tcp_test_manager.global_stats.total_errors);
+ printf(" 数据校验错误: %d\n", g_tcp_test_manager.global_stats.data_verification_errors);
+
+ if (g_tcp_test_manager.global_stats.total_packets_sent > 0) {
+ printf(" 错误率: %.3f%%\n",
+ (float)g_tcp_test_manager.global_stats.total_errors /
+ g_tcp_test_manager.global_stats.total_packets_sent * 100);
+ }
+
+ printf("========================================\n");
+
+ return PPP_ERR_OK;
+}
\ No newline at end of file
--- /dev/null
+/**
+ * @file ppp_tcp_test_main.c
+ * @brief PPP TCP性能测试客户端主程序
+ *
+ * 提供命令行参数解析和测试程序入口
+ * 支持与Python版本相同的参数格式
+ */
+
+#include "ppp_tcp_test.h"
+#include "ppp_debug.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+
+/**
+ * @brief 打印使用帮助
+ */
+void tcp_test_print_help(void)
+{
+ printf("TCP性能测试客户端\n");
+ printf("用法: tcp_test [选项]\n\n");
+ printf("选项:\n");
+ printf(" -H, --host <地址> 服务器地址 (默认: %s)\n", TCP_TEST_DEFAULT_HOST);
+ printf(" -P, --port <端口> 服务器端口 (默认: %d)\n", TCP_TEST_DEFAULT_PORT);
+ printf(" -t, --time <秒数> 测试时间(秒) (默认: %d)\n", TCP_TEST_DEFAULT_TIME);
+ printf(" -c, --connections <数量> 并发连接数 (默认: %d, 最大: %d)\n",
+ TCP_TEST_DEFAULT_CONNECTIONS, TCP_TEST_MAX_CONNECTIONS);
+ printf(" -v, --verbose 详细输出模式\n");
+ printf(" -i, --interval <毫秒> 发送间隔(毫秒) (默认: 自动)\n");
+ printf(" --min-size <字节> 最小数据包大小 (默认: %d)\n", TCP_TEST_MIN_DATA_SIZE);
+ printf(" --max-size <字节> 最大数据包大小 (默认: %d)\n", TCP_TEST_MAX_DATA_SIZE);
+ printf(" -h, --help 显示此帮助信息\n\n");
+ printf("示例:\n");
+ printf(" tcp_test --host 192.168.1.100 --port 8080 --connections 5 --time 60\n");
+ printf(" tcp_test -H 110.42.224.129 -P 8910 -c 10 -t 30 -v\n");
+ printf(" tcp_test --host echo.server.com --port 7777 --verbose\n\n");
+ printf("说明:\n");
+ printf(" - 测试需要服务器支持TCP回显(echo)功能\n");
+ printf(" - 程序会发送测试数据并验证服务器返回的回显数据\n");
+ printf(" - 使用Ctrl+C可以提前终止测试\n");
+}
+
+/**
+ * @brief 解析命令行参数
+ */
+ppp_error_t tcp_test_parse_args(int argc, char *argv[], tcp_test_config_t *config)
+{
+ if (!config) {
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ // 设置默认值
+ strncpy(config->server_host, TCP_TEST_DEFAULT_HOST, sizeof(config->server_host) - 1);
+ config->server_host[sizeof(config->server_host) - 1] = '\0';
+ config->server_port = TCP_TEST_DEFAULT_PORT;
+ config->test_duration = TCP_TEST_DEFAULT_TIME;
+ config->connection_count = TCP_TEST_DEFAULT_CONNECTIONS;
+ config->verbose = false;
+ config->send_interval_ms = 0; // 自动
+ config->data_min_size = TCP_TEST_MIN_DATA_SIZE;
+ config->data_max_size = TCP_TEST_MAX_DATA_SIZE;
+
+ // 长选项定义
+ static struct option long_options[] = {
+ {"host", required_argument, 0, 'H'},
+ {"port", required_argument, 0, 'P'},
+ {"time", required_argument, 0, 't'},
+ {"connections", required_argument, 0, 'c'},
+ {"verbose", no_argument, 0, 'v'},
+ {"interval", required_argument, 0, 'i'},
+ {"min-size", required_argument, 0, 1000},
+ {"max-size", required_argument, 0, 1001},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ int option_index = 0;
+ int c;
+
+ while ((c = getopt_long(argc, argv, "H:P:t:c:vi:h", long_options, &option_index)) != -1) {
+ switch (c) {
+ case 'H':
+ strncpy(config->server_host, optarg, sizeof(config->server_host) - 1);
+ config->server_host[sizeof(config->server_host) - 1] = '\0';
+ break;
+
+ case 'P':
+ {
+ int port = atoi(optarg);
+ if (port < 1 || port > 65535) {
+ fprintf(stderr, "错误: 端口号必须在 1-65535 范围内\n");
+ return PPP_ERR_INVALID_PARAM;
+ }
+ config->server_port = (uint16_t)port;
+ }
+ break;
+
+ case 't':
+ {
+ int time = atoi(optarg);
+ if (time < 1) {
+ fprintf(stderr, "错误: 测试时间必须大于0秒\n");
+ return PPP_ERR_INVALID_PARAM;
+ }
+ config->test_duration = (uint32_t)time;
+ }
+ break;
+
+ case 'c':
+ {
+ int connections = atoi(optarg);
+ if (connections < 1 || connections > TCP_TEST_MAX_CONNECTIONS) {
+ fprintf(stderr, "错误: 连接数必须在 1-%d 范围内\n", TCP_TEST_MAX_CONNECTIONS);
+ return PPP_ERR_INVALID_PARAM;
+ }
+ config->connection_count = (uint16_t)connections;
+ }
+ break;
+
+ case 'v':
+ config->verbose = true;
+ break;
+
+ case 'i':
+ {
+ int interval = atoi(optarg);
+ if (interval < 0) {
+ fprintf(stderr, "错误: 发送间隔不能为负数\n");
+ return PPP_ERR_INVALID_PARAM;
+ }
+ config->send_interval_ms = (uint32_t)interval;
+ }
+ break;
+
+ case 1000: // --min-size
+ {
+ int min_size = atoi(optarg);
+ if (min_size < 1 || min_size > TCP_TEST_MAX_DATA_SIZE) {
+ fprintf(stderr, "错误: 最小数据包大小必须在 1-%d 范围内\n", TCP_TEST_MAX_DATA_SIZE);
+ return PPP_ERR_INVALID_PARAM;
+ }
+ config->data_min_size = (uint32_t)min_size;
+ }
+ break;
+
+ case 1001: // --max-size
+ {
+ int max_size = atoi(optarg);
+ if (max_size < 1 || max_size > TCP_TEST_MAX_DATA_SIZE) {
+ fprintf(stderr, "错误: 最大数据包大小必须在 1-%d 范围内\n", TCP_TEST_MAX_DATA_SIZE);
+ return PPP_ERR_INVALID_PARAM;
+ }
+ config->data_max_size = (uint32_t)max_size;
+ }
+ break;
+
+ case 'h':
+ tcp_test_print_help();
+ exit(0);
+ break;
+
+ case '?':
+ fprintf(stderr, "未知选项。使用 -h 或 --help 查看帮助信息。\n");
+ return PPP_ERR_INVALID_PARAM;
+
+ default:
+ return PPP_ERR_INVALID_PARAM;
+ }
+ }
+
+ // 验证参数逻辑
+ if (config->data_min_size > config->data_max_size) {
+ fprintf(stderr, "错误: 最小数据包大小不能大于最大数据包大小\n");
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ if (config->data_min_size < sizeof(tcp_test_packet_header_t)) {
+ fprintf(stderr, "错误: 最小数据包大小至少需要 %lu 字节 (包头大小)\n",
+ sizeof(tcp_test_packet_header_t));
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 打印配置信息
+ */
+static void print_config(const tcp_test_config_t *config)
+{
+ printf("测试配置:\n");
+ printf(" 服务器: %s:%d\n", config->server_host, config->server_port);
+ printf(" 测试时间: %d 秒\n", config->test_duration);
+ printf(" 并发连接: %d\n", config->connection_count);
+ printf(" 数据包大小: %d-%d 字节\n", config->data_min_size, config->data_max_size);
+ printf(" 详细输出: %s\n", config->verbose ? "是" : "否");
+
+ if (config->send_interval_ms > 0) {
+ printf(" 发送间隔: %d 毫秒\n", config->send_interval_ms);
+ } else {
+ printf(" 发送间隔: 自动(1-10毫秒随机)\n");
+ }
+ printf("\n");
+}
+
+/**
+ * @brief 主函数
+ */
+int main(int argc, char *argv[])
+{
+ tcp_test_config_t config;
+ ppp_error_t ret;
+
+ printf("PPP TCP性能测试客户端 v1.0\n");
+ printf("基于Python版本tcp_test_client.py实现\n\n");
+
+ // 解析命令行参数
+ ret = tcp_test_parse_args(argc, argv, &config);
+ if (ret != PPP_ERR_OK) {
+ fprintf(stderr, "参数解析失败\n");
+ return 1;
+ }
+
+ // 显示配置
+ print_config(&config);
+
+ // 初始化TCP测试
+ ret = tcp_test_init();
+ if (ret != PPP_ERR_OK) {
+ fprintf(stderr, "TCP测试初始化失败: %d\n", ret);
+ return 1;
+ }
+
+ // 启动测试
+ ret = tcp_test_start(&config);
+ if (ret != PPP_ERR_OK) {
+ fprintf(stderr, "TCP测试启动失败: %d\n", ret);
+ tcp_test_deinit();
+ return 1;
+ }
+
+ // 等待测试完成
+ printf("测试运行中,使用 Ctrl+C 可提前停止...\n\n");
+
+ // 等待测试时间结束
+ uint32_t test_end_time = time(NULL) + config.test_duration;
+ while (tcp_test_is_running() && time(NULL) < test_end_time) {
+ sleep(1);
+ }
+
+ // 停止测试
+ if (tcp_test_is_running()) {
+ printf("\n测试时间到达,正在停止...\n");
+ tcp_test_stop();
+ }
+
+ // 清理资源
+ tcp_test_deinit();
+
+ printf("\nTCP性能测试完成。\n");
+ return 0;
+}
\ No newline at end of file
#define PPP_UART_BAUDRATE 2000000
/* 支持的波特率列表(自适应模式) */
-#define PPP_BAUDRATE_AUTO_LIST {9600, 57600, 115200, 921600}
+#define PPP_BAUDRATE_AUTO_LIST {9600, 57600, 115200}
#define PPP_BAUDRATE_AUTO_COUNT 4
/* 支持的固定波特率列表 */
/* 调试配置 */
#define PPP_DEBUG_ENABLE 1 // 启用调试输出
-#define PPP_DEBUG_LEVEL PPP_DEBUG_LEVEL_DEBUG // 默认只显示警告和错误 (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG)
+#define PPP_DEBUG_LEVEL PPP_DEBUG_LEVEL_WARN // 默认只显示警告和错误 (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG)
/*
* 调试级别说明:
#if PPP_DEBUG_ENABLE
+/* 前向声明动态调试级别函数 */
+extern int ppp_debug_get_level(void);
+
#define PPP_DEBUG_ERROR(fmt, ...) \
do { \
- if (PPP_DEBUG_LEVEL >= PPP_DEBUG_LEVEL_ERROR) { \
+ if (ppp_debug_get_level() >= PPP_DEBUG_LEVEL_ERROR) { \
PRINT("[PPP ERROR] " fmt "\r\n", ##__VA_ARGS__); \
} \
} while(0)
#define PPP_DEBUG_WARN(fmt, ...) \
do { \
- if (PPP_DEBUG_LEVEL >= PPP_DEBUG_LEVEL_WARN) { \
+ if (ppp_debug_get_level() >= PPP_DEBUG_LEVEL_WARN) { \
PRINT("[PPP WARN] " fmt "\r\n", ##__VA_ARGS__); \
} \
} while(0)
#define PPP_DEBUG_INFO(fmt, ...) \
do { \
- if (PPP_DEBUG_LEVEL >= PPP_DEBUG_LEVEL_INFO) { \
+ if (ppp_debug_get_level() >= PPP_DEBUG_LEVEL_INFO) { \
PRINT("[PPP INFO] " fmt "\r\n", ##__VA_ARGS__); \
} \
} while(0)
#define PPP_DEBUG_DEBUG(fmt, ...) \
do { \
- if (PPP_DEBUG_LEVEL >= PPP_DEBUG_LEVEL_DEBUG) { \
+ if (ppp_debug_get_level() >= PPP_DEBUG_LEVEL_DEBUG) { \
PRINT("[PPP DEBUG] " fmt "\r\n", ##__VA_ARGS__); \
} \
} while(0)
#define PPP_DEBUG_HEXDUMP(data, len) \
do { \
- if (PPP_DEBUG_LEVEL >= PPP_DEBUG_LEVEL_DEBUG) { \
+ if (ppp_debug_get_level() >= PPP_DEBUG_LEVEL_DEBUG) { \
ppp_debug_hexdump(data, len); \
} \
} while(0)
/* 兼容性宏 - 用于旧代码 */
#define PPP_DEBUG_PRINT(fmt, ...) \
do { \
- if (PPP_DEBUG_LEVEL >= PPP_DEBUG_LEVEL_INFO) { \
+ if (ppp_debug_get_level() >= PPP_DEBUG_LEVEL_INFO) { \
print_str(fmt, ##__VA_ARGS__); \
} \
} while(0)
--- /dev/null
+/**
+ * @file ppp_debug_manager.h
+ * @brief PPP调试级别动态管理模块头文件
+ */
+
+#ifndef PPP_DEBUG_MANAGER_H
+#define PPP_DEBUG_MANAGER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ppp_types.h"
+
+/**
+ * @brief 获取当前动态调试级别
+ * @return 当前调试级别
+ */
+int ppp_debug_get_level(void);
+
+/**
+ * @brief 设置动态调试级别
+ * @param level 调试级别 (0-4)
+ * @return PPP_ERR_OK-成功,其他-失败
+ */
+ppp_error_t ppp_debug_set_level(int level);
+
+/**
+ * @brief 获取调试级别名称
+ * @param level 调试级别
+ * @return 级别名称字符串
+ */
+const char* ppp_debug_get_level_name(int level);
+
+/**
+ * @brief 根据名称设置调试级别
+ * @param level_name 级别名称 ("NONE", "ERROR", "WARN", "INFO", "DEBUG")
+ * @return PPP_ERR_OK-成功,其他-失败
+ */
+ppp_error_t ppp_debug_set_level_by_name(const char* level_name);
+
+/**
+ * @brief 重置调试级别为默认值
+ * @return PPP_ERR_OK-成功
+ */
+ppp_error_t ppp_debug_reset_level(void);
+
+/**
+ * @brief 检查指定级别是否启用
+ * @param level 要检查的级别
+ * @return true-启用,false-未启用
+ */
+bool ppp_debug_is_level_enabled(int level);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PPP_DEBUG_MANAGER_H */
\ No newline at end of file
*/
struct netif *ppp_lwip_get_netif(void);
+
+/**
+ * @brief 获取本地IP地址字符串
+ * @return IP地址字符串(静态缓冲区,非线程安全)
+ */
+const char* ppp_lwip_get_ip_address(void);
+
+/**
+ * @brief 获取子网掩码字符串
+ * @return 子网掩码字符串(静态缓冲区,非线程安全)
+ */
+const char* ppp_lwip_get_netmask(void);
+
+/**
+ * @brief 获取网关地址字符串
+ * @return 网关地址字符串(静态缓冲区,非线程安全)
+ */
+const char* ppp_lwip_get_gateway(void);
+
+/**
+ * @brief 获取DNS服务器地址字符串(主/备,用逗号分隔)
+ * @return DNS地址字符串(静态缓冲区,非线程安全)
+ */
+const char* ppp_lwip_get_dns(void);
#ifdef __cplusplus
}
#endif
--- /dev/null
+/**
+ * @file ppp_tcp_lwip_compat.h
+ * @brief lwIP socket接口兼容性定义
+ *
+ * 处理lwIP socket接口中可能缺失的定义和兼容性问题
+ */
+
+#ifndef PPP_TCP_LWIP_COMPAT_H
+#define PPP_TCP_LWIP_COMPAT_H
+
+#ifdef USE_LWIP_SOCKET
+
+#include "lwip/sockets.h"
+#include "lwip/netdb.h"
+
+/* 确保必要的socket结构体可用 */
+#ifndef AF_INET
+#define AF_INET 2
+#endif
+
+#ifndef SOCK_STREAM
+#define SOCK_STREAM 1
+#endif
+
+#ifndef SOL_SOCKET
+#define SOL_SOCKET 1
+#endif
+
+/* 如果lwIP没有定义这些错误码,提供默认值 */
+#ifndef EAGAIN
+#define EAGAIN 11
+#endif
+
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif
+
+#ifndef EINTR
+#define EINTR 4
+#endif
+
+#ifndef ECONNRESET
+#define ECONNRESET 104
+#endif
+
+#ifndef ETIMEDOUT
+#define ETIMEDOUT 110
+#endif
+
+/* 如果lwIP没有定义这些socket选项,提供默认值 */
+#ifndef SO_RCVTIMEO
+#define SO_RCVTIMEO 20
+#endif
+
+#ifndef SO_SNDTIMEO
+#define SO_SNDTIMEO 21
+#endif
+
+/* 如果lwIP没有定义inet_pton,提供简化实现 */
+#ifndef LWIP_INET_PTON
+static inline int lwip_inet_pton_simple(int af, const char *src, void *dst)
+{
+ if (af != AF_INET) {
+ return -1;
+ }
+
+ /* 简化的IPv4地址解析 */
+ unsigned int a, b, c, d;
+ if (sscanf(src, "%u.%u.%u.%u", &a, &b, &c, &d) == 4) {
+ if (a <= 255 && b <= 255 && c <= 255 && d <= 255) {
+ uint32_t *addr = (uint32_t*)dst;
+ *addr = (a << 24) | (b << 16) | (c << 8) | d;
+ *addr = lwip_htonl(*addr);
+ return 1;
+ }
+ }
+ return 0;
+}
+#define lwip_inet_pton lwip_inet_pton_simple
+#endif
+
+/* 确保必要的字节序转换函数存在 */
+// #ifndef lwip_htons
+// #define lwip_htons(x) htons(x)
+// #endif
+
+// #ifndef lwip_htonl
+// #define lwip_htonl(x) htonl(x)
+// #endif
+
+// #ifndef lwip_ntohs
+// #define lwip_ntohs(x) ntohs(x)
+// #endif
+
+// #ifndef lwip_ntohl
+// #define lwip_ntohl(x) ntohl(x)
+// #endif
+
+/* errno处理 */
+#ifndef errno
+extern int errno;
+#endif
+
+#endif /* USE_LWIP_SOCKET */
+
+#endif /* PPP_TCP_LWIP_COMPAT_H */
\ No newline at end of file
--- /dev/null
+/**
+ * @file ppp_tcp_test.h
+ * @brief PPP TCP性能测试客户端头文件
+ *
+ * 功能:
+ * - 支持参数配置:服务器地址、端口、测试时间、连接数
+ * - 多连接并发测试
+ * - 性能统计和报告
+ * - 数据发送和接收验证
+ */
+
+#ifndef PPP_TCP_TEST_H
+#define PPP_TCP_TEST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <time.h>
+#include "ppp_types.h"
+#define USE_LWIP_SOCKET
+
+/* Socket接口兼容性宏定义 */
+#ifdef USE_LWIP_SOCKET
+ /* 使用lwIP的socket接口 */
+ #include "lwip/sockets.h"
+ #include "lwip/netdb.h"
+ #include "lwip/sys.h"
+ #include "ppp_tcp_lwip_compat.h" /* 兼容性定义 */
+
+ #define TCP_SOCKET(domain, type, protocol) lwip_socket(domain, type, protocol)
+ #define TCP_CONNECT(s, name, namelen) lwip_connect(s, name, namelen)
+ #define TCP_SEND(s, dataptr, size, flags) lwip_send(s, dataptr, size, flags)
+ #define TCP_RECV(s, mem, len, flags) lwip_recv(s, mem, len, flags)
+ #define TCP_CLOSE(s) lwip_close(s)
+ #define TCP_SETSOCKOPT(s, level, optname, optval, optlen) lwip_setsockopt(s, level, optname, optval, optlen)
+ #define TCP_GETSOCKOPT(s, level, optname, optval, optlen) lwip_getsockopt(s, level, optname, optval, optlen)
+ #define TCP_INET_PTON(af, src, dst) lwip_inet_pton(af, src, dst)
+ #define TCP_HTONS(n) lwip_htons(n)
+ #define TCP_HTONL(n) lwip_htonl(n)
+ #define TCP_NTOHS(n) lwip_ntohs(n)
+ #define TCP_NTOHL(n) lwip_ntohl(n)
+
+ /* lwIP错误码定义 */
+ #define TCP_EAGAIN EAGAIN
+ #define TCP_EWOULDBLOCK EWOULDBLOCK
+ #define TCP_EINTR EINTR
+ #define TCP_ECONNRESET ECONNRESET
+ #define TCP_ETIMEDOUT ETIMEDOUT
+
+ /* lwIP socket选项 */
+ #define TCP_SOL_SOCKET SOL_SOCKET
+ #define TCP_SO_RCVTIMEO SO_RCVTIMEO
+ #define TCP_SO_SNDTIMEO SO_SNDTIMEO
+ #define TCP_AF_INET AF_INET
+ #define TCP_SOCK_STREAM SOCK_STREAM
+
+ /* 获取错误号 */
+ #define TCP_GET_ERRNO() errno
+
+#else
+ /* 使用标准socket接口 */
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <netdb.h>
+ #include <errno.h>
+ #include <unistd.h>
+
+ #define TCP_SOCKET(domain, type, protocol) socket(domain, type, protocol)
+ #define TCP_CONNECT(s, name, namelen) connect(s, name, namelen)
+ #define TCP_SEND(s, dataptr, size, flags) send(s, dataptr, size, flags)
+ #define TCP_RECV(s, mem, len, flags) recv(s, mem, len, flags)
+ #define TCP_CLOSE(s) close(s)
+ #define TCP_SETSOCKOPT(s, level, optname, optval, optlen) setsockopt(s, level, optname, optval, optlen)
+ #define TCP_GETSOCKOPT(s, level, optname, optval, optlen) getsockopt(s, level, optname, optval, optlen)
+ #define TCP_INET_PTON(af, src, dst) inet_pton(af, src, dst)
+ #define TCP_HTONS(n) htons(n)
+ #define TCP_HTONL(n) htonl(n)
+ #define TCP_NTOHS(n) ntohs(n)
+ #define TCP_NTOHL(n) ntohl(n)
+
+ /* 标准错误码定义 */
+ #define TCP_EAGAIN EAGAIN
+ #define TCP_EWOULDBLOCK EWOULDBLOCK
+ #define TCP_EINTR EINTR
+ #define TCP_ECONNRESET ECONNRESET
+ #define TCP_ETIMEDOUT ETIMEDOUT
+
+ /* 标准socket选项 */
+ #define TCP_SOL_SOCKET SOL_SOCKET
+ #define TCP_SO_RCVTIMEO SO_RCVTIMEO
+ #define TCP_SO_SNDTIMEO SO_SNDTIMEO
+ #define TCP_AF_INET AF_INET
+ #define TCP_SOCK_STREAM SOCK_STREAM
+
+ /* 获取错误号 */
+ #define TCP_GET_ERRNO() errno
+
+#endif
+
+/* TCP测试配置 */
+#define TCP_TEST_MAX_CONNECTIONS 50 // 最大连接数
+#define TCP_TEST_MIN_DATA_SIZE 1 // 最小数据包大小
+#define TCP_TEST_MAX_DATA_SIZE 4096 // 最大数据包大小
+#define TCP_TEST_STATS_INTERVAL 5 // 统计报告间隔(秒)
+#define TCP_TEST_CONNECT_TIMEOUT 10 // 连接超时时间(秒)
+#define TCP_TEST_RECV_TIMEOUT 1 // 接收超时时间(秒)
+#define TCP_TEST_DEFAULT_HOST "110.42.224.129"
+#define TCP_TEST_DEFAULT_PORT 8910
+#define TCP_TEST_DEFAULT_TIME 30
+#define TCP_TEST_DEFAULT_CONNECTIONS 10
+
+/* TCP测试配置结构体 */
+typedef struct {
+ char server_host[256]; // 服务器地址
+ uint16_t server_port; // 服务器端口
+ uint32_t test_duration; // 测试时间(秒)
+ uint16_t connection_count; // 连接数
+ bool verbose; // 详细输出
+ uint32_t send_interval_ms; // 发送间隔(毫秒)
+ uint32_t data_min_size; // 最小数据包大小
+ uint32_t data_max_size; // 最大数据包大小
+} tcp_test_config_t;
+
+/* 单个连接统计信息 */
+typedef struct {
+ uint16_t conn_id; // 连接ID
+ int socket_fd; // socket文件描述符
+ bool connected; // 连接状态
+ uint32_t connect_time_ms; // 连接耗时(毫秒)
+ uint32_t packets_sent; // 发送包数
+ uint32_t packets_received; // 接收包数
+ uint64_t bytes_sent; // 发送字节数
+ uint64_t bytes_received; // 接收字节数
+ uint32_t errors; // 错误数
+ uint32_t data_errors; // 数据校验错误数
+ uint32_t last_activity_time; // 最后活动时间
+ uint64_t throughput_bps; // 当前吞吐量(字节/秒)
+ uint64_t max_throughput_bps; // 最大吞吐量(字节/秒)
+ bool thread_running; // 线程运行状态
+} tcp_connection_stats_t;
+
+/* 全局测试统计信息 */
+typedef struct {
+ uint32_t start_time; // 测试开始时间
+ uint32_t end_time; // 测试结束时间
+ uint16_t successful_connections; // 成功连接数
+ uint16_t failed_connections; // 失败连接数
+ uint64_t total_packets_sent; // 总发送包数
+ uint64_t total_packets_received; // 总接收包数
+ uint64_t total_bytes_sent; // 总发送字节数
+ uint64_t total_bytes_received; // 总接收字节数
+ uint32_t total_errors; // 总错误数
+ uint32_t data_verification_errors; // 数据校验错误数
+ uint64_t max_throughput_bps; // 最大吞吐量(字节/秒)
+ uint64_t avg_throughput_bps; // 平均吞吐量(字节/秒)
+ bool test_running; // 测试运行状态
+} tcp_global_stats_t;
+
+/* TCP测试管理器 */
+typedef struct {
+ tcp_test_config_t config; // 配置信息
+ tcp_connection_stats_t connections[TCP_TEST_MAX_CONNECTIONS]; // 连接统计
+ tcp_global_stats_t global_stats; // 全局统计
+ volatile bool stop_flag; // 停止标志
+ uint32_t stats_timer_id; // 统计定时器ID
+} tcp_test_manager_t;
+
+/* 测试数据包头结构 */
+typedef struct {
+ uint16_t conn_id; // 连接ID
+ uint32_t packet_id; // 包ID
+ uint16_t data_size; // 数据大小
+ uint32_t timestamp; // 时间戳
+ uint32_t checksum; // 校验和
+} __attribute__((packed)) tcp_test_packet_header_t;
+
+/**
+ * @brief 初始化TCP测试
+ * @return PPP_ERR_OK-成功,其他-失败
+ */
+ppp_error_t tcp_test_init(void);
+
+/**
+ * @brief 反初始化TCP测试
+ * @return PPP_ERR_OK-成功,其他-失败
+ */
+ppp_error_t tcp_test_deinit(void);
+
+/**
+ * @brief 启动TCP测试
+ * @param config 测试配置
+ * @return PPP_ERR_OK-成功,其他-失败
+ */
+ppp_error_t tcp_test_start(const tcp_test_config_t *config);
+
+/**
+ * @brief 停止TCP测试
+ * @return PPP_ERR_OK-成功,其他-失败
+ */
+ppp_error_t tcp_test_stop(void);
+
+/**
+ * @brief 获取测试状态
+ * @return true-正在运行,false-已停止
+ */
+bool tcp_test_is_running(void);
+
+/**
+ * @brief 获取全局统计信息
+ * @param stats 统计信息输出
+ * @return PPP_ERR_OK-成功,其他-失败
+ */
+ppp_error_t tcp_test_get_stats(tcp_global_stats_t *stats);
+
+/**
+ * @brief 获取连接统计信息
+ * @param conn_id 连接ID
+ * @param stats 连接统计信息输出
+ * @return PPP_ERR_OK-成功,其他-失败
+ */
+ppp_error_t tcp_test_get_connection_stats(uint16_t conn_id, tcp_connection_stats_t *stats);
+
+/**
+ * @brief 打印测试报告
+ * @return PPP_ERR_OK-成功,其他-失败
+ */
+ppp_error_t tcp_test_print_report(void);
+
+/**
+ * @brief 格式化字节数显示
+ * @param bytes 字节数
+ * @param buffer 输出缓冲区
+ * @param buffer_size 缓冲区大小
+ * @return 格式化后的字符串
+ */
+const char* tcp_test_format_bytes(uint64_t bytes, char *buffer, size_t buffer_size);
+
+/**
+ * @brief 获取当前时间(毫秒) - 导出给AT命令使用
+ * @return 当前时间(毫秒)
+ */
+uint32_t tcp_test_get_time_ms(void);
+
+/**
+ * @brief 解析命令行参数
+ * @param argc 参数个数
+ * @param argv 参数数组
+ * @param config 配置输出
+ * @return PPP_ERR_OK-成功,其他-失败
+ */
+ppp_error_t tcp_test_parse_args(int argc, char *argv[], tcp_test_config_t *config);
+
+/**
+ * @brief 打印使用帮助
+ */
+void tcp_test_print_help(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PPP_TCP_TEST_H */
\ No newline at end of file
--- /dev/null
+/**
+ * @file ppp_debug_manager.c
+ * @brief PPP调试级别动态管理模块
+ *
+ * 提供运行时动态调整PPP调试输出级别的功能
+ */
+
+#include "ppp_debug_manager.h"
+#include "ppp_debug.h"
+#include "ppp_config.h"
+#include <string.h>
+
+/* 全局调试级别变量 */
+static volatile int g_ppp_dynamic_debug_level = PPP_DEBUG_LEVEL;
+
+/**
+ * @brief 获取当前动态调试级别
+ * @return 当前调试级别
+ */
+int ppp_debug_get_level(void)
+{
+ return g_ppp_dynamic_debug_level;
+}
+
+/**
+ * @brief 设置动态调试级别
+ * @param level 调试级别 (0-4)
+ * @return PPP_ERR_OK-成功,其他-失败
+ */
+ppp_error_t ppp_debug_set_level(int level)
+{
+ if (level < PPP_DEBUG_LEVEL_NONE || level > PPP_DEBUG_LEVEL_DEBUG) {
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ g_ppp_dynamic_debug_level = level;
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 获取调试级别名称
+ * @param level 调试级别
+ * @return 级别名称字符串
+ */
+const char* ppp_debug_get_level_name(int level)
+{
+ switch (level) {
+ case PPP_DEBUG_LEVEL_NONE: return "NONE";
+ case PPP_DEBUG_LEVEL_ERROR: return "ERROR";
+ case PPP_DEBUG_LEVEL_WARN: return "WARN";
+ case PPP_DEBUG_LEVEL_INFO: return "INFO";
+ case PPP_DEBUG_LEVEL_DEBUG: return "DEBUG";
+ default: return "UNKNOWN";
+ }
+}
+
+/**
+ * @brief 根据名称设置调试级别
+ * @param level_name 级别名称 ("NONE", "ERROR", "WARN", "INFO", "DEBUG")
+ * @return PPP_ERR_OK-成功,其他-失败
+ */
+ppp_error_t ppp_debug_set_level_by_name(const char* level_name)
+{
+ if (!level_name) {
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ if (strcasecmp(level_name, "NONE") == 0) {
+ return ppp_debug_set_level(PPP_DEBUG_LEVEL_NONE);
+ } else if (strcasecmp(level_name, "ERROR") == 0) {
+ return ppp_debug_set_level(PPP_DEBUG_LEVEL_ERROR);
+ } else if (strcasecmp(level_name, "WARN") == 0) {
+ return ppp_debug_set_level(PPP_DEBUG_LEVEL_WARN);
+ } else if (strcasecmp(level_name, "INFO") == 0) {
+ return ppp_debug_set_level(PPP_DEBUG_LEVEL_INFO);
+ } else if (strcasecmp(level_name, "DEBUG") == 0) {
+ return ppp_debug_set_level(PPP_DEBUG_LEVEL_DEBUG);
+ } else {
+ return PPP_ERR_INVALID_PARAM;
+ }
+}
+
+/**
+ * @brief 重置调试级别为默认值
+ * @return PPP_ERR_OK-成功
+ */
+ppp_error_t ppp_debug_reset_level(void)
+{
+ g_ppp_dynamic_debug_level = PPP_DEBUG_LEVEL;
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 检查指定级别是否启用
+ * @param level 要检查的级别
+ * @return true-启用,false-未启用
+ */
+bool ppp_debug_is_level_enabled(int level)
+{
+ return g_ppp_dynamic_debug_level >= level;
+}
\ No newline at end of file
#include "lwip/dns.h"
#include "netif/ppp/ppp.h"
#include "netif/ppp/pppos.h"
+#include "netif/ppp/pppapi.h" // 添加pppapi头文件,用于线程安全的PPP API
#include "lwip/sio.h" // 添加SIO头文件
#endif
memset_s(g_lwip_ctx.netif, sizeof(struct netif), 0, sizeof(struct netif));
- /* 创建PPPoS接口 */
- g_lwip_ctx.ppp_pcb = pppos_create(g_lwip_ctx.netif,
- ppp_lwip_output_callback,
- ppp_lwip_link_status_callback,
- &g_lwip_ctx);
+ /* 创建PPPoS接口 - 使用线程安全的API */
+ PPP_DEBUG_INFO("Creating PPPoS interface using thread-safe API...");
+ g_lwip_ctx.ppp_pcb = pppapi_pppos_create(g_lwip_ctx.netif,
+ ppp_lwip_output_callback,
+ ppp_lwip_link_status_callback,
+ &g_lwip_ctx);
if (!g_lwip_ctx.ppp_pcb) {
PPP_DEBUG_ERROR("Failed to create PPPoS interface");
/* 删除PPP控制块 */
if (g_lwip_ctx.ppp_pcb) {
PPP_DEBUG_INFO("Freeing PPP control block");
- ppp_free(g_lwip_ctx.ppp_pcb);
+ pppapi_free(g_lwip_ctx.ppp_pcb);
g_lwip_ctx.ppp_pcb = NULL;
}
PPP_DEBUG_PRINT("Initiating PPP connection with lwIP...\n");
PPP_DEBUG_PRINT("This will trigger LCP and IPCP negotiation\n");
- /* 启动PPP连接 */
- err_t err = ppp_connect(g_lwip_ctx.ppp_pcb, 0);
+ PPP_DEBUG_INFO("Starting PPP connection...");
+
+ err_t err = pppapi_connect(g_lwip_ctx.ppp_pcb, 0);
if (err != ERR_OK) {
PPP_DEBUG_ERROR("Failed to start PPP connection: %d", err);
- PPP_DEBUG_PRINT("=== PPP Connection FAILED ===\n");
- return PPP_ERR_DIAL_FAILED;
+ return PPP_ERR_UNKNOWN;
}
PPP_DEBUG_PRINT("PPP connection initiated successfully\n");
return PPP_ERR_OK;
}
- PPP_DEBUG_INFO("Disconnecting PPP");
-
- /* 关闭PPP连接 */
- err_t err = ppp_close(g_lwip_ctx.ppp_pcb, 0);
+ PPP_DEBUG_INFO("Disconnecting PPP connection...");
+
+ err_t err = pppapi_close(g_lwip_ctx.ppp_pcb, 0);
if (err != ERR_OK) {
PPP_DEBUG_ERROR("Failed to close PPP connection: %d", err);
- return PPP_ERR_DIAL_FAILED;
+ return PPP_ERR_UNKNOWN;
}
g_lwip_ctx.connected = false;
return PPP_ERR_INVALID_PARAM;
}
- PPP_DEBUG_PRINT("=== PPP Protocol Input ===\n");
- PPP_DEBUG_PRINT("PPP RX: %u bytes\n", length);
-
- /* 解析PPP协议包 */
- if (length >= 4) {
- /* 跳过PPP Flag (0x7E) 如果存在 */
- uint32_t offset = 0;
- if (data[0] == 0x7E) {
- offset = 1;
- }
-
- /* 检查Address/Control字段 */
- if (offset + 3 < length && data[offset] == 0xFF && data[offset + 1] == 0x03) {
- offset += 2; /* 跳过Address/Control */
-
- /* 解析协议字段 */
- if (offset + 1 < length) {
- uint16_t protocol = (data[offset] << 8) | data[offset + 1];
- offset += 2;
-
- PPP_DEBUG_PRINT("Protocol: 0x%04X (%s)\n", protocol, ppp_get_protocol_name(protocol));
-
- /* 解析LCP/IPCP包 */
- if ((protocol == 0xC021 || protocol == 0x8021) && offset + 3 < length) {
- uint8_t code = data[offset];
- uint8_t id = data[offset + 1];
- uint16_t pkt_length = (data[offset + 2] << 8) | data[offset + 3];
-
- PPP_DEBUG_PRINT(" Code: %u (%s)\n", code, ppp_get_lcp_code_name(code));
- PPP_DEBUG_PRINT(" ID: %u\n", id);
- PPP_DEBUG_PRINT(" Length: %u\n", pkt_length);
-
- /* 解析Configure-Request/Ack/Nak的选项 */
- if ((code >= 1 && code <= 4) && offset + 4 < length) { /* Configure packets */
- uint32_t opt_offset = offset + 4;
- PPP_DEBUG_PRINT(" Options:\n");
-
- while (opt_offset + 1 < length && opt_offset < offset + pkt_length) {
- uint8_t opt_type = data[opt_offset];
- uint8_t opt_len = data[opt_offset + 1];
-
- if (opt_len < 2 || opt_offset + opt_len > length) break;
-
- PPP_DEBUG_PRINT(" Type: %u, Length: %u", opt_type, opt_len);
-
- /* 解析常见选项 */
- if (protocol == 0x8021 && opt_type == 3 && opt_len == 6) { /* IPCP IP Address */
- PPP_DEBUG_PRINT(" (IP Address: %u.%u.%u.%u)",
- data[opt_offset + 2], data[opt_offset + 3],
- data[opt_offset + 4], data[opt_offset + 5]);
- } else if (protocol == 0x8021 && opt_type == 129 && opt_len == 6) { /* Primary DNS */
- PPP_DEBUG_PRINT(" (Primary DNS: %u.%u.%u.%u)",
- data[opt_offset + 2], data[opt_offset + 3],
- data[opt_offset + 4], data[opt_offset + 5]);
- } else if (protocol == 0x8021 && opt_type == 131 && opt_len == 6) { /* Secondary DNS */
- PPP_DEBUG_PRINT(" (Secondary DNS: %u.%u.%u.%u)",
- data[opt_offset + 2], data[opt_offset + 3],
- data[opt_offset + 4], data[opt_offset + 5]);
- }
-
- PPP_DEBUG_PRINT("\n");
- opt_offset += opt_len;
- }
- }
- }
- }
- }
- }
-
- /* 打印原始数据 */
- PPP_DEBUG_PRINT("Raw Data: ");
- for (uint32_t i = 0; i < length && i < 32; i++) {
- PPP_DEBUG_PRINT("%02X ", data[i]);
- }
- if (length > 32) {
- PPP_DEBUG_PRINT("... (total %u bytes)", length);
- }
- PPP_DEBUG_PRINT("\n");
+ PPP_DEBUG_PRINT("=== PPP Input Data ===\n");
+ PPP_DEBUG_PRINT("Length: %d bytes\n", length);
+ // PPP_DEBUG_HEXDUMP("RX", data, length > 32 ? 32 : length);
- /* 将数据传递给PPPoS */
+#if !NO_SYS && !PPP_INPROC_IRQ_SAFE
+ /* 在多线程环境中使用线程安全的输入函数 */
+ err_t result = pppos_input_tcpip(g_lwip_ctx.ppp_pcb, (u8_t *)data, length);
+ if (result != ERR_OK) {
+ PPP_DEBUG_ERROR("pppos_input_tcpip failed with error: %d", result);
+ return PPP_ERR_UNKNOWN;
+ }
+#else
+ /* 在单线程或中断安全环境中使用直接输入 */
pppos_input(g_lwip_ctx.ppp_pcb, (u8_t *)data, length);
+#endif
PPP_DEBUG_PRINT("=== PPP Input Processed ===\n");
return PPP_ERR_OK;
(void)ctx;
PPP_DEBUG_INFO("PPP status callback: err_code=%d", err_code);
-
- /* æ\89\93å\8d°PPPé\98¶æ®µä¿¡æ\81¯ */
+
+ /* è¿\99é\87\8cå\8fªå¤\84ç\90\86PPPé\98¶æ®µå\8f\98å\8c\96ï¼\8cä¸\8då¤\84ç\90\86é\94\99误 */
const char* phase_str = "UNKNOWN";
switch (err_code) {
- case PPPERR_NONE: phase_str = "CONNECTED"; break;
- case PPPERR_PARAM: phase_str = "PARAM_ERROR"; break;
- case PPPERR_OPEN: phase_str = "OPEN_ERROR"; break;
- case PPPERR_DEVICE: phase_str = "DEVICE_ERROR"; break;
- case PPPERR_ALLOC: phase_str = "ALLOC_ERROR"; break;
- case PPPERR_USER: phase_str = "USER_ERROR"; break;
- case PPPERR_CONNECT: phase_str = "CONNECT_ERROR"; break;
- case PPPERR_AUTHFAIL: phase_str = "AUTH_FAIL"; break;
- case PPPERR_PROTOCOL: phase_str = "PROTOCOL_ERROR"; break;
- case PPPERR_PEERDEAD: phase_str = "PEER_DEAD"; break;
- case PPPERR_IDLETIMEOUT: phase_str = "IDLE_TIMEOUT"; break;
- case PPPERR_CONNECTTIME: phase_str = "CONNECT_TIMEOUT"; break;
- case PPPERR_LOOPBACK: phase_str = "LOOPBACK"; break;
+ case PPP_PHASE_DEAD: phase_str = "DEAD"; break;
+ case PPP_PHASE_MASTER: phase_str = "MASTER"; break;
+ case PPP_PHASE_HOLDOFF: phase_str = "HOLDOFF"; break;
+ case PPP_PHASE_INITIALIZE: phase_str = "INITIALIZE"; break;
+ case PPP_PHASE_SERIALCONN: phase_str = "SERIALCONN"; break;
+ case PPP_PHASE_DORMANT: phase_str = "DORMANT"; break;
+ case PPP_PHASE_ESTABLISH: phase_str = "ESTABLISH"; break;
+ case PPP_PHASE_AUTHENTICATE: phase_str = "AUTHENTICATE"; break;
+ case PPP_PHASE_CALLBACK: phase_str = "CALLBACK"; break;
+ case PPP_PHASE_NETWORK: phase_str = "NETWORK"; break;
+ case PPP_PHASE_RUNNING: phase_str = "RUNNING"; break;
+ case PPP_PHASE_TERMINATE: phase_str = "TERMINATE"; break;
+ case PPP_PHASE_DISCONNECT: phase_str = "DISCONNECT"; break;
default: phase_str = "OTHER"; break;
}
PPP_DEBUG_INFO("PPP Phase: %s (%d)", phase_str, err_code);
memset_s(&event, sizeof(event), 0, sizeof(event));
switch (err_code) {
- case PPPERR_NONE:
- /* 连接成功 */
+ case PPP_PHASE_RUNNING:
+ /* 连接成功 - PPP协议栈运行中 */
g_lwip_ctx.connected = true;
event.type = PPP_LWIP_EVENT_CONNECTED;
PPP_DEBUG_CRITICAL("PPP connection established successfully");
PPP_DEBUG_INFO("netif->gw: 0x%08x", ip4_addr_get_u32(&g_lwip_ctx.netif->gw));
PPP_DEBUG_INFO("netif->netmask: 0x%08x", ip4_addr_get_u32(&g_lwip_ctx.netif->netmask));
PPP_DEBUG_INFO("netif flags: 0x%02x", g_lwip_ctx.netif->flags);
-
+
g_lwip_ctx.local_ip = ip4_addr_get_u32(&g_lwip_ctx.netif->ip_addr);
g_lwip_ctx.remote_ip = ip4_addr_get_u32(&g_lwip_ctx.netif->gw);
-
+
/* 获取DNS服务器地址 */
const ip_addr_t *dns1 = dns_getserver(0);
const ip_addr_t *dns2 = dns_getserver(1);
g_lwip_ctx.secondary_dns = ip4_addr_get_u32(ip_2_ip4(dns2));
PPP_DEBUG_INFO("DNS2: 0x%08x", g_lwip_ctx.secondary_dns);
}
-
+
PPP_DEBUG_INFO("PPP connected - Local IP: %u.%u.%u.%u",
(g_lwip_ctx.local_ip >> 0) & 0xFF,
(g_lwip_ctx.local_ip >> 8) & 0xFF,
(g_lwip_ctx.remote_ip >> 8) & 0xFF,
(g_lwip_ctx.remote_ip >> 16) & 0xFF,
(g_lwip_ctx.remote_ip >> 24) & 0xFF);
-
+
/* 设置PPP接口为默认网络接口 */
if (g_lwip_ctx.netif->ip_addr.addr != 0) {
PPP_DEBUG_INFO("Setting PPP interface as default...");
} else {
PPP_DEBUG_INFO("PPP IP address is 0, IPCP negotiation may still be in progress");
PPP_DEBUG_INFO("Network interface will be set as default when IP is assigned via netif callback");
-
- /* 确保网络接口处于激活状态 */
netif_set_up(g_lwip_ctx.netif);
netif_set_link_up(g_lwip_ctx.netif);
-
- /* 启动备用定时器检查(2秒后检查一次) */
- PPP_DEBUG_INFO("Starting fallback timer to ensure default interface is set");
- // 注意:这里使用简单的延迟检查,避免复杂的定时器管理
}
} else {
PPP_DEBUG_ERROR("PPP netif is NULL!");
}
break;
- case PPPERR_PARAM:
- case PPPERR_OPEN:
- case PPPERR_DEVICE:
- case PPPERR_ALLOC:
- case PPPERR_USER:
- case PPPERR_CONNECT:
- case PPPERR_AUTHFAIL:
- case PPPERR_PROTOCOL:
- case PPPERR_PEERDEAD:
- case PPPERR_IDLETIMEOUT:
- case PPPERR_CONNECTTIME:
- case PPPERR_LOOPBACK:
- /* 连接错误 */
+ case PPP_PHASE_DISCONNECT:
+ /* 正常断开 - 这是阶段,不是错误 */
g_lwip_ctx.connected = false;
- event.type = PPP_LWIP_EVENT_ERROR;
- event.error_code = err_code;
- PPP_DEBUG_ERROR("PPP connection error: %d", err_code);
+ event.type = PPP_LWIP_EVENT_DISCONNECTED;
+ PPP_DEBUG_INFO("PPP connection disconnected (phase DISCONNECT)");
break;
default:
- /* 其他状态 */
+ /* 其他阶段,仅通知状态变化 */
event.type = PPP_LWIP_EVENT_STATUS_CHANGE;
event.error_code = err_code;
+ PPP_DEBUG_INFO("PPP status change: %d", err_code);
break;
}
PPP_DEBUG_PRINT("=== PPP Output SUCCESS ===\n");
return len;
}
+
+const char* ppp_lwip_get_ip_address(void)
+{
+#ifdef LWIP_PPP_SUPPORT
+ if (!g_lwip_ctx.initialized) {
+ return "0.0.0.0";
+ }
+ static char ip_str[16];
+ uint32_t ip = g_lwip_ctx.local_ip;
+ snprintf(ip_str, sizeof(ip_str), "%u.%u.%u.%u",
+ (ip >> 0) & 0xFF,
+ (ip >> 8) & 0xFF,
+ (ip >> 16) & 0xFF,
+ (ip >> 24) & 0xFF);
+ return ip_str;
+#else
+ return "0.0.0.0";
+#endif
+}
+
+const char* ppp_lwip_get_netmask(void)
+{
+#ifdef LWIP_PPP_SUPPORT
+ if (!g_lwip_ctx.initialized || !g_lwip_ctx.netif) {
+ return "0.0.0.0";
+ }
+ static char netmask_str[16];
+ ip4addr_ntoa_r(ip_2_ip4(&g_lwip_ctx.netif->netmask), netmask_str, sizeof(netmask_str));
+ return netmask_str;
+#else
+ return "0.0.0.0";
+#endif
+}
+
+const char* ppp_lwip_get_gateway(void)
+{
+#ifdef LWIP_PPP_SUPPORT
+ if (!g_lwip_ctx.initialized) {
+ return "0.0.0.0";
+ }
+ static char gw_str[16];
+ uint32_t ip = g_lwip_ctx.remote_ip;
+ snprintf(gw_str, sizeof(gw_str), "%u.%u.%u.%u",
+ (ip >> 0) & 0xFF,
+ (ip >> 8) & 0xFF,
+ (ip >> 16) & 0xFF,
+ (ip >> 24) & 0xFF);
+ return gw_str;
+#else
+ return "0.0.0.0";
+#endif
+}
+
+const char* ppp_lwip_get_dns(void)
+{
+#ifdef LWIP_PPP_SUPPORT
+ if (!g_lwip_ctx.initialized) {
+ return "0.0.0.0";
+ }
+ static char dns_str[32];
+ char dns1_str[16] = "0.0.0.0";
+ char dns2_str[16] = "0.0.0.0";
+ uint32_t dns1 = g_lwip_ctx.primary_dns;
+ uint32_t dns2 = g_lwip_ctx.secondary_dns;
+ snprintf(dns1_str, sizeof(dns1_str), "%u.%u.%u.%u",
+ (dns1 >> 0) & 0xFF,
+ (dns1 >> 8) & 0xFF,
+ (dns1 >> 16) & 0xFF,
+ (dns1 >> 24) & 0xFF);
+ snprintf(dns2_str, sizeof(dns2_str), "%u.%u.%u.%u",
+ (dns2 >> 0) & 0xFF,
+ (dns2 >> 8) & 0xFF,
+ (dns2 >> 16) & 0xFF,
+ (dns2 >> 24) & 0xFF);
+ snprintf(dns_str, sizeof(dns_str), "%s,%s", dns1_str, dns2_str);
+ return dns_str;
+#else
+ return "0.0.0.0";
+#endif
+}
+
+
#endif /* LWIP_PPP_SUPPORT */
\ No newline at end of file