中间结果,仍然不通 2732/target/1
author孙春阳 <snickersun@163.com>
Mon, 3 Nov 2025 07:02:50 +0000 (15:02 +0800)
committer孙春阳 <snickersun@163.com>
Mon, 3 Nov 2025 07:02:50 +0000 (15:02 +0800)
12 files changed:
code/sdk/kernel/osal/src/liteos/osal_semaphore.c
code/sdk/zhihui/n706a_net/CMakeLists.txt
code/sdk/zhihui/n706a_net/include/n706a_at_handler.h
code/sdk/zhihui/n706a_net/include/n706a_http_client.h
code/sdk/zhihui/n706a_net/include/n706a_tcp_client.h
code/sdk/zhihui/n706a_net/include/ppp_config.h
code/sdk/zhihui/n706a_net/src/n706a_at_handler.c
code/sdk/zhihui/n706a_net/src/n706a_http_client.c
code/sdk/zhihui/n706a_net/src/n706a_net_api.c
code/sdk/zhihui/n706a_net/src/n706a_tcp_client.c
code/sdk/zhihui/n706a_net/src/n706a_websocket.c
code/sdk/zhihui/zhihui_net/src/zhihui_net_http.c

index 9196557..7454254 100644 (file)
@@ -80,7 +80,8 @@ int osal_sem_down_timeout(osal_semaphore *sem, unsigned int timeout)
 \r
     unsigned int ret = LOS_SemPend((unsigned int)(UINTPTR)sem->sem, ticks);\r
     if (ret == LOS_ERRNO_SEM_TIMEOUT) {\r
-        osal_log("LOS_ERRNO_SEM_TIMEOUT!\n");\r
+        // 超时是正常行为(例如mbedtls等待数据时),不打印日志以避免日志刷屏\r
+        // osal_log("LOS_ERRNO_SEM_TIMEOUT!\n");\r
         return OSAL_ETIME;\r
     } else if (ret != OSAL_SUCCESS) {\r
         osal_log("LOS_SemPend failed! ret = %#x.\n", ret);\r
index 7c08449..7cb2f32 100644 (file)
@@ -28,8 +28,8 @@ set(PUBLIC_DEFINES
     SUPPORT_N706A_NET           # 定义此宏启用 N706A AT 模式(独立于PPP)
     SUPPORT_AT_N706A_NET        # 开机自动注册 N706A AT 命令
     # SSL实现方式(二选一,仅影响n706a_net内部):
-    N706A_SSL_USE_AT_COMMAND    # 使用AT指令实现SSL(推荐,利用N706A内置SSL)
-    # N706A_SSL_USE_MBEDTLS     # 使用mbedtls库实现SSL(不推荐:与AT模式不兼容)
+    # N706A_SSL_USE_AT_COMMAND    # 使用AT指令实现SSL(推荐,利用N706A内置SSL)
+    N706A_SSL_USE_MBEDTLS     # 使用mbedtls库实现SSL(不推荐:与AT模式不兼容)
 )
 
 set(PRIVATE_HEADER
index 431023d..fca032a 100644 (file)
@@ -125,12 +125,64 @@ n706a_at_error_t n706a_at_get_network_signal_info(n706a_network_signal_info_t *i
  */
 typedef void (*n706a_tcp_urc_callback_t)(int socket_id, const uint8_t *data, size_t length);
 
+/**
+ * @brief +TCPSETUP URC结果回调函数类型
+ * @param socket_id Socket ID (0-5)
+ * @param success true表示+TCPSETUP: n,OK,false表示+TCPSETUP: n,FAIL
+ */
+typedef void (*n706a_tcpsetup_urc_callback_t)(int socket_id, bool success);
+
+/**
+ * @brief +TCPCLOSE URC回调函数类型
+ * @param socket_id Socket ID (0-5)
+ */
+typedef void (*n706a_tcpclose_urc_callback_t)(int socket_id);
+
+/**
+ * @brief +TCPSEND URC回调函数类型(发送完成通知)
+ * @param socket_id Socket ID (0-5)
+ * @param sent_bytes 实际发送的字节数
+ */
+typedef void (*n706a_tcpsend_urc_callback_t)(int socket_id, size_t sent_bytes);
+
+/**
+ * @brief 网络状态URC回调函数类型
+ * @param urc_type URC类型字符串(如"+CREG", "+CGREG", "+CGATT")
+ * @param data URC数据内容(不含前缀)
+ * @param length 数据长度
+ */
+typedef void (*n706a_network_status_urc_callback_t)(const char *urc_type, const char *data, size_t length);
+
 /**
  * @brief 注册TCP URC接收回调
  * @param callback 回调函数指针,NULL表示取消注册
  */
 void n706a_at_register_tcp_urc_callback(n706a_tcp_urc_callback_t callback);
 
+/**
+ * @brief 注册+TCPSETUP URC回调
+ * @param callback 回调函数指针,NULL表示取消注册
+ */
+void n706a_at_register_tcpsetup_urc_callback(n706a_tcpsetup_urc_callback_t callback);
+
+/**
+ * @brief 注册+TCPCLOSE URC回调
+ * @param callback 回调函数指针,NULL表示取消注册
+ */
+void n706a_at_register_tcpclose_urc_callback(n706a_tcpclose_urc_callback_t callback);
+
+/**
+ * @brief 注册+TCPSEND URC回调
+ * @param callback 回调函数指针,NULL表示取消注册
+ */
+void n706a_at_register_tcpsend_urc_callback(n706a_tcpsend_urc_callback_t callback);
+
+/**
+ * @brief 注册网络状态URC回调
+ * @param callback 回调函数指针,NULL表示取消注册
+ */
+void n706a_at_register_network_status_urc_callback(n706a_network_status_urc_callback_t callback);
+
 #ifdef __cplusplus
 }
 #endif
index 5e6a918..530fd3f 100644 (file)
@@ -96,10 +96,10 @@ typedef struct {
 } n706a_http_client_data_t;
 
 /**
- * @brief 初始化N706A HTTP客户端
- * @param client HTTP客户端结构指针
- * @param socket_id TCP socket编号(0-5)
- * @return N706A_HTTP_SUCCESS成功,其他失败
+ * @brief 初始化HTTP客户端
+ * @param client HTTP客户端结构体指针
+ * @param socket_id socket ID (0-5),如果传入-1则自动分配空闲的socket_id(推荐,避免冲突)
+ * @return N706A_HTTP_SUCCESS 成功,其他值失败
  */
 n706a_httpc_result_t n706a_http_client_init(n706a_http_client_t *client, int socket_id);
 
index 8687c14..a54eb91 100644 (file)
 extern "C" {
 #endif
 
+/* ========== Buffer大小定义 ========== */
+/**
+ * @brief URC接收缓冲区大小分级定义
+ * 
+ * 根据使用场景选择合适的大小:
+ * - SMALL (2KB): 普通TCP连接,无SSL
+ * - MEDIUM (4KB): WebSocket长连接,无SSL
+ * - LARGE (6KB): SSL/TLS连接,推荐默认值,覆盖99%场景
+ * - XLARGE (8KB): 超大证书链场景(银行/政府网站)
+ */
+#define N706A_TCP_URC_BUFFER_SIZE_SMALL   2048   /**< 2KB:普通TCP */
+#define N706A_TCP_URC_BUFFER_SIZE_MEDIUM  4096   /**< 4KB:WebSocket */
+#define N706A_TCP_URC_BUFFER_SIZE_LARGE   6144   /**< 6KB:SSL/TLS(推荐默认) */
+#define N706A_TCP_URC_BUFFER_SIZE_XLARGE  8192   /**< 8KB:超大证书链 */
+
+#define N706A_TCP_URC_BUFFER_SIZE_DEFAULT N706A_TCP_URC_BUFFER_SIZE_LARGE  /**< 默认6KB */
+
 /* N706A TCP错误码 */
 typedef enum {
     N706A_TCP_SUCCESS  = 0,      /**< 操作成功 */
@@ -79,6 +96,7 @@ typedef struct {
     size_t urc_recv_capacity;       /**< 缓冲区容量 */
     size_t urc_recv_length;         /**< 当前数据长度 */
     void *urc_recv_mutex;           /**< 缓冲区互斥锁 */
+    void *urc_data_available_sem;   /**< 数据可用信号量(用于mbedtls recv等待) */
     
     /* SSL相关字段(根据编译宏不同而不同) */
 #ifdef N706A_SSL_USE_AT_COMMAND
@@ -104,10 +122,27 @@ typedef struct {
 } n706a_tcp_socket_t;
 
 /**
- * @brief 创建TCP socket
+ * @brief 创建TCP socket(带自定义URC buffer大小)
  * @param sock TCP socket指针
  * @param socket_id socket编号(0-5)
+ * @param urc_buffer_size URC缓冲区大小(0=使用默认值N706A_TCP_URC_BUFFER_SIZE_DEFAULT)
  * @return N706A_TCP_SUCCESS成功,其他值表示失败
+ * 
+ * @note 根据使用场景选择buffer大小:
+ *   - 普通TCP: N706A_TCP_URC_BUFFER_SIZE_SMALL (2KB)
+ *   - WebSocket: N706A_TCP_URC_BUFFER_SIZE_MEDIUM (4KB)
+ *   - SSL/TLS: N706A_TCP_URC_BUFFER_SIZE_LARGE (6KB, 默认)
+ *   - 超大证书: N706A_TCP_URC_BUFFER_SIZE_XLARGE (8KB)
+ */
+n706a_tcp_result_t n706a_tcp_socket_create_ex(n706a_tcp_socket_t *sock, int socket_id, size_t urc_buffer_size);
+
+/**
+ * @brief 创建TCP socket(使用默认buffer大小)
+ * @param sock TCP socket指针
+ * @param socket_id socket编号(0-5)
+ * @return N706A_TCP_SUCCESS成功,其他值表示失败
+ * 
+ * @note 内部调用 n706a_tcp_socket_create_ex(),使用默认6KB buffer
  */
 n706a_tcp_result_t n706a_tcp_socket_create(n706a_tcp_socket_t *sock, int socket_id);
 
@@ -203,9 +238,14 @@ n706a_tcp_state_t n706a_tcp_get_state(const n706a_tcp_socket_t *sock);
 /**
  * @brief 初始化TCP socket的URC接收缓存
  * @param sock TCP socket指针
- * @param buffer_size 缓冲区大小(建议2048字节)
+ * @param buffer_size 缓冲区大小(建议使用N706A_TCP_URC_BUFFER_SIZE_*宏)
  * @return N706A_TCP_SUCCESS成功,其他值表示失败
  * @note 由 n706a_tcp_socket_create 自动调用,通常不需要手动调用
+ * 
+ * 功能:
+ * - 分配URC接收缓冲区
+ * - 创建互斥锁(保护buffer)
+ * - 创建信号量(通知数据可用,用于mbedtls recv等待)
  */
 n706a_tcp_result_t n706a_tcp_init_urc_buffer(n706a_tcp_socket_t *sock, size_t buffer_size);
 
@@ -225,6 +265,14 @@ void n706a_tcp_free_urc_buffer(n706a_tcp_socket_t *sock);
  */
 void n706a_tcp_on_urc_received(int socket_id, const uint8_t *data, size_t length);
 
+/**
+ * @brief +TCPSETUP URC回调(由n706a_at_handler调用)
+ * @param socket_id Socket ID
+ * @param success true=OK, false=FAIL
+ * @note 此函数在中断/线程上下文中被调用,需要注意线程安全
+ */
+void n706a_tcp_on_tcpsetup_urc(int socket_id, bool success);
+
 #ifdef __cplusplus
 }
 #endif
index 2f98361..a45c70c 100644 (file)
@@ -83,9 +83,9 @@ extern "C" {
 
 /* 调试配置 */
 #define PPP_DEBUG_ENABLE            1                   // 启用调试输出
-// #define PPP_DEBUG_LEVEL             PPP_DEBUG_LEVEL_DEBUG // 默认只显示警告和错误 (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG)
+#define PPP_DEBUG_LEVEL             PPP_DEBUG_LEVEL_DEBUG // 默认只显示警告和错误 (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG)
 // #define PPP_DEBUG_LEVEL             PPP_DEBUG_LEVEL_INFO // 默认只显示警告和错误 (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG)
-#define PPP_DEBUG_LEVEL             PPP_DEBUG_LEVEL_WARN // 默认只显示警告和错误 (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG)
+// #define PPP_DEBUG_LEVEL             PPP_DEBUG_LEVEL_WARN // 默认只显示警告和错误 (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG)
 
 /*
  * 调试级别说明:
index 089b754..27fd4c8 100644 (file)
@@ -44,6 +44,18 @@ static uint32_t g_at_buffer_size = 1024;
 /* TCP URC回调 */
 static n706a_tcp_urc_callback_t g_tcp_urc_callback = NULL;
 
+/* +TCPSETUP URC回调 */
+static n706a_tcpsetup_urc_callback_t g_tcpsetup_urc_callback = NULL;
+
+/* +TCPCLOSE URC回调 */
+static n706a_tcpclose_urc_callback_t g_tcpclose_urc_callback = NULL;
+
+/* +TCPSEND URC回调 */
+static n706a_tcpsend_urc_callback_t g_tcpsend_urc_callback = NULL;
+
+/* 网络状态URC回调 */
+static n706a_network_status_urc_callback_t g_network_status_urc_callback = NULL;
+
 /* AT命令响应解析 */
 static bool ppp_at_parse_response(const char *response, const char *expected);
 static ppp_error_t ppp_at_wait_response(ppp_at_response_t *response, uint32_t timeout);
@@ -54,39 +66,296 @@ static ppp_error_t ppp_at_send_command(const char *command, const char *expected
 /* URC解析函数 */
 static bool n706a_parse_tcprecv_urc(const char *urc_data, size_t urc_len, 
                                     int *socket_id, size_t *data_len, const uint8_t **data);
+static bool n706a_parse_tcpsetup_urc(const char *urc_data, size_t urc_len,
+                                     int *socket_id, bool *success);
+static bool n706a_parse_tcpclose_urc(const char *urc_data, size_t urc_len, int *socket_id);
+static bool n706a_parse_tcpsend_urc(const char *urc_data, size_t urc_len, 
+                                    int *socket_id, size_t *sent_bytes);
+static bool n706a_hex_char_to_value(char c, uint8_t *value);
+static size_t n706a_binary_to_hex_string(const uint8_t *binary_data, size_t binary_len,
+                                         char *hex_str, size_t hex_buf_size);
+static size_t n706a_hex_string_to_binary(const char *hex_str, size_t hex_len, 
+                                         uint8_t *binary_buf, size_t binary_buf_size);
 
 /**
- * @brief 写入AT响应数据到环形缓冲区(由ppp_interrupt.c调用)
+ * @brief AT响应分类处理和分发
  * @param data 数据指针
  * @param length 数据长度
+ * @return true=已处理(URC),false=需要写入环形缓冲区(普通AT响应)
+ * 
+ * 按照优先级顺序检测各类URC,一旦匹配就立即触发callback
  */
-void n706a_at_response_buffer_write(const uint8_t *data, uint32_t length)
+static bool n706a_classify_and_dispatch_urc(const uint8_t *data, uint32_t length);
+
+/**
+ * @brief AT响应分类处理和分发
+ * @param data 数据指针
+ * @param length 数据长度
+ * @return true=已处理(URC),false=需要写入环形缓冲区(普通AT响应)
+ * 
+ * 按照优先级顺序检测各类URC,一旦匹配就立即触发callback
+ */
+static bool n706a_classify_and_dispatch_urc(const uint8_t *data, uint32_t length)
 {
     if (!data || length == 0) {
-        return;
+        return false;
+    }
+    
+    const char *data_str = (const char *)data;
+    
+    PPP_DEBUG_DEBUG("[URC分类] Checking data block: length=%u, first 64 bytes: [%.*s]", 
+                   length, (length < 64) ? (int)length : 64, data_str);
+    
+    /* ========== 类别1:TCP数据接收URC(最高优先级,因为包含数据) ========== */
+    if (length >= 10 && g_tcp_urc_callback) {
+        if (memcmp(data, "+TCPRECV: ", 10) == 0 || memcmp(data, "+SSLTCPRECV: ", 13) == 0) {
+            int socket_id;
+            size_t data_len;
+            const uint8_t *tcp_data;
+            
+            if (n706a_parse_tcprecv_urc((const char *)data, length, &socket_id, &data_len, &tcp_data)) {
+                // 注意:如果使用HEX模式,tcp_data指向的是HEX字符串,需要转换为二进制
+                // 这里假设当前使用的是HEX模式(AT+RECVMODE=1,1)
+                // HEX字符串长度是实际数据长度的2倍
+                
+                // 使用双buffer ping-pong机制避免并发冲突
+                // 注意:解码后的数据会立即拷贝到URC buffer,所以hex buffer可以立即重用
+                static uint8_t hex_decode_buffer_0[2048];  // Ping buffer
+                static uint8_t hex_decode_buffer_1[2048];  // Pong buffer
+                static volatile int hex_decode_buffer_active = 0;  // 当前使用的buffer索引(0或1)
+                
+                size_t binary_data_len = data_len;
+                const uint8_t *binary_data = tcp_data;
+                
+                // 检查是否是HEX格式(HEX字符串长度应该是数据长度的2倍)
+                // 或者可以通过检查是否所有字符都是0-9A-F来判断
+                bool is_hex_format = false;
+                if (data_len > 0) {
+                    // 简单检查:如果数据长度是偶数,且所有字符都是十六进制字符,可能是HEX格式
+                    size_t hex_str_len = 0;
+                    const char *p = (const char *)tcp_data;
+                    while (hex_str_len < data_len && 
+                           ((*p >= '0' && *p <= '9') || (*p >= 'A' && *p <= 'F') || (*p >= 'a' && *p <= 'f'))) {
+                        p++;
+                        hex_str_len++;
+                    }
+                    
+                    // 如果所有字符都是HEX字符,且长度是2的倍数,认为是HEX格式
+                    if (hex_str_len == data_len && data_len % 2 == 0) {
+                        is_hex_format = true;
+                        
+                        // 选择非活跃的buffer进行解码(ping-pong机制)
+                        // 由于解码后立即拷贝到URC buffer,active buffer可以立即切换
+                        int buffer_idx = hex_decode_buffer_active;
+                        uint8_t *decode_buffer = (buffer_idx == 0) ? hex_decode_buffer_0 : hex_decode_buffer_1;
+                        
+                        // 将HEX字符串转换为二进制
+                        binary_data_len = n706a_hex_string_to_binary((const char *)tcp_data, data_len,
+                                                                     decode_buffer, sizeof(hex_decode_buffer_0));
+                        if (binary_data_len > 0) {
+                            binary_data = decode_buffer;
+                            
+                            // 切换active buffer(虽然不必须,但保持ping-pong逻辑)
+                            // 注意:由于数据会立即拷贝到URC buffer,这里切换是安全的
+                            hex_decode_buffer_active = 1 - hex_decode_buffer_active;
+                            
+                            PPP_DEBUG_DEBUG("HEX decoded: hex_len=%u -> binary_len=%u (buffer=%d)", 
+                                          (unsigned int)data_len, (unsigned int)binary_data_len, buffer_idx);
+                        } else {
+                            PPP_DEBUG_ERROR("Failed to decode HEX string");
+                            is_hex_format = false;
+                        }
+                    }
+                }
+                
+                if (binary_data_len > 0) {
+                    PPP_DEBUG_INFO("[URC分类] TCP URC detected: socket=%d, len=%u (format=%s)", 
+                                  socket_id, (unsigned int)binary_data_len, 
+                                  is_hex_format ? "HEX" : "ASCII");
+                    
+                    // 立即回调应用层(在中断上下文或处理线程中)
+                    g_tcp_urc_callback(socket_id, binary_data, binary_data_len);
+                    
+                    // URC已处理,不写入AT响应缓冲区
+                    return true;
+                } else {
+                    PPP_DEBUG_WARN("Invalid TCP URC data length");
+                }
+            } else {
+                PPP_DEBUG_WARN("Failed to parse +TCPRECV URC");
+            }
+        }
+    }
+    
+    /* ========== 类别2:TCP连接状态URC ========== */
+    // 检查数据开头或数据中间是否包含+TCPSETUP或+SSLTCPSETUP
+    if (length >= 11) {
+        const char *tcpsetup_pos = strstr(data_str, "+TCPSETUP: ");
+        const char *ssltcpsetup_pos = strstr(data_str, "+SSLTCPSETUP: ");
+        
+        if (tcpsetup_pos || ssltcpsetup_pos) {
+            const char *urc_start = tcpsetup_pos ? tcpsetup_pos : ssltcpsetup_pos;
+            const char *urc_end = strstr(urc_start, "\r\n");
+            if (!urc_end) {
+                urc_end = strstr(urc_start, "\n");
+            }
+            if (!urc_end) {
+                urc_end = data_str + length;
+            }
+            
+            size_t urc_len = urc_end - urc_start;
+            if (urc_len >= 15) {
+                int socket_id;
+                bool success;
+                if (n706a_parse_tcpsetup_urc(urc_start, urc_len, &socket_id, &success)) {
+                    PPP_DEBUG_INFO("[URC分类] +TCPSETUP URC detected: socket=%d, success=%d", socket_id, success);
+                    if (g_tcpsetup_urc_callback) {
+                        g_tcpsetup_urc_callback(socket_id, success);
+                    }
+                    // URC已处理,如果是独立URC则不写入缓冲区,否则继续(混合响应)
+                    if (urc_start == data_str && urc_end >= data_str + length - 2) {
+                        return true;  // 独立URC,不写入缓冲区
+                    }
+                } else {
+                    PPP_DEBUG_WARN("[URC分类] +TCPSETUP URC found but parse failed, urc_len=%u", (unsigned int)urc_len);
+                    // 输出原始URC内容用于调试
+                    char debug_urc[128] = {0};
+                    size_t debug_len = (urc_len < sizeof(debug_urc) - 1) ? urc_len : (sizeof(debug_urc) - 1);
+                    memcpy(debug_urc, urc_start, debug_len);
+                    PPP_DEBUG_WARN("[URC分类] Raw URC content: [%.*s]", (int)debug_len, debug_urc);
+                }
+            }
+        }
     }
     
-    // 检测是否是 +TCPRECV URC(TCP数据接收通知)
-    // 格式:+TCPRECV: <socket_id>,<length>,<data>\r\n
-    if (length >= 10 && memcmp(data, "+TCPRECV: ", 10) == 0 && g_tcp_urc_callback) {
-        int socket_id;
-        size_t data_len;
-        const uint8_t *tcp_data;
+    // 检查+TCPCLOSE或+SSLTCPCLOSE
+    if (length >= 11) {
+        const char *tcpclose_pos = strstr(data_str, "+TCPCLOSE: ");
+        const char *ssltcpclose_pos = strstr(data_str, "+SSLTCPCLOSE: ");
         
-        if (n706a_parse_tcprecv_urc((const char *)data, length, &socket_id, &data_len, &tcp_data)) {
-            PPP_DEBUG_INFO("TCP URC detected: socket=%d, len=%u", socket_id, (unsigned int)data_len);
+        if (tcpclose_pos || ssltcpclose_pos) {
+            const char *urc_start = tcpclose_pos ? tcpclose_pos : ssltcpclose_pos;
+            const char *urc_end = strstr(urc_start, "\r\n");
+            if (!urc_end) {
+                urc_end = strstr(urc_start, "\n");
+            }
+            if (!urc_end) {
+                urc_end = data_str + length;
+            }
             
-            // 立即回调应用层(在中断上下文或处理线程中)
-            g_tcp_urc_callback(socket_id, tcp_data, data_len);
+            size_t urc_len = urc_end - urc_start;
+            int socket_id;
+            if (n706a_parse_tcpclose_urc(urc_start, urc_len, &socket_id)) {
+                PPP_DEBUG_INFO("[URC分类] +TCPCLOSE URC detected: socket=%d", socket_id);
+                if (g_tcpclose_urc_callback) {
+                    g_tcpclose_urc_callback(socket_id);
+                }
+                // URC已处理,如果是独立URC则不写入缓冲区
+                if (urc_start == data_str && urc_end >= data_str + length - 2) {
+                    return true;
+                }
+            } else {
+                PPP_DEBUG_WARN("[URC分类] +TCPCLOSE URC found but parse failed");
+            }
+        }
+    }
+    
+    /* ========== 类别3:TCP发送结果URC ========== */
+    if (length >= 10 && g_tcpsend_urc_callback) {
+        const char *tcpsend_pos = strstr(data_str, "+TCPSEND: ");
+        const char *ssltcpend_pos = strstr(data_str, "+SSLTCPEND: ");
+        
+        if (tcpsend_pos || ssltcpend_pos) {
+            const char *urc_start = tcpsend_pos ? tcpsend_pos : ssltcpend_pos;
+            const char *urc_end = strstr(urc_start, "\r\n");
+            if (!urc_end) {
+                urc_end = strstr(urc_start, "\n");
+            }
+            if (!urc_end) {
+                urc_end = data_str + length;
+            }
             
-            // URC已处理,不需要写入AT响应缓冲区
-            return;
-        } else {
-            PPP_DEBUG_WARN("Failed to parse +TCPRECV URC");
+            size_t urc_len = urc_end - urc_start;
+            int socket_id;
+            size_t sent_bytes;
+            if (n706a_parse_tcpsend_urc(urc_start, urc_len, &socket_id, &sent_bytes)) {
+                PPP_DEBUG_INFO("[URC分类] +TCPSEND URC detected: socket=%d, sent=%u", socket_id, (unsigned int)sent_bytes);
+                g_tcpsend_urc_callback(socket_id, sent_bytes);
+                // URC已处理,如果是独立URC则不写入缓冲区
+                if (urc_start == data_str && urc_end >= data_str + length - 2) {
+                    return true;
+                }
+            }
         }
     }
     
-    // 普通AT响应或无法识别的数据,写入环形缓冲区
+    /* ========== 类别4:网络状态URC ========== */
+    if (length >= 6 && g_network_status_urc_callback) {
+        const char *creg_pos = strstr(data_str, "+CREG: ");
+        const char *cgreg_pos = strstr(data_str, "+CGREG: ");
+        const char *cgatt_pos = strstr(data_str, "+CGATT: ");
+        
+        const char *urc_start = NULL;
+        const char *urc_type = NULL;
+        
+        if (creg_pos) {
+            urc_start = creg_pos;
+            urc_type = "+CREG";
+        } else if (cgreg_pos) {
+            urc_start = cgreg_pos;
+            urc_type = "+CGREG";
+        } else if (cgatt_pos) {
+            urc_start = cgatt_pos;
+            urc_type = "+CGATT";
+        }
+        
+        if (urc_start) {
+            const char *colon = strchr(urc_start, ':');
+            if (colon) {
+                const char *urc_data_start = colon + 2;  // 跳过 ": "
+                const char *urc_end = strstr(urc_data_start, "\r\n");
+                if (!urc_end) {
+                    urc_end = strstr(urc_data_start, "\n");
+                }
+                if (!urc_end) {
+                    urc_end = data_str + length;
+                }
+                
+                size_t urc_data_len = urc_end - urc_data_start;
+                PPP_DEBUG_INFO("[URC分类] Network status URC detected: %s, data_len=%u", urc_type, (unsigned int)urc_data_len);
+                g_network_status_urc_callback(urc_type, urc_data_start, urc_data_len);
+                // URC已处理,如果是独立URC则不写入缓冲区
+                if (urc_start == data_str && urc_end >= data_str + length - 2) {
+                    return true;
+                }
+            }
+        }
+    }
+    
+    /* ========== 不是URC,是普通AT响应 ========== */
+    return false;
+}
+
+/**
+ * @brief 写入AT响应数据到环形缓冲区(由ppp_interrupt.c调用)
+ * @param data 数据指针
+ * @param length 数据长度
+ */
+void n706a_at_response_buffer_write(const uint8_t *data, uint32_t length)
+{
+    if (!data || length == 0) {
+        return;
+    }
+    
+    /* ========== 第一步:分类处理和分发URC ========== */
+    /* 如果返回true,说明是URC已处理,不需要写入缓冲区 */
+    bool is_urc = n706a_classify_and_dispatch_urc(data, length);
+    if (is_urc) {
+        // URC已通过callback处理,不写入AT响应缓冲区
+        return;
+    }
+    
+    /* ========== 第二步:普通AT响应写入环形缓冲区 ========== */
     osal_mutex_lock(&g_at_response_mutex);
     
     for (uint32_t i = 0; i < length; i++) {
@@ -102,7 +371,7 @@ void n706a_at_response_buffer_write(const uint8_t *data, uint32_t length)
     
     osal_mutex_unlock(&g_at_response_mutex);
     
-    // 通知有新数据到达
+    // 通知等待线程有新数据
     osal_sem_up(&g_at_response_sem);
     
     PPP_DEBUG_DEBUG("AT response buffer: wrote %u bytes", length);
@@ -630,9 +899,42 @@ static ppp_error_t ppp_at_send_command(const char *command, const char *expected
     return ret;
 }
 
+/**
+ * @brief 等待 '>' 提示符(用于 AT+TCPSEND/AT+SSLTCPSEND)
+ * @param timeout 超时时间(毫秒)
+ * @return PPP_ERR_OK 成功,其他值失败
+ * 
+ * 根据N706A AT命令手册,AT+TCPSEND发送后会收到 '>' 提示符,
+ * 此时需要延迟50-100ms后再发送数据。
+ */
+static ppp_error_t ppp_at_wait_for_prompt(uint32_t timeout)
+{
+    ppp_at_response_t response;
+    ppp_error_t ret = ppp_at_wait_response(&response, timeout);
+    
+    if (ret != PPP_ERR_OK) {
+        PPP_DEBUG_ERROR("Failed to wait for '>' prompt: error %d", ret);
+        return ret;
+    }
+    
+    /* 检查响应中是否包含 '>' */
+    if (strstr((const char *)response.response, ">") == NULL) {
+        PPP_DEBUG_ERROR("Response does not contain '>' prompt: %s", response.response);
+        return PPP_ERR_AT_FAILED;
+    }
+    
+    PPP_DEBUG_DEBUG("Received '>' prompt, delaying 75ms before sending data...");
+    
+    /* 延迟75ms(在50-100ms范围内,取中间值) */
+    osal_msleep(75);
+    
+    return PPP_ERR_OK;
+}
+
 /**
  * @brief 发送原始数据(不带AT命令格式)
  * @note 用于 TCP/SSL 数据发送,在 AT+TCPSEND/AT+SSLTCPSEND 命令后使用
+ * @note 调用此函数前,必须先调用 ppp_at_send_command 发送 AT+TCPSEND 命令并等待 '>' 提示符
  */
 ppp_error_t ppp_at_send_raw_data(const void *data, size_t len, uint32_t timeout)
 {
@@ -642,19 +944,38 @@ ppp_error_t ppp_at_send_raw_data(const void *data, size_t len, uint32_t timeout)
         return PPP_ERR_INVALID_PARAM;
     }
 
-    PPP_DEBUG_DEBUG("=== Sending Raw Data ===");
-    PPP_DEBUG_DEBUG("Length: %zu bytes", len);
-    PPP_DEBUG_DEBUG("Timeout: %u ms", timeout);
+    PPP_DEBUG_DEBUG("=== Sending Raw Data (HEX Mode) ===");
+    PPP_DEBUG_DEBUG("Binary length: %zu bytes", len);
+
+    /* 将二进制数据编码为HEX字符串 */
+    size_t hex_str_len = len * 2;  // 每个字节转换为2个HEX字符
+    char *hex_str = (char *)malloc(hex_str_len + 1);  // +1 for null terminator
+    if (!hex_str) {
+        PPP_DEBUG_ERROR("Failed to allocate memory for HEX string");
+        return PPP_ERR_MEMORY;
+    }
+    
+    size_t encoded_len = n706a_binary_to_hex_string((const uint8_t *)data, len, hex_str, hex_str_len + 1);
+    if (encoded_len == 0) {
+        free(hex_str);
+        PPP_DEBUG_ERROR("Failed to encode binary data to HEX string");
+        return PPP_ERR_INVALID_PARAM;
+    }
+    
+    PPP_DEBUG_DEBUG("HEX encoded: binary_len=%zu -> hex_len=%zu", len, encoded_len);
+    
+    /* 通过 UART 发送HEX字符串(ASCII字符),不添加 \r\n */
+    int32_t write_result = uapi_uart_write(g_at_ctx.uart_bus, (const uint8_t *)hex_str, encoded_len, 0);
 
-    /* 直接通过 UART 发送原始数据,不添加 \r\n */
-    int32_t write_result = uapi_uart_write(g_at_ctx.uart_bus, (const uint8_t *)data, len, 0);
+    free(hex_str);
 
-    if (write_result != (int32_t)len) {
-        PPP_DEBUG_ERROR("Failed to send raw data: wrote %d bytes, expected %zu", write_result, len);
+    if (write_result != (int32_t)encoded_len) {
+        PPP_DEBUG_ERROR("Failed to send HEX data: wrote %d bytes, expected %zu", write_result, encoded_len);
         return PPP_ERR_UART;
     }
 
-    PPP_DEBUG_DEBUG("Raw data sent successfully (%zu bytes) on bus %d", len, g_at_ctx.uart_bus);
+    PPP_DEBUG_DEBUG("HEX data sent successfully (%zu hex chars, %zu binary bytes) on bus %d", 
+                   encoded_len, len, g_at_ctx.uart_bus);
     return PPP_ERR_OK;
 }
 
@@ -1204,11 +1525,24 @@ uint32_t n706a_at_get_current_baudrate(void)
  * @param urc_len URC数据长度
  * @param socket_id 输出:socket ID
  * @param data_len 输出:数据长度
+ *   - ASCII模式:二进制数据长度(字节数)
+ *   - HEX模式:HEX字符串长度(字节数),需要除以2得到二进制数据长度
  * @param data 输出:数据指针(指向 urc_data 内部)
+ *   - ASCII模式:指向ASCII数据
+ *   - HEX模式:指向HEX字符串
  * @return true=解析成功,false=失败
  * 
- * URC格式:+TCPRECV: <socket_id>,<length>,<data>\r\n
- * 例如:+TCPRECV: 0,10,1234567890\r\n
+ * URC格式(ASCII模式):+TCPRECV: <socket_id>,<binary_len>,<ascii_data>\r\n
+ * 例如:+TCPRECV: 0,10,1234567890\r\n (10字节ASCII数据)
+ * 注意:<length>是二进制数据长度(10)
+ * 
+ * URC格式(HEX模式):+TCPRECV: <socket_id>,<hex_str_len>,<hex_data>\r\n
+ * 例如:+TCPRECV: 0,6,313233\r\n (表示3字节二进制数据:0x31, 0x32, 0x33)
+ * 注意:<length>是HEX字符串长度(6),不是二进制数据长度(3)
+ * 
+ * 与AT+TCPSEND的对应关系:
+ * - AT+TCPSEND的length参数:二进制数据长度(字节数)
+ * - +TCPRECV的length参数:HEX模式下是HEX字符串长度(字节数)= 二进制数据长度 × 2
  */
 static bool n706a_parse_tcprecv_urc(const char *urc_data, size_t urc_len, 
                                     int *socket_id, size_t *data_len, const uint8_t **data)
@@ -1234,7 +1568,7 @@ static bool n706a_parse_tcprecv_urc(const char *urc_data, size_t urc_len,
     }
     p++;  // 跳过逗号
     
-    // 解析 length
+    // 解析 length(HEX模式下这是HEX字符串的长度)
     *data_len = 0;
     while (p < end && *p >= '0' && *p <= '9') {
         *data_len = *data_len * 10 + (*p - '0');
@@ -1263,10 +1597,285 @@ static bool n706a_parse_tcprecv_urc(const char *urc_data, size_t urc_len,
         }
     }
     
-    PPP_DEBUG_DEBUG("Parsed URC: socket=%d, len=%u", *socket_id, (unsigned int)*data_len);
+    PPP_DEBUG_DEBUG("Parsed URC: socket=%d, data_len=%u", *socket_id, (unsigned int)*data_len);
     return true;
 }
 
+/**
+ * @brief 解析 +TCPCLOSE URC
+ * @param urc_data URC数据(以 "+TCPCLOSE: " 或 "+SSLTCPCLOSE: " 开头)
+ * @param urc_len URC数据长度
+ * @param socket_id 输出:socket ID(如果格式是ERROR,socket_id设为-1)
+ * @return true=解析成功,false=失败
+ * 
+ * URC格式:
+ *   +TCPCLOSE: <socket_id>
+ *   +TCPCLOSE: <socket_id>,Link Closed
+ *   +TCPCLOSE: ERROR(错误格式,socket_id设为-1)
+ *     或:+SSLTCPCLOSE: <socket_id>
+ */
+static bool n706a_parse_tcpclose_urc(const char *urc_data, size_t urc_len, int *socket_id)
+{
+    if (!urc_data || !socket_id || urc_len < 12) {
+        return false;
+    }
+    
+    // 查找 ": " 位置
+    const char *colon_space = strstr(urc_data, ": ");
+    if (!colon_space) {
+        return false;
+    }
+    
+    const char *p = colon_space + 2;  // 跳过 ": "
+    const char *end = urc_data + urc_len;
+    
+    // 检查是否是ERROR格式
+    if (p + 5 <= end && memcmp(p, "ERROR", 5) == 0 &&
+        (p[5] == '\r' || p[5] == '\n' || p[5] == '\0' || p[5] == ' ')) {
+        *socket_id = -1;  // ERROR格式,socket_id设为-1表示错误
+        return true;
+    }
+    
+    // 解析 socket_id
+    *socket_id = 0;
+    while (p < end && *p >= '0' && *p <= '9') {
+        *socket_id = *socket_id * 10 + (*p - '0');
+        p++;
+    }
+    
+    // 可能后面有 ",Link Closed" 或其他信息,但socket_id已经解析完成
+    return (*socket_id >= 0);  // 确保至少解析到一个有效的socket_id或ERROR
+}
+
+/**
+ * @brief 解析 +TCPSEND URC
+ * @param urc_data URC数据(以 "+TCPSEND: " 或 "+SSLTCPEND: " 开头)
+ * @param urc_len URC数据长度
+ * @param socket_id 输出:socket ID
+ * @param sent_bytes 输出:实际发送的字节数
+ * @return true=解析成功,false=失败
+ * 
+ * URC格式:+TCPSEND: <socket_id>,<sent_bytes>
+ *     或:+SSLTCPEND: <socket_id>,<sent_bytes>
+ */
+static bool n706a_parse_tcpsend_urc(const char *urc_data, size_t urc_len, 
+                                    int *socket_id, size_t *sent_bytes)
+{
+    if (!urc_data || !socket_id || !sent_bytes || urc_len < 15) {
+        return false;
+    }
+    
+    // 查找 ": " 位置
+    const char *colon_space = strstr(urc_data, ": ");
+    if (!colon_space) {
+        return false;
+    }
+    
+    const char *p = colon_space + 2;  // 跳过 ": "
+    const char *end = urc_data + urc_len;
+    
+    // 解析 socket_id
+    *socket_id = 0;
+    while (p < end && *p >= '0' && *p <= '9') {
+        *socket_id = *socket_id * 10 + (*p - '0');
+        p++;
+    }
+    
+    if (p >= end || *p != ',') {
+        PPP_DEBUG_ERROR("TCPSEND URC parse error: no comma after socket_id");
+        return false;
+    }
+    p++;  // 跳过逗号
+    
+    // 解析 sent_bytes
+    *sent_bytes = 0;
+    while (p < end && *p >= '0' && *p <= '9') {
+        *sent_bytes = *sent_bytes * 10 + (*p - '0');
+        p++;
+    }
+    
+    return true;
+}
+
+/**
+ * @brief 解析 +TCPSETUP URC
+ * @param urc_data URC数据(以 "+TCPSETUP: " 或 "+SSLTCPSETUP: " 开头)
+ * @param urc_len URC数据长度
+ * @param socket_id 输出:socket ID
+ * @param success 输出:true表示OK,false表示FAIL
+ * @return true=解析成功,false=失败
+ * 
+ * URC格式:+TCPSETUP: <socket_id>,OK 或 +TCPSETUP: <socket_id>,FAIL
+ *     或:+SSLTCPSETUP: <socket_id>,OK 或 +SSLTCPSETUP: <socket_id>,FAIL
+ * 例如:+TCPSETUP: 0,OK 或 +TCPSETUP: 0,FAIL
+ */
+static bool n706a_parse_tcpsetup_urc(const char *urc_data, size_t urc_len,
+                                     int *socket_id, bool *success)
+{
+    if (!urc_data || !socket_id || !success || urc_len < 15) {
+        return false;
+    }
+    
+    // 查找 ": " 位置(跳过 "+TCPSETUP" 或 "+SSLTCPSETUP")
+    const char *colon_space = strstr(urc_data, ": ");
+    if (!colon_space) {
+        return false;
+    }
+    
+    const char *p = colon_space + 2;  // 跳过 ": "
+    const char *end = urc_data + urc_len;
+    
+    // 跳过可能的空格
+    while (p < end && (*p == ' ' || *p == '\t')) {
+        p++;
+    }
+    
+    // 解析 socket_id
+    *socket_id = 0;
+    while (p < end && *p >= '0' && *p <= '9') {
+        *socket_id = *socket_id * 10 + (*p - '0');
+        p++;
+    }
+    
+    if (p >= end || *p != ',') {
+        PPP_DEBUG_ERROR("TCPSETUP URC parse error: no comma after socket_id (found: 0x%02x)", 
+                       p < end ? (unsigned char)*p : 0);
+        return false;
+    }
+    p++;  // 跳过逗号
+    
+    // 跳过可能的空格
+    while (p < end && (*p == ' ' || *p == '\t')) {
+        p++;
+    }
+    
+    // 解析结果(OK或FAIL),忽略前后空白字符
+    if (p < end) {
+        // 检查OK
+        if (p + 2 <= end && (p[0] == 'O' || p[0] == 'o') && (p[1] == 'K' || p[1] == 'k')) {
+            // 检查OK后面是否是结束符或空白字符
+            if (p + 2 >= end || p[2] == '\r' || p[2] == '\n' || p[2] == '\0' || 
+                p[2] == ' ' || p[2] == '\t') {
+                *success = true;
+                return true;
+            }
+        }
+        
+        // 检查FAIL
+        if (p + 4 <= end && 
+            (p[0] == 'F' || p[0] == 'f') && 
+            (p[1] == 'A' || p[1] == 'a') && 
+            (p[2] == 'I' || p[2] == 'i') && 
+            (p[3] == 'L' || p[3] == 'l')) {
+            // 检查FAIL后面是否是结束符或空白字符
+            if (p + 4 >= end || p[4] == '\r' || p[4] == '\n' || p[4] == '\0' || 
+                p[4] == ' ' || p[4] == '\t') {
+                *success = false;
+                return true;
+            }
+        }
+    }
+    
+    // 如果都不匹配,输出详细的调试信息
+    char debug_buf[64] = {0};
+    size_t debug_len = (end - p < sizeof(debug_buf) - 1) ? (end - p) : (sizeof(debug_buf) - 1);
+    memcpy(debug_buf, p, debug_len);
+    PPP_DEBUG_ERROR("TCPSETUP URC parse error: invalid result (expected OK/FAIL), found: [%.*s] (len=%u)", 
+                   (int)debug_len, debug_buf, (unsigned int)(end - p));
+    return false;
+}
+
+/**
+ * @brief 将单个HEX字符转换为数值
+ * @param c HEX字符('0'-'9', 'A'-'F', 'a'-'f')
+ * @param value 输出的数值
+ * @return true=成功,false=失败
+ */
+static bool n706a_hex_char_to_value(char c, uint8_t *value)
+{
+    if (c >= '0' && c <= '9') {
+        *value = c - '0';
+        return true;
+    } else if (c >= 'A' && c <= 'F') {
+        *value = c - 'A' + 10;
+        return true;
+    } else if (c >= 'a' && c <= 'f') {
+        *value = c - 'a' + 10;
+        return true;
+    }
+    return false;
+}
+
+/**
+ * @brief 将二进制数据转换为HEX字符串
+ * @param binary_data 二进制数据
+ * @param binary_len 二进制数据长度
+ * @param hex_str 输出的HEX字符串缓冲区
+ * @param hex_buf_size HEX缓冲区大小(至少需要binary_len*2+1)
+ * @return 转换后的HEX字符串长度(不含结束符),0表示失败
+ */
+static size_t n706a_binary_to_hex_string(const uint8_t *binary_data, size_t binary_len,
+                                         char *hex_str, size_t hex_buf_size)
+{
+    if (!binary_data || !hex_str || binary_len == 0) {
+        return 0;
+    }
+    
+    // 需要binary_len * 2字节(每个字节转换为2个HEX字符),再加1个结束符
+    if (hex_buf_size < binary_len * 2 + 1) {
+        PPP_DEBUG_ERROR("HEX encode: buffer too small (need %u, got %u)", 
+                       (unsigned int)(binary_len * 2 + 1), (unsigned int)hex_buf_size);
+        return 0;
+    }
+    
+    static const char hex_chars[] = "0123456789ABCDEF";
+    
+    for (size_t i = 0; i < binary_len; i++) {
+        hex_str[i * 2] = hex_chars[(binary_data[i] >> 4) & 0x0F];
+        hex_str[i * 2 + 1] = hex_chars[binary_data[i] & 0x0F];
+    }
+    
+    hex_str[binary_len * 2] = '\0';
+    return binary_len * 2;
+}
+
+/**
+ * @brief 将HEX字符串转换为二进制数据
+ * @param hex_str HEX字符串(如 "313233")
+ * @param hex_len HEX字符串长度(字节数,必须是偶数)
+ * @param binary_buf 输出的二进制缓冲区
+ * @param binary_buf_size 二进制缓冲区大小
+ * @return 转换后的二进制数据长度(字节数),0表示失败
+ */
+static size_t n706a_hex_string_to_binary(const char *hex_str, size_t hex_len, 
+                                         uint8_t *binary_buf, size_t binary_buf_size)
+{
+    if (!hex_str || !binary_buf || hex_len == 0 || hex_len % 2 != 0) {
+        return 0;
+    }
+    
+    size_t binary_len = hex_len / 2;
+    if (binary_len > binary_buf_size) {
+        PPP_DEBUG_ERROR("HEX decode: binary_len=%u exceeds buffer size=%u", 
+                       (unsigned int)binary_len, (unsigned int)binary_buf_size);
+        return 0;
+    }
+    
+    for (size_t i = 0; i < binary_len; i++) {
+        uint8_t high_nibble, low_nibble;
+        
+        if (!n706a_hex_char_to_value(hex_str[i * 2], &high_nibble) ||
+            !n706a_hex_char_to_value(hex_str[i * 2 + 1], &low_nibble)) {
+            PPP_DEBUG_ERROR("Invalid HEX character at position %u", (unsigned int)(i * 2));
+            return 0;
+        }
+        
+        binary_buf[i] = (high_nibble << 4) | low_nibble;
+    }
+    
+    return binary_len;
+}
+
 /**
  * @brief 注册TCP URC接收回调
  * @param callback 回调函数指针,NULL表示取消注册
@@ -1275,4 +1884,41 @@ void n706a_at_register_tcp_urc_callback(n706a_tcp_urc_callback_t callback)
 {
     g_tcp_urc_callback = callback;
     PPP_DEBUG_INFO("TCP URC callback %s", callback ? "registered" : "unregistered");
+}
+
+/**
+ * @brief 注册+TCPSETUP URC回调
+ * @param callback 回调函数指针,NULL表示取消注册
+ */
+void n706a_at_register_tcpsetup_urc_callback(n706a_tcpsetup_urc_callback_t callback)
+{
+    g_tcpsetup_urc_callback = callback;
+    PPP_DEBUG_INFO("+TCPSETUP URC callback %s", callback ? "registered" : "unregistered");
+}
+
+/**
+ * @brief 注册+TCPCLOSE URC回调
+ */
+void n706a_at_register_tcpclose_urc_callback(n706a_tcpclose_urc_callback_t callback)
+{
+    g_tcpclose_urc_callback = callback;
+    PPP_DEBUG_INFO("+TCPCLOSE URC callback %s", callback ? "registered" : "unregistered");
+}
+
+/**
+ * @brief 注册+TCPSEND URC回调
+ */
+void n706a_at_register_tcpsend_urc_callback(n706a_tcpsend_urc_callback_t callback)
+{
+    g_tcpsend_urc_callback = callback;
+    PPP_DEBUG_INFO("+TCPSEND URC callback %s", callback ? "registered" : "unregistered");
+}
+
+/**
+ * @brief 注册网络状态URC回调
+ */
+void n706a_at_register_network_status_urc_callback(n706a_network_status_urc_callback_t callback)
+{
+    g_network_status_urc_callback = callback;
+    PPP_DEBUG_INFO("Network status URC callback %s", callback ? "registered" : "unregistered");
 }
\ No newline at end of file
index d289d59..2e2cc4b 100644 (file)
@@ -10,6 +10,8 @@
  */
 
 #include "n706a_http_client.h"
+#include "n706a_tcp_client.h"
+#include "ppp_debug.h"
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -46,15 +48,30 @@ static int http_parse_url(const char *url,
 
 /**
  * @brief 初始化HTTP客户端
+ * @param client HTTP客户端结构体指针
+ * @param socket_id socket ID (0-5),如果传入-1则自动分配空闲的socket_id
+ * @return N706A_HTTP_SUCCESS 成功,其他值失败
  */
 n706a_httpc_result_t n706a_http_client_init(n706a_http_client_t *client, int socket_id)
 {
-    if (!client || socket_id < 0 || socket_id > 5) {
+    if (!client) {
         return N706A_HTTP_EARG;
     }
     
     memset(client, 0, sizeof(n706a_http_client_t));
     
+    /* 如果socket_id为-1,自动分配空闲的socket_id(避免与WebSocket冲突) */
+    if (socket_id == -1) {
+        socket_id = n706a_tcp_find_free_socket_id();
+        if (socket_id < 0 || socket_id > 5) {
+            PPP_DEBUG_ERROR("[HTTP] No free socket ID available for HTTP client");
+            return N706A_HTTP_ENOBUFS;
+        }
+        PPP_DEBUG_INFO("[HTTP] Auto-allocated socket ID: %d", socket_id);
+    } else if (socket_id < 0 || socket_id > 5) {
+        return N706A_HTTP_EARG;
+    }
+    
     client->socket_id = socket_id;
     client->is_https = false;
     client->remote_port = 0;
index e72adf4..bdbb00a 100644 (file)
@@ -183,17 +183,31 @@ errcode_t n706a_net_init(const n706a_net_config_t *config)
         return ERRCODE_FAIL;
     }
 
-    // 7. 配置TCP接收模式为直接输出(URC模式)
-    PPP_DEBUG_PRINT("Step 7: Configuring TCP URC mode\n");
+    // 7. é\85\8dç½®TCPæ\8e¥æ\94¶æ¨¡å¼\8f为ç\9b´æ\8e¥è¾\93å\87ºï¼\88URC模å¼\8fï¼\8cHEXä¸\8aæ\8a¥ï¼\89
+    PPP_DEBUG_PRINT("Step 7: Configuring TCP URC mode (HEX format)\n");
     n706a_at_response_t at_resp;
-    n706a_at_error_t at_ret = n706a_at_send_command("AT+RECVMODE=1", "OK", 3000, &at_resp);
+    n706a_at_error_t at_ret = n706a_at_send_command("AT+RECVMODE=1,1", "OK", 3000, &at_resp);
     if (at_ret != N706A_AT_OK) {
-        PPP_DEBUG_WARN("Failed to set RECVMODE=1, using default\n");
+        PPP_DEBUG_WARN("Failed to set RECVMODE=1,1 (HEX mode), trying ASCII mode\n");
+        // 如果HEX模式失败,尝试ASCII模式作为备用
+        at_ret = n706a_at_send_command("AT+RECVMODE=1,0", "OK", 3000, &at_resp);
+        if (at_ret != N706A_AT_OK) {
+            PPP_DEBUG_WARN("Failed to set RECVMODE=1,0, using default\n");
+        } else {
+            PPP_DEBUG_WARN("Using ASCII mode as fallback\n");
+        }
+    } else {
+        PPP_DEBUG_INFO("TCP receive mode set to HEX format\n");
     }
     PPP_DEBUG_INFO("response: %d , %s\n",at_resp.length,at_resp.response);
     // 8. 注册TCP URC接收回调
     PPP_DEBUG_PRINT("Step 8: Registering TCP URC callback\n");
     n706a_at_register_tcp_urc_callback(n706a_tcp_on_urc_received);
+    
+    // 8.1. 注册+TCPSETUP URC回调(用于TCP连接状态验证)
+    PPP_DEBUG_PRINT("Step 8.1: Registering +TCPSETUP URC callback\n");
+    // n706a_tcp_on_tcpsetup_urc在n706a_tcp_client.c中实现,直接调用
+    n706a_at_register_tcpsetup_urc_callback(n706a_tcp_on_tcpsetup_urc);
 
     // 9. 检查GPRS附着状态(AT+CGATT?)
     PPP_DEBUG_PRINT("Step 9: Checking GPRS attachment status (AT+CGATT?)\n");
index 219bf67..70e0a5e 100644 (file)
@@ -13,6 +13,8 @@
 #include "ppp_serial.h"
 #include "ppp_debug.h"
 #include "lock/osal_mutex.h"
+#include "semaphore/osal_semaphore.h"
+#include "soc_osal.h"  // 定义 OSAL_SUCCESS
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -24,6 +26,16 @@ static n706a_tcp_socket_t *g_tcp_sockets[N706A_MAX_SOCKETS] = {NULL};
 static osal_mutex g_socket_table_mutex;
 static bool g_socket_table_initialized = false;
 
+/* URC buffer的mutex和semaphore池(每个socket一个) */
+static osal_mutex g_socket_urc_mutexes[N706A_MAX_SOCKETS];
+static osal_semaphore g_socket_urc_sems[N706A_MAX_SOCKETS];
+static bool g_urc_resources_initialized = false;
+
+/* +TCPSETUP URC等待机制(每个socket一个信号量) */
+static osal_semaphore g_tcpsetup_urc_sems[N706A_MAX_SOCKETS];
+static bool g_tcpsetup_urc_results[N706A_MAX_SOCKETS];  // true=OK, false=FAIL
+static osal_mutex g_tcpsetup_urc_mutex;
+
 /* ========== 私有函数声明 ========== */
 
 #ifdef N706A_SSL_USE_MBEDTLS
@@ -33,12 +45,17 @@ static n706a_tcp_result_t tcp_mbedtls_init_ssl(n706a_tcp_socket_t *sock);
 static void tcp_mbedtls_cleanup_ssl(n706a_tcp_socket_t *sock);
 #endif
 
+/* Socket管理辅助函数 */
+static n706a_tcp_result_t n706a_tcp_force_close_socket_by_id(int socket_id);
+int n706a_tcp_find_free_socket_id(void);  /* 公共API,供HTTP和WebSocket使用 */
+static bool n706a_tcp_wait_for_tcpsetup_urc(int socket_id, uint32_t timeout_ms, bool *success);
+
 /* ========== 公共函数实现 ========== */
 
 /**
- * @brief 创建TCP socket
+ * @brief 创建TCP socket(带自定义URC buffer大小)
  */
-n706a_tcp_result_t n706a_tcp_socket_create(n706a_tcp_socket_t *sock, int socket_id)
+n706a_tcp_result_t n706a_tcp_socket_create_ex(n706a_tcp_socket_t *sock, int socket_id, size_t urc_buffer_size)
 {
     if (!sock || socket_id < 0 || socket_id > 5) {
         return N706A_TCP_EINVAL;
@@ -51,10 +68,15 @@ n706a_tcp_result_t n706a_tcp_socket_create(n706a_tcp_socket_t *sock, int socket_
     sock->is_ssl = false;
     sock->timeout_ms = 15000;  // 默认15秒超时
     
-    // 初始化URC接收缓存(2KB)
-    n706a_tcp_result_t ret = n706a_tcp_init_urc_buffer(sock, 2048);
+    // 确定buffer大小(0表示使用默认值)
+    if (urc_buffer_size == 0) {
+        urc_buffer_size = N706A_TCP_URC_BUFFER_SIZE_DEFAULT;  // 默认6KB
+    }
+    
+    // 初始化URC接收缓存
+    n706a_tcp_result_t ret = n706a_tcp_init_urc_buffer(sock, urc_buffer_size);
     if (ret != N706A_TCP_SUCCESS) {
-        PPP_DEBUG_ERROR("Failed to init URC buffer for socket %d", socket_id);
+        PPP_DEBUG_ERROR("Failed to init URC buffer (%zu bytes) for socket %d", urc_buffer_size, socket_id);
         return ret;
     }
     
@@ -64,11 +86,41 @@ n706a_tcp_result_t n706a_tcp_socket_create(n706a_tcp_socket_t *sock, int socket_
         g_socket_table_initialized = true;
     }
     
+    // 初始化URC资源池(mutex和semaphore)
+    if (!g_urc_resources_initialized) {
+        for (int i = 0; i < N706A_MAX_SOCKETS; i++) {
+            if (osal_mutex_init(&g_socket_urc_mutexes[i]) != OSAL_SUCCESS) {
+                PPP_DEBUG_ERROR("Failed to init URC mutex for socket %d", i);
+                return N706A_TCP_ERROR;
+            }
+            if (osal_sem_init(&g_socket_urc_sems[i], 0) != OSAL_SUCCESS) {
+                PPP_DEBUG_ERROR("Failed to init URC semaphore for socket %d", i);
+                osal_mutex_destroy(&g_socket_urc_mutexes[i]);
+                return N706A_TCP_ERROR;
+            }
+        }
+        g_urc_resources_initialized = true;
+        PPP_DEBUG_DEBUG("URC resource pool initialized for %d sockets", N706A_MAX_SOCKETS);
+    }
+    
     osal_mutex_lock(&g_socket_table_mutex);
     g_tcp_sockets[socket_id] = sock;
     osal_mutex_unlock(&g_socket_table_mutex);
     
-    PPP_DEBUG_INFO("Socket %d created with URC buffer", socket_id);
+    PPP_DEBUG_INFO("Socket %d created with %zu bytes URC buffer", socket_id, urc_buffer_size);
+    
+    return N706A_TCP_SUCCESS;
+}
+
+/**
+ * @brief 创建TCP socket(使用默认buffer大小)
+ */
+n706a_tcp_result_t n706a_tcp_socket_create(n706a_tcp_socket_t *sock, int socket_id)
+{
+    n706a_tcp_result_t ret = n706a_tcp_socket_create_ex(sock, socket_id, 0);  // 使用默认大小
+    if (ret != N706A_TCP_SUCCESS) {
+        return ret;
+    }
     
 #ifdef N706A_SSL_USE_AT_COMMAND
     sock->ssl_version = 3;  // 默认TLS 1.2
@@ -184,8 +236,193 @@ n706a_tcp_result_t n706a_tcp_config_ssl_client_cert(n706a_tcp_socket_t *sock,
 }
 #endif
 
+/**
+ * @brief 强制关闭指定socket ID的socket(方案1:连接前强制关闭旧socket)
+ * @param socket_id socket ID (0-5)
+ * @return N706A_TCP_SUCCESS 成功,其他值失败
+ */
+static n706a_tcp_result_t n706a_tcp_force_close_socket_by_id(int socket_id)
+{
+    if (socket_id < 0 || socket_id >= N706A_MAX_SOCKETS) {
+        return N706A_TCP_EINVAL;
+    }
+    
+    /* 尝试通过AT命令强制关闭socket */
+    char at_cmd[32];
+    n706a_at_response_t response;
+    
+    /* 先尝试关闭普通TCP */
+    snprintf(at_cmd, sizeof(at_cmd), "AT+TCPCLOSE=%d", socket_id);
+    n706a_at_error_t ret = n706a_at_send_command(at_cmd, "OK", 3000, &response);
+    
+    if (ret == N706A_AT_OK && response.length > 0 &&
+        strstr(response.response, "OK") && !strstr(response.response, "ERROR")) {
+        PPP_DEBUG_DEBUG("Socket %d force closed successfully (TCP)", socket_id);
+        return N706A_TCP_SUCCESS;
+    }
+    
+    /* 如果普通TCP关闭失败,尝试关闭SSL TCP */
+    snprintf(at_cmd, sizeof(at_cmd), "AT+SSLTCPCLOSE=%d", socket_id);
+    ret = n706a_at_send_command(at_cmd, "OK", 3000, &response);
+    
+    if (ret == N706A_AT_OK && response.length > 0 &&
+        strstr(response.response, "OK") && !strstr(response.response, "ERROR")) {
+        PPP_DEBUG_DEBUG("Socket %d force closed successfully (SSL TCP)", socket_id);
+        return N706A_TCP_SUCCESS;
+    }
+    
+    /* 即使关闭命令失败,也返回成功(模块端可能已经关闭) */
+    PPP_DEBUG_WARN("Socket %d force close command failed, but continuing (module may have closed it)", socket_id);
+    
+    /* 等待一段时间让模块端完全清理socket状态(避免状态混乱) */
+    osal_msleep(100);
+    
+    return N706A_TCP_SUCCESS;
+}
+
+/**
+ * @brief 查找空闲的socket ID(公共API,供HTTP和WebSocket使用)
+ * @return 空闲的socket ID (0-5),如果没有空闲则返回-1
+ */
+int n706a_tcp_find_free_socket_id(void)
+{
+    if (!g_socket_table_initialized) {
+        return 0;  // 如果表未初始化,返回0(默认)
+    }
+    
+    osal_mutex_lock(&g_socket_table_mutex);
+    
+    /* 查找空闲的socket ID(表中没有注册的socket) */
+    for (int i = 0; i < N706A_MAX_SOCKETS; i++) {
+        if (g_tcp_sockets[i] == NULL) {
+            osal_mutex_unlock(&g_socket_table_mutex);
+            PPP_DEBUG_DEBUG("Found free socket ID: %d", i);
+            return i;
+        }
+    }
+    
+    osal_mutex_unlock(&g_socket_table_mutex);
+    
+    /* 如果所有socket都被占用,尝试查找状态为CLOSED的socket */
+    osal_mutex_lock(&g_socket_table_mutex);
+    for (int i = 0; i < N706A_MAX_SOCKETS; i++) {
+        if (g_tcp_sockets[i] != NULL && 
+            g_tcp_sockets[i]->state == N706A_TCP_STATE_CLOSED) {
+            osal_mutex_unlock(&g_socket_table_mutex);
+            PPP_DEBUG_DEBUG("Found closed socket ID: %d", i);
+            return i;
+        }
+    }
+    osal_mutex_unlock(&g_socket_table_mutex);
+    
+    PPP_DEBUG_WARN("No free socket ID found, will use socket 0");
+    return -1;  // 没有空闲socket,返回-1表示失败
+}
+
+/**
+ * @brief 初始化+TCPSETUP URC等待机制
+ */
+static void n706a_tcp_init_tcpsetup_urc_wait(void)
+{
+    static bool initialized = false;
+    if (initialized) {
+        return;
+    }
+    
+    osal_mutex_init(&g_tcpsetup_urc_mutex);
+    for (int i = 0; i < N706A_MAX_SOCKETS; i++) {
+        osal_sem_init(&g_tcpsetup_urc_sems[i], 0);
+        g_tcpsetup_urc_results[i] = false;
+    }
+    initialized = true;
+    PPP_DEBUG_DEBUG("+TCPSETUP URC wait mechanism initialized");
+}
+
+/**
+ * @brief +TCPSETUP URC回调(由n706a_at_handler调用)
+ * @param socket_id Socket ID
+ * @param success true=OK, false=FAIL
+ * 
+ * 注意:此函数由n706a_at_handler.c通过URC回调调用,不是应用层API
+ */
+void n706a_tcp_on_tcpsetup_urc(int socket_id, bool success)
+{
+    if (socket_id < 0 || socket_id >= N706A_MAX_SOCKETS) {
+        return;
+    }
+    
+    osal_mutex_lock(&g_tcpsetup_urc_mutex);
+    g_tcpsetup_urc_results[socket_id] = success;
+    osal_mutex_unlock(&g_tcpsetup_urc_mutex);
+    
+    /* 通知等待的线程 */
+    osal_sem_up(&g_tcpsetup_urc_sems[socket_id]);
+    
+    PPP_DEBUG_INFO("+TCPSETUP URC received: socket=%d, success=%d", socket_id, success);
+}
+
+/**
+ * @brief 等待+TCPSETUP URC(方案3:验证+TCPSETUP URC)
+ * @param socket_id 等待的socket ID
+ * @param timeout_ms 超时时间(毫秒)
+ * @param success 输出:true表示收到+TCPSETUP: n,OK,false表示收到FAIL或超时
+ * @return true=收到URC,false=超时
+ * 
+ * 使用信号量机制等待URC回调,实现真正的异步等待
+ */
+static bool n706a_tcp_wait_for_tcpsetup_urc(int socket_id, uint32_t timeout_ms, bool *success)
+{
+    if (!success || socket_id < 0 || socket_id >= N706A_MAX_SOCKETS) {
+        return false;
+    }
+    
+    /* 初始化等待机制(首次调用时) */
+    n706a_tcp_init_tcpsetup_urc_wait();
+    
+    /* 清除之前的结果 */
+    osal_mutex_lock(&g_tcpsetup_urc_mutex);
+    g_tcpsetup_urc_results[socket_id] = false;
+    osal_mutex_unlock(&g_tcpsetup_urc_mutex);
+    
+    /* 等待URC信号量(超时时间) */
+    /* 注意:增加等待时间到2000ms,因为URC可能异步延迟到达 */
+    uint32_t actual_timeout = (timeout_ms < 2000) ? 2000 : timeout_ms;
+    int ret = osal_sem_down_timeout(&g_tcpsetup_urc_sems[socket_id], actual_timeout);
+    
+    if (ret == OSAL_SUCCESS) {
+        /* 收到URC,读取结果 */
+        osal_mutex_lock(&g_tcpsetup_urc_mutex);
+        *success = g_tcpsetup_urc_results[socket_id];
+        osal_mutex_unlock(&g_tcpsetup_urc_mutex);
+        PPP_DEBUG_INFO("+TCPSETUP URC received via semaphore: socket=%d, success=%d", socket_id, *success);
+        return true;
+    } else {
+        /* 超时 */
+        PPP_DEBUG_WARN("+TCPSETUP URC wait timeout for socket %d (timeout=%u ms, actual waited=%u ms)", 
+                      socket_id, timeout_ms, actual_timeout);
+        
+        /* 即使超时,也检查一下是否有之前已经设置的结果(可能URC在等待之前就到了) */
+        osal_mutex_lock(&g_tcpsetup_urc_mutex);
+        if (g_tcpsetup_urc_results[socket_id] != false) {  // 如果结果不是默认的false,说明URC已经到达过
+            *success = g_tcpsetup_urc_results[socket_id];
+            osal_mutex_unlock(&g_tcpsetup_urc_mutex);
+            PPP_DEBUG_INFO("+TCPSETUP URC result found (URC arrived before wait): socket=%d, success=%d", socket_id, *success);
+            return true;
+        }
+        osal_mutex_unlock(&g_tcpsetup_urc_mutex);
+        
+        *success = false;
+        return false;
+    }
+}
+
 /**
  * @brief 连接到TCP服务器
+ * 
+ * 实现了三个方案:
+ * 1. 方案1:连接前强制关闭旧socket
+ * 2. 方案2:如果当前socket有问题,尝试使用其他socket ID
+ * 3. 方案3:验证+TCPSETUP URC响应
  */
 n706a_tcp_result_t n706a_tcp_connect(n706a_tcp_socket_t *sock,
                                      const char *host,
@@ -201,6 +438,24 @@ n706a_tcp_result_t n706a_tcp_connect(n706a_tcp_socket_t *sock,
         return N706A_TCP_SUCCESS;  // 已连接
     }
     
+    /* ========== 方案1:连接前强制关闭旧socket ========== */
+    if (sock->state != N706A_TCP_STATE_CLOSED) {
+        PPP_DEBUG_INFO("Socket %d not in CLOSED state (current: %d), forcing close before reconnect", 
+                      sock->socket_id, sock->state);
+        n706a_tcp_result_t close_ret = n706a_tcp_close(sock);
+        if (close_ret != N706A_TCP_SUCCESS) {
+            PPP_DEBUG_WARN("Failed to close socket %d before reconnect, trying force close", sock->socket_id);
+            n706a_tcp_force_close_socket_by_id(sock->socket_id);
+        }
+    }
+    
+    /* 额外检查:即使状态是CLOSED,也强制关闭模块端的socket(防止模块端状态不一致) */
+    PPP_DEBUG_DEBUG("Force closing socket %d at module side before new connection", sock->socket_id);
+    n706a_tcp_force_close_socket_by_id(sock->socket_id);
+    
+    /* 等待模块端完全清理socket状态(避免状态混乱导致连接失败) */
+    osal_msleep(200);
+    
     /* 保存连接信息 */
     strncpy(sock->remote_ip, host, sizeof(sock->remote_ip) - 1);
     sock->remote_port = port;
@@ -230,16 +485,93 @@ n706a_tcp_result_t n706a_tcp_connect(n706a_tcp_socket_t *sock,
             PPP_DEBUG_CRITICAL("[N706A_TCP] Response: %s", response.response);
         }
         
+        /* ========== 方案3:验证+TCPSETUP URC响应 ========== */
         /* 检查响应是否包含OK且不包含ERROR */
         if (ret == N706A_AT_OK && response.length > 0 &&
             strstr(response.response, "OK") &&
             !strstr(response.response, "ERROR")) {
-            PPP_DEBUG_CRITICAL("[N706A_TCP] SSL TCP connection established successfully!");
-            sock->state = N706A_TCP_STATE_CONNECTED;
-            return N706A_TCP_SUCCESS;
+            
+            /* 进一步验证:检查是否有+SSLTCPSETUP或+TCPSETUP URC */
+            bool urc_ok = false;
+            char urc_pattern[32];
+            
+            /* SSL模式可能返回+SSLTCPSETUP或+TCPSETUP URC */
+            snprintf(urc_pattern, sizeof(urc_pattern), "+SSLTCPSETUP: %d,OK", sock->socket_id);
+            if (strstr(response.response, urc_pattern)) {
+                urc_ok = true;
+            } else {
+                snprintf(urc_pattern, sizeof(urc_pattern), "+TCPSETUP: %d,OK", sock->socket_id);
+                if (strstr(response.response, urc_pattern)) {
+                    urc_ok = true;
+                } else {
+                    /* 检查是否有FAIL */
+                    snprintf(urc_pattern, sizeof(urc_pattern), "+SSLTCPSETUP: %d,FAIL", sock->socket_id);
+                    if (strstr(response.response, urc_pattern)) {
+                        PPP_DEBUG_ERROR("[N706A_TCP] Found +SSLTCPSETUP: %d,FAIL in response", sock->socket_id);
+                        sock->state = N706A_TCP_STATE_ERROR;
+                        return N706A_TCP_ECONNREF;
+                    }
+                    
+                    /* 等待异步URC */
+                    bool urc_success = false;
+                    if (n706a_tcp_wait_for_tcpsetup_urc(sock->socket_id, 500, &urc_success)) {
+                        urc_ok = urc_success;
+                    } else {
+                        PPP_DEBUG_WARN("[N706A_TCP] +SSLTCPSETUP URC wait timeout, but command returned OK, assuming success");
+                        urc_ok = true;
+                    }
+                }
+            }
+            
+            if (urc_ok) {
+                PPP_DEBUG_CRITICAL("[N706A_TCP] SSL TCP connection established successfully!");
+                sock->state = N706A_TCP_STATE_CONNECTED;
+                return N706A_TCP_SUCCESS;
+            } else {
+                PPP_DEBUG_ERROR("[N706A_TCP] SSL TCP connection failed: URC indicates FAIL");
+                sock->state = N706A_TCP_STATE_ERROR;
+                return N706A_TCP_ECONNREF;
+            }
         } else {
             PPP_DEBUG_ERROR("[N706A_TCP] SSL TCP connection failed! Response: %s", 
                            response.length > 0 ? response.response : "(empty)");
+            
+            /* ========== 方案2:如果当前socket连接失败,尝试使用其他socket ID ========== */
+            int free_socket_id = n706a_tcp_find_free_socket_id();
+            if (free_socket_id >= 0 && free_socket_id != sock->socket_id) {
+                PPP_DEBUG_WARN("[N706A_TCP] SSL connection failed on socket %d, trying free socket %d", 
+                              sock->socket_id, free_socket_id);
+                
+                /* 更新socket ID并重试 */
+                int old_socket_id = sock->socket_id;
+                sock->socket_id = free_socket_id;
+                
+                /* 重新注册到全局表 */
+                if (g_socket_table_initialized) {
+                    osal_mutex_lock(&g_socket_table_mutex);
+                    if (g_tcp_sockets[old_socket_id] == sock) {
+                        g_tcp_sockets[old_socket_id] = NULL;
+                    }
+                    g_tcp_sockets[free_socket_id] = sock;
+                    osal_mutex_unlock(&g_socket_table_mutex);
+                }
+                
+                /* 重新初始化URC buffer */
+                n706a_tcp_free_urc_buffer(sock);
+                n706a_tcp_result_t buffer_ret = n706a_tcp_init_urc_buffer(sock, 0);
+                if (buffer_ret != N706A_TCP_SUCCESS) {
+                    PPP_DEBUG_ERROR("[N706A_TCP] Failed to reinit URC buffer for new socket %d", free_socket_id);
+                    sock->state = N706A_TCP_STATE_ERROR;
+                    return N706A_TCP_ECONNREF;
+                }
+                
+                /* 强制关闭新socket */
+                n706a_tcp_force_close_socket_by_id(free_socket_id);
+                
+                /* 递归重试连接 */
+                return n706a_tcp_connect(sock, host, port, use_ssl, timeout_ms);
+            }
+            
             sock->state = N706A_TCP_STATE_ERROR;
             return N706A_TCP_ECONNREF;
         }
@@ -258,16 +590,91 @@ n706a_tcp_result_t n706a_tcp_connect(n706a_tcp_socket_t *sock,
             PPP_DEBUG_CRITICAL("[N706A_TCP] Response: %s", response.response);
         }
         
+        /* ========== 方案3:验证+TCPSETUP URC响应 ========== */
         /* 检查响应是否包含OK且不包含ERROR */
         if (ret == N706A_AT_OK && response.length > 0 &&
             strstr(response.response, "OK") &&
             !strstr(response.response, "ERROR")) {
-            PPP_DEBUG_CRITICAL("[N706A_TCP] TCP connection established successfully!");
-            sock->state = N706A_TCP_STATE_CONNECTED;
-            return N706A_TCP_SUCCESS;
+            
+            /* 进一步验证:检查是否有+TCPSETUP URC(可能在响应中,也可能是异步URC) */
+            bool urc_ok = false;
+            
+            /* 检查响应中是否包含+TCPSETUP: n,OK */
+            char urc_pattern[32];
+            snprintf(urc_pattern, sizeof(urc_pattern), "+TCPSETUP: %d,OK", sock->socket_id);
+            if (strstr(response.response, urc_pattern)) {
+                urc_ok = true;
+                PPP_DEBUG_CRITICAL("[N706A_TCP] Found +TCPSETUP: %d,OK in response", sock->socket_id);
+            } else {
+                /* 检查是否有+TCPSETUP: n,FAIL */
+                snprintf(urc_pattern, sizeof(urc_pattern), "+TCPSETUP: %d,FAIL", sock->socket_id);
+                if (strstr(response.response, urc_pattern)) {
+                    PPP_DEBUG_ERROR("[N706A_TCP] Found +TCPSETUP: %d,FAIL in response", sock->socket_id);
+                    sock->state = N706A_TCP_STATE_ERROR;
+                    return N706A_TCP_ECONNREF;
+                }
+                
+                /* 如果没有找到明确的URC,等待一下看是否有异步URC到达 */
+                bool urc_success = false;
+                if (n706a_tcp_wait_for_tcpsetup_urc(sock->socket_id, 500, &urc_success)) {
+                    urc_ok = urc_success;
+                } else {
+                    /* 超时,但命令返回OK,认为连接成功(可能是URC还没到达) */
+                    PPP_DEBUG_WARN("[N706A_TCP] +TCPSETUP URC wait timeout, but command returned OK, assuming success");
+                    urc_ok = true;
+                }
+            }
+            
+            if (urc_ok) {
+                PPP_DEBUG_CRITICAL("[N706A_TCP] TCP connection established successfully!");
+                sock->state = N706A_TCP_STATE_CONNECTED;
+                return N706A_TCP_SUCCESS;
+            } else {
+                PPP_DEBUG_ERROR("[N706A_TCP] TCP connection failed: URC indicates FAIL");
+                sock->state = N706A_TCP_STATE_ERROR;
+                return N706A_TCP_ECONNREF;
+            }
         } else {
             PPP_DEBUG_ERROR("[N706A_TCP] TCP connection failed! Response: %s", 
                            response.length > 0 ? response.response : "(empty)");
+            
+            /* ========== 方案2:如果当前socket连接失败,尝试使用其他socket ID ========== */
+            /* 检查是否有空闲的socket ID可以使用 */
+            int free_socket_id = n706a_tcp_find_free_socket_id();
+            if (free_socket_id >= 0 && free_socket_id != sock->socket_id) {
+                PPP_DEBUG_WARN("[N706A_TCP] Connection failed on socket %d, trying free socket %d", 
+                              sock->socket_id, free_socket_id);
+                
+                /* 更新socket ID并重试连接 */
+                int old_socket_id = sock->socket_id;
+                sock->socket_id = free_socket_id;
+                
+                /* 重新注册到全局表 */
+                if (g_socket_table_initialized) {
+                    osal_mutex_lock(&g_socket_table_mutex);
+                    if (g_tcp_sockets[old_socket_id] == sock) {
+                        g_tcp_sockets[old_socket_id] = NULL;
+                    }
+                    g_tcp_sockets[free_socket_id] = sock;
+                    osal_mutex_unlock(&g_socket_table_mutex);
+                }
+                
+                /* 重新初始化URC buffer(因为socket_id改变了) */
+                n706a_tcp_free_urc_buffer(sock);
+                n706a_tcp_result_t buffer_ret = n706a_tcp_init_urc_buffer(sock, 0);
+                if (buffer_ret != N706A_TCP_SUCCESS) {
+                    PPP_DEBUG_ERROR("[N706A_TCP] Failed to reinit URC buffer for new socket %d", free_socket_id);
+                    sock->state = N706A_TCP_STATE_ERROR;
+                    return N706A_TCP_ECONNREF;
+                }
+                
+                /* 强制关闭新socket(确保干净状态) */
+                n706a_tcp_force_close_socket_by_id(free_socket_id);
+                
+                /* 递归重试连接(使用新的socket_id) */
+                return n706a_tcp_connect(sock, host, port, use_ssl, timeout_ms);
+            }
+            
             sock->state = N706A_TCP_STATE_ERROR;
             return N706A_TCP_ECONNREF;
         }
@@ -286,22 +693,153 @@ n706a_tcp_result_t n706a_tcp_connect(n706a_tcp_socket_t *sock,
     
     ret = n706a_at_send_command(at_cmd, NULL, timeout_ms, &response);
     
-    PPP_DEBUG_CRITICAL("[N706A_TCP] AT+TCPSETUP (mbedtls mode) response: ret=%d, len=%u", ret, response.length);
+    PPP_DEBUG_CRITICAL("[N706A_TCP] AT+TCPSETUP response: ret=%d, len=%u", ret, response.length);
     if (response.length > 0) {
         PPP_DEBUG_CRITICAL("[N706A_TCP] Response: %s", response.response);
     }
     
+    /* ========== 方案3:验证+TCPSETUP URC响应 ========== */
     /* N706A的AT+TCPSETUP成功响应格式:
      * AT+TCPSETUP=0,host,port
      * OK
+     * +TCPSETUP: 0,OK  (异步URC,可能在响应中或稍后到达)
      * 
-     * 只需检查是否包含"OK"且不包含"ERROR"
+     * 需要检查是否包含"OK"且不包含"ERROR",同时验证URC
      */
     if (ret != N706A_AT_OK || response.length == 0 ||
         !strstr(response.response, "OK") ||
         strstr(response.response, "ERROR")) {
         PPP_DEBUG_ERROR("[N706A_TCP] TCP connection failed! Response: %s", 
                        response.length > 0 ? response.response : "(empty)");
+        
+        /* ========== 方案2:如果当前socket连接失败,尝试使用其他socket ID ========== */
+        int free_socket_id = n706a_tcp_find_free_socket_id();
+        if (free_socket_id >= 0 && free_socket_id != sock->socket_id) {
+            PPP_DEBUG_WARN("[N706A_TCP] Connection failed on socket %d (mbedtls mode), trying free socket %d", 
+                          sock->socket_id, free_socket_id);
+            
+            /* 更新socket ID并重试 */
+            int old_socket_id = sock->socket_id;
+            sock->socket_id = free_socket_id;
+            
+            /* 重新注册到全局表 */
+            if (g_socket_table_initialized) {
+                osal_mutex_lock(&g_socket_table_mutex);
+                if (g_tcp_sockets[old_socket_id] == sock) {
+                    g_tcp_sockets[old_socket_id] = NULL;
+                }
+                g_tcp_sockets[free_socket_id] = sock;
+                osal_mutex_unlock(&g_socket_table_mutex);
+            }
+            
+            /* 重新初始化URC buffer */
+            n706a_tcp_free_urc_buffer(sock);
+            n706a_tcp_result_t buffer_ret = n706a_tcp_init_urc_buffer(sock, 0);
+            if (buffer_ret != N706A_TCP_SUCCESS) {
+                PPP_DEBUG_ERROR("[N706A_TCP] Failed to reinit URC buffer for new socket %d", free_socket_id);
+                sock->state = N706A_TCP_STATE_ERROR;
+                return N706A_TCP_ECONNREF;
+            }
+            
+            /* 强制关闭新socket */
+            n706a_tcp_force_close_socket_by_id(free_socket_id);
+            
+            /* 递归重试连接 */
+            return n706a_tcp_connect(sock, host, port, use_ssl, timeout_ms);
+        }
+        
+        sock->state = N706A_TCP_STATE_ERROR;
+        return N706A_TCP_ECONNREF;
+    }
+    
+    /* 进一步验证+TCPSETUP URC */
+    bool urc_ok = false;
+    char urc_pattern[32];
+    snprintf(urc_pattern, sizeof(urc_pattern), "+TCPSETUP: %d,OK", sock->socket_id);
+    if (strstr(response.response, urc_pattern)) {
+        urc_ok = true;
+        PPP_DEBUG_CRITICAL("[N706A_TCP] Found +TCPSETUP: %d,OK in response", sock->socket_id);
+    } else {
+        /* 检查是否有FAIL */
+        snprintf(urc_pattern, sizeof(urc_pattern), "+TCPSETUP: %d,FAIL", sock->socket_id);
+        if (strstr(response.response, urc_pattern)) {
+            PPP_DEBUG_ERROR("[N706A_TCP] Found +TCPSETUP: %d,FAIL in response", sock->socket_id);
+            sock->state = N706A_TCP_STATE_ERROR;
+            return N706A_TCP_ECONNREF;
+        }
+        
+        /* 检查响应中是否有SSLTCPSETUP URC(SSL模式) */
+        snprintf(urc_pattern, sizeof(urc_pattern), "+SSLTCPSETUP: %d,OK", sock->socket_id);
+        if (strstr(response.response, urc_pattern)) {
+            urc_ok = true;
+            PPP_DEBUG_CRITICAL("[N706A_TCP] Found +SSLTCPSETUP: %d,OK in response", sock->socket_id);
+        } else {
+            snprintf(urc_pattern, sizeof(urc_pattern), "+SSLTCPSETUP: %d,FAIL", sock->socket_id);
+            if (strstr(response.response, urc_pattern)) {
+                PPP_DEBUG_ERROR("[N706A_TCP] Found +SSLTCPSETUP: %d,FAIL in response", sock->socket_id);
+                sock->state = N706A_TCP_STATE_ERROR;
+                return N706A_TCP_ECONNREF;
+            }
+        }
+        
+        /* 如果响应中没有找到URC,等待异步URC到达(最多等待2秒) */
+        if (!urc_ok) {
+            PPP_DEBUG_WARN("[N706A_TCP] No URC found in response, waiting for async URC...");
+            bool urc_success = false;
+            if (n706a_tcp_wait_for_tcpsetup_urc(sock->socket_id, 2000, &urc_success)) {
+                urc_ok = urc_success;
+                if (urc_ok) {
+                    PPP_DEBUG_CRITICAL("[N706A_TCP] +TCPSETUP URC received: OK");
+                } else {
+                    PPP_DEBUG_ERROR("[N706A_TCP] +TCPSETUP URC received: FAIL");
+                }
+            } else {
+                /* URC超时,但命令返回OK,假设连接成功 */
+                PPP_DEBUG_WARN("[N706A_TCP] +TCPSETUP URC timeout, but command returned OK, assuming success");
+                urc_ok = true;
+            }
+        }
+    }
+    
+    if (!urc_ok) {
+        PPP_DEBUG_ERROR("[N706A_TCP] TCP connection failed: URC indicates FAIL");
+        
+        /* ========== 方案2:如果当前socket连接失败,尝试使用其他socket ID ========== */
+        int free_socket_id = n706a_tcp_find_free_socket_id();
+        if (free_socket_id >= 0 && free_socket_id != sock->socket_id) {
+            PPP_DEBUG_WARN("[N706A_TCP] Connection failed on socket %d, trying free socket %d", 
+                          sock->socket_id, free_socket_id);
+            
+            /* 更新socket ID并重试 */
+            int old_socket_id = sock->socket_id;
+            sock->socket_id = free_socket_id;
+            
+            /* 重新注册到全局表 */
+            if (g_socket_table_initialized) {
+                osal_mutex_lock(&g_socket_table_mutex);
+                if (g_tcp_sockets[old_socket_id] == sock) {
+                    g_tcp_sockets[old_socket_id] = NULL;
+                }
+                g_tcp_sockets[free_socket_id] = sock;
+                osal_mutex_unlock(&g_socket_table_mutex);
+            }
+            
+            /* 重新初始化URC buffer */
+            n706a_tcp_free_urc_buffer(sock);
+            n706a_tcp_result_t buffer_ret = n706a_tcp_init_urc_buffer(sock, 0);
+            if (buffer_ret != N706A_TCP_SUCCESS) {
+                PPP_DEBUG_ERROR("[N706A_TCP] Failed to reinit URC buffer for new socket %d", free_socket_id);
+                sock->state = N706A_TCP_STATE_ERROR;
+                return N706A_TCP_ECONNREF;
+            }
+            
+            /* 强制关闭新socket */
+            n706a_tcp_force_close_socket_by_id(free_socket_id);
+            
+            /* 递归重试连接 */
+            return n706a_tcp_connect(sock, host, port, use_ssl, timeout_ms);
+        }
+        
         sock->state = N706A_TCP_STATE_ERROR;
         return N706A_TCP_ECONNREF;
     }
@@ -336,8 +874,15 @@ n706a_tcp_result_t n706a_tcp_connect(n706a_tcp_socket_t *sock,
         int handshake_attempts = 0;
         while ((handshake_ret = mbedtls_ssl_handshake(&sock->ssl)) != 0) {
             handshake_attempts++;
-            if (handshake_ret != MBEDTLS_ERR_SSL_WANT_READ &&
-                handshake_ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+            
+            if (handshake_ret == MBEDTLS_ERR_SSL_WANT_READ) {
+                if (handshake_attempts == 1 || handshake_attempts % 50 == 0) {
+                    PPP_DEBUG_DEBUG("[N706A_TCP] SSL handshake waiting for data... (attempt %d)", 
+                                   handshake_attempts);
+                }
+            } else if (handshake_ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+                PPP_DEBUG_DEBUG("[N706A_TCP] SSL handshake needs to send data... (attempt %d)", handshake_attempts);
+            } else {
                 /* 握手失败 */
                 PPP_DEBUG_ERROR("[N706A_TCP] SSL handshake failed after %d attempts! Error: -0x%04x", 
                                handshake_attempts, -handshake_ret);
@@ -346,10 +891,6 @@ n706a_tcp_result_t n706a_tcp_connect(n706a_tcp_socket_t *sock,
                 sock->state = N706A_TCP_STATE_ERROR;
                 return N706A_TCP_ERROR;
             }
-            
-            if (handshake_attempts % 10 == 0) {
-                PPP_DEBUG_DEBUG("[N706A_TCP] SSL handshake in progress... (attempt %d)", handshake_attempts);
-            }
         }
         
         PPP_DEBUG_CRITICAL("[N706A_TCP] SSL handshake completed successfully after %d attempts", handshake_attempts);
@@ -403,26 +944,40 @@ n706a_tcp_result_t n706a_tcp_send(n706a_tcp_socket_t *sock,
 #endif
     
     /* AT指令模式或普通TCP */
+    /* 注意:使用HEX模式发送(mode=1),数据需要编码为HEX字符串 */
     char at_cmd[64];
     n706a_at_response_t response;
     
 #ifdef N706A_SSL_USE_AT_COMMAND
     if (sock->is_ssl) {
-        snprintf(at_cmd, sizeof(at_cmd), "AT+SSLTCPSEND=%d,%zu",
+        /* HEX模式:AT+SSLTCPSEND=<n>,<binary_len>,,1 */
+        snprintf(at_cmd, sizeof(at_cmd), "AT+SSLTCPSEND=%d,%zu,,1",
                 sock->socket_id, len);
     } else
 #endif
     {
-        snprintf(at_cmd, sizeof(at_cmd), "AT+TCPSEND=%d,%zu",
+        /* HEX模式:AT+TCPSEND=<n>,<binary_len>,,1 */
+        snprintf(at_cmd, sizeof(at_cmd), "AT+TCPSEND=%d,%zu,,1",
                 sock->socket_id, len);
     }
     
-    /* 发送命令,等待'>'提示符 */
+    /* 发送 AT+TCPSEND 命令 */
     n706a_at_error_t ret = n706a_at_send_command(at_cmd, NULL, 5000, &response);
     if (ret != N706A_AT_OK) {
+        PPP_DEBUG_ERROR("Failed to send %s command", at_cmd);
+        return N706A_TCP_ERROR;
+    }
+    
+    /* 检查响应中是否包含 '>' 提示符(根据AT命令手册要求) */
+    if (strstr((const char *)response.response, ">") == NULL) {
+        PPP_DEBUG_ERROR("Response does not contain '>' prompt: %s", response.response);
         return N706A_TCP_ERROR;
     }
     
+    /* 延迟50-100ms(根据AT命令手册要求,这里取75ms) */
+    PPP_DEBUG_DEBUG("Received '>' prompt, delaying 75ms before sending data...");
+    osal_msleep(75);
+    
     /* 发送实际数据 */
     ret = ppp_at_send_raw_data(data, len, sock->timeout_ms);
     if (ret != N706A_AT_OK) {
@@ -554,7 +1109,7 @@ n706a_tcp_result_t n706a_tcp_close(n706a_tcp_socket_t *sock)
     }
 #endif
     
-    /* 发送关闭命令 */
+    /* 发送关闭命令,必须确认关闭成功 */
     char at_cmd[32];
     n706a_at_response_t response;
     
@@ -567,8 +1122,45 @@ n706a_tcp_result_t n706a_tcp_close(n706a_tcp_socket_t *sock)
         snprintf(at_cmd, sizeof(at_cmd), "AT+TCPCLOSE=%d", sock->socket_id);
     }
     
-    n706a_at_send_command(at_cmd, NULL, 5000, &response);
+    /* 尝试关闭socket,最多重试3次 */
+    n706a_at_error_t close_ret;
+    int retry_count = 0;
+    const int max_retries = 3;
+    bool close_success = false;
     
+    while (retry_count < max_retries) {
+        close_ret = n706a_at_send_command(at_cmd, "OK", 5000, &response);
+        
+        if (close_ret == N706A_AT_OK && response.length > 0 &&
+            strstr(response.response, "OK") &&
+            !strstr(response.response, "ERROR")) {
+            /* 关闭成功 */
+            PPP_DEBUG_INFO("Socket %d closed successfully (attempt %d/%d)", 
+                          sock->socket_id, retry_count + 1, max_retries);
+            close_success = true;
+            break;
+        }
+        
+        retry_count++;
+        if (retry_count < max_retries) {
+            PPP_DEBUG_WARN("Socket %d close attempt %d/%d failed, retrying...", 
+                          sock->socket_id, retry_count, max_retries);
+            /* 短暂延迟后重试(使用简单的忙等待,避免引入额外依赖) */
+            /* 注意:这里使用简单的循环延迟,在实际应用中可以考虑使用定时器 */
+            volatile int delay_count = 0;
+            for (volatile int i = 0; i < 10000; i++) {  // 约100ms延迟(取决于CPU频率)
+                delay_count++;
+            }
+        } else {
+            PPP_DEBUG_ERROR("Socket %d close failed after %d attempts! Response: %s", 
+                          sock->socket_id, max_retries,
+                          response.length > 0 ? response.response : "(empty)");
+            /* 即使失败也标记为关闭,避免资源泄露,但记录错误 */
+        }
+    }
+    
+    /* 无论成功与否,都标记为关闭(避免资源泄露) */
+    /* 但如果关闭失败,socket在模块端可能仍在打开状态,需要等待或强制关闭 */
     sock->state = N706A_TCP_STATE_CLOSED;
     sock->is_ssl = false;
     
@@ -658,6 +1250,9 @@ static n706a_tcp_result_t tcp_mbedtls_init_ssl(n706a_tcp_socket_t *sock)
                         mbedtls_ctr_drbg_random,
                         &sock->ctr_drbg);
     
+    /* 设置握手超时时间(30秒) */
+    mbedtls_ssl_conf_handshake_timeout(&sock->conf, 30000, 60000);
+    
     /* 设置CA证书 */
     mbedtls_ssl_conf_ca_chain(&sock->conf, &sock->cacert, NULL);
     
@@ -713,7 +1308,19 @@ static void tcp_mbedtls_cleanup_ssl(n706a_tcp_socket_t *sock)
 }
 
 /**
- * @brief mbedtls发送回调(通过AT命令发送)
+ * @brief mbedtls发送回调(BIO接口)
+ * 
+ * mbedtls会自动调用此回调发送加密后的数据。
+ * 
+ * 数据流:
+ * 1. 应用调用 mbedtls_ssl_write(plaintext_data)
+ * 2. mbedtls内部加密 → 调用此回调,buf=加密后的二进制数据
+ * 3. 此函数将加密数据编码为HEX字符串发送到模块
+ * 
+ * @param ctx socket上下文
+ * @param buf 加密后的二进制数据(由mbedtls提供,已加密)
+ * @param len 加密数据长度(字节数)
+ * @return 成功返回发送的字节数,失败返回负数错误码
  */
 static int tcp_mbedtls_send_callback(void *ctx, const unsigned char *buf, size_t len)
 {
@@ -723,65 +1330,137 @@ static int tcp_mbedtls_send_callback(void *ctx, const unsigned char *buf, size_t
         return MBEDTLS_ERR_NET_SEND_FAILED;
     }
     
-    /* 通过AT+TCPSEND发送加密后的数据 */
+    /* buf已经是mbedtls加密后的二进制数据,直接通过AT+TCPSEND发送(使用HEX模式) */
     char at_cmd[64];
-    snprintf(at_cmd, sizeof(at_cmd), "AT+TCPSEND=%d,%zu",
+    snprintf(at_cmd, sizeof(at_cmd), "AT+TCPSEND=%d,%zu,,1",
             sock->socket_id, len);
     
     n706a_at_response_t response;
     n706a_at_error_t ret = n706a_at_send_command(at_cmd, NULL, 5000, &response);
     if (ret != N706A_AT_OK) {
+        PPP_DEBUG_ERROR("Failed to send %s command (mbedtls)", at_cmd);
+        return MBEDTLS_ERR_NET_SEND_FAILED;
+    }
+    
+    /* 检查响应中是否包含 '>' 提示符(根据AT命令手册要求) */
+    if (strstr((const char *)response.response, ">") == NULL) {
+        PPP_DEBUG_ERROR("Response does not contain '>' prompt (mbedtls): %s", response.response);
         return MBEDTLS_ERR_NET_SEND_FAILED;
     }
     
-    /* 发送数据 */
+    /* 延迟50-100ms(根据AT命令手册要求,这里取75ms) */
+    PPP_DEBUG_DEBUG("Received '>' prompt (mbedtls), delaying 75ms before sending data...");
+    osal_msleep(75);
+    
+    /* 发送加密后的二进制数据(ppp_at_send_raw_data内部会将二进制编码为HEX字符串发送) */
     ret = ppp_at_send_raw_data(buf, len, sock->timeout_ms);
     if (ret != N706A_AT_OK) {
         return MBEDTLS_ERR_NET_SEND_FAILED;
     }
     
+    /* 返回实际发送的字节数(len是加密后的数据长度) */
     return len;
 }
 
 /**
- * @brief mbedtls接收回调(通过AT命令接收)
+ * @brief mbedtls接收回调(基于URC buffer,无AT命令,避免死锁)
+ * 
+ * 设计思路:
+ * 1. 从URC buffer读取数据(如果有)
+ * 2. 如果buffer空,等待信号量(有超时)
+ * 3. 超时返回WANT_READ,让mbedtls重试
+ * 4. ✓ 全程不发送AT命令,避免与SSL握手的AT命令冲突
  */
 static int tcp_mbedtls_recv_callback(void *ctx, unsigned char *buf, size_t len)
 {
     n706a_tcp_socket_t *sock = (n706a_tcp_socket_t *)ctx;
     
     if (!sock || !buf || len == 0) {
+        PPP_DEBUG_ERROR("[mbedtls_recv] Invalid parameters");
+        return MBEDTLS_ERR_NET_INVALID_CONTEXT;
+    }
+    
+    if (!sock->urc_recv_buffer || !sock->urc_recv_mutex || !sock->urc_data_available_sem) {
+        PPP_DEBUG_ERROR("[mbedtls_recv] URC buffer not initialized for socket %d", sock->socket_id);
         return MBEDTLS_ERR_NET_RECV_FAILED;
     }
     
-    /* 通过AT+TCPREAD接收加密数据 */
-    char at_cmd[64];
-    snprintf(at_cmd, sizeof(at_cmd), "AT+TCPREAD=%d,%zu",
-            sock->socket_id, len);
+    osal_mutex *mutex = (osal_mutex *)sock->urc_recv_mutex;
+    osal_semaphore *sem = (osal_semaphore *)sock->urc_data_available_sem;
     
-    n706a_at_response_t response;
-    n706a_at_error_t ret = n706a_at_send_command(at_cmd, NULL, sock->timeout_ms, &response);
-    if (ret != N706A_AT_OK) {
-        return MBEDTLS_ERR_NET_RECV_FAILED;
+    // 第一次尝试:检查buffer是否有数据
+    osal_mutex_lock(mutex);
+    
+    if (sock->urc_recv_length > 0) {
+        // ✓ 有数据,直接读取
+        size_t copy_len = (sock->urc_recv_length < len) ? sock->urc_recv_length : len;
+        memcpy(buf, sock->urc_recv_buffer, copy_len);
+        
+        // 移动剩余数据到缓冲区开头
+        if (copy_len < sock->urc_recv_length) {
+            memmove(sock->urc_recv_buffer, sock->urc_recv_buffer + copy_len, 
+                   sock->urc_recv_length - copy_len);
+        }
+        sock->urc_recv_length -= copy_len;
+        
+        osal_mutex_unlock(mutex);
+        
+        PPP_DEBUG_DEBUG("[mbedtls_recv] Read %zu bytes from URC buffer (socket=%d, remaining=%u)", 
+                       copy_len, sock->socket_id, (unsigned int)sock->urc_recv_length);
+        return (int)copy_len;
     }
     
-    /* 解析数据 */
-    if (response.length > 0) {
-        const char *data_start = strstr(response.response, "\r\n");
-        if (data_start) {
-            data_start += 2;
-            size_t data_len = response.length - (data_start - response.response);
+    osal_mutex_unlock(mutex);
+    
+    // Buffer空,等待URC数据到达
+    // 使用静态计数器减少日志打印频率(只在第一次或每100次超时时打印)
+    static uint32_t s_wait_counter = 0;
+    s_wait_counter++;
+    
+    if (s_wait_counter == 1 || (s_wait_counter % 100) == 0) {
+        PPP_DEBUG_DEBUG("[mbedtls_recv] Buffer empty, waiting for URC data (socket=%d, wait_count=%u)...", 
+                       sock->socket_id, s_wait_counter);
+    }
+    
+    // 等待信号量(超时设置为100ms,避免长时间阻塞)
+    // mbedtls会在WANT_READ后重试,所以短超时是合理的
+    int ret = osal_sem_down_timeout(sem, 100);  // 100ms超时
+    
+    if (ret == 0) {  // 0表示成功
+        // 有新数据到达,重置计数器
+        s_wait_counter = 0;
+        
+        // 有新数据到达,重新尝试读取
+        osal_mutex_lock(mutex);
+        
+        if (sock->urc_recv_length > 0) {
+            size_t copy_len = (sock->urc_recv_length < len) ? sock->urc_recv_length : len;
+            memcpy(buf, sock->urc_recv_buffer, copy_len);
             
-            if (data_len > len) {
-                data_len = len;
+            if (copy_len < sock->urc_recv_length) {
+                memmove(sock->urc_recv_buffer, sock->urc_recv_buffer + copy_len, 
+                       sock->urc_recv_length - copy_len);
             }
+            sock->urc_recv_length -= copy_len;
+            
+            osal_mutex_unlock(mutex);
             
-            memcpy(buf, data_start, data_len);
-            return data_len;
+            PPP_DEBUG_DEBUG("[mbedtls_recv] Read %zu bytes after wait (socket=%d)", 
+                           copy_len, sock->socket_id);
+            return (int)copy_len;
         }
+        
+        osal_mutex_unlock(mutex);
     }
     
-    return 0;  // 没有数据
+    // 超时或无数据,返回WANT_READ让mbedtls重试
+    // 这是正常的,mbedtls会不断重试直到收到数据或真正超时
+    // 减少超时日志打印频率(只在每100次或特定次数时打印)
+    if (s_wait_counter == 1 || (s_wait_counter % 100) == 0) {
+        PPP_DEBUG_DEBUG("[mbedtls_recv] Timeout, returning WANT_READ (socket=%d, wait_count=%u)", 
+                       sock->socket_id, s_wait_counter);
+    }
+    return MBEDTLS_ERR_SSL_WANT_READ;
 }
 
 #endif /* N706A_SSL_USE_MBEDTLS */
@@ -807,18 +1486,17 @@ n706a_tcp_result_t n706a_tcp_init_urc_buffer(n706a_tcp_socket_t *sock, size_t bu
     sock->urc_recv_capacity = buffer_size;
     sock->urc_recv_length = 0;
     
-    // 初始化互斥锁
-    osal_mutex *mutex = (osal_mutex *)malloc(sizeof(osal_mutex));
-    if (!mutex) {
+    // 使用全局资源池中的mutex和semaphore(已初始化)
+    if (sock->socket_id < 0 || sock->socket_id >= N706A_MAX_SOCKETS) {
         free(sock->urc_recv_buffer);
         sock->urc_recv_buffer = NULL;
-        return N706A_TCP_ENOBUFS;
+        return N706A_TCP_EINVAL;
     }
     
-    osal_mutex_init(mutex);
-    sock->urc_recv_mutex = mutex;
+    sock->urc_recv_mutex = &g_socket_urc_mutexes[sock->socket_id];
+    sock->urc_data_available_sem = &g_socket_urc_sems[sock->socket_id];
     
-    PPP_DEBUG_DEBUG("URC buffer initialized: socket=%d, size=%u", 
+    PPP_DEBUG_DEBUG("URC buffer initialized: socket=%d, size=%u (mutex+sem created)", 
                    sock->socket_id, (unsigned int)buffer_size);
     
     return N706A_TCP_SUCCESS;
@@ -833,13 +1511,12 @@ void n706a_tcp_free_urc_buffer(n706a_tcp_socket_t *sock)
         return;
     }
     
-    if (sock->urc_recv_mutex) {
-        osal_mutex *mutex = (osal_mutex *)sock->urc_recv_mutex;
-        osal_mutex_destroy(mutex);
-        free(mutex);
-        sock->urc_recv_mutex = NULL;
-    }
+    // 注意:mutex和semaphore是全局资源池中的,不需要销毁
+    // 只需要清除指针引用即可
+    sock->urc_recv_mutex = NULL;
+    sock->urc_data_available_sem = NULL;
     
+    // 释放缓冲区
     if (sock->urc_recv_buffer) {
         free(sock->urc_recv_buffer);
         sock->urc_recv_buffer = NULL;
@@ -848,7 +1525,7 @@ void n706a_tcp_free_urc_buffer(n706a_tcp_socket_t *sock)
     sock->urc_recv_capacity = 0;
     sock->urc_recv_length = 0;
     
-    PPP_DEBUG_DEBUG("URC buffer freed: socket=%d", sock->socket_id);
+    PPP_DEBUG_DEBUG("URC buffer freed: socket=%d (mutex+sem destroyed)", sock->socket_id);
 }
 
 /**
@@ -883,6 +1560,8 @@ void n706a_tcp_on_urc_received(int socket_id, const uint8_t *data, size_t length
     size_t available_space = sock->urc_recv_capacity - sock->urc_recv_length;
     size_t copy_len = (length <= available_space) ? length : available_space;
     
+    bool data_added = false;
+    
     if (copy_len < length) {
         PPP_DEBUG_WARN("URC buffer overflow: socket=%d, need=%u, available=%u", 
                       socket_id, (unsigned int)length, (unsigned int)available_space);
@@ -891,13 +1570,25 @@ void n706a_tcp_on_urc_received(int socket_id, const uint8_t *data, size_t length
     if (copy_len > 0) {
         memcpy(sock->urc_recv_buffer + sock->urc_recv_length, data, copy_len);
         sock->urc_recv_length += copy_len;
+        data_added = true;
         
-        PPP_DEBUG_INFO("URC data buffered: socket=%d, received=%u, total=%u/%u", 
+        PPP_DEBUG_DEBUG("URC data buffered: socket=%d, received=%u, total=%u/%u", 
                       socket_id, (unsigned int)copy_len, 
                       (unsigned int)sock->urc_recv_length, 
                       (unsigned int)sock->urc_recv_capacity);
     }
     
+    // 通知等待的recv函数(mbedtls recv回调)
+    if (data_added && sock->urc_data_available_sem) {
+        osal_semaphore *sem = (osal_semaphore *)sock->urc_data_available_sem;
+        osal_sem_up(sem);  // 增加信号量计数,唤醒等待者
+    }
+    
     osal_mutex_unlock(mutex);
+    
+    if (copy_len < length) {
+        PPP_DEBUG_WARN("URC buffer overflow: socket=%d, dropped %u bytes", 
+                      socket_id, (unsigned int)(length - copy_len));
+    }
 }
 
index 02e9eb9..1720bea 100644 (file)
  */
 
 #include "n706a_websocket.h"
+#include "n706a_tcp_client.h"
+#include "ppp_debug.h"
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <time.h>
+#include <stdint.h>
+
+#ifdef __unix__
+#include <pthread.h>
+#include <unistd.h>
+#elif defined(__rtthread__)
+#include <rtthread.h>
+#endif
 
 /* WebSocket GUID(RFC 6455) */
 #define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
@@ -60,16 +70,16 @@ int n706a_websocket_constructor(n706a_ws_on_open_callback_t on_open,
                                 n706a_ws_on_error_callback_t on_error,
                                 n706a_ws_on_close_callback_t on_close)
 {
-    /* 查找空闲slot */
-    int client_id = -1;
+    /* 查找空闲的WebSocket客户端slot */
+    int client_slot = -1;
     for (int i = 0; i < N706A_WS_MAX_CLIENTS; i++) {
         if (g_ws_clients[i] == NULL) {
-            client_id = i;
+            client_slot = i;
             break;
         }
     }
     
-    if (client_id < 0) {
+    if (client_slot < 0) {
         return -1;  // 没有可用slot
     }
     
@@ -83,12 +93,21 @@ int n706a_websocket_constructor(n706a_ws_on_open_callback_t on_open,
     
     memset(client, 0, sizeof(n706a_websocket_client_t));
     
-    client->client_id = client_id;
+    /* 使用TCP的socket ID分配机制,避免与HTTP冲突 */
+    int socket_id = n706a_tcp_find_free_socket_id();
+    if (socket_id < 0 || socket_id > 5) {
+        PPP_DEBUG_ERROR("[WebSocket] No free socket ID available for WebSocket client");
+        free(client);
+        return -1;
+    }
+    
+    client->client_id = client_slot;  /* WebSocket客户端slot */
     client->state = N706A_WS_STATE_CLOSED;
     client->is_ssl = false;
     
-    /* 初始化TCP socket */
-    n706a_tcp_socket_create(&client->tcp_sock, client_id);
+    /* 初始化TCP socket(使用自动分配的socket_id,避免与HTTP冲突) */
+    n706a_tcp_socket_create(&client->tcp_sock, socket_id);
+    PPP_DEBUG_INFO("[WebSocket] Auto-allocated socket ID: %d (client_slot: %d)", socket_id, client_slot);
     
     /* 设置回调 */
     client->on_open = on_open;
@@ -107,9 +126,9 @@ int n706a_websocket_constructor(n706a_ws_on_open_callback_t on_open,
     client->recv_buffer_len = 0;
     client->running = false;
     
-    g_ws_clients[client_id] = client;
+    g_ws_clients[client_slot] = client;
     
-    return client_id;
+    return client_slot;
 }
 
 /**
@@ -224,8 +243,32 @@ int n706a_websocket_connect(int client_id, const char *url, const char *option)
     
     /* 启动接收线程 */
     client->running = true;
-    // TODO: 创建接收线程
-    // pthread_create(&client->recv_thread, NULL, ws_recv_thread_func, client);
+#ifdef __unix__
+    if (pthread_create((pthread_t *)&client->recv_thread, NULL, ws_recv_thread_func, client) != 0) {
+        PPP_DEBUG_ERROR("Failed to create WebSocket receive thread for client %d", client_id);
+        client->running = false;
+        return N706A_WS_ERROR_SEND_FAIL;
+    }
+#elif defined(__rtthread__)
+    /* RT-Thread使用rt_thread_create */
+    rt_thread_t thread = rt_thread_create("ws_recv",
+                                         (void (*)(void *))ws_recv_thread_func,
+                                         client,
+                                         4096,
+                                         20,
+                                         5);
+    if (thread) {
+        client->recv_thread = thread;
+        rt_thread_startup(thread);
+    } else {
+        PPP_DEBUG_ERROR("Failed to create WebSocket receive thread for client %d", client_id);
+        client->running = false;
+        return N706A_WS_ERROR_SEND_FAIL;
+    }
+#else
+    /* 其他平台暂不支持线程 */
+    PPP_DEBUG_WARN("WebSocket receive thread not supported on this platform");
+#endif
     
     /* 调用on_open回调 */
     if (client->on_open) {
@@ -351,8 +394,17 @@ int n706a_websocket_close_with_reason(int client_id,
     
     /* 停止接收线程 */
     client->running = false;
-    // TODO: 等待线程结束
-    // pthread_join(client->recv_thread, NULL);
+#ifdef __unix__
+    if (client->recv_thread) {
+        pthread_join((pthread_t)client->recv_thread, NULL);
+        client->recv_thread = NULL;
+    }
+#elif defined(__rtthread__)
+    if (client->recv_thread) {
+        rt_thread_delete((rt_thread_t)client->recv_thread);
+        client->recv_thread = NULL;
+    }
+#endif
     
     /* 关闭TCP连接 */
     n706a_tcp_close(&client->tcp_sock);
@@ -608,6 +660,15 @@ static int ws_recv_frame(n706a_websocket_client_t *client)
         }
     }
     
+    /* 接收masking key(如果有) */
+    uint8_t mask_key[4] = {0};
+    if (masked) {
+        n706a_tcp_recv(&client->tcp_sock, mask_key, 4, &received, 5000);
+        if (received < 4) {
+            return -1;
+        }
+    }
+    
     /* 接收payload */
     if (payload_len > 0) {
         uint8_t *payload = (uint8_t *)malloc(payload_len + 1);
@@ -616,8 +677,17 @@ static int ws_recv_frame(n706a_websocket_client_t *client)
         }
         
         n706a_tcp_recv(&client->tcp_sock, payload, payload_len, &received, 10000);
+        if (received < payload_len) {
+            free(payload);
+            return -1;
+        }
         payload[payload_len] = '\0';
         
+        /* 如果数据被掩码,需要解掩码 */
+        if (masked) {
+            ws_mask_data(payload, payload_len, mask_key);
+        }
+        
         /* 处理不同类型的帧 */
         switch (opcode) {
             case N706A_WS_OPCODE_TEXT:
@@ -789,22 +859,201 @@ int n706a_websocket_calculate_accept(const char *key, char *accept)
 /* ========== 辅助函数 ========== */
 
 /**
- * @brief 简化的SHA-1实现(仅用于WebSocket握手)
- * 注意:这是简化版,生产环境建议使用成熟的加密库
+ * @brief SHA-1哈希实现(用于WebSocket握手)
+ * 
+ * 使用完整的SHA-1算法实现,符合RFC 3174标准
+ * 这个实现是独立的,不依赖外部加密库
  */
 static void sha1_simple(const unsigned char *input, size_t len, unsigned char output[20])
 {
-    /* 这里应该是完整的SHA-1实现 */
-    /* 为了简化,这里仅做占位 */
-    /* 生产环境应使用mbedtls_sha1或OpenSSL的SHA1函数 */
+    uint32_t h[5] = {
+        0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0
+    };
+    
+    uint32_t w[80];
+    uint32_t a, b, c, d, e, f, k, temp;
+    size_t i;
+    
+    /* 创建填充后的消息缓冲区 */
+    size_t padded_len = ((len + 9 + 63) / 64) * 64;
+    unsigned char *padded = (unsigned char *)malloc(padded_len);
+    if (!padded) {
+        /* 内存分配失败,返回全0(不应该发生) */
+        memset(output, 0, 20);
+        return;
+    }
+    
+    /* 复制原始数据 */
+    memcpy(padded, input, len);
+    
+    /* 添加填充:首先是0x80字节 */
+    padded[len] = 0x80;
+    
+    /* 填充0字节 */
+    memset(padded + len + 1, 0, padded_len - len - 9);
+    
+    /* 添加长度(64位,大端序) */
+    uint64_t bit_len = (uint64_t)len * 8;
+    padded[padded_len - 8] = (unsigned char)((bit_len >> 56) & 0xFF);
+    padded[padded_len - 7] = (unsigned char)((bit_len >> 48) & 0xFF);
+    padded[padded_len - 6] = (unsigned char)((bit_len >> 40) & 0xFF);
+    padded[padded_len - 5] = (unsigned char)((bit_len >> 32) & 0xFF);
+    padded[padded_len - 4] = (unsigned char)((bit_len >> 24) & 0xFF);
+    padded[padded_len - 3] = (unsigned char)((bit_len >> 16) & 0xFF);
+    padded[padded_len - 2] = (unsigned char)((bit_len >> 8) & 0xFF);
+    padded[padded_len - 1] = (unsigned char)(bit_len & 0xFF);
+    
+    /* 处理每个512位(64字节)块 */
+    for (size_t chunk = 0; chunk < padded_len; chunk += 64) {
+        /* 准备消息调度数组(w[0..15]) */
+        for (i = 0; i < 16; i++) {
+            w[i] = ((uint32_t)padded[chunk + i * 4] << 24) |
+                   ((uint32_t)padded[chunk + i * 4 + 1] << 16) |
+                   ((uint32_t)padded[chunk + i * 4 + 2] << 8) |
+                   ((uint32_t)padded[chunk + i * 4 + 3]);
+        }
+        
+        /* 扩展消息调度数组(w[16..79]) */
+        for (i = 16; i < 80; i++) {
+            temp = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16];
+            w[i] = (temp << 1) | (temp >> 31);  /* 左循环移位1位 */
+        }
+        
+        /* 初始化工作变量 */
+        a = h[0];
+        b = h[1];
+        c = h[2];
+        d = h[3];
+        e = h[4];
+        
+        /* 主循环(80轮) */
+        for (i = 0; i < 80; i++) {
+            if (i < 20) {
+                f = (b & c) | ((~b) & d);
+                k = 0x5A827999;
+            } else if (i < 40) {
+                f = b ^ c ^ d;
+                k = 0x6ED9EBA1;
+            } else if (i < 60) {
+                f = (b & c) | (b & d) | (c & d);
+                k = 0x8F1BBCDC;
+            } else {
+                f = b ^ c ^ d;
+                k = 0xCA62C1D6;
+            }
+            
+            temp = ((a << 5) | (a >> 27)) + f + e + k + w[i];
+            e = d;
+            d = c;
+            c = (b << 30) | (b >> 2);
+            b = a;
+            a = temp;
+        }
+        
+        /* 添加到哈希值 */
+        h[0] += a;
+        h[1] += b;
+        h[2] += c;
+        h[3] += d;
+        h[4] += e;
+    }
+    
+    /* 释放临时缓冲区 */
+    free(padded);
+    
+    /* 输出哈希值(大端序) */
+    output[0] = (unsigned char)(h[0] >> 24);
+    output[1] = (unsigned char)(h[0] >> 16);
+    output[2] = (unsigned char)(h[0] >> 8);
+    output[3] = (unsigned char)h[0];
+    output[4] = (unsigned char)(h[1] >> 24);
+    output[5] = (unsigned char)(h[1] >> 16);
+    output[6] = (unsigned char)(h[1] >> 8);
+    output[7] = (unsigned char)h[1];
+    output[8] = (unsigned char)(h[2] >> 24);
+    output[9] = (unsigned char)(h[2] >> 16);
+    output[10] = (unsigned char)(h[2] >> 8);
+    output[11] = (unsigned char)h[2];
+    output[12] = (unsigned char)(h[3] >> 24);
+    output[13] = (unsigned char)(h[3] >> 16);
+    output[14] = (unsigned char)(h[3] >> 8);
+    output[15] = (unsigned char)h[3];
+    output[16] = (unsigned char)(h[4] >> 24);
+    output[17] = (unsigned char)(h[4] >> 16);
+    output[18] = (unsigned char)(h[4] >> 8);
+    output[19] = (unsigned char)h[4];
+}
+
+/**
+ * @brief WebSocket接收线程函数
+ * 
+ * 持续接收WebSocket帧并调用回调函数通知应用层
+ */
+static void *ws_recv_thread_func(void *arg)
+{
+    n706a_websocket_client_t *client = (n706a_websocket_client_t *)arg;
+    if (!client) {
+        return NULL;
+    }
+    
+    PPP_DEBUG_INFO("WebSocket receive thread started for client %d", client->client_id);
+    
+    while (client->running && client->state == N706A_WS_STATE_OPEN) {
+        /* 尝试接收一帧数据 */
+        int ret = ws_recv_frame(client);
+        
+        if (ret != 0) {
+            /* 接收失败,可能是连接断开或超时 */
+            if (client->running) {
+                PPP_DEBUG_WARN("WebSocket receive frame failed for client %d (ret=%d)", 
+                              client->client_id, ret);
+                
+                /* 调用错误回调 */
+                if (client->on_error) {
+                    client->on_error(client->client_id, 
+                                    N706A_WS_ERROR_RECV_FAIL,
+                                    "Receive frame failed");
+                }
+                
+                /* 自动关闭连接 */
+                client->state = N706A_WS_STATE_CLOSING;
+                break;
+            }
+        }
+        
+        /* 如果状态变为CLOSING,退出循环 */
+        if (client->state == N706A_WS_STATE_CLOSING || 
+            client->state == N706A_WS_STATE_CLOSED) {
+            break;
+        }
+        
+        /* 短暂延迟,避免CPU占用过高 */
+#ifdef __unix__
+        usleep(1000);  // 1ms
+#elif defined(__rtthread__)
+        rt_thread_mdelay(1);
+#else
+        /* 其他平台:简单延迟循环 */
+        volatile int i;
+        for (i = 0; i < 1000; i++);
+#endif
+    }
     
-    /* TODO: 集成真实的SHA-1实现 */
-    memset(output, 0, 20);
+    PPP_DEBUG_INFO("WebSocket receive thread stopped for client %d", client->client_id);
     
-    /* 临时:使用简单哈希作为占位符 */
-    for (size_t i = 0; i < len && i < 20; i++) {
-        output[i % 20] ^= input[i];
+    /* 如果是因为接收失败而退出,关闭连接 */
+    if (client->state == N706A_WS_STATE_OPEN || client->state == N706A_WS_STATE_CLOSING) {
+        client->state = N706A_WS_STATE_CLOSED;
+        
+        /* 调用关闭回调 */
+        if (client->on_close) {
+            client->on_close(client->client_id, 
+                           N706A_WS_CLOSE_ABNORMAL,
+                           "Receive thread exited");
+        }
     }
+    
+    return NULL;
 }
 
 /**
index cab9034..8487b1f 100644 (file)
@@ -141,7 +141,7 @@ int ZhihuiHttpClientSend(HttpClient *client, const char *url, int method, HttpCl
             return -1;
         }
         
-        n706a_httpc_result_t ret = n706a_http_client_init(ppp_client, 0);
+        n706a_httpc_result_t ret = n706a_http_client_init(ppp_client, -1);  /* 自动分配socket_id,避免与WebSocket冲突 */
         if (ret != N706A_HTTP_SUCCESS) {
             free(ppp_client);
             return -1;