From 481b1b64e1d78f49ff2f6d85d8f02c20d41ecb8d Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=AD=99=E6=98=A5=E9=98=B3?= Date: Thu, 11 Sep 2025 17:25:50 +0800 Subject: [PATCH] =?utf8?q?=E4=BC=98=E5=8C=96ppp=20=E4=B8=B2=E5=8F=A3?= =?utf8?q?=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- code/sdk/zhihui/ppp/include/ppp_config.h | 4 +- code/sdk/zhihui/ppp/include/ppp_serial.h | 77 +++-- code/sdk/zhihui/ppp/src/ppp_api.c | 103 +++--- code/sdk/zhihui/ppp/src/ppp_lwip.c | 37 ++- code/sdk/zhihui/ppp/src/ppp_serial.c | 389 +++++++++++++++++------ 5 files changed, 434 insertions(+), 176 deletions(-) diff --git a/code/sdk/zhihui/ppp/include/ppp_config.h b/code/sdk/zhihui/ppp/include/ppp_config.h index 01499707a..62bb67b2c 100644 --- a/code/sdk/zhihui/ppp/include/ppp_config.h +++ b/code/sdk/zhihui/ppp/include/ppp_config.h @@ -25,8 +25,8 @@ extern "C" { #endif /* 支持的波特率列表(自适应模式) */ -#define PPP_BAUDRATE_AUTO_LIST {9600, 57600, 115200} -#define PPP_BAUDRATE_AUTO_COUNT 3 +#define PPP_BAUDRATE_AUTO_LIST {9600, 57600, 115200 , 2000000} +#define PPP_BAUDRATE_AUTO_COUNT 4 /* 支持的固定波特率列表 */ #define PPP_BAUDRATE_FIXED_LIST {4800, 9600, 57600, 115200, 230400, 460800, 750000, 921600, 1000000, 2000000, 4000000} diff --git a/code/sdk/zhihui/ppp/include/ppp_serial.h b/code/sdk/zhihui/ppp/include/ppp_serial.h index 064e5f27e..274a37a02 100644 --- a/code/sdk/zhihui/ppp/include/ppp_serial.h +++ b/code/sdk/zhihui/ppp/include/ppp_serial.h @@ -1,3 +1,7 @@ +/** + * @brief PPP串口模块头文件 - 恢复缓存机制 + */ + #ifndef PPP_SERIAL_H #define PPP_SERIAL_H @@ -8,24 +12,34 @@ extern "C" { #include #include #include "ppp_types.h" -#include "lwip/sio.h" /* 串口接收回调函数类型 */ typedef void (*ppp_serial_rx_callback_t)(const uint8_t *data, uint16_t length, void *arg); -/* 串口配置结构 */ +/* 串口工作模式 */ +typedef enum { + PPP_SERIAL_MODE_NONE = 0, // 未初始化 + PPP_SERIAL_MODE_AT, // AT命令模式(使用普通UART) + PPP_SERIAL_MODE_PPP_DATA // PPP数据模式(使用普通UART + 缓存) +} ppp_serial_mode_t; + +/** + * @brief 串口配置结构 + */ typedef struct { - uint8_t uart_bus; // 串口总线号 + uint8_t uart_bus; // UART总线号 uint32_t baudrate; // 波特率 - uint8_t tx_pin; // TX引脚 - uint8_t rx_pin; // RX引脚 + uint8_t tx_pin; // 发送引脚 + uint8_t rx_pin; // 接收引脚 uint32_t rx_buffer_size; // 接收缓冲区大小 uint32_t tx_buffer_size; // 发送缓冲区大小 ppp_serial_rx_callback_t rx_callback; // 接收回调函数 void *rx_callback_arg; // 回调函数参数 } ppp_serial_config_t; -/* 串口统计信息结构 */ +/** + * @brief 串口统计信息 + */ typedef struct { uint32_t tx_bytes; // 发送字节数 uint32_t rx_bytes; // 接收字节数 @@ -36,38 +50,56 @@ typedef struct { } ppp_serial_stats_t; /** - * @brief 初始化PPP串口 + * @brief 初始化PPP串口(AT命令模式,准备缓存机制) * @param config 串口配置 - * @return PPP错误码 + * @return 错误码 */ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config); /** - * @brief 反初始化PPP串口 + * @brief 去初始化PPP串口 */ void ppp_serial_deinit(void); /** - * @brief 发送数据 + * @brief 切换到PPP数据模式(启用缓存机制) + * @return 错误码 + */ +ppp_error_t ppp_serial_switch_to_ppp_mode(void); + +/** + * @brief 切换回AT命令模式(禁用缓存机制) + * @return 错误码 + */ +ppp_error_t ppp_serial_switch_to_at_mode(void); + +/** + * @brief 获取当前串口模式 + * @return 当前模式 + */ +ppp_serial_mode_t ppp_serial_get_mode(void); + +/** + * @brief 发送数据(根据模式选择直接发送或缓存发送) * @param data 数据指针 * @param length 数据长度 - * @return PPP错误码 + * @return 错误码 */ ppp_error_t ppp_serial_write(const uint8_t *data, uint32_t length); /** - * @brief 读取数据 + * @brief 读取数据(根据模式选择直接读取或从缓存读取) * @param buffer 接收缓冲区 * @param buffer_size 缓冲区大小 - * @param bytes_read 实际读取的字节数 - * @return PPP错误码 + * @param bytes_read 实际读取字节数 + * @return 错误码 */ ppp_error_t ppp_serial_read(uint8_t *buffer, uint32_t buffer_size, uint32_t *bytes_read); /** * @brief 等待数据接收 * @param timeout_ms 超时时间(毫秒) - * @return PPP错误码 + * @return 错误码 */ ppp_error_t ppp_serial_wait_data(uint32_t timeout_ms); @@ -83,11 +115,12 @@ uint32_t ppp_serial_available(void); void ppp_serial_flush_rx(void); /** - * @brief 设置串口波特率 - * @param baudrate 波特率 - * @return PPP错误码 + * @brief 设置接收回调函数 + * @param callback 回调函数 + * @param arg 回调函数参数 + * @return 错误码 */ -ppp_error_t ppp_serial_set_baudrate(uint32_t baudrate); +ppp_error_t ppp_serial_set_rx_callback(ppp_serial_rx_callback_t callback, void *arg); /** * @brief 获取统计信息 @@ -95,12 +128,6 @@ ppp_error_t ppp_serial_set_baudrate(uint32_t baudrate); */ void ppp_serial_get_stats(ppp_serial_stats_t *stats); -/** - * @brief 获取PPP模块SIO句柄 - * @return SIO句柄,如果未初始化则返回NULL - */ -sio_fd_t ppp_get_sio_fd(void); - #ifdef __cplusplus } #endif diff --git a/code/sdk/zhihui/ppp/src/ppp_api.c b/code/sdk/zhihui/ppp/src/ppp_api.c index 8ccff1ca3..db3f2203a 100644 --- a/code/sdk/zhihui/ppp/src/ppp_api.c +++ b/code/sdk/zhihui/ppp/src/ppp_api.c @@ -60,55 +60,68 @@ errcode_t ppp_start_dial(void) // 2. 等待4G模块启动 osal_msleep(2000); - // 3. 初始化AT命令处理(AT命令模式) - ppp_error_t ret = ppp_at_handler_init(SIO_UART_BUS); + // 3. 初始化串口(AT命令模式) + ppp_serial_config_t serial_config = { + .uart_bus = SIO_UART_BUS, + .baudrate = g_ppp_config.baudrate, + .tx_pin = SIO_UART_TX_PIN, + .rx_pin = SIO_UART_RX_PIN, + .rx_buffer_size = PPP_RX_BUFFER_SIZE, + .tx_buffer_size = PPP_TX_BUFFER_SIZE, + .rx_callback = NULL, + .rx_callback_arg = NULL + }; + + 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; + } + + // 4. 初始化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; } - // 4. 执行波特率握手(如果启用自动波特率) + // 5. 执行波特率握手(如果启用自动波特率) 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; } } - // 5. 执行完整的AT指令序列(对应chat文件) + // 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; return ERRCODE_FAIL; } PPP_DEBUG_PRINT("AT dial sequence completed - switching to PPP data mode\n"); - // 6. 关闭AT命令处理器(释放UART资源) + // 7. 关闭AT命令处理器(AT阶段结束) ppp_at_handler_deinit(); - PPP_DEBUG_PRINT("AT handler deinitialized - UART released\n"); + PPP_DEBUG_PRINT("AT handler deinitialized\n"); - // 7. 初始化SIO串口(PPP数据模式) - ppp_serial_config_t serial_config = { - .uart_bus = SIO_UART_BUS, - .baudrate = g_ppp_config.baudrate, - .tx_pin = SIO_UART_TX_PIN, - .rx_pin = SIO_UART_RX_PIN, - .rx_buffer_size = PPP_RX_BUFFER_SIZE, - .tx_buffer_size = PPP_TX_BUFFER_SIZE, - .rx_callback = NULL, // 将在PPP数据接收线程中设置 - .rx_callback_arg = NULL - }; - - ret = ppp_serial_init(&serial_config); + // 8. 切换串口到PPP数据模式 + ret = ppp_serial_switch_to_ppp_mode(); if (ret != PPP_ERR_OK) { - PPP_DEBUG_PRINT("Failed to initialize serial for PPP data mode: %d\n", ret); + PPP_DEBUG_PRINT("Failed to switch serial to PPP data mode: %d\n", ret); + ppp_serial_deinit(); return ERRCODE_FAIL; } - // 8. 初始化lwIP PPP协议栈 + // 9. 初始化lwIP PPP协议栈 ret = ppp_lwip_init(); if (ret != PPP_ERR_OK) { PPP_DEBUG_PRINT("Failed to initialize lwIP PPP: %d\n", ret); @@ -116,7 +129,7 @@ errcode_t ppp_start_dial(void) return ERRCODE_FAIL; } - // 9. 启动PPP连接 + // 10. 启动PPP连接 ret = ppp_lwip_connect(); if (ret != PPP_ERR_OK) { PPP_DEBUG_PRINT("Failed to start PPP connection: %d\n", ret); @@ -125,7 +138,7 @@ errcode_t ppp_start_dial(void) return ERRCODE_FAIL; } - // 10. 启动PPP数据接收处理 + // 11. 启动PPP数据接收处理 ret = ppp_start_data_receive_thread(); if (ret != PPP_ERR_OK) { PPP_DEBUG_PRINT("Failed to start PPP data receive thread: %d\n", ret); @@ -162,29 +175,35 @@ errcode_t ppp_stop_dial(void) // 3. 清理lwIP PPP资源 ppp_lwip_deinit(); - // 4. 关闭SIO串口(释放串口资源) - ppp_serial_deinit(); - PPP_DEBUG_PRINT("SIO serial deinitialized - switching back to AT mode\n"); - - // 5. 重新初始化AT命令处理器(切换回AT命令模式) - ppp_error_t ret = ppp_at_handler_init(SIO_UART_BUS); + // 4. 切换串口回AT命令模式(用于发送挂断命令) + ppp_error_t ret = ppp_serial_switch_to_at_mode(); if (ret != PPP_ERR_OK) { - PPP_DEBUG_ERROR("Failed to reinitialize AT handler: %d", ret); - g_ppp_state = PPP_STATE_ERROR; - return ERRCODE_FAIL; - } - - // 6. 发送PPP挂断命令(切换回命令模式) - ret = ppp_at_hangup_ppp(); - if (ret != PPP_ERR_OK) { - PPP_DEBUG_WARN("Failed to send hangup command: %d", ret); - // 继续执行,不返回错误 + 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); + // 继续执行,不返回错误 + } + + // 7. 关闭AT命令处理器 + ppp_at_handler_deinit(); + } else { + PPP_DEBUG_WARN("Failed to reinitialize AT handler for hangup: %d", ret); + } } - // 7. 关闭AT命令处理器 - ppp_at_handler_deinit(); + // 8. 关闭串口 + ppp_serial_deinit(); - // 8. 关闭4G电源 + // 9. 关闭4G电源 cat1_api_enable_cat1(false); g_ppp_state = PPP_STATE_INITIALIZED; diff --git a/code/sdk/zhihui/ppp/src/ppp_lwip.c b/code/sdk/zhihui/ppp/src/ppp_lwip.c index 845c056fb..521d9e4dc 100644 --- a/code/sdk/zhihui/ppp/src/ppp_lwip.c +++ b/code/sdk/zhihui/ppp/src/ppp_lwip.c @@ -152,16 +152,31 @@ ppp_error_t ppp_lwip_connect(void) return PPP_ERR_OK; } - PPP_DEBUG_INFO("Connecting PPP"); + PPP_DEBUG_INFO("Connecting PPP using custom serial interface"); + + /* 创建PPPoS连接,使用自定义输出回调 */ + g_lwip_ctx.ppp_pcb = pppos_create(&g_lwip_ctx.netif, + ppp_lwip_output_callback, // 自定义输出回调 + ppp_lwip_status_callback, + &g_lwip_ctx); + if (g_lwip_ctx.ppp_pcb == NULL) { + PPP_DEBUG_ERROR("Failed to create PPPoS connection"); + return PPP_ERR_MEMORY; + } + + /* 设置认证信息 */ + ppp_set_auth(g_lwip_ctx.ppp_pcb, PPPAUTHTYPE_NONE, "", ""); /* 启动PPP连接 */ err_t err = ppp_connect(g_lwip_ctx.ppp_pcb, 0); if (err != ERR_OK) { PPP_DEBUG_ERROR("Failed to start PPP connection: %d", err); + ppp_free(g_lwip_ctx.ppp_pcb); + g_lwip_ctx.ppp_pcb = NULL; return PPP_ERR_DIAL_FAILED; } - PPP_DEBUG_INFO("PPP connection started"); + PPP_DEBUG_INFO("PPP connection initiated with custom serial interface"); return PPP_ERR_OK; #endif } @@ -369,7 +384,7 @@ static void ppp_lwip_link_status_callback(ppp_pcb *pcb, int err_code, void *ctx) } /** - * @brief PPP输出回调函数 - 使用SIO接口,像SLIP一样 + * @brief PPP输出回调函数 - 使用自定义串口接口,不依赖SIO */ static u32_t ppp_lwip_output_callback(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) { @@ -379,19 +394,13 @@ static u32_t ppp_lwip_output_callback(ppp_pcb *pcb, u8_t *data, u32_t len, void PPP_DEBUG_DEBUG("PPP output %u bytes", len); PPP_DEBUG_HEXDUMP(data, len); - /* 通过SIO接口发送数据,像SLIP一样 */ - sio_fd_t sio_fd = ppp_get_sio_fd(); - if (sio_fd == NULL) { - PPP_DEBUG_ERROR("SIO interface not initialized"); - return 0; - } - - u32_t sent = sio_write(sio_fd, data, len); - if (sent != len) { - PPP_DEBUG_ERROR("Failed to send PPP data via SIO: %u/%u", sent, len); + /* 直接使用我们自己的串口写函数,不依赖SIO */ + ppp_error_t ret = ppp_serial_write(data, len); + if (ret != PPP_ERR_OK) { + PPP_DEBUG_ERROR("Failed to send PPP data via custom serial: %d", ret); return 0; } - return sent; + return len; } #endif /* LWIP_PPP_SUPPORT */ \ No newline at end of file diff --git a/code/sdk/zhihui/ppp/src/ppp_serial.c b/code/sdk/zhihui/ppp/src/ppp_serial.c index d3b112d84..fe33775f3 100644 --- a/code/sdk/zhihui/ppp/src/ppp_serial.c +++ b/code/sdk/zhihui/ppp/src/ppp_serial.c @@ -2,7 +2,7 @@ #include "ppp_config.h" #include "ppp_types.h" #include "ppp_debug.h" -#include "uart.h" +#include "driver/uart.h" // 使用完整路径 #include "schedule/osal_task.h" #include "semaphore/osal_semaphore.h" #include "lock/osal_mutex.h" @@ -11,35 +11,31 @@ #include "securec.h" #include -// 添加SIO相关头文件,让PPP像SLIP一样使用SIO接口 -#include "lwip/sio.h" -#include "lwip/opt.h" - -/* 串口上下文结构 */ +/* 串口上下文结构 - 恢复缓存机制 */ typedef struct { bool initialized; + ppp_serial_mode_t current_mode; uint8_t uart_bus; + + /* UART配置参数 */ uart_pin_config_t pin_config; uart_attr_t uart_attr; uart_buffer_config_t buffer_config; - /* SIO接口句柄 */ - sio_fd_t sio_fd; - - /* 接收缓冲区 */ + /* 接收缓冲区(用于PPP数据模式) */ uint8_t *rx_buffer; uint32_t rx_buffer_size; uint32_t rx_head; uint32_t rx_tail; uint32_t rx_count; - /* 发送缓冲区 */ + /* 发送缓冲区(用于PPP数据模式) */ uint8_t *tx_buffer; uint32_t tx_buffer_size; /* 同步对象 */ - osal_mutex *rx_mutex; - osal_semaphore *rx_semaphore; + osal_mutex rx_mutex; // 改为结构体而不是指针 + osal_semaphore rx_semaphore; // 改为结构体而不是指针 /* 回调函数 */ ppp_serial_rx_callback_t rx_callback; @@ -60,7 +56,7 @@ static uint32_t ppp_serial_buffer_available_space(void); static uint32_t ppp_serial_buffer_data_count(void); /** - * @brief 初始化PPP串口 + * @brief 初始化PPP串口 - AT命令模式,准备缓存机制 */ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) { @@ -68,95 +64,272 @@ ppp_error_t ppp_serial_init(const ppp_serial_config_t *config) return PPP_ERR_INVALID_PARAM; } - PPP_DEBUG_INFO("Initializing PPP serial using SIO interface like SLIP"); + PPP_DEBUG_INFO("Initializing PPP serial in AT command mode with buffer support"); - /* 打开SIO接口,使用与SLIP相同的方式但不同的设备号 */ - g_serial_ctx.sio_fd = sio_open(PPP_IFNUM); - if (g_serial_ctx.sio_fd == NULL) { - PPP_DEBUG_ERROR("Failed to open SIO interface for PPP, device=%d", PPP_IFNUM); + /* 配置UART参数 */ + g_serial_ctx.uart_bus = config->uart_bus; + g_serial_ctx.pin_config.tx_pin = config->tx_pin; + g_serial_ctx.pin_config.rx_pin = config->rx_pin; + g_serial_ctx.uart_attr.baud_rate = config->baudrate; + g_serial_ctx.uart_attr.data_bits = UART_DATA_BIT_8; + 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); + + /* 初始化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; } - /* 配置基本参数 */ - g_serial_ctx.uart_bus = config->uart_bus; + /* 分配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); + return PPP_ERR_MEMORY; + } + + /* 分配PPP数据模式的发送缓冲区 */ 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"); + osal_kfree(g_serial_ctx.rx_buffer); + uapi_uart_deinit(g_serial_ctx.uart_bus); + return PPP_ERR_MEMORY; + } + + /* 创建同步对象 */ + 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); + uapi_uart_deinit(g_serial_ctx.uart_bus); + return PPP_ERR_MEMORY; + } + + 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); + uapi_uart_deinit(g_serial_ctx.uart_bus); + return PPP_ERR_MEMORY; + } + + /* 初始化缓冲区状态 */ + g_serial_ctx.rx_head = 0; + g_serial_ctx.rx_tail = 0; + g_serial_ctx.rx_count = 0; g_serial_ctx.rx_callback = config->rx_callback; g_serial_ctx.rx_callback_arg = config->rx_callback_arg; - } + g_serial_ctx.initialized = true; + g_serial_ctx.current_mode = PPP_SERIAL_MODE_AT; - memset_s(&g_serial_ctx, sizeof(g_serial_ctx), 0, sizeof(g_serial_ctx)); - PPP_DEBUG_INFO("PPP serial deinitialized"); + /* 重置统计信息 */ + g_serial_ctx.tx_bytes = 0; + 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"); + return PPP_ERR_OK; } /** - * @brief 发送数据 + * @brief 切换到PPP数据模式 - 启用缓存机制和UART接收回调 */ -ppp_error_t ppp_serial_write(const uint8_t *data, uint32_t length) +ppp_error_t ppp_serial_switch_to_ppp_mode(void) { - if (!g_serial_ctx.initialized || !data || length == 0) { + if (!g_serial_ctx.initialized) { return PPP_ERR_INVALID_PARAM; } - if (g_serial_ctx.sio_fd == NULL) { - PPP_DEBUG_ERROR("SIO interface not initialized"); - return PPP_ERR_UART; + if (g_serial_ctx.current_mode == PPP_SERIAL_MODE_PPP_DATA) { + PPP_DEBUG_WARN("Already in PPP data mode"); + return PPP_ERR_OK; } - PPP_DEBUG_DEBUG("Sending %u bytes via SIO", length); - PPP_DEBUG_HEXDUMP(data, length); + PPP_DEBUG_INFO("Switching serial from AT mode to PPP data mode (enable buffering)"); - /* 通过SIO接口发送数据,像SLIP一样 */ - u32_t bytes_written = sio_write(g_serial_ctx.sio_fd, (u8_t*)data, length); - - if (bytes_written != length) { - PPP_DEBUG_ERROR("SIO write failed: %u/%u bytes", bytes_written, length); - g_serial_ctx.tx_errors++; + /* 清空接收缓冲区 */ + 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); + + /* 注册UART接收回调,启用缓存机制 */ + 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); return PPP_ERR_UART; } - - g_serial_ctx.tx_bytes += bytes_written; - PPP_DEBUG_DEBUG("Sent %u bytes successfully via SIO", bytes_written); - + + g_serial_ctx.current_mode = PPP_SERIAL_MODE_PPP_DATA; + PPP_DEBUG_INFO("Successfully switched to PPP data mode with buffering enabled"); return PPP_ERR_OK; } /** - * @brief 读取数据 + * @brief 切换回AT命令模式 - 禁用缓存机制和UART接收回调 */ -ppp_error_t ppp_serial_read(uint8_t *buffer, uint32_t buffer_size, uint32_t *bytes_read) +ppp_error_t ppp_serial_switch_to_at_mode(void) { - if (!g_serial_ctx.initialized || !buffer || !bytes_read || buffer_size == 0) { + if (!g_serial_ctx.initialized) { return PPP_ERR_INVALID_PARAM; } - *bytes_read = 0; + if (g_serial_ctx.current_mode == PPP_SERIAL_MODE_AT) { + PPP_DEBUG_WARN("Already in AT command mode"); + return PPP_ERR_OK; + } + + PPP_DEBUG_INFO("Switching serial from PPP data mode to AT mode (disable buffering)"); + + /* 取消注册UART接收回调,禁用缓存机制 */ + uapi_uart_unregister_rx_callback(g_serial_ctx.uart_bus); + + /* 清空接收缓冲区 */ + 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.rx_mutex); + g_serial_ctx.current_mode = PPP_SERIAL_MODE_AT; + PPP_DEBUG_INFO("Successfully switched back to AT command mode"); + return PPP_ERR_OK; +} - uint32_t available = ppp_serial_buffer_data_count(); - if (available == 0) { - osal_mutex_unlock(g_serial_ctx.rx_mutex); - return PPP_ERR_OK; // 没有数据可读 +/** + * @brief 发送数据 - 根据模式选择直接发送或缓存发送 + */ +ppp_error_t ppp_serial_write(const uint8_t *data, uint32_t length) +{ + if (!g_serial_ctx.initialized || !data || length == 0) { + return PPP_ERR_INVALID_PARAM; } - uint32_t to_read = (available < buffer_size) ? available : buffer_size; - - for (uint32_t i = 0; i < to_read; i++) { - buffer[i] = g_serial_ctx.rx_buffer[g_serial_ctx.rx_tail]; - g_serial_ctx.rx_tail = (g_serial_ctx.rx_tail + 1) % g_serial_ctx.rx_buffer_size; - g_serial_ctx.rx_count--; + 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); + + if (uapi_uart_write(g_serial_ctx.uart_bus, data, length, 1000) != (int32_t)length) { + PPP_DEBUG_ERROR("UART write failed in AT mode"); + 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); + } + 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); + + 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; + } else { + g_serial_ctx.tx_bytes += length; + PPP_DEBUG_DEBUG("Sent %u bytes successfully via UART", length); + } + break; + + default: + PPP_DEBUG_ERROR("Invalid serial mode: %d", g_serial_ctx.current_mode); + result = PPP_ERR_INVALID_PARAM; + break; } - *bytes_read = to_read; + return result; +} - osal_mutex_unlock(g_serial_ctx.rx_mutex); +/** + * @brief 读取数据 - 根据模式选择直接读取或从缓存读取 + */ +ppp_error_t ppp_serial_read(uint8_t *buffer, uint32_t buffer_size, uint32_t *bytes_read) +{ + if (!g_serial_ctx.initialized || !buffer || !bytes_read || buffer_size == 0) { + return PPP_ERR_INVALID_PARAM; + } - PPP_DEBUG_DEBUG("Read %u bytes", to_read); - PPP_DEBUG_HEXDUMP(buffer, to_read); + *bytes_read = 0; + ppp_error_t result = PPP_ERR_OK; + + switch (g_serial_ctx.current_mode) { + case PPP_SERIAL_MODE_AT: + /* AT命令模式:直接从UART读取 */ + { + int32_t read_result = uapi_uart_read(g_serial_ctx.uart_bus, buffer, buffer_size, 100); + if (read_result > 0) { + *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); + } else if (read_result < 0) { + PPP_DEBUG_ERROR("UART read error in AT mode: %d", read_result); + g_serial_ctx.rx_errors++; + result = PPP_ERR_UART; + } + } + break; + + case PPP_SERIAL_MODE_PPP_DATA: + /* PPP数据模式:从缓存读取 */ + osal_mutex_lock(&g_serial_ctx.rx_mutex); + + uint32_t available = ppp_serial_buffer_data_count(); + if (available == 0) { + osal_mutex_unlock(&g_serial_ctx.rx_mutex); + return PPP_ERR_OK; // 没有数据可读 + } + + uint32_t to_read = (available < buffer_size) ? available : buffer_size; + + for (uint32_t i = 0; i < to_read; i++) { + buffer[i] = g_serial_ctx.rx_buffer[g_serial_ctx.rx_tail]; + g_serial_ctx.rx_tail = (g_serial_ctx.rx_tail + 1) % g_serial_ctx.rx_buffer_size; + g_serial_ctx.rx_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); + break; + + default: + PPP_DEBUG_ERROR("Invalid serial mode: %d", g_serial_ctx.current_mode); + result = PPP_ERR_INVALID_PARAM; + break; + } - return PPP_ERR_OK; + return result; } /** @@ -169,16 +342,16 @@ ppp_error_t ppp_serial_wait_data(uint32_t timeout_ms) } /* 检查是否已有数据 */ - osal_mutex_lock(g_serial_ctx.rx_mutex); + osal_mutex_lock(&g_serial_ctx.rx_mutex); bool has_data = (g_serial_ctx.rx_count > 0); - osal_mutex_unlock(g_serial_ctx.rx_mutex); + osal_mutex_unlock(&g_serial_ctx.rx_mutex); if (has_data) { return PPP_ERR_OK; } /* 等待数据到达 */ - if (osal_sem_wait(g_serial_ctx.rx_semaphore, timeout_ms) != OSAL_SUCCESS) { + if (osal_sem_wait(&g_serial_ctx.rx_semaphore, timeout_ms) != OSAL_SUCCESS) { return PPP_ERR_TIMEOUT; } @@ -194,9 +367,9 @@ uint32_t ppp_serial_available(void) return 0; } - osal_mutex_lock(g_serial_ctx.rx_mutex); + osal_mutex_lock(&g_serial_ctx.rx_mutex); uint32_t count = ppp_serial_buffer_data_count(); - osal_mutex_unlock(g_serial_ctx.rx_mutex); + osal_mutex_unlock(&g_serial_ctx.rx_mutex); return count; } @@ -210,36 +383,75 @@ void ppp_serial_flush_rx(void) return; } - osal_mutex_lock(g_serial_ctx.rx_mutex); + 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_unlock(&g_serial_ctx.rx_mutex); PPP_DEBUG_DEBUG("RX buffer flushed"); } /** - * @brief 设置串口波特率 + * @brief 设置接收回调函数 */ -ppp_error_t ppp_serial_set_baudrate(uint32_t baudrate) +ppp_error_t ppp_serial_set_rx_callback(ppp_serial_rx_callback_t callback, void *arg) { if (!g_serial_ctx.initialized) { return PPP_ERR_INVALID_PARAM; } - PPP_DEBUG_INFO("Setting baudrate to %u", baudrate); + g_serial_ctx.rx_callback = callback; + g_serial_ctx.rx_callback_arg = arg; - g_serial_ctx.uart_attr.baud_rate = baudrate; - - errcode_t ret = uapi_uart_set_attr(g_serial_ctx.uart_bus, &g_serial_ctx.uart_attr); - if (ret != ERRCODE_SUCC) { - PPP_DEBUG_ERROR("Failed to set baudrate: %d", ret); - return PPP_ERR_UART; + return PPP_ERR_OK; +} + +/** + * @brief 去初始化PPP串口 + */ +void ppp_serial_deinit(void) +{ + if (!g_serial_ctx.initialized) { + return; } - PPP_DEBUG_INFO("Baudrate set to %u successfully", baudrate); - return PPP_ERR_OK; + PPP_DEBUG_INFO("Deinitializing PPP serial, current mode: %d", g_serial_ctx.current_mode); + + /* 取消注册UART接收回调 */ + if (g_serial_ctx.current_mode == PPP_SERIAL_MODE_PPP_DATA) { + uapi_uart_unregister_rx_callback(g_serial_ctx.uart_bus); + } + + /* 关闭UART */ + uapi_uart_deinit(g_serial_ctx.uart_bus); + + /* 释放缓冲区 */ + if (g_serial_ctx.rx_buffer) { + 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); + + /* 清理上下文 */ + memset_s(&g_serial_ctx, sizeof(g_serial_ctx), 0, sizeof(g_serial_ctx)); + PPP_DEBUG_INFO("PPP serial deinitialized"); +} + +/** + * @brief 获取当前串口模式 + */ +ppp_serial_mode_t ppp_serial_get_mode(void) +{ + return g_serial_ctx.current_mode; } /** @@ -257,7 +469,7 @@ void ppp_serial_get_stats(ppp_serial_stats_t *stats) stats->rx_errors = g_serial_ctx.rx_errors; stats->rx_buffer_usage = g_serial_ctx.rx_count; stats->rx_buffer_size = g_serial_ctx.rx_buffer_size; -} +} /* 内部函数实现 */ @@ -274,7 +486,7 @@ static void ppp_serial_rx_callback(const void *buffer, uint16_t length, bool rem const uint8_t *data = (const uint8_t *)buffer; - osal_mutex_lock(g_serial_ctx.rx_mutex); + osal_mutex_lock(&g_serial_ctx.rx_mutex); /* 检查缓冲区空间 */ uint32_t available_space = ppp_serial_buffer_available_space(); @@ -293,10 +505,10 @@ static void ppp_serial_rx_callback(const void *buffer, uint16_t length, bool rem g_serial_ctx.rx_bytes += length; - osal_mutex_unlock(g_serial_ctx.rx_mutex); + osal_mutex_unlock(&g_serial_ctx.rx_mutex); /* 通知有数据到达 */ - osal_sem_signal(g_serial_ctx.rx_semaphore); + osal_sem_signal(&g_serial_ctx.rx_semaphore); /* 调用用户回调函数 */ if (g_serial_ctx.rx_callback) { @@ -320,13 +532,4 @@ static uint32_t ppp_serial_buffer_available_space(void) static uint32_t ppp_serial_buffer_data_count(void) { return g_serial_ctx.rx_count; -} - -/** - * @brief 获取PPP模块SIO句柄 - * @return SIO句柄,如果未初始化则返回NULL - */ -sio_fd_t ppp_get_sio_fd(void) -{ - return g_serial_ctx.sio_fd; } \ No newline at end of file -- 2.17.1