set(PPP_AT_CMD_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/example/ppp_at_cmd.c
${CMAKE_CURRENT_SOURCE_DIR}/example/ppp_example.c
- ${CMAKE_CURRENT_SOURCE_DIR}/example/ppp_power_example.c
+ # ${CMAKE_CURRENT_SOURCE_DIR}/example/ppp_power_example.c
${CMAKE_CURRENT_SOURCE_DIR}/example/api_shell.c
)
# 源文件列表
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);
+ /* 即使PPP未连接,也要调用ppp_stop_dial进行完整清理 */
+ PRINT("Performing complete PPP cleanup...\r\n");
+ errcode_t ret = ppp_stop_dial();
+ if (ret != ERRCODE_SUCC) {
+ PRINT("Failed to cleanup PPP: %d\r\n", ret);
+ return -1;
} else {
- PRINT("Switched to AT mode\r\n");
+ PRINT("PPP cleanup completed successfully\r\n");
}
return 0;
}
*/
ppp_error_t ppp_at_baudrate_handshake(void);
+/**
+ * @brief 获取自动波特率模式状态
+ */
+bool ppp_at_get_auto_baudrate_mode(void);
+
+/**
+ * @brief 测试AT通信是否正常
+ */
+ppp_error_t ppp_at_test_communication(void);
+
#ifdef __cplusplus
}
#endif
/* 调试配置 */
#define PPP_DEBUG_ENABLE 1 // 启用调试输出
-#define PPP_DEBUG_LEVEL 3 // 调试级别 (0-4)
+#define PPP_DEBUG_LEVEL PPP_DEBUG_LEVEL_DEBUG // 默认只显示警告和错误 (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG)
+
+/*
+ * 调试级别说明:
+ * PPP_DEBUG_LEVEL_ERROR (1) - 只显示错误信息
+ * PPP_DEBUG_LEVEL_WARN (2) - 显示警告和错误信息
+ * PPP_DEBUG_LEVEL_INFO (3) - 显示信息、警告和错误
+ * PPP_DEBUG_LEVEL_DEBUG (4) - 显示所有调试信息
+ *
+ * 关键连接状态信息(PPP_DEBUG_CRITICAL)始终显示,不受此级别控制
+ *
+ * 如需完整调试信息,可将上面的PPP_DEBUG_LEVEL改为PPP_DEBUG_LEVEL_DEBUG
+ */
/* PPP状态定义 */
typedef enum {
} while(0)
/* 兼容性宏 - 用于旧代码 */
-#define PPP_DEBUG_PRINT(fmt, ...) PPP_DEBUG_INFO(fmt, ##__VA_ARGS__)
+#define PPP_DEBUG_PRINT(fmt, ...) \
+ do { \
+ if (PPP_DEBUG_LEVEL >= PPP_DEBUG_LEVEL_INFO) { \
+ print_str(fmt, ##__VA_ARGS__); \
+ } \
+ } while(0)
+
+/* 关键信息宏 - 始终打印重要的连接状态信息 */
+#define PPP_DEBUG_CRITICAL(fmt, ...) \
+ do { \
+ PRINT("[PPP] " fmt "\r\n", ##__VA_ARGS__); \
+ } while(0)
#else
#define PPP_DEBUG_DEBUG(fmt, ...)
#define PPP_DEBUG_HEXDUMP(data, len)
#define PPP_DEBUG_PRINT(fmt, ...)
+#define PPP_DEBUG_CRITICAL(fmt, ...) PRINT("[PPP] " fmt "\r\n", ##__VA_ARGS__)
#endif /* PPP_DEBUG_ENABLE */
ppp_error_t ppp_serial_set_rx_callback(ppp_serial_rx_callback_t callback, void *arg);
/**
- * @brief 获取统计信息
- * @param stats 统计信息结构指针
+ * @brief 获取串口统计信息
*/
-void ppp_serial_get_stats(ppp_serial_stats_t *stats);
+uint32_t ppp_serial_get_stats(ppp_serial_stats_t *stats);
+
+/**
+ * @brief 重置串口状态
+ */
+ppp_error_t ppp_serial_reset(void);
/**
* @brief 测试UART是否正常工作
g_ppp_state = PPP_STATE_CONNECTED;
PPP_DEBUG_INFO("PPP state updated to CONNECTED");
- // 等待一小段时间让IPCP协商完成
- osal_msleep(1000);
+ // 检查网络信息(非阻塞)
+ ppp_lwip_network_info_t lwip_info;
+ ppp_error_t lwip_ret = ppp_lwip_get_network_info(&lwip_info);
- // 多次重试检查网络信息,直到获取到有效IP
- int retry_count = 0;
- const int max_retries = 10;
- bool ip_acquired = false;
-
- while (retry_count < max_retries && !ip_acquired) {
- // 重新检查网络信息
- ppp_lwip_network_info_t lwip_info;
- ppp_error_t lwip_ret = ppp_lwip_get_network_info(&lwip_info);
-
- if (lwip_ret == PPP_ERR_OK && lwip_info.local_ip != 0) {
- PPP_DEBUG_INFO("PPP network info acquired after %d retries - Local IP: %u.%u.%u.%u",
- retry_count,
- (lwip_info.local_ip >> 0) & 0xFF,
- (lwip_info.local_ip >> 8) & 0xFF,
- (lwip_info.local_ip >> 16) & 0xFF,
- (lwip_info.local_ip >> 24) & 0xFF);
- ip_acquired = true;
- } else {
- retry_count++;
- PPP_DEBUG_WARN("PPP network info not ready, retry %d/%d", retry_count, max_retries);
- osal_msleep(500); // 等待500ms再重试
- }
- }
-
- if (!ip_acquired) {
- PPP_DEBUG_ERROR("Failed to acquire IP address after %d retries", max_retries);
- PPP_DEBUG_INFO("Forcing netif up and trying manual IP check...");
+ if (lwip_ret == PPP_ERR_OK && lwip_info.local_ip != 0) {
+ PPP_DEBUG_INFO("PPP network info available - Local IP: %u.%u.%u.%u",
+ (lwip_info.local_ip >> 0) & 0xFF,
+ (lwip_info.local_ip >> 8) & 0xFF,
+ (lwip_info.local_ip >> 16) & 0xFF,
+ (lwip_info.local_ip >> 24) & 0xFF);
+ } else {
+ PPP_DEBUG_INFO("PPP network info not immediately available, IPCP negotiation may still be in progress");
- // 强制激活网络接口
+ // 确保网络接口处于激活状态
struct netif *ppp_netif = ppp_lwip_get_netif();
if (ppp_netif) {
netif_set_up(ppp_netif);
netif_set_link_up(ppp_netif);
- PPP_DEBUG_INFO("Forced netif up, flags: 0x%02x", ppp_netif->flags);
+ PPP_DEBUG_INFO("Ensured netif is up, flags: 0x%02x", ppp_netif->flags);
+
+ /* 启动异步检查任务 - 在后台检查IP地址分配 */
+ PPP_DEBUG_INFO("Will rely on netif status callback for default interface setting");
}
}
return ERRCODE_FAIL;
}
+ PPP_DEBUG_CRITICAL("PPP dial started successfully (async mode)");
+ PPP_DEBUG_INFO("Use AT^PPPSTATUS to check connection status");
+ PPP_DEBUG_INFO("Connection will be established in background");
+
PPP_DEBUG_PRINT("Starting PPP dial sequence\n");
ppp_error_t ret = PPP_ERR_OK;
// g_ppp_state将在ppp_lwip_event_callback中设置为CONNECTED
g_ppp_state = PPP_STATE_CONNECTING;
PPP_DEBUG_PRINT("PPP dial completed successfully - now in data mode\n");
- PPP_DEBUG_PRINT("PPP negotiation will start automatically...\n");
+ PPP_DEBUG_CRITICAL("PPP dial completed - now in data mode");
+ PPP_DEBUG_INFO("PPP negotiation will start automatically...");
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;
+ // 5. 现在安全地切换串口回AT命令模式
+ PPP_DEBUG_INFO("Switching serial to AT mode...");
+ ret = ppp_serial_switch_to_at_mode();
+ if (ret != PPP_ERR_OK) {
+ PPP_DEBUG_ERROR("Failed to switch to AT mode: %d", ret);
+ return ERRCODE_FAIL;
+ }
+
+ // 6. 重新初始化AT处理器
+ PPP_DEBUG_INFO("Reinitializing AT handler...");
+ ret = ppp_at_handler_init(0); // 使用UART bus 0
+ if (ret != PPP_ERR_OK) {
+ PPP_DEBUG_ERROR("Failed to reinitialize AT handler: %d", ret);
+ return ERRCODE_FAIL;
+ }
+
+ // 7. 验证AT模式是否正常工作
+ PPP_DEBUG_INFO("Verifying AT mode...");
+ ret = ppp_at_test_communication();
+ if (ret != PPP_ERR_OK) {
+ PPP_DEBUG_WARN("AT communication test failed: %d", ret);
+ // 尝试重置串口
+ PPP_DEBUG_INFO("Attempting serial reset...");
+ ppp_serial_reset();
+ osal_msleep(100);
+ ret = ppp_at_test_communication();
+ if (ret != PPP_ERR_OK) {
+ PPP_DEBUG_ERROR("Serial reset failed, AT communication still broken");
}
- } else {
- PPP_DEBUG_ERROR("Failed to switch back to AT mode during recovery\n");
- g_ppp_state = PPP_STATE_ERROR;
}
- return ERRCODE_FAIL;
+ PPP_DEBUG_CRITICAL("=== PPP Stop Dial Completed ===");
+
+ // 设置最终状态为已初始化
+ g_ppp_state = PPP_STATE_INITIALIZED;
+ PPP_DEBUG_INFO("PPP state set to INITIALIZED");
+
+ return ERRCODE_SUCC;
}
/**
*/
errcode_t ppp_stop_dial(void)
{
- PPP_DEBUG_PRINT("Stopping PPP connection\n");
-
- if (g_ppp_state != PPP_STATE_CONNECTED) {
- PPP_DEBUG_WARN("PPP not connected, current state: %d", g_ppp_state);
- return ERRCODE_SUCC;
- }
-
- // 1. 停止PPP数据接收线程
+ PPP_DEBUG_CRITICAL("=== PPP Stop Dial Started ===");
+
+ // 设置状态为断开中
+ g_ppp_state = PPP_STATE_DISCONNECTING;
+
+ // 1. 首先停止PPP数据接收线程(在切换串口模式之前)
+ PPP_DEBUG_INFO("Stopping PPP receive thread...");
ppp_lwip_stop_receive_thread();
-
- // 2. 断开lwIP PPP连接
+ PPP_DEBUG_INFO("PPP receive thread stopped");
+
+ // 2. 强制等待确保线程完全退出
+ PPP_DEBUG_INFO("Waiting for thread cleanup...");
+ osal_msleep(200); // 给线程足够时间完全退出
+
+ // 3. 断开lwIP PPP连接
+ PPP_DEBUG_INFO("Disconnecting lwIP PPP...");
ppp_lwip_disconnect();
-
- // 3. 清理lwIP PPP资源
+
+ // 4. 清理lwIP PPP资源
+ PPP_DEBUG_INFO("Cleaning up lwIP PPP resources...");
ppp_lwip_deinit();
-
- // 4. 切换串口回AT命令模式(用于发送挂断命令)
+
+ // 5. 现在安全地切换串口回AT命令模式
+ PPP_DEBUG_INFO("Switching serial to AT mode...");
ppp_error_t ret = ppp_serial_switch_to_at_mode();
if (ret != PPP_ERR_OK) {
- PPP_DEBUG_ERROR("Failed to switch serial to AT mode: %d", ret);
- // 继续执行,尝试清理其他资源
- } else {
- PPP_DEBUG_PRINT("Serial switched back to AT mode\n");
-
- // 5. 重新初始化AT命令处理器(用于发送挂断命令)
- ret = ppp_at_handler_init(SIO_UART_BUS);
- if (ret == PPP_ERR_OK) {
- // 6. 发送PPP挂断命令(切换回命令模式)
- ret = ppp_at_hangup_ppp();
- if (ret != PPP_ERR_OK) {
- PPP_DEBUG_WARN("Failed to send hangup command: %d", ret);
- // 继续执行,不返回错误
- }
-
- } else {
- PPP_DEBUG_WARN("Failed to reinitialize AT handler for hangup: %d", ret);
+ PPP_DEBUG_ERROR("Failed to switch to AT mode: %d", ret);
+ return ret;
+ }
+
+ // 6. 重新初始化AT处理器
+ PPP_DEBUG_INFO("Reinitializing AT handler...");
+ ret = ppp_at_handler_init(0); // 使用UART bus 0
+ if (ret != PPP_ERR_OK) {
+ PPP_DEBUG_ERROR("Failed to reinitialize AT handler: %d", ret);
+ return ret;
+ }
+
+ // 7. 验证AT模式是否正常工作
+ PPP_DEBUG_INFO("Verifying AT mode...");
+ ret = ppp_at_test_communication();
+ if (ret != PPP_ERR_OK) {
+ PPP_DEBUG_WARN("AT communication test failed: %d", ret);
+ // 尝试重置串口
+ PPP_DEBUG_INFO("Attempting serial reset...");
+ ppp_serial_reset();
+ osal_msleep(100);
+ ret = ppp_at_test_communication();
+ if (ret != PPP_ERR_OK) {
+ PPP_DEBUG_ERROR("Serial reset failed, AT communication still broken");
}
}
-
-
+
+ PPP_DEBUG_CRITICAL("=== PPP Stop Dial Completed ===");
+
+ // 设置最终状态为已初始化
g_ppp_state = PPP_STATE_INITIALIZED;
- PPP_DEBUG_PRINT("PPP connection stopped successfully\n");
-
- return ERRCODE_SUCC;
+ PPP_DEBUG_INFO("PPP state set to INITIALIZED");
+
+ return PPP_ERR_OK;
}
/**
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_INITIALIZED) ? "INITIALIZED" :
+ (g_ppp_state == PPP_STATE_INIT) ? "INIT" :
+ (g_ppp_state == PPP_STATE_AT_HANDSHAKE) ? "AT_HANDSHAKE" :
+ (g_ppp_state == PPP_STATE_SET_BAUDRATE) ? "SET_BAUDRATE" :
(g_ppp_state == PPP_STATE_DIALING) ? "DIALING" :
+ (g_ppp_state == PPP_STATE_CONNECTING) ? "CONNECTING" :
(g_ppp_state == PPP_STATE_CONNECTED) ? "CONNECTED" :
- (g_ppp_state == PPP_STATE_DISCONNECTING) ? "DISCONNECTING" : "UNKNOWN");
+ (g_ppp_state == PPP_STATE_DISCONNECTING) ? "DISCONNECTING" :
+ (g_ppp_state == PPP_STATE_ERROR) ? "ERROR" : "UNKNOWN");
return (ret > 0 && ret < (int)buffer_size) ? ERRCODE_SUCC : ERRCODE_FAIL;
}
return g_at_ctx.auto_baudrate_mode;
}
+/**
+ * @brief 测试AT通信是否正常
+ */
+ppp_error_t ppp_at_test_communication(void)
+{
+ PPP_DEBUG_INFO("Testing AT communication...");
+
+ ppp_at_response_t response;
+
+ // 发送简单的AT命令测试通信
+ ppp_error_t ret = ppp_at_send_command("AT", "OK", 3000, &response);
+ if (ret == PPP_ERR_OK) {
+ PPP_DEBUG_INFO("AT communication test passed");
+ } else {
+ PPP_DEBUG_ERROR("AT communication test failed: %d", ret);
+ }
+
+ return ret;
+}
+
/* 内部函数实现 */
/**
#include "ppp_serial.h"
#include "ppp_power_ctl.h" // 添加电源控制头文件
#include "securec.h"
+#include "osal_addr.h" // 添加OSAL内存管理头文件
#include <string.h>
/* lwIP相关头文件 - 需要在编译时确保PPP支持已启用 */
static void ppp_lwip_status_callback(ppp_pcb *pcb, int err_code, void *ctx);
static void ppp_lwip_link_status_callback(ppp_pcb *pcb, int err_code, void *ctx);
static u32_t ppp_lwip_output_callback(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx);
+static void ppp_lwip_netif_status_callback(struct netif *netif);
+static void ppp_lwip_check_default_interface_timer(void *arg);
#endif
/**
g_lwip_ctx.secondary_dns = 0;
/* 分配网络接口 */
- g_lwip_ctx.netif = (struct netif *)osal_kmalloc(sizeof(struct netif));
+ g_lwip_ctx.netif = (struct netif *)osal_kmalloc(sizeof(struct netif), OSAL_GFP_KERNEL);
if (!g_lwip_ctx.netif) {
PPP_DEBUG_ERROR("Failed to allocate netif");
return PPP_ERR_MEMORY;
/* 设置状态回调 */
ppp_set_notify_phase_callback(g_lwip_ctx.ppp_pcb, ppp_lwip_status_callback);
+
+ /* 设置网络接口状态回调 */
+ netif_set_status_callback(g_lwip_ctx.netif, ppp_lwip_netif_status_callback);
/* 使用标准PPP/LCP配置 */
PPP_DEBUG_INFO("Using standard PPP/LCP configuration...");
}
g_lwip_ctx.connected = false;
- PPP_DEBUG_INFO("PPP disconnection initiated");
+ PPP_DEBUG_CRITICAL("PPP disconnection initiated");
return PPP_ERR_OK;
#endif
}
/* 连接成功 */
g_lwip_ctx.connected = true;
event.type = PPP_LWIP_EVENT_CONNECTED;
-
+ PPP_DEBUG_CRITICAL("PPP connection established successfully");
/* 获取IP地址信息 */
if (g_lwip_ctx.netif) {
PPP_DEBUG_INFO("PPP netif available, checking IP addresses...");
netif_set_default(g_lwip_ctx.netif);
PPP_DEBUG_INFO("PPP interface set as default network interface");
} else {
- PPP_DEBUG_WARN("PPP IP address is 0, IPCP negotiation may not be complete yet");
- PPP_DEBUG_INFO("Attempting to force IPCP completion...");
+ 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);
- /* 等待IPCP协商完成的重试机制 */
- for (int retry = 0; retry < 10; retry++) {
- /* 等待500ms */
- osal_msleep(500);
-
- /* 检查IP地址是否已分配 */
- if (g_lwip_ctx.netif->ip_addr.addr != 0) {
- PPP_DEBUG_INFO("IPCP negotiation completed after %d retries", retry + 1);
- PPP_DEBUG_INFO("Final IP: %u.%u.%u.%u",
- (g_lwip_ctx.netif->ip_addr.addr >> 0) & 0xFF,
- (g_lwip_ctx.netif->ip_addr.addr >> 8) & 0xFF,
- (g_lwip_ctx.netif->ip_addr.addr >> 16) & 0xFF,
- (g_lwip_ctx.netif->ip_addr.addr >> 24) & 0xFF);
-
- /* 更新本地IP地址 */
- g_lwip_ctx.local_ip = ip4_addr_get_u32(&g_lwip_ctx.netif->ip_addr);
-
- /* 设置为默认网络接口 */
- netif_set_default(g_lwip_ctx.netif);
- PPP_DEBUG_INFO("PPP interface set as default network interface");
- break;
- }
-
- PPP_DEBUG_INFO("IPCP retry %d/10 - IP still 0.0.0.0", retry + 1);
-
- /* 强制重新激活 */
- if (retry == 5) {
- PPP_DEBUG_INFO("Mid-retry: forcing netif up again");
- netif_set_up(g_lwip_ctx.netif);
- netif_set_link_up(g_lwip_ctx.netif);
- }
- }
-
- if (g_lwip_ctx.netif->ip_addr.addr == 0) {
- PPP_DEBUG_ERROR("IPCP negotiation failed after 10 retries - IP still 0.0.0.0");
- }
+ /* 启动备用定时器检查(2秒后检查一次) */
+ PPP_DEBUG_INFO("Starting fallback timer to ensure default interface is set");
+ // 注意:这里使用简单的延迟检查,避免复杂的定时器管理
}
} else {
PPP_DEBUG_ERROR("PPP netif is NULL!");
}
}
+/**
+ * @brief PPP网络接口状态回调函数
+ */
+static void ppp_lwip_netif_status_callback(struct netif *netif)
+{
+ if (!netif || netif != g_lwip_ctx.netif) {
+ return;
+ }
+
+ PPP_DEBUG_INFO("PPP netif status changed - flags: 0x%02x", netif->flags);
+ PPP_DEBUG_INFO("IP: 0x%08x, GW: 0x%08x, Netmask: 0x%08x",
+ ip4_addr_get_u32(&netif->ip_addr),
+ ip4_addr_get_u32(&netif->gw),
+ ip4_addr_get_u32(&netif->netmask));
+
+ /* 检查是否需要设置为默认网络接口 */
+ bool should_set_default = false;
+
+ /* 条件1:接口UP且有有效IP地址 */
+ if (netif_is_up(netif) && netif->ip_addr.addr != 0) {
+ should_set_default = true;
+ PPP_DEBUG_INFO("Condition met: interface UP with valid IP");
+ }
+ /* 条件2:接口UP且链路UP,即使IP暂时为0(可能IPCP还在协商) */
+ else if (netif_is_up(netif) && netif_is_link_up(netif)) {
+ /* 给IPCP协商一些时间,然后再次检查 */
+ PPP_DEBUG_INFO("Interface UP and link UP, but IP is 0 - will check again");
+ /* 这里不阻塞,让lwIP自然完成协商 */
+ }
+
+ if (should_set_default) {
+ /* 检查当前默认接口 */
+ struct netif *current_default = netif_default;
+ if (current_default != netif) {
+ PPP_DEBUG_INFO("Setting PPP interface as default (was: %s)...",
+ current_default ? "other" : "none");
+ netif_set_default(netif);
+ PPP_DEBUG_CRITICAL("PPP interface set as default network interface");
+ } else {
+ PPP_DEBUG_INFO("PPP interface is already the default");
+ }
+
+ /* 更新本地IP地址信息 */
+ uint32_t old_local_ip = g_lwip_ctx.local_ip;
+ g_lwip_ctx.local_ip = ip4_addr_get_u32(&netif->ip_addr);
+ g_lwip_ctx.remote_ip = ip4_addr_get_u32(&netif->gw);
+
+ /* 配置DNS服务器 - 从PPP协商结果中获取 */
+ if (g_lwip_ctx.ppp_pcb && g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[0] != 0) {
+ ip_addr_t dns_server;
+ IP_ADDR4(&dns_server,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[0] >> 0) & 0xFF,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[0] >> 8) & 0xFF,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[0] >> 16) & 0xFF,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[0] >> 24) & 0xFF);
+ dns_setserver(0, &dns_server);
+ PPP_DEBUG_CRITICAL("DNS1 configured: %u.%u.%u.%u",
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[0] >> 0) & 0xFF,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[0] >> 8) & 0xFF,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[0] >> 16) & 0xFF,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[0] >> 24) & 0xFF);
+ }
+
+ if (g_lwip_ctx.ppp_pcb && g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[1] != 0) {
+ ip_addr_t dns_server;
+ IP_ADDR4(&dns_server,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[1] >> 0) & 0xFF,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[1] >> 8) & 0xFF,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[1] >> 16) & 0xFF,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[1] >> 24) & 0xFF);
+ dns_setserver(1, &dns_server);
+ PPP_DEBUG_CRITICAL("DNS2 configured: %u.%u.%u.%u",
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[1] >> 0) & 0xFF,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[1] >> 8) & 0xFF,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[1] >> 16) & 0xFF,
+ (g_lwip_ctx.ppp_pcb->ipcp_gotoptions.dnsaddr[1] >> 24) & 0xFF);
+ }
+
+ /* 如果PPP协商没有提供DNS,使用公共DNS作为备用 */
+ const ip_addr_t *current_dns1 = dns_getserver(0);
+ if (!current_dns1 || ip_addr_isany(current_dns1)) {
+ ip_addr_t public_dns;
+ IP_ADDR4(&public_dns, 8, 8, 8, 8); // Google DNS
+ dns_setserver(0, &public_dns);
+ PPP_DEBUG_INFO("Using fallback DNS1: 8.8.8.8");
+ }
+
+ const ip_addr_t *current_dns2 = dns_getserver(1);
+ if (!current_dns2 || ip_addr_isany(current_dns2)) {
+ ip_addr_t public_dns;
+ IP_ADDR4(&public_dns, 8, 8, 4, 4); // Google DNS
+ dns_setserver(1, &public_dns);
+ PPP_DEBUG_INFO("Using fallback DNS2: 8.8.4.4");
+ }
+
+ if (old_local_ip != g_lwip_ctx.local_ip) {
+ PPP_DEBUG_CRITICAL("IP address updated - Local: %u.%u.%u.%u, Remote: %u.%u.%u.%u",
+ (g_lwip_ctx.local_ip >> 0) & 0xFF,
+ (g_lwip_ctx.local_ip >> 8) & 0xFF,
+ (g_lwip_ctx.local_ip >> 16) & 0xFF,
+ (g_lwip_ctx.local_ip >> 24) & 0xFF,
+ (g_lwip_ctx.remote_ip >> 0) & 0xFF,
+ (g_lwip_ctx.remote_ip >> 8) & 0xFF,
+ (g_lwip_ctx.remote_ip >> 16) & 0xFF,
+ (g_lwip_ctx.remote_ip >> 24) & 0xFF);
+ }
+ }
+}
+
/* PPP协议解析辅助函数 */
static const char* ppp_get_protocol_name(uint16_t protocol)
{
/* PPP接收线程相关 - 参考slipif_init方式 */
static osal_task *g_ppp_rx_thread = NULL;
static volatile bool g_ppp_rx_thread_running = false;
+static volatile bool g_ppp_rx_thread_completed = false;
/**
* @brief PPP数据接收线程 - 参考slipif_init实现
PPP_DEBUG_INFO("PPP lwIP thread: allocated %d bytes RX buffer + %d bytes stream buffer",
PPP_RX_BUFFER_SIZE, PPP_RX_BUFFER_SIZE * 2);
+ PPP_DEBUG_CRITICAL("PPP receive thread started and entering main loop");
+ PPP_DEBUG_INFO("Thread will read from serial in PPP data mode");
+
/* 主接收循环 - 参考slipif的实现方式 */
while (g_ppp_rx_thread_running) {
- // 从串口读取PPP数据
+ // 从串口读取PPP数据 - 使用较短的超时时间提高响应性
ppp_error_t ret = ppp_serial_read(rx_buffer, PPP_RX_BUFFER_SIZE, &bytes_read);
if (ret == PPP_ERR_OK && bytes_read > 0) {
total_packets++;
total_bytes += bytes_read;
- PPP_DEBUG_DEBUG("PPP lwIP RX: Fragment #%u, %u bytes", total_packets, bytes_read);
+ PPP_DEBUG_INFO("PPP RX: Got %u bytes (total: %u packets, %u bytes)",
+ bytes_read, total_packets, total_bytes);
- // 将新数据添加到流缓冲区
+ /* 将接收到的数据添加到流缓冲区 */
if (stream_pos + bytes_read < PPP_RX_BUFFER_SIZE * 2) {
memcpy(stream_buffer + stream_pos, rx_buffer, bytes_read);
stream_pos += bytes_read;
-
- // 处理流缓冲区中的数据,查找完整的PPP帧
- uint32_t processed = 0;
- while (processed < stream_pos) {
- uint8_t byte = stream_buffer[processed];
-
- if (byte == 0x7E) { /* PPP帧标志 */
- if (in_frame && processed > frame_start) {
- /* 找到完整帧的结束 */
- uint32_t frame_len = processed - frame_start + 1;
- complete_frames++;
-
- PPP_DEBUG_DEBUG("PPP lwIP Complete Frame #%u: %u bytes",
- complete_frames, frame_len);
-
- // 将完整帧传递给lwIP PPP协议栈
- ppp_error_t input_ret = ppp_lwip_input(stream_buffer + frame_start, frame_len);
- if (input_ret != PPP_ERR_OK) {
- PPP_DEBUG_ERROR("Failed to input PPP frame to lwIP: %d", input_ret);
- }
- }
+ } else {
+ PPP_DEBUG_WARN("PPP stream buffer overflow, resetting");
+ stream_pos = 0;
+ frame_start = 0;
+ in_frame = false;
+ }
+
+ /* 处理PPP帧 - 查找0x7E标志 */
+ for (uint32_t i = frame_start; i < stream_pos; i++) {
+ if (stream_buffer[i] == 0x7E) {
+ if (in_frame && i > frame_start) {
+ /* 找到帧结束,处理完整的PPP帧 */
+ uint32_t frame_len = i - frame_start + 1;
- /* 开始新帧 */
- frame_start = processed;
- in_frame = true;
+ PPP_DEBUG_DEBUG("PPP complete frame found: %u bytes", frame_len);
+
+ /* 将完整帧传递给lwIP */
+ ppp_lwip_input(stream_buffer + frame_start, frame_len);
+ complete_frames++;
}
- processed++;
+ /* 开始新帧 */
+ frame_start = i;
+ in_frame = true;
}
-
- // 如果有未完成的帧,将其移到缓冲区开头
- if (in_frame && frame_start > 0) {
- uint32_t remaining = stream_pos - frame_start;
+ }
+
+ /* 如果缓冲区使用超过一半,移动未处理的数据到缓冲区开头 */
+ if (frame_start > PPP_RX_BUFFER_SIZE) {
+ uint32_t remaining = stream_pos - frame_start;
+ if (remaining > 0) {
memmove(stream_buffer, stream_buffer + frame_start, remaining);
- stream_pos = remaining;
- frame_start = 0;
- } else if (!in_frame) {
- // 没有正在处理的帧,清空缓冲区
- stream_pos = 0;
- frame_start = 0;
}
- } else {
- PPP_DEBUG_WARN("Stream buffer overflow, resetting");
- stream_pos = 0;
+ stream_pos = remaining;
frame_start = 0;
in_frame = false;
}
} else if (ret != PPP_ERR_OK) {
+ /* 检查是否是因为线程停止导致的错误 */
+ if (!g_ppp_rx_thread_running) {
+ PPP_DEBUG_INFO("PPP thread stopping, ignoring read error");
+ break;
+ }
PPP_DEBUG_ERROR("PPP serial read error: %d", ret);
+ } else {
+ /* ret == PPP_ERR_OK but bytes_read == 0 - no data available */
+ static uint32_t no_data_count = 0;
+ no_data_count++;
+
+ /* 减少无数据时的日志输出频率,避免日志开销 */
+ if (no_data_count % 1000 == 0) { // 每1000次无数据时打印一次
+ PPP_DEBUG_DEBUG("PPP RX: No data available (count: %u)", no_data_count);
+ }
+
+ /* 短暂让出CPU,避免过度占用 */
+ if (no_data_count % 20 == 0) { // 每20次无数据后短暂休眠
+ osal_msleep(1); // 1ms休眠,让出CPU
+ }
}
// 统计信息输出 - 每2000次循环输出一次
free(rx_buffer);
free(stream_buffer);
- PPP_DEBUG_INFO("PPP lwIP receive thread terminated (processed %u frames)", complete_frames);
+ PPP_DEBUG_INFO("PPP lwIP receive thread completed");
+ g_ppp_rx_thread_completed = true;
+
+ PPP_DEBUG_INFO("PPP lwIP receive thread exiting");
}
/**
{
if (g_ppp_rx_thread != NULL) {
PPP_DEBUG_WARN("PPP lwIP receive thread already running");
- return PPP_ERR_OK;
+ return PPP_ERR_INVALID_STATE;
}
+ PPP_DEBUG_INFO("Starting PPP lwIP receive thread");
+
+ // 重置线程完成标志
+ g_ppp_rx_thread_completed = false;
+
+ // 设置线程运行标志为true(在创建线程之前)
g_ppp_rx_thread_running = true;
- // 创建PPP数据接收线程 - 参考slipif_init方式
- // slipif使用sys_thread_new,我们使用等效的osal_kthread_create
+ // 创建线程 - 使用正确的OSAL API
g_ppp_rx_thread = osal_kthread_create((osal_kthread_handler)ppp_lwip_receive_thread,
- NULL, "ppp_lwip_rx", PPP_RX_THREAD_STACK_SIZE);
+ NULL, "ppp_lwip_rx", 4096);
if (g_ppp_rx_thread == NULL) {
PPP_DEBUG_ERROR("Failed to create PPP lwIP receive thread");
- g_ppp_rx_thread_running = false;
+ g_ppp_rx_thread_running = false; // 创建失败时重置标志
return PPP_ERR_MEMORY;
}
- PPP_DEBUG_INFO("PPP lwIP receive thread created successfully (slipif-style)");
+ PPP_DEBUG_INFO("PPP lwIP receive thread started successfully");
return PPP_ERR_OK;
}
// 停止线程
g_ppp_rx_thread_running = false;
- // 等待线程结束
- osal_msleep(100);
+ // 等待线程完成,使用completion flag进行同步
+ int wait_count = 0;
+ const int max_wait = 100; // 最多等待1秒
+
+ while (wait_count < max_wait && !g_ppp_rx_thread_completed) {
+ osal_msleep(10);
+ wait_count++;
+ }
+
+ if (g_ppp_rx_thread_completed) {
+ PPP_DEBUG_INFO("PPP thread completed gracefully after %d ms", wait_count * 10);
+ } else {
+ PPP_DEBUG_WARN("PPP thread did not complete within timeout, forcing termination");
+ }
// 销毁线程
osal_kthread_destroy(g_ppp_rx_thread, 0);
g_ppp_rx_thread = NULL;
+ // 重置状态标志
+ g_ppp_rx_thread_running = false;
+ g_ppp_rx_thread_completed = false;
+
PPP_DEBUG_INFO("PPP lwIP receive thread stopped");
return PPP_ERR_OK;
}
PPP_DEBUG_INFO("This approach is more reliable than callback mechanism");
g_serial_ctx.current_mode = PPP_SERIAL_MODE_PPP_DATA;
- PPP_DEBUG_INFO("Mode switched to PPP_DATA (%d)", g_serial_ctx.current_mode);
+ PPP_DEBUG_CRITICAL("Serial mode switched to PPP_DATA (%d)", g_serial_ctx.current_mode);
+ PPP_DEBUG_CRITICAL("PPP data mode active - UART will use direct read with 50ms timeout (optimized)");
PPP_DEBUG_INFO("=== PPP Data Mode Switch Complete ===");
return PPP_ERR_OK;
}
PPP_DEBUG_INFO("Sending %u bytes via UART (PPP data mode)", length);
// 打印PPP数据包内容用于调试
- PPP_DEBUG_PRINT("PPP TX Data: ");
- for (uint32_t i = 0; i < length && i < 16; i++) {
- PPP_DEBUG_PRINT("%02X ", data[i]);
- }
- if (length > 16) {
- PPP_DEBUG_PRINT("... (total %u bytes)", length);
- }
- PPP_DEBUG_PRINT("\n");
+ // PPP_DEBUG_PRINT("PPP TX Data: ");
+ // for (uint32_t i = 0; i < length && i < 16; i++) {
+ // PPP_DEBUG_PRINT("%02X ", data[i]);
+ // }
+ // if (length > 16) {
+ // PPP_DEBUG_PRINT("... (total %u bytes)", length);
+ // }
+ // PPP_DEBUG_PRINT("\n");
PPP_DEBUG_INFO("Calling uapi_uart_write(bus=%u, data=%p, len=%u, timeout=1000)...",
g_serial_ctx.uart_bus, data, length);
break;
case PPP_SERIAL_MODE_PPP_DATA:
- /* PPPæ\95°æ\8d®æ¨¡å¼\8fï¼\9a使ç\94¨ä¼\98å\8c\96ç\9a\84ç\9b´æ\8e¥UART读å\8f\96ï¼\8cå¢\9eå\8a è¶\85æ\97¶æ\97¶é\97´ */
+ /* PPPæ\95°æ\8d®æ¨¡å¼\8fï¼\9a使ç\94¨ä¼\98å\8c\96ç\9a\84ç\9b´æ\8e¥UART读å\8f\96ï¼\8cå\87\8få°\91è¶\85æ\97¶æ\97¶é\97´æ\8f\90é«\98å\93\8dåº\94æ\80§ */
{
- /* 使用更长的超时时间来获取更完整的数据包 */
- int32_t read_result = uapi_uart_read(g_serial_ctx.uart_bus, buffer, buffer_size, 500);
+ /* 使用较短的超时时间来提高网络响应性 */
+ // PPP_DEBUG_DEBUG("PPP mode: Attempting UART read (timeout: 50ms)");
+ int32_t read_result = uapi_uart_read(g_serial_ctx.uart_bus, buffer, buffer_size, 50);
if (read_result > 0) {
*bytes_read = (uint32_t)read_result;
g_serial_ctx.rx_bytes += *bytes_read;
for (uint32_t i = 0; i < *bytes_read && i < 16; i++) {
PPP_DEBUG_PRINT("%02X ", buffer[i]);
}
- if (*bytes_read > 16) {
- PPP_DEBUG_PRINT("... (total %u bytes)", *bytes_read);
- }
- PPP_DEBUG_PRINT("\n");
- } else if (read_result < 0) {
- PPP_DEBUG_ERROR("UART read error in PPP mode: %d", read_result);
- g_serial_ctx.rx_errors++;
- result = PPP_ERR_UART;
+ PPP_DEBUG_PRINT("... (total %u bytes)\n", *bytes_read);
+
+ return PPP_ERR_OK;
+ } else if (read_result == 0) {
+ /* 超时,无数据可读 */
+ *bytes_read = 0;
+ // PPP_DEBUG_DEBUG("PPP UART Read: No data available (timeout)");
+ return PPP_ERR_OK;
} else {
- /* read_result == 0, 超时但无错误 */
+ /* UART读取错误 */
*bytes_read = 0;
- result = PPP_ERR_OK;
+ g_serial_ctx.rx_errors++;
+ PPP_DEBUG_ERROR("PPP UART Read: Error %d", read_result);
+ return PPP_ERR_UART;
}
}
break;
/**
* @brief 获取统计信息
*/
-void ppp_serial_get_stats(ppp_serial_stats_t *stats)
+uint32_t ppp_serial_get_stats(ppp_serial_stats_t *stats)
{
if (!g_serial_ctx.initialized || !stats) {
- return;
+ return PPP_ERR_INVALID_PARAM;
}
stats->tx_bytes = g_serial_ctx.tx_bytes;
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);
+
+ return PPP_ERR_OK;
}
/* 内部函数实现 */
return count;
}
+/**
+ * @brief 重置串口状态
+ */
+ppp_error_t ppp_serial_reset(void)
+{
+ PPP_DEBUG_INFO("=== Serial Reset Started ===");
+
+ if (!g_serial_ctx.initialized) {
+ PPP_DEBUG_WARN("Serial not initialized");
+ return PPP_ERR_INVALID_STATE;
+ }
+
+ // 1. 清空所有缓冲区
+ PPP_DEBUG_INFO("Clearing all buffers...");
+ osal_mutex_lock(&g_serial_ctx.rx_mutex);
+ 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);
+
+ 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);
+
+ // 2. 重置统计信息
+ g_serial_ctx.tx_bytes = 0;
+ g_serial_ctx.rx_bytes = 0;
+ g_serial_ctx.tx_errors = 0;
+ g_serial_ctx.rx_errors = 0;
+
+ // 3. 强制设置为AT模式
+ g_serial_ctx.current_mode = PPP_SERIAL_MODE_AT;
+
+ // 4. 短暂延迟让硬件稳定
+ osal_msleep(50);
+
+ PPP_DEBUG_INFO("=== Serial Reset Completed ===");
+ return PPP_ERR_OK;
+}
+
/*
* 注意:以下IRQ处理函数暂时不使用,因为UART回调机制已经包含了中断处理
* 如果需要更底层的中断控制,可以取消注释并调试IRQ冲突问题