{ HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_DISABLE }, // S_MGPIO16 I2C2 SDA Sensor
{ HAL_PIO_FUNC_I2C3_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO17 i2c3 SCL smart pa\ 预留马达控制 \安全芯片
{ HAL_PIO_FUNC_I2C3_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO18 I2C3 SDA
- { HAL_PIO_FUNC_UART1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_DISABLE }, // S_MGPIO19 uart1 tx
+ { HAL_PIO_FUNC_UART1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_DISABLE }, // S_MGPIO19 uart1 tx
{ HAL_PIO_FUNC_UART1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_ENBALE }, // S_MGPIO20 uart1 rx
{ HAL_PIO_FUNC_UART1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO21 uart1 rts
{ HAL_PIO_FUNC_UART1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO22 uart1 cts
#include <string.h>
#include <math.h>
#include "ppp_log.h"
+#include "ppp_serial.h"
+#include "ppp_types.h"
+#include "ppp_api.h"
+#include "ppp_at_handler.h"
+#include "ppp_example.h"
-/* 外部函数声明 */
-extern void ppp_dial_with_power_example(void);
#ifdef __cplusplus
return ERRCODE_SUCC;
}
#endif
+
+/* PPP串口模式切换测试指令 */
+static errcode_t at_ppp_mode_switch(uint8_t *para, uint32_t paraLen)
+{
+ uint8_t argv[CUSTOM_UTILS_MAX_ARGC][CUSTOM_UTILS_MAX_ARGV_LEN];
+ uint32_t argc;
+
+ if (ConvertCmdToParam(para, paraLen, argv, &argc) != CUSTOM_UTILS_SUCCESS) {
+ ppp_print_err("PPP MODE SWITCH Convert Command Failed\n");
+ return ERRCODE_FAIL;
+ }
+
+ if (argc != 1) {
+ ppp_print_err("PPP MODE SWITCH Set Parameter Failed argc %d\nUsage: AT^PPPMODE=AT|PPP\n", argc);
+ return ERRCODE_FAIL;
+ }
+
+ errcode_t ret = ppp_test_switch_mode((char*)argv[0]);
+ if (ret == ERRCODE_SUCC) {
+ ppp_print_info("PPP MODE SWITCH: Successfully switched to %s mode\n", argv[0]);
+ } else {
+ ppp_print_err("PPP MODE SWITCH: Failed to switch to %s mode, error: %d\n", argv[0], ret);
+ }
+
+ return ret;
+}
+
+/* PPP串口状态查询指令 */
+static errcode_t at_ppp_status(uint8_t *para, uint32_t paraLen)
+{
+ (void)para;
+ (void)paraLen;
+
+ char status_info[512];
+ errcode_t ret = ppp_test_get_status(status_info, sizeof(status_info));
+ if (ret == ERRCODE_SUCC) {
+ ppp_print_info("%s", status_info);
+ } else {
+ ppp_print_err("Failed to get PPP status, error: %d\n", ret);
+ }
+
+ return ret;
+}
+
+/* AT指令透传功能 */
+static errcode_t at_ppp_transparent(uint8_t *para, uint32_t paraLen)
+{
+ if (paraLen == 0) {
+ ppp_print_err("PPP TRANSPARENT: No AT command provided\nUsage: AT^PPPTRANS=AT+CSQ\n");
+ return ERRCODE_FAIL;
+ }
+
+ /* 构建AT命令字符串 */
+ char at_cmd[256];
+ if (paraLen >= sizeof(at_cmd)) {
+ ppp_print_err("PPP TRANSPARENT: AT command too long (max %d chars)\n", sizeof(at_cmd) - 1);
+ return ERRCODE_FAIL;
+ }
+
+ memcpy(at_cmd, para, paraLen);
+ at_cmd[paraLen] = '\0';
+
+ ppp_print_info("PPP TRANSPARENT: Executing AT command: %s", at_cmd);
+
+ /* 使用ppp_at_send_command函数 */
+ ppp_at_response_t at_response;
+ const uint32_t timeout_ms = 5000; // 5秒超时
+
+ ppp_error_t ret = ppp_at_send_command(at_cmd, NULL, timeout_ms, &at_response);
+
+ if (ret == PPP_ERR_OK && at_response.success) {
+ if (at_response.length > 0) {
+ ppp_print_info("PPP TRANSPARENT: Response (%u bytes):\n%s", at_response.length, at_response.response);
+ } else {
+ ppp_print_info("PPP TRANSPARENT: Command executed successfully (no response data)");
+ }
+ return ERRCODE_SUCC;
+ } else {
+ switch (ret) {
+ case PPP_ERR_INVALID_STATE:
+ case PPP_ERR_INVALID_PARAM:
+ ppp_print_err("PPP TRANSPARENT: Must be in AT mode for transparent transmission\n");
+ ppp_print_info("Please use AT^PPPMODE=AT to switch to AT mode first\n");
+ break;
+ case PPP_ERR_TIMEOUT:
+ ppp_print_warning("PPP TRANSPARENT: No response received (timeout)\n");
+ break;
+ case PPP_ERR_MEMORY:
+ ppp_print_err("PPP TRANSPARENT: Memory allocation failed\n");
+ break;
+ default:
+ ppp_print_err("PPP TRANSPARENT: Failed to execute AT command, error: %d\n", ret);
+ break;
+ }
+ return ERRCODE_FAIL;
+ }
+}
+
+/* PPP串口测试指令 */
+static errcode_t at_ppp_test(uint8_t *para, uint32_t paraLen)
+{
+ (void)para;
+ (void)paraLen;
+
+ ppp_print_info("PPP TEST: Starting PPP serial test...\n");
+
+ errcode_t ret = ppp_test_uart_function();
+ if (ret == ERRCODE_SUCC) {
+ ppp_print_info("PPP TEST: UART test completed successfully\n");
+ } else {
+ ppp_print_err("PPP TEST: UART test failed, error: %d\n", ret);
+ }
+
+ return ret;
+}
+
+/* PPP智能flush测试指令 */
+static errcode_t at_ppp_flush(uint8_t *para, uint32_t paraLen)
+{
+ (void)para;
+ (void)paraLen;
+
+ ppp_print_info("PPP FLUSH: Triggering periodic flush check...\n");
+
+ errcode_t ret = ppp_test_smart_flush();
+ if (ret == ERRCODE_SUCC) {
+ ppp_print_info("PPP FLUSH: Periodic flush completed successfully\n");
+ } else {
+ ppp_print_err("PPP FLUSH: Periodic flush failed, error: %d\n", ret);
+ }
+
+ return ret;
+}
+
+/* PPP环境初始化测试指令 */
+static errcode_t at_ppp_env_init(uint8_t *para, uint32_t paraLen)
+{
+ (void)para;
+ (void)paraLen;
+
+ ppp_print_info("PPP ENV INIT: Initializing PPP environment...\n");
+
+ int ret = ppp_env_init();
+ if (ret == 0) {
+ ppp_print_info("PPP ENV INIT: PPP environment initialized successfully (AT mode)\n");
+ return ERRCODE_SUCC;
+ } else {
+ ppp_print_err("PPP ENV INIT: Failed to initialize PPP environment, error: %d\n", ret);
+ return ERRCODE_FAIL;
+ }
+}
+
+/* PPP开始拨号测试指令 */
+static errcode_t at_ppp_start_dial(uint8_t *para, uint32_t paraLen)
+{
+ (void)para;
+ (void)paraLen;
+
+ ppp_print_info("PPP START DIAL: Starting PPP dial (will auto switch to PPP mode)...\n");
+
+ int ret = ppp_test_start_dial();
+ if (ret == 0) {
+ ppp_print_info("PPP START DIAL: PPP dial started successfully (now in PPP mode)\n");
+ return ERRCODE_SUCC;
+ } else {
+ ppp_print_err("PPP START DIAL: Failed to start PPP dial, error: %d (back to AT mode)\n", ret);
+ return ERRCODE_FAIL;
+ }
+}
+
+/* PPP停止拨号测试指令 */
+static errcode_t at_ppp_stop_dial(uint8_t *para, uint32_t paraLen)
+{
+ (void)para;
+ (void)paraLen;
+
+ ppp_print_info("PPP STOP DIAL: Stopping PPP dial (will auto switch to AT mode)...\n");
+
+ int ret = ppp_test_stop_dial();
+ if (ret == 0) {
+ ppp_print_info("PPP STOP DIAL: PPP dial stopped successfully (now in AT mode)\n");
+ return ERRCODE_SUCC;
+ } else {
+ ppp_print_err("PPP STOP DIAL: Failed to stop PPP dial, error: %d\n", ret);
+ return ERRCODE_FAIL;
+ }
+}
+
+/* PPP环境去初始化测试指令 */
+static errcode_t at_ppp_env_deinit(uint8_t *para, uint32_t paraLen)
+{
+ (void)para;
+ (void)paraLen;
+
+ ppp_print_info("PPP ENV DEINIT: De-initializing PPP environment...\n");
+
+ int ret = ppp_env_deinit();
+ if (ret == 0) {
+ ppp_print_info("PPP ENV DEINIT: PPP environment de-initialized successfully\n");
+ return ERRCODE_SUCC;
+ } else {
+ ppp_print_err("PPP ENV DEINIT: Failed to de-initialize PPP environment, error: %d\n", ret);
+ return ERRCODE_FAIL;
+ }
+}
+
+/* PPP完整示例测试指令 */
+static errcode_t at_ppp_example_main(uint8_t *para, uint32_t paraLen)
+{
+ (void)para;
+ (void)paraLen;
+
+ ppp_print_info("PPP EXAMPLE MAIN: Starting complete PPP example sequence...\n");
+
+ int ret = ppp_example_main();
+ if (ret == 0) {
+ ppp_print_info("PPP EXAMPLE MAIN: Complete PPP example finished successfully\n");
+ return ERRCODE_SUCC;
+ } else {
+ ppp_print_err("PPP EXAMPLE MAIN: PPP example failed, error: %d\n", ret);
+ return ERRCODE_FAIL;
+ }
+}
+
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^CAT1AT", at_cat1_atcmd, (char *)"1" },
{ (char *)"AT^HTTPDOWNLOAD", custom_start_ota_download, (char *)" " },
{ (char *)"AT^CAT1LOGLEVEL", custom_enable_cat1_debug_log, (char *)" " },
- { (char *)"AT^PPPDIAL", ppp_dial_with_power_example, (char *)" " },
+ /* PPP串口测试指令 */
+ { (char *)"AT^PPPMODE", at_ppp_mode_switch, (char *)"AT|PPP" },
+ { (char *)"AT^PPPSTATUS", at_ppp_status, (char *)" " },
+ { (char *)"AT^PPPTRANS", at_ppp_transparent, (char *)"AT_COMMAND" },
+ { (char *)"AT^PPPTEST", at_ppp_test, (char *)" " },
+ { (char *)"AT^PPPFLUSH", at_ppp_flush, (char *)" " },
+ /* PPP模块化函数测试指令 */
+ { (char *)"AT^PPPENVINIT", at_ppp_env_init, (char *)" " },
+ { (char *)"AT^PPPSTARTDIAL", at_ppp_start_dial, (char *)" " },
+ { (char *)"AT^PPPSTOPDIAL", at_ppp_stop_dial, (char *)" " },
+ { (char *)"AT^PPPENVIDEINIT", at_ppp_env_deinit, (char *)" " },
+ { (char *)"AT^PPPEXAMPLE", at_ppp_example_main, (char *)" " },
#ifdef SUPPORT_ZHIHUI_WEBSOCKET
{ (char *)"AT^WEBSOCKETTEST", at_websocket_test_start, (char *)"serverip,port,test_time" },
{ (char *)"AT^STOPWEBSOCKET", at_websocket_test_stop, (char *)" " },
#include "ppp_api.h"
#include "ppp_config.h"
#include "ppp_debug.h"
+#include "ppp_serial.h"
+#include "ppp_power_ctl.h"
#include "osal_task.h"
#include "soc_osal.h"
#include "debug_print.h"
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
/* PPP事件回调函数 */
static void ppp_event_callback(const ppp_event_t *event);
/* 网络状态监控任务 */
static void network_monitor_task(void *arg);
+/* 外部声明cat1Service兼容接口 */
+extern void cat1_api_enable_cat1(bool isopen);
+extern bool cat1_api_is_cat1_enabled(void);
+extern uint8_t cat1_api_runtime_get_cat1_powerstat(void);
+extern void cat1_api_wakeup_cat1(bool isopen);
+
/* 全局变量 */
static bool g_ppp_connected = false;
static osal_task *g_monitor_task = NULL;
+static bool g_ppp_env_initialized = false;
/**
- * @brief PPP拨号示例主函数
+ * @brief PPP环境初始化
+ * @return 0成功,-1失败
*/
-int ppp_example_main(void)
+int ppp_env_init(void)
{
- PRINT("PPP Dial Example Started\r\n");
+ if (g_ppp_env_initialized) {
+ PRINT("PPP environment already initialized\r\n");
+ return 0;
+ }
+
+ PRINT("PPP Environment Initialization Started\r\n");
- /* 配置PPP拨号参数 */
+ /* 1. 配置PPP拨号参数 */
ppp_config_t config = {
- .apn = "cmnet", // 中国移动APN (对应AT+CGDCONT中的APN)
+ .apn = "cmnet", // 中国移动APN
.username = "", // 用户名(通常为空)
.password = "", // 密码(通常为空)
- .baudrate = 2000000, // 2M波特率 (对应AT+IPR=2000000)
- .auto_baudrate = true, // 启用自动波特率检测 (对应chat文件中的AT握手)
- .dial_timeout = 30000, // 30秒拨号超时 (对应chat文件TIMEOUT 5)
+ .baudrate = 2000000, // 2M波特率
+ .auto_baudrate = true, // 启用自动波特率检测
+ .dial_timeout = 30000, // 30秒拨号超时
.retry_count = 3 // 重试3次
- };
-
- /* 初始化PPP拨号系统 */
- /* 这将执行完整的chat文件流程:
- * 1. 跳过开机日志 (对应 '' \rAT)
- * 2. AT握手 (对应 AT -> OK)
- * 3. 设置PDP上下文 (对应 AT+CGDCONT=3,"IP")
- * 4. PPP拨号 (对应 ATD*99***2# -> CONNECTED)
- */
- errcode_t ret = zhihui_ppp_init(&config);
+ };
+ /* 2. 初始化PPP拨号系统 (包含GPIO、电源、串口等所有初始化) */
+ PRINT("Initializing PPP system...\r\n");
+ errcode_t ret = zhihui_ppp_init(&config);
if (ret != ERRCODE_SUCC) {
PRINT("PPP init failed: error code %d\r\n", ret);
return -1;
}
- /* 注册事件回调函数 */
+ /* 3. 注册事件回调函数 */
+ PRINT("Registering PPP event callback...\r\n");
ret = ppp_register_event_callback(ppp_event_callback);
if (ret != ERRCODE_SUCC) {
PRINT("PPP register callback failed\r\n");
return -1;
}
- PRINT("PPP system initialized successfully\r\n");
-
- /* 创建网络监控任务 */
- /* 使用正确的OSAL任务创建方式 */
- // osal_task_attr_t task_attr = {
- // .name = "net_monitor",
- // .stack_size = 2048,
- // .priority = OSAL_TASK_PRIORITY_LOW,
- // .detached = false
- // };
-
- g_monitor_task = osal_kthread_create(network_monitor_task, NULL, "net_monitor", 2048);
+ /* 4. 创建网络监控任务 */
+ PRINT("Creating network monitor task...\r\n");
+ g_monitor_task = osal_kthread_create(network_monitor_task, NULL, "net_monitor", (2048+1024));
if (g_monitor_task == NULL) {
PRINT("Failed to create monitor task\r\n");
zhihui_ppp_deinit();
return -1;
}
- /* 开始PPP拨号 */
+ g_ppp_env_initialized = true;
+ PRINT("PPP environment initialized successfully (AT mode)\r\n");
+ if (ppp_is_4g_power_initialized()) {
+ PRINT("4G power control is enabled\r\n");
+ } else {
+ PRINT("4G power control is disabled (using internal power management)\r\n");
+ }
+
+ return 0;
+
+
+}
+
+/**
+ * @brief 开始PPP拨号
+ * @return 0成功,-1失败
+ */
+int ppp_test_start_dial(void)
+{
+ if (!g_ppp_env_initialized) {
+ PRINT("PPP environment not initialized, call ppp_env_init() first\r\n");
+ PRINT("Please execute: AT^PPPENVINIT\r\n");
+ return -1;
+ }
+
+ if (g_ppp_connected) {
+ PRINT("PPP already connected\r\n");
+ return 0;
+ }
+
PRINT("Starting PPP dial...\r\n");
- ret = ppp_start_dial();
+
+ /* 检查PPP模块状态 */
+ ppp_state_t current_state = ppp_get_state();
+ PRINT("Current PPP state: %d\r\n", current_state);
+
+ if (current_state != PPP_STATE_INITIALIZED) {
+ PRINT("PPP module state error (expected: %d, actual: %d)\r\n",
+ PPP_STATE_INITIALIZED, current_state);
+ PRINT("Please check if AT^PPPENVINIT was executed successfully\r\n");
+ return -1;
+ }
+
+ /* 开始PPP拨号,这会自动切换到PPP模式 */
+ errcode_t ret = ppp_start_dial();
if (ret != ERRCODE_SUCC) {
+ PRINT("Failed to start PPP dial: %d\r\n", ret);
+ /* 拨号失败,自动切回AT模式 */
+ ppp_error_t serial_ret = ppp_serial_switch_to_at_mode();
+ if (serial_ret != PPP_ERR_OK) {
+ PRINT("Failed to switch back to AT mode: %d\r\n", serial_ret);
+ } else {
+ PRINT("Switched back to AT mode after dial failure\r\n");
+ }
return -1;
}
uint32_t timeout = 60000; // 60秒超时
uint32_t start_time = (uint32_t)osal_get_jiffies();
+ PRINT("Waiting for PPP connection...\r\n");
while (!g_ppp_connected && (osal_get_jiffies() - start_time) < osal_msecs_to_jiffies(timeout)) {
ppp_state_t state = ppp_get_state();
- PRINT("PPP state: %d\r\n", state);
if (state == PPP_STATE_ERROR) {
PRINT("PPP connection failed\r\n");
- break;
+ /* 连接失败,自动切回AT模式 */
+ ppp_error_t serial_ret = ppp_serial_switch_to_at_mode();
+ if (serial_ret != PPP_ERR_OK) {
+ PRINT("Failed to switch back to AT mode: %d\r\n", serial_ret);
+ } else {
+ PRINT("Switched back to AT mode after connection failure\r\n");
+ }
+ return -1;
}
osal_msleep(1000);
if (g_ppp_connected) {
PRINT("PPP connection established successfully!\r\n");
- /* 获取网络信息 */
+ /* 获取并显示网络信息 */
ppp_connection_info_t network_info;
ret = ppp_get_connection_info(&network_info);
if (ret == ERRCODE_SUCC) {
(network_info.secondary_dns >> 24) & 0xFF);
PRINT(" MTU: %u\r\n", network_info.mtu);
}
-
- /* 保持连接一段时间进行测试 */
- PRINT("Keeping connection for 30 seconds...\r\n");
- osal_msleep(30000);
-
- /* 断开连接 */
- PRINT("Disconnecting PPP...\r\n");
- ppp_stop_dial();
- /* 等待断开完成 */
- timeout = 10000; // 10秒超时
- start_time = (uint32_t)osal_get_jiffies();
-
- while (g_ppp_connected && (osal_get_jiffies() - start_time) < osal_msecs_to_jiffies(timeout)) {
- osal_msleep(100);
+ return 0;
+ } else {
+ PRINT("PPP connection timeout\r\n");
+ /* 连接超时,自动切回AT模式 */
+ ppp_error_t serial_ret = ppp_serial_switch_to_at_mode();
+ if (serial_ret != PPP_ERR_OK) {
+ PRINT("Failed to switch back to AT mode: %d\r\n", serial_ret);
+ } else {
+ PRINT("Switched back to AT mode after timeout\r\n");
}
-
- if (!g_ppp_connected) {
- PRINT("PPP disconnected successfully\r\n");
+ return -1;
+ }
+}
+
+/**
+ * @brief 停止PPP拨号
+ * @return 0成功,-1失败
+ */
+int ppp_test_stop_dial(void)
+{
+ if (!g_ppp_env_initialized) {
+ PRINT("PPP environment not initialized\r\n");
+ PRINT("Please execute: AT^PPPENVINIT first\r\n");
+ return -1;
+ }
+
+ /* 检查PPP模块状态 */
+ ppp_state_t current_state = ppp_get_state();
+ PRINT("Current PPP state: %d\r\n", current_state);
+
+ if (!g_ppp_connected) {
+ PRINT("PPP not connected\r\n");
+ /* 确保切换到AT模式 */
+ ppp_error_t serial_ret = ppp_serial_switch_to_at_mode();
+ if (serial_ret != PPP_ERR_OK) {
+ PRINT("Failed to switch to AT mode: %d\r\n", serial_ret);
} else {
- PRINT("PPP disconnect timeout\r\n");
+ PRINT("Switched to AT mode\r\n");
}
+ return 0;
+ }
+
+ PRINT("Disconnecting PPP...\r\n");
+
+ /* 停止PPP连接 */
+ errcode_t ret = ppp_stop_dial();
+ if (ret != ERRCODE_SUCC) {
+ PRINT("Failed to stop PPP dial: %d\r\n", ret);
+ return -1;
+ }
+
+ /* 等待断开完成 */
+ uint32_t timeout = 10000; // 10秒超时
+ uint32_t start_time = (uint32_t)osal_get_jiffies();
+
+ while (g_ppp_connected && (osal_get_jiffies() - start_time) < osal_msecs_to_jiffies(timeout)) {
+ osal_msleep(100);
+ }
+
+ if (!g_ppp_connected) {
+ PRINT("PPP disconnected successfully\r\n");
} else {
- PRINT("PPP connection timeout\r\n");
+ PRINT("PPP disconnect timeout\r\n");
+ }
+
+ /* 自动切换回AT模式 */
+ ppp_error_t serial_ret = ppp_serial_switch_to_at_mode();
+ if (serial_ret != PPP_ERR_OK) {
+ PRINT("Failed to switch back to AT mode: %d\r\n", serial_ret);
+ return -1;
+ } else {
+ PRINT("Switched back to AT mode\r\n");
+ }
+
+ return 0;
+}
+
+/**
+ * @brief PPP环境去初始化
+ * @return 0成功,-1失败
+ */
+int ppp_env_deinit(void)
+{
+ if (!g_ppp_env_initialized) {
+ PRINT("PPP environment not initialized\r\n");
+ return 0;
+ }
+
+ PRINT("PPP Environment De-initialization Started\r\n");
+
+ /* 1. 如果还在连接状态,先断开 */
+ if (g_ppp_connected) {
+ PRINT("Stopping active PPP connection...\r\n");
+ ppp_stop_dial();
}
- /* 清理资源 */
+ /* 2. 销毁监控任务 */
if (g_monitor_task) {
+ PRINT("Destroying monitor task...\r\n");
osal_kthread_destroy(g_monitor_task, 1);
g_monitor_task = NULL;
}
+
+ /* 3. 去初始化PPP系统 (包含4G电源管理) */
+ PRINT("De-initializing PPP system...\r\n");
+ errcode_t ret = zhihui_ppp_deinit();
+ if (ret != ERRCODE_SUCC) {
+ PRINT("PPP deinit failed: %d\r\n", ret);
+ }
+
+ g_ppp_env_initialized = false;
+ g_ppp_connected = false;
+
+ PRINT("PPP environment de-initialized successfully\r\n");
+
+ /* 如果PPP去初始化失败,返回错误 */
+ if (ret != ERRCODE_SUCC) {
+ return -1;
+ }
- zhihui_ppp_deinit();
- PRINT("PPP example completed\r\n");
+ return 0;
+}
+
+/**
+ * @brief PPP拨号示例主函数(使用新的分离函数)
+ */
+int ppp_example_main(void)
+{
+ PRINT("PPP Dial Example Started (New Modular Version)\r\n");
+
+ /* 1. 初始化PPP环境 */
+ if (ppp_env_init() != 0) {
+ PRINT("Failed to initialize PPP environment\r\n");
+ return -1;
+ }
+
+ /* 2. 开始拨号 */
+ if (ppp_test_start_dial() != 0) {
+ PRINT("Failed to start PPP dial\r\n");
+ ppp_env_deinit();
+ return -1;
+ }
+
+ /* 3. 保持连接一段时间进行测试 */
+ PRINT("Keeping connection for 30 seconds...\r\n");
+ osal_msleep(30000);
+
+ /* 4. 停止拨号 */
+ if (ppp_test_stop_dial() != 0) {
+ PRINT("Failed to stop PPP dial\r\n");
+ }
+
+ /* 5. 清理环境 */
+ if (ppp_env_deinit() != 0) {
+ PRINT("Failed to deinitialize PPP environment\r\n");
+ return -1;
+ }
+ PRINT("PPP example completed successfully\r\n");
return 0;
}
}
}
+
+#define STATS_INFO_SIZE 512
/**
* @brief 网络状态监控任务
*/
(void)arg;
PRINT("Network monitor task started\r\n");
+ char *stats_info = (char *)malloc(STATS_INFO_SIZE);
+ if (stats_info == NULL) {
+ PRINT("Failed to allocate memory for stats_info\r\n");
+ return;
+ }
while (1) {
/* 获取统计信息 */
- ppp_stats_t stats;
+ ppp_test_get_status(stats_info, STATS_INFO_SIZE);
+ PRINT("%s", stats_info);
- /* 每10秒输出一次统计信息 */
- osal_msleep(10000);
+ ppp_state_t state = ppp_get_state();
+ switch (state) {
+ case PPP_STATE_IDLE:
+ PRINT("PPP state: IDLE\r\n");
+ break;
+ case PPP_STATE_INITIALIZED:
+ PRINT("PPP state: INITIALIZED\r\n");
+ break;
+ case PPP_STATE_INIT:
+ PRINT("PPP state: INIT\r\n");
+ break;
+ case PPP_STATE_AT_HANDSHAKE:
+ PRINT("PPP state: AT_HANDSHAKE\r\n");
+ break;
+ case PPP_STATE_SET_BAUDRATE:
+ PRINT("PPP state: SET_BAUDRATE\r\n");
+ break;
+ case PPP_STATE_DIALING:
+ PRINT("PPP state: DIALING\r\n");
+ break;
+ case PPP_STATE_CONNECTED:
+ PRINT("PPP state: CONNECTED\r\n");
+ break;
+ case PPP_STATE_DISCONNECTING:
+ PRINT("PPP state: DISCONNECTING\r\n");
+ break;
+ case PPP_STATE_ERROR:
+ PRINT("PPP state: ERROR\r\n");
+ break;
+ default:
+ PRINT("PPP state: UNKNOWN\r\n");
+ break;
+ }
+
/* 如果PPP未连接且不在拨号过程中,退出监控任务 */
- ppp_state_t state = ppp_get_state();
- if (!g_ppp_connected && state == PPP_STATE_IDLE) {
+ if (!g_ppp_connected &&
+ (state == PPP_STATE_IDLE || state == PPP_STATE_ERROR)) {
break;
}
+ /* 每10秒输出一次统计信息 */
+ osal_msleep(10000);
+
}
PRINT("Network monitor task exited\r\n");
*/
errcode_t ppp_get_connection_info(ppp_connection_info_t *info);
+/**
+ * @brief PPP状态重置(从错误状态恢复)
+ * @return 错误码
+ */
+errcode_t ppp_reset_from_error(void);
+
+/* ========== PPP测试接口 ========== */
+
+/**
+ * @brief PPP串口模式切换
+ * @param mode 目标模式 ("AT" 或 "PPP")
+ * @return 错误码
+ */
+errcode_t ppp_test_switch_mode(const char *mode);
+
+/**
+ * @brief 获取PPP串口状态信息
+ * @param status_info 状态信息字符串缓冲区
+ * @param buffer_size 缓冲区大小
+ * @return 错误码
+ */
+errcode_t ppp_test_get_status(char *status_info, uint32_t buffer_size);
+
+/**
+ * @brief 执行AT指令透传
+ * @param at_command AT指令字符串
+ * @param response 响应缓冲区
+ * @param response_size 响应缓冲区大小
+ * @param response_len 实际响应长度(输出参数)
+ * @param timeout_ms 超时时间(毫秒)
+ * @return 错误码
+ */
+errcode_t ppp_test_execute_at_command(const char *at_command,
+ char *response,
+ uint32_t response_size,
+ uint32_t *response_len,
+ uint32_t timeout_ms);
+
+/**
+ * @brief PPP串口基础功能测试
+ * @return 错误码
+ */
+errcode_t ppp_test_uart_function(void);
+
+/**
+ * @brief PPP智能flush测试
+ * @return 错误码
+ */
+errcode_t ppp_test_smart_flush(void);
+
+/**
+ * @brief 检查4G电源是否已初始化
+ * @return true已初始化,false未初始化
+ */
+bool ppp_is_4g_power_initialized(void);
+
#ifdef __cplusplus
}
#endif
*/
uint32_t ppp_at_get_current_baudrate(void);
+/**
+ * @brief 执行波特率自适应握手
+ * @return 错误码
+ */
+ppp_error_t ppp_at_baudrate_handshake(void);
+
#ifdef __cplusplus
}
#endif
*/
void cat1_api_enable_cat1(bool isopen);
+
/**
* @brief 获取cat1是否使能(开机)状态
*/
/********************** 控制接口 **********************/
/**
- * @brief 唤醒Cat1
+ * @brief cat1 唤醒设置, 输入 true 唤醒cat1 modem, false cat1 modem自动休眠
*/
void cat1_api_wakeup_cat1(uint8_t wakeup);
#endif
/* 支持的波特率列表(自适应模式) */
-#define PPP_BAUDRATE_AUTO_LIST {9600, 57600, 115200 , 2000000}
+#define PPP_BAUDRATE_AUTO_LIST {2000000, 9600, 57600, 115200 }
#define PPP_BAUDRATE_AUTO_COUNT 4
/* 支持的固定波特率列表 */
PPP_ERR_INVALID_PARAM, // 无效参数
PPP_ERR_MEMORY, // 内存错误
PPP_ERR_UART, // 串口错误
+ PPP_ERR_INVALID_STATE, // 无效状态
PPP_ERR_UNKNOWN // 未知错误
} ppp_error_t;
--- /dev/null
+/**
+ * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n
+ *
+ * Description: PPP Example Functions Header \n
+ * Author: @CompanyNameTag \n
+ * History: \n
+ * 2022-07-20, Create file. \n
+ */
+#ifndef PPP_EXAMPLE_H
+#define PPP_EXAMPLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief PPP环境初始化
+ *
+ * 负责完整的PPP环境初始化,包括:
+ * 1. 配置和启用4G模块电源控制
+ * 2. 唤醒4G模块
+ * 3. 初始化PPP系统 (zhihui_ppp_init)
+ * 4. 注册事件回调 (ppp_register_event_callback)
+ * 5. 创建PPP状态监控任务
+ * 6. 确保默认工作在AT模式
+ *
+ * @return 0成功,-1失败
+ */
+int ppp_env_init(void);
+
+/**
+ * @brief 开始PPP拨号
+ *
+ * env_init之后,可以ppp_start_dial,它会自动切换到ppp模式,
+ * 然后执行拨号,失败后自动切回AT模式。
+ *
+ * @return 0成功,-1失败
+ */
+int ppp_test_start_dial(void);
+
+/**
+ * @brief 停止PPP拨号
+ *
+ * 进入ppp后,如果不想上网,或者打算使用at指令,需要先执行它
+ * 断开ppp链接,然后自动切换回AT模式。
+ *
+ * @return 0成功,-1失败
+ */
+int ppp_test_stop_dial(void);
+
+/**
+ * @brief PPP环境去初始化
+ *
+ * 销毁所有ppp_env_init建立起来的资源,包括:
+ * 1. 断开活动的PPP连接
+ * 2. 销毁网络监控任务
+ * 3. 去初始化PPP系统
+ * 4. 让4G模块进入休眠状态
+ * 5. 关闭4G模块电源
+ *
+ * @return 0成功,-1失败
+ */
+int ppp_env_deinit(void);
+
+/**
+ * @brief PPP拨号示例主函数
+ *
+ * 使用新的模块化函数实现的示例主函数,展示完整的PPP使用流程。
+ *
+ * @return 0成功,-1失败
+ */
+int ppp_example_main(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PPP_EXAMPLE_H */
\ No newline at end of file
/**
- * @brief PPP串口模块头文件 - 恢复缓存机制
+ * @brief PPP串口模块头文件 - 统一缓冲区管理 + PPP模式智能发送缓冲
*/
#ifndef PPP_SERIAL_H
/* 串口工作模式 */
typedef enum {
PPP_SERIAL_MODE_NONE = 0, // 未初始化
- PPP_SERIAL_MODE_AT, // AT命令模式(使用普通UART)
- PPP_SERIAL_MODE_PPP_DATA // PPP数据模式(使用普通UART + 缓存)
+ PPP_SERIAL_MODE_AT, // AT命令模式(直接使用UART)
+ PPP_SERIAL_MODE_PPP_DATA // PPP数据模式(使用UART + 软件缓冲区 + 智能发送缓冲)
} ppp_serial_mode_t;
/**
uint8_t tx_pin; // 发送引脚
uint8_t rx_pin; // 接收引脚
uint32_t rx_buffer_size; // 接收缓冲区大小
- uint32_t tx_buffer_size; // 发送缓冲区大小
+ uint32_t tx_buffer_size; // 发送缓冲区大小(PPP模式使用)
ppp_serial_rx_callback_t rx_callback; // 接收回调函数
void *rx_callback_arg; // 回调函数参数
} ppp_serial_config_t;
uint32_t rx_errors; // 接收错误数
uint32_t rx_buffer_usage; // 接收缓冲区使用量
uint32_t rx_buffer_size; // 接收缓冲区大小
+ uint32_t tx_buffer_usage; // 发送缓冲区使用量
+ uint32_t tx_buffer_size; // 发送缓冲区大小
} ppp_serial_stats_t;
/**
- * @brief 初始化PPP串口(AT命令模式,准备缓存机制)
+ * @brief 初始化PPP串口(统一缓冲区管理)
* @param config 串口配置
* @return 错误码
*/
void ppp_serial_deinit(void);
/**
- * @brief 切换到PPP数据模式(启用缓存机制)
+ * @brief 切换到PPP数据模式(启用软件缓冲区管理)
* @return 错误码
*/
ppp_error_t ppp_serial_switch_to_ppp_mode(void);
/**
- * @brief å\88\87æ\8d¢å\9b\9eATå\91½ä»¤æ¨¡å¼\8fï¼\88ç¦\81ç\94¨ç¼\93å\98æ\9cºå\88¶)
+ * @brief å\88\87æ\8d¢å\9b\9eATå\91½ä»¤æ¨¡å¼\8fï¼\88ç\9b´æ\8e¥ä½¿ç\94¨UART)
* @return 错误码
*/
ppp_error_t ppp_serial_switch_to_at_mode(void);
ppp_serial_mode_t ppp_serial_get_mode(void);
/**
- * @brief 发送数据(根据模式选择直接发送或缓存发送)
+ * @brief 发送数据(AT模式直接发送,PPP模式使用智能缓冲发送)
* @param data 数据指针
* @param length 数据长度
* @return 错误码
ppp_error_t ppp_serial_write(const uint8_t *data, uint32_t length);
/**
- * @brief 读取数据(根据模式选择直接读取或从缓存读取)
+ * @brief 读取数据(AT模式直接从UART读取,PPP模式从软件缓冲区读取)
* @param buffer 接收缓冲区
* @param buffer_size 缓冲区大小
* @param bytes_read 实际读取字节数
*/
void ppp_serial_flush_rx(void);
+/**
+ * @brief 强制发送缓冲区中的所有数据
+ * @return 错误码
+ */
+ppp_error_t ppp_serial_flush_tx(void);
+
+/**
+ * @brief 清空发送缓冲区(丢弃数据)
+ */
+void ppp_serial_flush_tx_discard(void);
+
+/**
+ * @brief 获取发送缓冲区使用情况
+ * @return 发送缓冲区中的数据量
+ */
+uint32_t ppp_serial_tx_available(void);
+
+/**
+ * @brief 定时flush检查函数(智能flush策略)
+ * @return 错误码
+ */
+ppp_error_t ppp_serial_periodic_flush(void);
+
/**
* @brief 设置接收回调函数
* @param callback 回调函数
*/
void ppp_serial_get_stats(ppp_serial_stats_t *stats);
+/**
+ * @brief 测试UART是否正常工作
+ * @return 错误码
+ */
+ppp_error_t ppp_serial_test_uart(void);
+
#ifdef __cplusplus
}
#endif
#include "schedule/osal_task.h"
#include "securec.h"
#include "ppp_log.h"
+#include "ppp_types.h" // 添加类型定义头文件
// PPP连接状态
static ppp_state_t g_ppp_state = PPP_STATE_IDLE;
// PPP配置参数
static ppp_config_t g_ppp_config = {0};
+// 4G电源初始化状态
+static bool g_4g_power_initialized = false;
+
uint8_t g_ppp_enable_debug = PPP_LOG_LEVEL_INFO;
// 外部声明cat1_api_enable_cat1函数(在ppp_cat1_api.c中实现)
// 保存用户配置
memcpy_s(&g_ppp_config, sizeof(ppp_config_t), config, sizeof(ppp_config_t));
- // 初始化电源控制
+ // 1. GPIO初始化
+ PPP_DEBUG_PRINT("Step 1: Initializing GPIO system\n");
ppp_api_gpio_init();
- g_ppp_state = PPP_STATE_INITIALIZED;
+ // 2. CAT1电源操作
+ PPP_DEBUG_PRINT("Step 2: Configuring and enabling CAT1 power\n");
- PPP_DEBUG_PRINT("PPP module initialized successfully\n");
-
- return ERRCODE_SUCC;
-}
+ // 配置4G电源控制引脚
+ ppp_ctl_pin_4g_t pin_config = {
+ .bat_pin = S_AGPIO_L18,
+ .bat_pin_en_value = 1,
+ .pwr_pin = S_AGPIO_L23,
+ .pwr_pin_en_value = 1,
+ .reset_pin = S_AGPIO_L24,
+ .reset_pin_en_value = 0,
+ .ring_pin = PIN_NONE,
+ .ring_pin_en_value = 0,
+ .wakemodem_pin = S_MGPIO22,
+ .wakemodem_pin_en_value = 1
+ };
-/**
- * @brief 启动PPP拨号
- */
-errcode_t ppp_start_dial(void)
-{
- if (g_ppp_state != PPP_STATE_INITIALIZED) {
- PPP_DEBUG_PRINT("PPP start dial: module not initialized\n");
- return ERRCODE_FAIL;
+ // 注册4G电源控制引脚配置
+ errcode_t power_ret = ppp_register_ctl_pin(&pin_config);
+ if (power_ret != ERRCODE_SUCC) {
+ PPP_DEBUG_PRINT("Failed to register 4G power control pins: %d\n", power_ret);
+ PPP_DEBUG_PRINT("Continuing without power control...\n");
+ g_4g_power_initialized = false;
+ } else {
+ PPP_DEBUG_PRINT("4G power control pins registered successfully\n");
+ g_4g_power_initialized = true;
+
+ // 启用4G电源
+ PPP_DEBUG_PRINT("Enabling 4G module power...\n");
+ cat1_api_enable_cat1(true);
+ osal_msleep(2000); // 等待电源稳定
+
+ // 唤醒4G模块
+ PPP_DEBUG_PRINT("Waking up 4G module...\n");
+ cat1_api_wakeup_cat1(true);
+ osal_msleep(1000); // 等待唤醒完成
+
+ // 检查电源状态
+ bool power_enabled = cat1_api_is_cat1_enabled();
+ uint8_t power_stat = cat1_api_runtime_get_cat1_powerstat();
+ PPP_DEBUG_PRINT("4G power status: %s (runtime stat: %d)\n",
+ power_enabled ? "ON" : "OFF", power_stat);
}
- PPP_DEBUG_PRINT("Starting PPP dial sequence\n");
-
- // 1. 启动4G电源(通过兼容接口)
- cat1_api_enable_cat1(true);
- PPP_DEBUG_PRINT("4G module power enabled\n");
-
- // 2. 等待4G模块启动(增加等待时间)
- PPP_DEBUG_PRINT("Waiting for 4G module startup...\n");
- osal_msleep(5000); // 增加到5秒
- PPP_DEBUG_PRINT("4G module startup wait completed\n");
-
- // 3. 初始化串口(AT命令模式)
+ // 3. UART初始化
+ PPP_DEBUG_PRINT("Step 3: Initializing UART for AT mode\n");
ppp_serial_config_t serial_config = {
.uart_bus = SIO_UART_BUS,
.baudrate = g_ppp_config.baudrate,
ppp_error_t ret = ppp_serial_init(&serial_config);
if (ret != PPP_ERR_OK) {
PPP_DEBUG_PRINT("Failed to initialize serial for AT mode: %d\n", ret);
- return ERRCODE_FAIL;
+ goto init_failed;
}
- // 4. 初始化AT命令处理器(使用串口AT模式)
+ // 初始化AT命令处理器
ret = ppp_at_handler_init(SIO_UART_BUS);
if (ret != PPP_ERR_OK) {
PPP_DEBUG_PRINT("Failed to initialize AT handler: %d\n", ret);
ppp_serial_deinit();
- return ERRCODE_FAIL;
+ goto init_failed;
}
- // 5. 执行波特率握手(如果启用自动波特率)
+ // 4. 串口波特率确认
+ PPP_DEBUG_PRINT("Step 4: Confirming UART baudrate\n");
if (g_ppp_config.auto_baudrate) {
ret = ppp_at_baudrate_handshake();
if (ret != PPP_ERR_OK) {
PPP_DEBUG_PRINT("Baudrate handshake failed: %d\n", ret);
ppp_at_handler_deinit();
ppp_serial_deinit();
- return ERRCODE_FAIL;
+ goto init_failed;
}
+ PPP_DEBUG_PRINT("Baudrate handshake completed successfully\n");
+ }
+
+ // 5. 默认工作在AT指令模式
+ PPP_DEBUG_PRINT("Step 5: Ensuring default AT command mode\n");
+ ret = ppp_serial_switch_to_at_mode();
+ if (ret != PPP_ERR_OK) {
+ PPP_DEBUG_PRINT("Failed to switch to AT mode: %d\n", ret);
+ // 不作为致命错误,继续执行
+ } else {
+ PPP_DEBUG_PRINT("Successfully switched to AT mode\n");
+ }
+
+
+ g_ppp_state = PPP_STATE_INITIALIZED;
+
+ PPP_DEBUG_PRINT("PPP module initialized successfully\n");
+
+ return ERRCODE_SUCC;
+
+init_failed:
+ // 初始化失败,关闭4G电源
+ if (g_4g_power_initialized) {
+ PPP_DEBUG_PRINT("Disabling 4G power due to initialization failure\n");
+ cat1_api_wakeup_cat1(false);
+ osal_msleep(500);
+ cat1_api_enable_cat1(false);
+ g_4g_power_initialized = false;
}
+ return ERRCODE_FAIL;
+}
+
+static void ppp_lwip_event_callback(const ppp_lwip_event_t *event, void *arg)
+{
+ PPP_DEBUG_PRINT("PPP lwIP event: %d\n", event->type);
+}
+
+/**
+ * @brief 启动PPP拨号
+ */
+errcode_t ppp_start_dial(void)
+{
+ if (g_ppp_state != PPP_STATE_INITIALIZED) {
+ PPP_DEBUG_PRINT("PPP start dial: module not initialized\n");
+ return ERRCODE_FAIL;
+ }
+
+ PPP_DEBUG_PRINT("Starting PPP dial sequence\n");
+ ppp_error_t ret = PPP_ERR_OK;
+
+ // 注意:波特率握手已在ppp_env_init中完成,这里直接开始AT指令序列
// 6. 执行完整的AT指令序列(对应chat文件)
ret = ppp_at_complete_dial_sequence(g_ppp_config.apn);
if (ret != PPP_ERR_OK) {
PPP_DEBUG_PRINT("PPP dial sequence failed: %d\n", ret);
- ppp_at_handler_deinit();
- ppp_serial_deinit();
- g_ppp_state = PPP_STATE_ERROR;
+ // AT指令序列失败,状态保持INITIALIZED,可以重试
return ERRCODE_FAIL;
}
ret = ppp_serial_switch_to_ppp_mode();
if (ret != PPP_ERR_OK) {
PPP_DEBUG_PRINT("Failed to switch serial to PPP data mode: %d\n", ret);
- ppp_serial_deinit();
- return ERRCODE_FAIL;
+ goto error_recovery_at_mode;
}
// 9. 启动PPP数据接收处理(在lwIP连接之前启动)
ret = ppp_start_data_receive_thread();
if (ret != PPP_ERR_OK) {
PPP_DEBUG_PRINT("Failed to start PPP data receive thread: %d\n", ret);
- ppp_serial_deinit();
- return ERRCODE_FAIL;
+ goto error_recovery_at_mode;
}
+ ppp_lwip_config_t lwip_config = {
+ .username = "",
+ .password = "",
+ .event_callback = ppp_lwip_event_callback,
+ .event_callback_arg = NULL
+ };
// 10. 初始化lwIP PPP协议栈
- ret = ppp_lwip_init(NULL); // 使用默认配置
+ ret = ppp_lwip_init(&lwip_config); // 使用默认配置
if (ret != PPP_ERR_OK) {
PPP_DEBUG_PRINT("Failed to initialize lwIP PPP: %d\n", ret);
ppp_stop_data_receive_thread();
- ppp_serial_deinit();
- return ERRCODE_FAIL;
+ goto error_recovery_at_mode;
}
// 11. 启动PPP连接(数据接收已准备好)
PPP_DEBUG_PRINT("Failed to start PPP connection: %d\n", ret);
ppp_lwip_deinit();
ppp_stop_data_receive_thread();
- ppp_serial_deinit();
- return ERRCODE_FAIL;
+ goto error_recovery_at_mode;
}
g_ppp_state = PPP_STATE_CONNECTED;
PPP_DEBUG_PRINT("PPP dial completed successfully - now in data mode\n");
return ERRCODE_SUCC;
+
+error_recovery_at_mode:
+ PPP_DEBUG_PRINT("PPP dial failed, recovering to AT mode\n");
+
+ // 尝试切换回AT模式
+ ppp_error_t recovery_ret = ppp_serial_switch_to_at_mode();
+ if (recovery_ret == PPP_ERR_OK) {
+ // 重新初始化AT处理器
+ recovery_ret = ppp_at_handler_init(SIO_UART_BUS);
+ if (recovery_ret == PPP_ERR_OK) {
+ PPP_DEBUG_PRINT("Successfully recovered to AT mode\n");
+ // 状态保持INITIALIZED,可以重试
+ } else {
+ PPP_DEBUG_ERROR("Failed to reinitialize AT handler during recovery\n");
+ g_ppp_state = PPP_STATE_ERROR;
+ }
+ } else {
+ PPP_DEBUG_ERROR("Failed to switch back to AT mode during recovery\n");
+ g_ppp_state = PPP_STATE_ERROR;
+ }
+
+ return ERRCODE_FAIL;
}
/**
// 继续执行,不返回错误
}
- // 7. 关闭AT命令处理器
- ppp_at_handler_deinit();
} else {
PPP_DEBUG_WARN("Failed to reinitialize AT handler for hangup: %d", ret);
}
}
- // 8. 关闭串口
- ppp_serial_deinit();
-
- // 9. 关闭4G电源
- cat1_api_enable_cat1(false);
-
+
g_ppp_state = PPP_STATE_INITIALIZED;
PPP_DEBUG_PRINT("PPP connection stopped successfully\n");
return ERRCODE_SUCC;
}
+/**
+ * @brief PPP状态重置(从错误状态恢复)
+ */
+errcode_t ppp_reset_from_error(void)
+{
+ if (g_ppp_state != PPP_STATE_ERROR) {
+ PPP_DEBUG_PRINT("PPP reset: not in error state, current state: %d\n", g_ppp_state);
+ return ERRCODE_SUCC;
+ }
+
+ PPP_DEBUG_PRINT("Resetting PPP from error state\n");
+
+ // 1. 停止所有可能的活动
+ ppp_stop_data_receive_thread();
+ ppp_lwip_deinit();
+
+ // 2. 尝试恢复到AT模式
+ ppp_error_t ret = ppp_serial_switch_to_at_mode();
+ if (ret == PPP_ERR_OK) {
+ // 3. 重新初始化AT处理器
+ ret = ppp_at_handler_init(SIO_UART_BUS);
+ if (ret == PPP_ERR_OK) {
+ g_ppp_state = PPP_STATE_INITIALIZED;
+ PPP_DEBUG_PRINT("PPP successfully reset to INITIALIZED state\n");
+ return ERRCODE_SUCC;
+ } else {
+ PPP_DEBUG_ERROR("Failed to reinitialize AT handler during reset\n");
+ }
+ } else {
+ PPP_DEBUG_ERROR("Failed to switch to AT mode during reset\n");
+ }
+
+ // 如果恢复失败,保持错误状态
+ PPP_DEBUG_ERROR("PPP reset failed, remains in error state\n");
+ return ERRCODE_FAIL;
+}
+
/**
* @brief PPP模块去初始化
*/
errcode_t zhihui_ppp_deinit(void)
{
- // 停止连接
+ PPP_DEBUG_PRINT("Starting PPP module deinitialization\n");
+
+ // 1. 停止连接
if (g_ppp_state != PPP_STATE_IDLE) {
+ PPP_DEBUG_PRINT("Stopping active PPP connection\n");
ppp_stop_dial();
}
- // 清理资源
+ // 2. 去初始化串口和AT处理器
+ PPP_DEBUG_PRINT("Deinitializing serial and AT handler\n");
+ ppp_at_handler_deinit();
+ ppp_serial_deinit();
+
+ // 3. 关闭4G电源
+ if (g_4g_power_initialized) {
+ PPP_DEBUG_PRINT("Disabling 4G module power\n");
+
+ // 让4G模块进入休眠状态
+ PPP_DEBUG_PRINT("Putting 4G module to sleep\n");
+ cat1_api_wakeup_cat1(false);
+ osal_msleep(500);
+
+ // 关闭4G电源
+ PPP_DEBUG_PRINT("Turning off 4G module power\n");
+ cat1_api_enable_cat1(false);
+ osal_msleep(1000);
+
+ g_4g_power_initialized = false;
+ PPP_DEBUG_PRINT("4G power disabled successfully\n");
+ }
+
+ // 4. 清理资源
(void)memset_s(&g_ppp_config, sizeof(ppp_config_t), 0, sizeof(ppp_config_t));
g_ppp_state = PPP_STATE_IDLE;
- PPP_DEBUG_PRINT("PPP module deinitialized\n");
+ PPP_DEBUG_PRINT("PPP module deinitialized successfully\n");
return ERRCODE_SUCC;
}
PPP_DEBUG_INFO("PPP data receive thread stopped");
return PPP_ERR_OK;
+}
+
+/* ========== PPP测试接口实现 ========== */
+
+/**
+ * @brief PPP串口模式切换
+ */
+errcode_t ppp_test_switch_mode(const char *mode)
+{
+ if (mode == NULL) {
+ return ERRCODE_INVALID_PARAM;
+ }
+
+ ppp_error_t ret;
+ if (strcmp(mode, "AT") == 0) {
+ ret = ppp_serial_switch_to_at_mode();
+ } else if (strcmp(mode, "PPP") == 0) {
+ ret = ppp_serial_switch_to_ppp_mode();
+ } else {
+ return ERRCODE_INVALID_PARAM;
+ }
+
+ return (ret == PPP_ERR_OK) ? ERRCODE_SUCC : ERRCODE_FAIL;
+}
+
+
+/**
+ * @brief 执行AT指令透传
+ */
+errcode_t ppp_test_execute_at_command(const char *at_command,
+ char *response,
+ uint32_t response_size,
+ uint32_t *response_len,
+ uint32_t timeout_ms)
+{
+ if (at_command == NULL || response == NULL || response_len == NULL) {
+ return ERRCODE_INVALID_PARAM;
+ }
+
+ ppp_at_response_t at_response;
+ ppp_error_t ret = ppp_at_send_command(at_command, NULL, timeout_ms, &at_response);
+
+ if (ret == PPP_ERR_OK && at_response.success) {
+ uint32_t copy_len = (at_response.length < response_size - 1) ? at_response.length : (response_size - 1);
+ memcpy(response, at_response.response, copy_len);
+ response[copy_len] = '\0';
+ *response_len = copy_len;
+ return ERRCODE_SUCC;
+ } else {
+ *response_len = 0;
+ switch (ret) {
+ case PPP_ERR_INVALID_STATE:
+ case PPP_ERR_INVALID_PARAM:
+ return ERRCODE_INVALID_PARAM;
+ case PPP_ERR_TIMEOUT:
+ return ERRCODE_FAIL;
+ case PPP_ERR_MEMORY:
+ return ERRCODE_MALLOC;
+ default:
+ return ERRCODE_FAIL;
+ }
+ }
+}
+
+/**
+ * @brief PPP串口基础功能测试
+ */
+errcode_t ppp_test_uart_function(void)
+{
+ ppp_error_t ret = ppp_serial_test_uart();
+ return (ret == PPP_ERR_OK) ? ERRCODE_SUCC : ERRCODE_FAIL;
+}
+
+/**
+ * @brief PPP智能flush测试
+ */
+errcode_t ppp_test_smart_flush(void)
+{
+ ppp_error_t ret = ppp_serial_periodic_flush();
+ return (ret == PPP_ERR_OK) ? ERRCODE_SUCC : ERRCODE_FAIL;
+}
+
+/**
+ * @brief 获取PPP测试统计信息
+ */
+errcode_t ppp_test_get_status(char *stats_info, uint32_t buffer_size)
+{
+ if (stats_info == NULL || buffer_size == 0) {
+ return ERRCODE_INVALID_PARAM;
+ }
+
+ ppp_serial_stats_t stats;
+ ppp_serial_get_stats(&stats);
+
+ int ret = snprintf(stats_info, buffer_size,
+ "=== PPP Statistics ===\n"
+ "Total TX Bytes: %u\n"
+ "Total RX Bytes: %u\n"
+ "TX Errors: %u\n"
+ "RX Errors: %u\n"
+ "Current RX Buffer Usage: %u/%u (%.1f%%)\n"
+ "Current TX Buffer Usage: %u/%u (%.1f%%)\n"
+ "PPP State: %s\n",
+ stats.tx_bytes,
+ stats.rx_bytes,
+ stats.tx_errors,
+ stats.rx_errors,
+ stats.rx_buffer_usage, stats.rx_buffer_size,
+ stats.rx_buffer_size > 0 ? (float)stats.rx_buffer_usage * 100.0f / stats.rx_buffer_size : 0.0f,
+ stats.tx_buffer_usage, stats.tx_buffer_size,
+ stats.tx_buffer_size > 0 ? (float)stats.tx_buffer_usage * 100.0f / stats.tx_buffer_size : 0.0f,
+ (g_ppp_state == PPP_STATE_IDLE) ? "IDLE" :
+ (g_ppp_state == PPP_STATE_DIALING) ? "DIALING" :
+ (g_ppp_state == PPP_STATE_CONNECTED) ? "CONNECTED" :
+ (g_ppp_state == PPP_STATE_DISCONNECTING) ? "DISCONNECTING" : "UNKNOWN");
+
+ return (ret > 0 && ret < (int)buffer_size) ? ERRCODE_SUCC : ERRCODE_FAIL;
+}
+
+/**
+ * @brief 检查4G电源是否已初始化
+ */
+bool ppp_is_4g_power_initialized(void)
+{
+ return g_4g_power_initialized;
}
\ No newline at end of file
/* 增加重试机制 */
ppp_error_t ret = PPP_ERR_AT_FAILED;
- for (int retry = 0; retry < 3; retry++) {
+ for (int retry = 0; retry < 1; retry++) {
PPP_DEBUG_INFO("--- AT Test at %u baud, retry %d/3 ---", baudrate, retry + 1);
ret = ppp_at_send_command("AT", "OK", 3000, &response); // 增加超时到3秒
uint32_t cmd_len = strlen(cmd_with_crlf);
/* 打印发送的原始数据(十六进制) */
- PPP_DEBUG_INFO("Sending %u bytes:", cmd_len);
- for (uint32_t i = 0; i < cmd_len; i++) {
- PPP_DEBUG_PRINT("%02X ", (uint8_t)cmd_with_crlf[i]);
- }
- PPP_DEBUG_PRINT("\n");
+ // PPP_DEBUG_INFO("Sending %u bytes:", cmd_len);
+ // for (uint32_t i = 0; i < cmd_len; i++) {
+ // PPP_DEBUG_PRINT("%02X ", (uint8_t)cmd_with_crlf[i]);
+ // }
+ // PPP_DEBUG_PRINT("\n");
/* 打印发送的字符串(可见字符) */
char printable_cmd[PPP_AT_CMD_MAX_LEN + 20];
PPP_DEBUG_INFO("Response received (%u bytes):", response->length);
/* 打印接收的原始数据(十六进制) */
- for (uint32_t i = 0; i < response->length; i++) {
- PPP_DEBUG_PRINT("%02X ", (uint8_t)response->response[i]);
- if ((i + 1) % 16 == 0) PPP_DEBUG_PRINT("\n");
- }
- if (response->length % 16 != 0) PPP_DEBUG_PRINT("\n");
+ // for (uint32_t i = 0; i < response->length; i++) {
+ // PPP_DEBUG_PRINT("%02X ", (uint8_t)response->response[i]);
+ // if ((i + 1) % 16 == 0) PPP_DEBUG_PRINT("\n");
+ // }
+ // if (response->length % 16 != 0) PPP_DEBUG_PRINT("\n");
/* 打印接收的字符串(可见字符) */
char printable_resp[PPP_AT_RESPONSE_MAX_LEN + 100];
}
PPP_DEBUG_INFO("AT handshake successful");
- // 3. 设置PDP上下文 (对应chat文件: OK 'AT+CGDCONT=3,"IP"')
+ // 3. 设置固定波特率 (AT+IPR=2000000,掉电保持)
+ // 获取当前波特率并设置为固定波特率
+ uint32_t current_baudrate = ppp_at_get_current_baudrate();
+ if (current_baudrate > 0) {
+ PPP_DEBUG_INFO("Setting fixed baudrate to %u (power-off persistent)", current_baudrate);
+ ret = ppp_at_send_command("AT+IPR=2000000", "OK", 5000, &response);
+ if (ret != PPP_ERR_OK) {
+ PPP_DEBUG_WARN("Failed to set fixed baudrate AT+IPR=2000000, continuing with current rate");
+ // 不作为致命错误,继续执行
+ } else {
+ PPP_DEBUG_INFO("Fixed baudrate 2000000 set successfully (power-off persistent)");
+ // 注意:这里不立即更改串口波特率,因为模块需要时间应用设置
+ // 下次开机时模块将自动使用2M波特率
+ }
+ }
+
+ // 4. 设置PDP上下文 (对应chat文件: OK 'AT+CGDCONT=3,"IP"')
char cgdcont_cmd[128];
if (apn && strlen(apn) > 0) {
snprintf_s(cgdcont_cmd, sizeof(cgdcont_cmd), sizeof(cgdcont_cmd) - 1,
}
PPP_DEBUG_INFO("PDP context set successfully");
- // 4. 发送PPP拨号指令 (对应chat文件: OK 'ATD*99***2#' -> CONNECTED)
+ // 5. 发送PPP拨号指令 (对应chat文件: OK 'ATD*99***2#' -> CONNECTED)
ret = ppp_at_send_command("ATD*99***2#", "CONNECT", 30000, &response);
if (ret != PPP_ERR_OK) {
PPP_DEBUG_ERROR("PPP dial failed");
}
}
+/**
+ * @brief cat1 唤醒设置, 输入 true 唤醒cat1 modem, false cat1 modem自动休眠
+ */
+void cat1_api_wakeup_cat1(uint8_t wakeup)
+{
+ ppp_api_wakeup_cat1(wakeup);
+}
+
/**
* @brief 获取cat1是否使能(开机)状态
*/
/********************** 控制接口 **********************/
-/**
- * @brief 唤醒Cat1
- */
-void cat1_api_wakeup_cat1(uint8_t wakeup)
-{
- ppp_api_wakeup_cat1(wakeup);
-}
/**
* @brief 保持唤醒Cat1
0,
PIN_NONE,//ring_pin
0,
- PIN_NONE,//wakemodem_pin
- 0,
+ S_MGPIO22,//wakemodem_pin
+ 1,
#else
PIN_NONE, //bat_pin
1,
#include "securec.h"
#include <string.h>
-/* 串口上下文结构 - 恢复缓存机制 */
+/* 串口上下文结构 - 优化缓存机制 */
typedef struct {
bool initialized;
ppp_serial_mode_t current_mode;
uart_attr_t uart_attr;
uart_buffer_config_t buffer_config;
- /* 接收缓冲区(用于PPP数据模式) */
+ /* 统一的接收缓冲区(AT和PPP模式共用) */
uint8_t *rx_buffer;
uint32_t rx_buffer_size;
uint32_t rx_head;
uint32_t rx_tail;
uint32_t rx_count;
- /* 发送缓冲区(用于PPP数据模式) */
+ /* PPP模式的发送缓冲区 */
uint8_t *tx_buffer;
uint32_t tx_buffer_size;
+ uint32_t tx_head;
+ uint32_t tx_tail;
+ uint32_t tx_count;
/* 同步对象 */
osal_mutex rx_mutex; // 改为结构体而不是指针
osal_semaphore rx_semaphore; // 改为结构体而不是指针
+ osal_mutex tx_mutex; // 发送缓冲区互斥锁
/* 回调函数 */
ppp_serial_rx_callback_t rx_callback;
uint32_t rx_bytes;
uint32_t tx_errors;
uint32_t rx_errors;
+
+ /* 智能flush策略相关 */
+ uint32_t last_tx_time; // 最后发送时间(ms)
+ uint32_t consecutive_small_packets; // 连续小包计数
+ uint32_t idle_flush_threshold; // 空闲flush阈值(ms)
} ppp_serial_context_t;
static ppp_serial_context_t g_serial_ctx = {0};
static void ppp_serial_rx_callback(const void *buffer, uint16_t length, bool remaining);
static uint32_t ppp_serial_buffer_available_space(void);
static uint32_t ppp_serial_buffer_data_count(void);
+static uint32_t ppp_serial_tx_buffer_available_space(void);
+static uint32_t ppp_serial_tx_buffer_data_count(void);
+static ppp_error_t ppp_serial_flush_tx_buffer_internal(void);
+static bool ppp_serial_is_ppp_control_packet(const uint8_t *data, uint32_t length);
+static bool ppp_serial_should_immediate_flush(const uint8_t *data, uint32_t length, uint32_t buffered_count);
+static uint32_t ppp_serial_get_current_time_ms(void);
/**
- * @brief 初始化PPP串口 - AT命令模式,准备缓存机制
+ * @brief 初始化PPP串口 - 统一缓冲区管理
*/
ppp_error_t ppp_serial_init(const ppp_serial_config_t *config)
{
return PPP_ERR_INVALID_PARAM;
}
- PPP_DEBUG_INFO("Initializing PPP serial in AT command mode with buffer support");
+ PPP_DEBUG_INFO("=== PPP Serial Initialization Start ===");
+ PPP_DEBUG_INFO("Initializing PPP serial with unified buffer management");
+
+ /* 打印配置参数 */
+ PPP_DEBUG_INFO("Configuration parameters:");
+ PPP_DEBUG_INFO(" - UART Bus: %u", config->uart_bus);
+ PPP_DEBUG_INFO(" - Baudrate: %u", config->baudrate);
+ PPP_DEBUG_INFO(" - TX Pin: %u", config->tx_pin);
+ PPP_DEBUG_INFO(" - RX Pin: %u", config->rx_pin);
+ PPP_DEBUG_INFO(" - RX Buffer Size: %u bytes", config->rx_buffer_size);
+ PPP_DEBUG_INFO(" - TX Buffer Size: %u bytes", config->tx_buffer_size);
+ PPP_DEBUG_INFO(" - RX Callback: %s", config->rx_callback ? "Set" : "NULL");
/* 配置UART参数 */
g_serial_ctx.uart_bus = config->uart_bus;
g_serial_ctx.uart_attr.stop_bits = UART_STOP_BIT_1;
g_serial_ctx.uart_attr.parity = UART_PARITY_NONE;
- /* 配置UART缓冲区 */
- static uint8_t uart_rx_buffer[256];
- g_serial_ctx.buffer_config.rx_buffer = uart_rx_buffer;
- g_serial_ctx.buffer_config.rx_buffer_size = sizeof(uart_rx_buffer);
+ PPP_DEBUG_INFO("UART attributes configured:");
+ PPP_DEBUG_INFO(" - Baud Rate: %u", g_serial_ctx.uart_attr.baud_rate);
+ PPP_DEBUG_INFO(" - Data Bits: %d", g_serial_ctx.uart_attr.data_bits);
+ PPP_DEBUG_INFO(" - Stop Bits: %d", g_serial_ctx.uart_attr.stop_bits);
+ PPP_DEBUG_INFO(" - Parity: %d", g_serial_ctx.uart_attr.parity);
- /* 初始化UART(AT命令模式) */
- 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);
- if (ret != ERRCODE_SUCC) {
- PPP_DEBUG_ERROR("Failed to initialize UART for AT mode: %d", ret);
- return PPP_ERR_UART;
- }
-
- /* 分配PPP数据模式的接收缓冲区 */
+ /* 动态分配统一的接收缓冲区 */
g_serial_ctx.rx_buffer_size = config->rx_buffer_size;
g_serial_ctx.rx_buffer = (uint8_t *)osal_kmalloc(g_serial_ctx.rx_buffer_size, OSAL_GFP_KERNEL);
if (g_serial_ctx.rx_buffer == NULL) {
- PPP_DEBUG_ERROR("Failed to allocate RX buffer");
- uapi_uart_deinit(g_serial_ctx.uart_bus);
+ PPP_DEBUG_ERROR("Failed to allocate RX buffer (%u bytes)", g_serial_ctx.rx_buffer_size);
return PPP_ERR_MEMORY;
}
+ PPP_DEBUG_INFO("RX buffer allocated: %u bytes at 0x%p", g_serial_ctx.rx_buffer_size, g_serial_ctx.rx_buffer);
- /* å\88\86é\85\8dPPPæ\95°æ\8d®æ¨¡å¼\8fç\9a\84发送缓冲区 */
+ /* å\8a¨æ\80\81å\88\86é\85\8d发送缓冲区 */
g_serial_ctx.tx_buffer_size = config->tx_buffer_size;
g_serial_ctx.tx_buffer = (uint8_t *)osal_kmalloc(g_serial_ctx.tx_buffer_size, OSAL_GFP_KERNEL);
if (g_serial_ctx.tx_buffer == NULL) {
- PPP_DEBUG_ERROR("Failed to allocate TX buffer");
+ PPP_DEBUG_ERROR("Failed to allocate TX buffer (%u bytes)", g_serial_ctx.tx_buffer_size);
osal_kfree(g_serial_ctx.rx_buffer);
+ g_serial_ctx.rx_buffer = NULL;
+ return PPP_ERR_MEMORY;
+ }
+ PPP_DEBUG_INFO("TX buffer allocated: %u bytes at 0x%p", g_serial_ctx.tx_buffer_size, g_serial_ctx.tx_buffer);
+
+ /* 创建发送缓冲区互斥锁 */
+ if (osal_mutex_init(&g_serial_ctx.tx_mutex) != OSAL_SUCCESS) {
+ PPP_DEBUG_ERROR("Failed to create TX mutex");
+ osal_kfree(g_serial_ctx.rx_buffer);
+ g_serial_ctx.rx_buffer = NULL;
+ osal_kfree(g_serial_ctx.tx_buffer);
+ g_serial_ctx.tx_buffer = NULL;
uapi_uart_deinit(g_serial_ctx.uart_bus);
return PPP_ERR_MEMORY;
}
+ PPP_DEBUG_INFO("TX mutex created successfully");
+
+ /* 配置UART使用我们分配的接收缓冲区 */
+ g_serial_ctx.buffer_config.rx_buffer = g_serial_ctx.rx_buffer;
+ g_serial_ctx.buffer_config.rx_buffer_size = g_serial_ctx.rx_buffer_size;
+
+ PPP_DEBUG_INFO("UART buffer config:");
+ PPP_DEBUG_INFO(" - RX Buffer Address: 0x%p", g_serial_ctx.buffer_config.rx_buffer);
+ PPP_DEBUG_INFO(" - RX Buffer Size: %u", g_serial_ctx.buffer_config.rx_buffer_size);
+ PPP_DEBUG_INFO("PPP TX buffer (software managed):");
+ PPP_DEBUG_INFO(" - TX Buffer Address: 0x%p", g_serial_ctx.tx_buffer);
+ PPP_DEBUG_INFO(" - TX Buffer Size: %u", g_serial_ctx.tx_buffer_size);
+
+ // errcode_t rett = uapi_uart_deinit(g_serial_ctx.uart_bus);
+ // if (rett != ERRCODE_SUCC) {
+ // PPP_DEBUG_ERROR("Failed to deinitialize UART: error code = %d (0x%x)", rett, rett);
+ // osal_kfree(g_serial_ctx.rx_buffer);
+ // g_serial_ctx.rx_buffer = NULL;
+ // return PPP_ERR_UART;
+ // }
+ // PPP_DEBUG_INFO("UART deinitialized successfully");
+
+ /* 初始化UART */
+ PPP_DEBUG_INFO("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);
+ 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",
+ g_serial_ctx.uart_bus, config->tx_pin, config->rx_pin, config->baudrate);
+ osal_kfree(g_serial_ctx.rx_buffer);
+ g_serial_ctx.rx_buffer = NULL;
+ osal_kfree(g_serial_ctx.tx_buffer);
+ g_serial_ctx.tx_buffer = NULL;
+ osal_mutex_destroy(&g_serial_ctx.tx_mutex);
+ return PPP_ERR_UART;
+ }
+ PPP_DEBUG_INFO("UART initialized successfully (error code = %d)", ret);
/* 创建同步对象 */
+ PPP_DEBUG_INFO("Creating synchronization objects...");
if (osal_mutex_init(&g_serial_ctx.rx_mutex) != OSAL_SUCCESS) {
PPP_DEBUG_ERROR("Failed to create RX mutex");
- osal_kfree(g_serial_ctx.tx_buffer);
osal_kfree(g_serial_ctx.rx_buffer);
+ g_serial_ctx.rx_buffer = NULL;
+ osal_kfree(g_serial_ctx.tx_buffer);
+ g_serial_ctx.tx_buffer = NULL;
uapi_uart_deinit(g_serial_ctx.uart_bus);
+ osal_mutex_destroy(&g_serial_ctx.tx_mutex);
return PPP_ERR_MEMORY;
}
+ PPP_DEBUG_INFO("RX mutex created successfully");
if (osal_sem_init(&g_serial_ctx.rx_semaphore, 0) != OSAL_SUCCESS) {
PPP_DEBUG_ERROR("Failed to create RX semaphore");
osal_mutex_destroy(&g_serial_ctx.rx_mutex);
- osal_kfree(g_serial_ctx.tx_buffer);
osal_kfree(g_serial_ctx.rx_buffer);
+ g_serial_ctx.rx_buffer = NULL;
+ osal_kfree(g_serial_ctx.tx_buffer);
+ g_serial_ctx.tx_buffer = NULL;
uapi_uart_deinit(g_serial_ctx.uart_bus);
+ osal_mutex_destroy(&g_serial_ctx.tx_mutex);
return PPP_ERR_MEMORY;
}
+ PPP_DEBUG_INFO("RX semaphore created successfully");
/* 初始化缓冲区状态 */
g_serial_ctx.rx_head = 0;
g_serial_ctx.rx_tail = 0;
g_serial_ctx.rx_count = 0;
+ g_serial_ctx.tx_head = 0;
+ g_serial_ctx.tx_tail = 0;
+ g_serial_ctx.tx_count = 0;
g_serial_ctx.rx_callback = config->rx_callback;
g_serial_ctx.rx_callback_arg = config->rx_callback_arg;
g_serial_ctx.rx_bytes = 0;
g_serial_ctx.tx_errors = 0;
g_serial_ctx.rx_errors = 0;
-
- PPP_DEBUG_INFO("PPP serial initialized in AT command mode with buffer support");
+
+ /* 初始化智能flush策略参数 */
+ g_serial_ctx.last_tx_time = ppp_serial_get_current_time_ms();
+ g_serial_ctx.consecutive_small_packets = 0;
+ g_serial_ctx.idle_flush_threshold = 10; // 10ms空闲超时
+
+ PPP_DEBUG_INFO("Buffer state initialized:");
+ PPP_DEBUG_INFO(" - RX Head/Tail/Count: %u/%u/%u", g_serial_ctx.rx_head, g_serial_ctx.rx_tail, g_serial_ctx.rx_count);
+ PPP_DEBUG_INFO(" - TX Head/Tail/Count: %u/%u/%u", g_serial_ctx.tx_head, g_serial_ctx.tx_tail, g_serial_ctx.tx_count);
+ PPP_DEBUG_INFO(" - Current Mode: %d (AT)", g_serial_ctx.current_mode);
+ PPP_DEBUG_INFO(" - Initialized Flag: %s", g_serial_ctx.initialized ? "true" : "false");
+
+ PPP_DEBUG_INFO("PPP serial initialized successfully with unified buffer (%u bytes)", g_serial_ctx.rx_buffer_size);
+ PPP_DEBUG_INFO("=== PPP Serial Initialization Complete ===");
return PPP_ERR_OK;
}
/**
- * @brief 切换到PPP数据模式 - 启用缓存机制和UART接收回调
+ * @brief 切换到PPP数据模式 - 启用回调机制进行缓冲区管理
*/
ppp_error_t ppp_serial_switch_to_ppp_mode(void)
{
if (!g_serial_ctx.initialized) {
+ PPP_DEBUG_ERROR("PPP serial not initialized");
return PPP_ERR_INVALID_PARAM;
}
return PPP_ERR_OK;
}
- PPP_DEBUG_INFO("Switching serial from AT mode to PPP data mode (enable buffering)");
+ PPP_DEBUG_INFO("=== Switching to PPP Data Mode ===");
+ PPP_DEBUG_INFO("Current mode: %d (AT) -> %d (PPP_DATA)", g_serial_ctx.current_mode, PPP_SERIAL_MODE_PPP_DATA);
+ PPP_DEBUG_INFO("UART Bus: %u", g_serial_ctx.uart_bus);
/* 清空接收缓冲区 */
osal_mutex_lock(&g_serial_ctx.rx_mutex);
g_serial_ctx.rx_count = 0;
osal_mutex_unlock(&g_serial_ctx.rx_mutex);
- /* 注册UART接收回调,启用缓存机制 */
+ /* 清空发送缓冲区 */
+ osal_mutex_lock(&g_serial_ctx.tx_mutex);
+ g_serial_ctx.tx_head = 0;
+ g_serial_ctx.tx_tail = 0;
+ g_serial_ctx.tx_count = 0;
+ osal_mutex_unlock(&g_serial_ctx.tx_mutex);
+ PPP_DEBUG_INFO("TX buffer cleared for mode switch");
+
+ /* 注册UART接收回调,启用软件缓冲区管理 */
+ PPP_DEBUG_INFO("Registering UART RX callback...");
+ PPP_DEBUG_INFO(" - Bus: %u", g_serial_ctx.uart_bus);
+ PPP_DEBUG_INFO(" - Condition: UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE");
+ PPP_DEBUG_INFO(" - Buffer size: %u", g_serial_ctx.rx_buffer_size);
+ PPP_DEBUG_INFO(" - Callback function: %p", ppp_serial_rx_callback);
+
errcode_t ret = uapi_uart_register_rx_callback(g_serial_ctx.uart_bus,
UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE,
g_serial_ctx.rx_buffer_size,
ppp_serial_rx_callback);
if (ret != ERRCODE_SUCC) {
- PPP_DEBUG_ERROR("Failed to register UART RX callback: %d", ret);
+ PPP_DEBUG_ERROR("Failed to register UART RX callback: error code = %d (0x%x)", ret, ret);
return PPP_ERR_UART;
}
+ PPP_DEBUG_INFO("UART RX callback registered successfully");
g_serial_ctx.current_mode = PPP_SERIAL_MODE_PPP_DATA;
- PPP_DEBUG_INFO("Successfully switched to PPP data mode with buffering enabled");
+ PPP_DEBUG_INFO("Mode switched to PPP_DATA (%d)", g_serial_ctx.current_mode);
+ PPP_DEBUG_INFO("=== PPP Data Mode Switch Complete ===");
return PPP_ERR_OK;
}
/**
- * @brief 切换回AT命令模式 - 禁用缓存机制和UART接收回调
+ * @brief 切换回AT命令模式 - 禁用回调机制,直接使用UART缓冲区
*/
ppp_error_t ppp_serial_switch_to_at_mode(void)
{
if (!g_serial_ctx.initialized) {
+ PPP_DEBUG_ERROR("PPP serial not initialized");
return PPP_ERR_INVALID_PARAM;
}
return PPP_ERR_OK;
}
- PPP_DEBUG_INFO("Switching serial from PPP data mode to AT mode (disable buffering)");
+ PPP_DEBUG_INFO("=== Switching to AT Mode ===");
+ PPP_DEBUG_INFO("Current mode: %d (PPP_DATA) -> %d (AT)", g_serial_ctx.current_mode, PPP_SERIAL_MODE_AT);
+ PPP_DEBUG_INFO("UART Bus: %u", g_serial_ctx.uart_bus);
- /* 取消注册UART接收回调,禁用缓存机制 */
+ /* 取消注册UART接收回调,回到直接UART读取模式 */
+ PPP_DEBUG_INFO("Unregistering UART RX callback...");
uapi_uart_unregister_rx_callback(g_serial_ctx.uart_bus);
+ PPP_DEBUG_INFO("UART RX callback unregistered");
/* 清空接收缓冲区 */
+ PPP_DEBUG_INFO("Clearing RX buffer...");
osal_mutex_lock(&g_serial_ctx.rx_mutex);
+ uint32_t old_rx_count = g_serial_ctx.rx_count;
g_serial_ctx.rx_head = 0;
g_serial_ctx.rx_tail = 0;
g_serial_ctx.rx_count = 0;
osal_mutex_unlock(&g_serial_ctx.rx_mutex);
+ PPP_DEBUG_INFO("RX buffer cleared (discarded %u bytes)", old_rx_count);
+
+ /* 清空发送缓冲区 */
+ PPP_DEBUG_INFO("Clearing TX buffer...");
+ osal_mutex_lock(&g_serial_ctx.tx_mutex);
+ uint32_t old_tx_count = g_serial_ctx.tx_count;
+ g_serial_ctx.tx_head = 0;
+ g_serial_ctx.tx_tail = 0;
+ g_serial_ctx.tx_count = 0;
+ osal_mutex_unlock(&g_serial_ctx.tx_mutex);
+ PPP_DEBUG_INFO("TX buffer cleared (discarded %u bytes)", old_tx_count);
g_serial_ctx.current_mode = PPP_SERIAL_MODE_AT;
- PPP_DEBUG_INFO("Successfully switched back to AT command mode");
+ PPP_DEBUG_INFO("Mode switched to AT (%d)", g_serial_ctx.current_mode);
+ PPP_DEBUG_INFO("=== AT Mode Switch Complete ===");
return PPP_ERR_OK;
}
/**
- * @brief 发送数据 - 根据模式选择直接发送或缓存发送
+ * @brief 发送数据 - 两种模式都直接通过UART发送
*/
ppp_error_t ppp_serial_write(const uint8_t *data, uint32_t length)
{
if (!g_serial_ctx.initialized || !data || length == 0) {
+ PPP_DEBUG_ERROR("Invalid parameters: initialized=%s, data=%p, length=%u",
+ g_serial_ctx.initialized ? "true" : "false", data, length);
return PPP_ERR_INVALID_PARAM;
}
+ PPP_DEBUG_INFO("=== PPP Serial Write Start ===");
+ PPP_DEBUG_INFO("Write request: %u bytes in mode %d", length, g_serial_ctx.current_mode);
+ PPP_DEBUG_INFO("UART Bus: %u", g_serial_ctx.uart_bus);
+
ppp_error_t result = PPP_ERR_OK;
switch (g_serial_ctx.current_mode) {
case PPP_SERIAL_MODE_AT:
/* AT命令模式:直接使用UART发送 */
- PPP_DEBUG_DEBUG("Sending %u bytes via UART (AT mode)", length);
- PPP_DEBUG_HEXDUMP(data, length);
+ PPP_DEBUG_INFO("Sending %u bytes via UART (AT mode)", length);
+ // PPP_DEBUG_HEXDUMP(data, length);
+
+ PPP_DEBUG_INFO("Calling uapi_uart_write(bus=%u, data=%p, len=%u, timeout=1000)...",
+ g_serial_ctx.uart_bus, data, length);
+
+ int32_t write_result = uapi_uart_write(g_serial_ctx.uart_bus, data, length, 1000);
+ PPP_DEBUG_INFO("uapi_uart_write returned: %d (expected: %u)", write_result, length);
- if (uapi_uart_write(g_serial_ctx.uart_bus, data, length, 1000) != (int32_t)length) {
- PPP_DEBUG_ERROR("UART write failed in AT mode");
+ if (write_result != (int32_t)length) {
+ PPP_DEBUG_ERROR("UART write failed in AT mode: returned %d, expected %u", write_result, length);
+ PPP_DEBUG_ERROR("Possible causes: UART not initialized, hardware error, or timeout");
g_serial_ctx.tx_errors++;
result = PPP_ERR_UART;
} else {
g_serial_ctx.tx_bytes += length;
- PPP_DEBUG_DEBUG("Sent %u bytes successfully via UART", length);
+ PPP_DEBUG_INFO("Sent %u bytes successfully via UART (total tx: %u bytes)",
+ length, g_serial_ctx.tx_bytes);
}
break;
case PPP_SERIAL_MODE_PPP_DATA:
- /* PPP数据模式:直接使用UART发送(PPP数据通常需要立即发送) */
- PPP_DEBUG_DEBUG("Sending %u bytes via UART (PPP data mode)", length);
- PPP_DEBUG_HEXDUMP(data, length);
+ /* PPP数据模式:使用缓冲发送 */
+ PPP_DEBUG_INFO("Buffering %u bytes for PPP data mode", length);
+ // PPP_DEBUG_HEXDUMP(data, length);
- if (uapi_uart_write(g_serial_ctx.uart_bus, data, length, 1000) != (int32_t)length) {
- PPP_DEBUG_ERROR("UART write failed in PPP data mode");
- g_serial_ctx.tx_errors++;
- result = PPP_ERR_UART;
+ osal_mutex_lock(&g_serial_ctx.tx_mutex);
+
+ /* 检查缓冲区空间 */
+ uint32_t available_space = ppp_serial_tx_buffer_available_space();
+ if (available_space < length) {
+ PPP_DEBUG_WARN("TX buffer insufficient space: need %u, available %u", length, available_space);
+
+ /* 先尝试发送现有缓冲区数据 */
+ osal_mutex_unlock(&g_serial_ctx.tx_mutex);
+ ppp_error_t flush_result = ppp_serial_flush_tx();
+ if (flush_result != PPP_ERR_OK) {
+ PPP_DEBUG_ERROR("Failed to flush TX buffer before new write");
+ result = flush_result;
+ break;
+ }
+ osal_mutex_lock(&g_serial_ctx.tx_mutex);
+
+ /* 重新检查空间 */
+ available_space = ppp_serial_tx_buffer_available_space();
+ if (available_space < length) {
+ PPP_DEBUG_ERROR("TX buffer still insufficient after flush: need %u, available %u",
+ length, available_space);
+ osal_mutex_unlock(&g_serial_ctx.tx_mutex);
+ g_serial_ctx.tx_errors++;
+ result = PPP_ERR_UART;
+ break;
+ }
+ }
+
+ /* 将数据复制到发送缓冲区 */
+ for (uint32_t i = 0; i < length; i++) {
+ g_serial_ctx.tx_buffer[g_serial_ctx.tx_head] = data[i];
+ g_serial_ctx.tx_head = (g_serial_ctx.tx_head + 1) % g_serial_ctx.tx_buffer_size;
+ g_serial_ctx.tx_count++;
+ }
+
+ uint32_t buffered_count = g_serial_ctx.tx_count;
+ osal_mutex_unlock(&g_serial_ctx.tx_mutex);
+
+ PPP_DEBUG_INFO("Buffered %u bytes (total buffered: %u bytes)", length, buffered_count);
+
+ /* 智能flush策略:根据PPP协议特性决定是否立即发送 */
+ if (ppp_serial_should_immediate_flush(data, length, buffered_count)) {
+ PPP_DEBUG_INFO("Smart flush triggered (buffered: %u, packet: %u bytes)",
+ buffered_count, length);
+ result = ppp_serial_flush_tx();
+ g_serial_ctx.last_tx_time = ppp_serial_get_current_time_ms();
} else {
g_serial_ctx.tx_bytes += length;
- PPP_DEBUG_DEBUG("Sent %u bytes successfully via UART", length);
+ PPP_DEBUG_INFO("Data buffered smartly (total: %u bytes, will flush when appropriate)", buffered_count);
}
break;
break;
}
+ PPP_DEBUG_INFO("Write result: %s (error code: %d)",
+ result == PPP_ERR_OK ? "SUCCESS" : "FAILED", result);
+ PPP_DEBUG_INFO("Statistics: tx_bytes=%u, tx_errors=%u", g_serial_ctx.tx_bytes, g_serial_ctx.tx_errors);
+ PPP_DEBUG_INFO("=== PPP Serial Write End ===");
+
return result;
}
/**
- * @brief 读取数据 - 根据模式选择直接读取或从缓存读取
+ * @brief 读取数据 - AT模式直接从UART读取,PPP模式从软件缓冲区读取
*/
ppp_error_t ppp_serial_read(uint8_t *buffer, uint32_t buffer_size, uint32_t *bytes_read)
{
*bytes_read = (uint32_t)read_result;
g_serial_ctx.rx_bytes += *bytes_read;
PPP_DEBUG_DEBUG("Read %u bytes via UART (AT mode)", *bytes_read);
- PPP_DEBUG_HEXDUMP(buffer, *bytes_read);
+ // PPP_DEBUG_HEXDUMP(buffer, *bytes_read);
} else if (read_result < 0) {
PPP_DEBUG_ERROR("UART read error in AT mode: %d", read_result);
g_serial_ctx.rx_errors++;
break;
case PPP_SERIAL_MODE_PPP_DATA:
- /* PPP数据模式:从缓存读取 */
+ /* PPP数据模式:从软件环形缓冲区读取 */
osal_mutex_lock(&g_serial_ctx.rx_mutex);
uint32_t available = ppp_serial_buffer_data_count();
*bytes_read = to_read;
osal_mutex_unlock(&g_serial_ctx.rx_mutex);
- PPP_DEBUG_DEBUG("Read %u bytes from buffer (PPP data mode)", to_read);
- PPP_DEBUG_HEXDUMP(buffer, to_read);
+ PPP_DEBUG_DEBUG("Read %u bytes from software buffer (PPP data mode)", to_read);
+ // PPP_DEBUG_HEXDUMP(buffer, to_read);
break;
default:
uint32_t count = ppp_serial_buffer_data_count();
osal_mutex_unlock(&g_serial_ctx.rx_mutex);
- return count;
+ return count;
}
+/* 智能flush策略实现函数 */
+
+/**
+ * @brief 获取当前时间(毫秒)
+ */
+static uint32_t ppp_serial_get_current_time_ms(void)
+{
+ unsigned long long jiffies = osal_get_jiffies();
+ return (uint32_t)osal_jiffies_to_msecs((unsigned int)jiffies);
+}
+
+/**
+ * @brief 检测是否为PPP控制包
+ */
+static bool ppp_serial_is_ppp_control_packet(const uint8_t *data, uint32_t length)
+{
+ if (length < 4) {
+ return false;
+ }
+
+ // PPP协议标识符检查 (跳过地址和控制字段)
+ uint16_t protocol = (data[2] << 8) | data[3];
+
+ switch (protocol) {
+ case 0xC021: // LCP (Link Control Protocol)
+ case 0xC023: // PAP (Password Authentication Protocol)
+ case 0xC223: // CHAP (Challenge Handshake Authentication Protocol)
+ case 0x8021: // IPCP (IP Control Protocol)
+ case 0x8057: // IPv6CP
+ PPP_DEBUG_DEBUG("PPP control packet detected: protocol=0x%04X", protocol);
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * @brief 智能flush决策函数
+ */
+static bool ppp_serial_should_immediate_flush(const uint8_t *data, uint32_t length, uint32_t buffered_count)
+{
+ uint32_t current_time = ppp_serial_get_current_time_ms();
+ uint32_t time_since_last_tx = current_time - g_serial_ctx.last_tx_time;
+
+ // 1. PPP控制包立即发送(最高优先级)
+ if (ppp_serial_is_ppp_control_packet(data, length)) {
+ PPP_DEBUG_INFO("PPP control packet detected, immediate flush");
+ return true;
+ }
+
+ // 2. 缓冲区接近满(87.5%阈值,比原来的75%更保守)
+ if (buffered_count >= (g_serial_ctx.tx_buffer_size * 7 / 8)) {
+ PPP_DEBUG_INFO("Buffer nearly full (%u/%u), immediate flush",
+ buffered_count, g_serial_ctx.tx_buffer_size);
+ return true;
+ }
+
+ // 3. 大包立即发送(降低阈值到128字节,避免分片)
+ if (length >= 128) {
+ PPP_DEBUG_INFO("Large packet (%u bytes), immediate flush", length);
+ return true;
+ }
+
+ // 4. 空闲时间超过阈值
+ if (time_since_last_tx >= g_serial_ctx.idle_flush_threshold) {
+ PPP_DEBUG_INFO("Idle timeout (%u ms), immediate flush", time_since_last_tx);
+ return true;
+ }
+
+ // 5. 连续小包累积策略
+ if (length <= 32) {
+ g_serial_ctx.consecutive_small_packets++;
+ if (g_serial_ctx.consecutive_small_packets >= 3) {
+ PPP_DEBUG_INFO("Multiple small packets accumulated (%u), immediate flush",
+ g_serial_ctx.consecutive_small_packets);
+ g_serial_ctx.consecutive_small_packets = 0;
+ return true;
+ }
+ } else {
+ g_serial_ctx.consecutive_small_packets = 0;
+ }
+
+ return false;
+}
+
+/**
+ * @brief 定时flush检查函数
+ */
+ppp_error_t ppp_serial_periodic_flush(void)
+{
+ if (!g_serial_ctx.initialized || g_serial_ctx.current_mode != PPP_SERIAL_MODE_PPP_DATA) {
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ uint32_t current_time = ppp_serial_get_current_time_ms();
+ uint32_t time_since_last_tx = current_time - g_serial_ctx.last_tx_time;
+
+ osal_mutex_lock(&g_serial_ctx.tx_mutex);
+ uint32_t buffered_count = g_serial_ctx.tx_count;
+ osal_mutex_unlock(&g_serial_ctx.tx_mutex);
+
+ // 如果有缓冲数据且空闲时间超过阈值,强制flush
+ if (buffered_count > 0 && time_since_last_tx >= g_serial_ctx.idle_flush_threshold) {
+ PPP_DEBUG_INFO("Periodic flush: %u bytes after %u ms idle",
+ buffered_count, time_since_last_tx);
+ g_serial_ctx.last_tx_time = current_time;
+ return ppp_serial_flush_tx();
+ }
+
+ return PPP_ERR_OK;
+}
+
/**
* @brief 清空接收缓冲区
*/
osal_kfree(g_serial_ctx.rx_buffer);
g_serial_ctx.rx_buffer = NULL;
}
-
if (g_serial_ctx.tx_buffer) {
osal_kfree(g_serial_ctx.tx_buffer);
g_serial_ctx.tx_buffer = NULL;
/* 销毁同步对象 */
osal_mutex_destroy(&g_serial_ctx.rx_mutex);
osal_sem_destroy(&g_serial_ctx.rx_semaphore);
+ osal_mutex_destroy(&g_serial_ctx.tx_mutex);
/* 清理上下文 */
memset_s(&g_serial_ctx, sizeof(g_serial_ctx), 0, sizeof(g_serial_ctx));
stats->rx_bytes = g_serial_ctx.rx_bytes;
stats->tx_errors = g_serial_ctx.tx_errors;
stats->rx_errors = g_serial_ctx.rx_errors;
+
+ osal_mutex_lock(&g_serial_ctx.rx_mutex);
stats->rx_buffer_usage = g_serial_ctx.rx_count;
stats->rx_buffer_size = g_serial_ctx.rx_buffer_size;
+ osal_mutex_unlock(&g_serial_ctx.rx_mutex);
+
+ osal_mutex_lock(&g_serial_ctx.tx_mutex);
+ stats->tx_buffer_usage = g_serial_ctx.tx_count;
+ stats->tx_buffer_size = g_serial_ctx.tx_buffer_size;
+ osal_mutex_unlock(&g_serial_ctx.tx_mutex);
}
/* 内部函数实现 */
static uint32_t ppp_serial_buffer_data_count(void)
{
return g_serial_ctx.rx_count;
+}
+
+/**
+ * @brief 获取发送缓冲区可用空间
+ */
+static uint32_t ppp_serial_tx_buffer_available_space(void)
+{
+ return g_serial_ctx.tx_buffer_size - g_serial_ctx.tx_count;
+}
+
+/**
+ * @brief 获取发送缓冲区数据数量
+ */
+static uint32_t ppp_serial_tx_buffer_data_count(void)
+{
+ return g_serial_ctx.tx_count;
+}
+
+/**
+ * @brief 清空发送缓冲区
+ */
+static ppp_error_t ppp_serial_flush_tx_buffer_internal(void)
+{
+ if (!g_serial_ctx.initialized) {
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ PPP_DEBUG_INFO("Flushing TX buffer...");
+ osal_mutex_lock(&g_serial_ctx.tx_mutex);
+
+ uint32_t old_count = g_serial_ctx.tx_count;
+ g_serial_ctx.tx_head = 0;
+ g_serial_ctx.tx_tail = 0;
+ g_serial_ctx.tx_count = 0;
+
+ osal_mutex_unlock(&g_serial_ctx.tx_mutex);
+ PPP_DEBUG_INFO("TX buffer flushed (discarded %u bytes)", old_count);
+ return PPP_ERR_OK;
+}
+
+/**
+ * @brief 测试UART是否正常工作
+ */
+ppp_error_t ppp_serial_test_uart(void)
+{
+ if (!g_serial_ctx.initialized) {
+ PPP_DEBUG_ERROR("PPP serial not initialized");
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ PPP_DEBUG_INFO("=== UART Test Start ===");
+ PPP_DEBUG_INFO("Current state:");
+ PPP_DEBUG_INFO(" - Initialized: %s", g_serial_ctx.initialized ? "true" : "false");
+ PPP_DEBUG_INFO(" - Mode: %d", g_serial_ctx.current_mode);
+ PPP_DEBUG_INFO(" - UART Bus: %u", g_serial_ctx.uart_bus);
+ PPP_DEBUG_INFO(" - TX Pin: %u", g_serial_ctx.pin_config.tx_pin);
+ PPP_DEBUG_INFO(" - RX Pin: %u", g_serial_ctx.pin_config.rx_pin);
+ PPP_DEBUG_INFO(" - Baudrate: %u", g_serial_ctx.uart_attr.baud_rate);
+
+ /* 发送测试字符串 */
+ const char *test_msg = "AT\r\n";
+ uint32_t test_len = strlen(test_msg);
+
+ PPP_DEBUG_INFO("Sending test AT command: \"%s\"", test_msg);
+ ppp_error_t result = ppp_serial_write((const uint8_t *)test_msg, test_len);
+
+ PPP_DEBUG_INFO("Test result: %s", result == PPP_ERR_OK ? "SUCCESS" : "FAILED");
+ PPP_DEBUG_INFO("=== UART Test End ===");
+
+ return result;
+}
+
+/**
+ * @brief 强制发送缓冲区中的所有数据
+ */
+ppp_error_t ppp_serial_flush_tx(void)
+{
+ if (!g_serial_ctx.initialized) {
+ PPP_DEBUG_ERROR("PPP serial not initialized");
+ return PPP_ERR_INVALID_PARAM;
+ }
+
+ PPP_DEBUG_INFO("=== TX Buffer Flush Start ===");
+
+ osal_mutex_lock(&g_serial_ctx.tx_mutex);
+
+ uint32_t data_count = ppp_serial_tx_buffer_data_count();
+ if (data_count == 0) {
+ osal_mutex_unlock(&g_serial_ctx.tx_mutex);
+ PPP_DEBUG_INFO("TX buffer is empty, nothing to flush");
+ PPP_DEBUG_INFO("=== TX Buffer Flush End ===");
+ return PPP_ERR_OK;
+ }
+
+ PPP_DEBUG_INFO("Flushing %u bytes from TX buffer", data_count);
+
+ /* 创建临时缓冲区来存储要发送的数据 */
+ uint8_t *temp_buffer = (uint8_t *)osal_kmalloc(data_count, OSAL_GFP_KERNEL);
+ if (temp_buffer == NULL) {
+ osal_mutex_unlock(&g_serial_ctx.tx_mutex);
+ PPP_DEBUG_ERROR("Failed to allocate temporary buffer for flush");
+ return PPP_ERR_MEMORY;
+ }
+
+ /* 从环形缓冲区复制数据到临时缓冲区 */
+ for (uint32_t i = 0; i < data_count; i++) {
+ temp_buffer[i] = g_serial_ctx.tx_buffer[g_serial_ctx.tx_tail];
+ g_serial_ctx.tx_tail = (g_serial_ctx.tx_tail + 1) % g_serial_ctx.tx_buffer_size;
+ g_serial_ctx.tx_count--;
+ }
+
+ osal_mutex_unlock(&g_serial_ctx.tx_mutex);
+
+ /* 发送数据 */
+ PPP_DEBUG_INFO("Calling uapi_uart_write(bus=%u, data=%p, len=%u, timeout=1000)...",
+ g_serial_ctx.uart_bus, temp_buffer, data_count);
+ // PPP_DEBUG_HEXDUMP(temp_buffer, data_count);
+
+ int32_t write_result = uapi_uart_write(g_serial_ctx.uart_bus, temp_buffer, data_count, 1000);
+ PPP_DEBUG_INFO("uapi_uart_write returned: %d (expected: %u)", write_result, data_count);
+
+ ppp_error_t result = PPP_ERR_OK;
+ if (write_result != (int32_t)data_count) {
+ PPP_DEBUG_ERROR("UART write failed during flush: returned %d, expected %u", write_result, data_count);
+ PPP_DEBUG_ERROR("Possible causes: UART not initialized, hardware error, or timeout");
+ g_serial_ctx.tx_errors++;
+ result = PPP_ERR_UART;
+ } else {
+ g_serial_ctx.tx_bytes += data_count;
+ PPP_DEBUG_INFO("Flushed %u bytes successfully (total tx: %u bytes)",
+ data_count, g_serial_ctx.tx_bytes);
+ }
+
+ /* 释放临时缓冲区 */
+ osal_kfree(temp_buffer);
+
+ PPP_DEBUG_INFO("Flush result: %s (error code: %d)",
+ result == PPP_ERR_OK ? "SUCCESS" : "FAILED", result);
+ PPP_DEBUG_INFO("=== TX Buffer Flush End ===");
+
+ return result;
+}
+
+/**
+ * @brief 清空发送缓冲区(丢弃数据)
+ */
+void ppp_serial_flush_tx_discard(void)
+{
+ if (!g_serial_ctx.initialized) {
+ return;
+ }
+
+ osal_mutex_lock(&g_serial_ctx.tx_mutex);
+ uint32_t old_count = g_serial_ctx.tx_count;
+ g_serial_ctx.tx_head = 0;
+ g_serial_ctx.tx_tail = 0;
+ g_serial_ctx.tx_count = 0;
+ osal_mutex_unlock(&g_serial_ctx.tx_mutex);
+
+ PPP_DEBUG_INFO("TX buffer discarded (%u bytes)", old_count);
+}
+
+/**
+ * @brief 获取发送缓冲区使用情况
+ */
+uint32_t ppp_serial_tx_available(void)
+{
+ if (!g_serial_ctx.initialized) {
+ return 0;
+ }
+
+ osal_mutex_lock(&g_serial_ctx.tx_mutex);
+ uint32_t count = ppp_serial_tx_buffer_data_count();
+ osal_mutex_unlock(&g_serial_ctx.tx_mutex);
+
+ return count;
}
\ No newline at end of file