给ppp的AT指令切换,加上空闲判定。尽量保证传输正常。 2512/1 2512/head
author孙春阳 <snickersun@163.com>
Wed, 15 Oct 2025 03:28:42 +0000 (11:28 +0800)
committer孙春阳 <snickersun@163.com>
Wed, 15 Oct 2025 03:28:42 +0000 (11:28 +0800)
code/sdk/zhihui/ppp/include/ppp_interrupt.h
code/sdk/zhihui/ppp/src/ppp_api.c
code/sdk/zhihui/ppp/src/ppp_interrupt.c

index 4f1483f..9fddb4a 100644 (file)
@@ -80,6 +80,30 @@ void ppp_interrupt_reset_stats(void);
  */
 void ppp_interrupt_print_stats(void);
 
+/**
+ * @brief 检查是否可以安全执行+++命令切换到命令模式
+ * @return true 安全,false 不安全
+ * 
+ * 判断标准:
+ * 1. PPP已连接
+ * 2. 接收空闲时间 >= 5秒
+ * 3. 接收速率 < 100 bps
+ * 4. 所有buffer都是EMPTY状态
+ */
+bool ppp_interrupt_is_safe_for_command_switch(void);
+
+/**
+ * @brief 等待安全切换窗口
+ * @param timeout_ms 超时时间(毫秒)
+ * @return true 找到安全窗口,false 超时
+ */
+bool ppp_interrupt_wait_for_safe_switch(uint32_t timeout_ms);
+
+/**
+ * @brief 打印数据传输状态信息(调试用)
+ */
+void ppp_interrupt_print_data_state(void);
+
 #ifdef __cplusplus
 }
 #endif
index e5a4b8c..ebff756 100644 (file)
@@ -1913,6 +1913,11 @@ errcode_t ppp_api_set_baudrate_in_all_mode(uint32_t baudrate)
     // 1. 如果在 PPP 模式,先暂停
     if(ppp_serial_get_mode() == PPP_SERIAL_MODE_PPP_DATA) {
         PPP_DEBUG_INFO("In PPP mode, pausing...");
+
+        if (ppp_interrupt_is_safe_for_command_switch() != true) {
+            PPP_DEBUG_ERROR("Not safe for command switch");
+            return ERRCODE_FAIL;
+        }
         if (ppp_ppp_mode_pause() != ERRCODE_SUCC) {
             PPP_DEBUG_ERROR("Failed to pause PPP mode");
             return ERRCODE_FAIL;
@@ -1937,9 +1942,15 @@ errcode_t ppp_api_set_baudrate_in_all_mode(uint32_t baudrate)
     
     // 3. 执行 AT 命令更新信息
     PPP_DEBUG_CRITICAL("Starting baudrate set... %u",baudrate);
-    if(ppp_at_set_baudrate(baudrate) != ERRCODE_SUCC) {
-        PPP_DEBUG_ERROR("Failed to set baudrate");
-        ret = ERRCODE_FAIL;
+    if(ppp_at_set_baudrate(baudrate) != PPP_ERR_OK) {
+        if (ret != PPP_ERR_OK) {
+            ret = ppp_at_set_baudrate(baudrate);
+            if (ret != PPP_ERR_OK) {
+                PPP_DEBUG_ERROR("Failed to set baudrate %u", baudrate);
+                ret = ERRCODE_FAIL;
+            }
+        }
+        
     }
 
     // 4. 如果需要,去初始化 AT handler 并恢复 PPP 模式
@@ -1993,6 +2004,10 @@ errcode_t ppp_api_update_netinfo_in_all_mode(void)
     // 1. 如果在 PPP 模式,先暂停
     if(ppp_serial_get_mode() == PPP_SERIAL_MODE_PPP_DATA) {
         PPP_DEBUG_INFO("In PPP mode, pausing...");
+        if (ppp_interrupt_is_safe_for_command_switch() != true) {
+            PPP_DEBUG_ERROR("Not safe for command switch");
+            return ERRCODE_FAIL;
+        }
         if (ppp_ppp_mode_pause() != ERRCODE_SUCC) {
             PPP_DEBUG_ERROR("Failed to pause PPP mode");
             return ERRCODE_FAIL;
index b09a3b0..4f62eff 100644 (file)
@@ -41,7 +41,7 @@
 
 /* PPP中断消息队列配置 */
 #define PPP_IRQ_MSG_QUEUE_SIZE     16    // 队列深度(乒乓模式下无需太大)
-#define PPP_IRQ_PROCESS_TASK_PRIO  28    // 处理线程优先级
+#define PPP_IRQ_PROCESS_TASK_PRIO  24    // 处理线程优先级
 #define PPP_IRQ_PROCESS_STACK_SIZE 4096  // 处理线程栈大小
 
 /* 乒乓缓冲区状态 */
@@ -117,6 +117,19 @@ typedef struct {
 
 static ppp_uart_error_stats_t g_uart_error_stats = {0};
 
+/* PPP数据传输状态检测(用于安全执行+++/ATO命令) */
+typedef struct {
+    uint32_t last_rx_time_ms;       // 最后接收数据时间
+    uint32_t rx_bytes_this_second;  // 本秒接收的字节数
+    uint32_t rx_rate_bps;           // 接收速率(bytes/sec)
+} ppp_data_state_t;
+
+static ppp_data_state_t g_ppp_data_state = {0};
+
+/* 配置参数 */
+#define PPP_SAFE_SWITCH_IDLE_MS     5000    // 5秒空闲才安全切换
+#define PPP_LIGHT_THRESHOLD_BPS     100     // 100 bps以下为轻量传输
+
 /* 外部函数声明(在ppp_lwip.c中实现) */
 extern ppp_pcb* ppp_lwip_get_pcb(void);
 extern bool ppp_lwip_is_initialized(void);
@@ -376,6 +389,20 @@ static void ppp_timeout_timer_callback(unsigned long arg)
     // ⚠️ 更新全局时间戳(供ISR使用,ISR中不能调用时间函数)
     g_timer_timestamp_ms = current_time;
     
+    // ✅ 每秒更新一次接收速率(用于安全执行+++/ATO命令)
+    static uint32_t last_rate_update_time = 0;
+    if (last_rate_update_time == 0) {
+        last_rate_update_time = current_time;
+    }
+    
+    uint32_t elapsed = current_time - last_rate_update_time;
+    if (elapsed >= 1000) {  // 每秒更新
+        g_ppp_data_state.rx_rate_bps = 
+            (g_ppp_data_state.rx_bytes_this_second * 1000) / elapsed;
+        g_ppp_data_state.rx_bytes_this_second = 0;
+        last_rate_update_time = current_time;
+    }
+    
     uint8_t current_idx = g_current_buffer_index;  // 读取一次,避免重复读取
     
     // ⚠️ 检查内存是否已分配
@@ -515,6 +542,10 @@ void _ppp_uart_rx_interrupt_handler(const void *buffer, uint16_t length, bool er
     g_ppp_interrupt_stats.total_interrupts++;
     g_ppp_interrupt_stats.total_bytes_received += length;
     
+    // ✅ 更新状态检测(用于安全执行+++/ATO命令)
+    g_ppp_data_state.last_rx_time_ms = g_timer_timestamp_ms;
+    g_ppp_data_state.rx_bytes_this_second += length;
+    
     // 获取当前buffer
     uint8_t current_idx = g_current_buffer_index;
     ppp_ping_pong_buffer_t *current_buffer = &g_ping_pong_buffers[current_idx];
@@ -708,7 +739,7 @@ ppp_error_t ppp_interrupt_enable(void)
     
     app_task_definition_t irq_task_cfg = {0};
     irq_task_cfg.attr.name = "ppp_irq_proc";
-    irq_task_cfg.attr.priority = osPriorityNormal;  // 优先级24(对应原MIDDLE)
+    irq_task_cfg.attr.priority = PPP_IRQ_PROCESS_TASK_PRIO;  // 优先级24(对应原MIDDLE)
     irq_task_cfg.attr.stack_size = PPP_IRQ_PROCESS_STACK_SIZE;
     irq_task_cfg.func = (osThreadFunc_t)ppp_irq_process_thread;
     irq_task_cfg.task_handle = &g_ppp_irq_process_task;
@@ -1147,4 +1178,136 @@ void ppp_interrupt_print_stats(void)
     // 性能总结(已经在上面各部分显示过了,这里不再重复)
     
     PPP_DEBUG_WARN("=================================================");
+}
+
+/**
+ * @brief 检查是否可以安全执行+++命令切换到命令模式
+ * @return true 安全,false 不安全
+ * 
+ * 判断标准:
+ * 1. PPP已连接
+ * 2. 接收空闲时间 >= 5秒
+ * 3. 接收速率 < 100 bps
+ * 4. 所有buffer都是EMPTY状态
+ */
+bool ppp_interrupt_is_safe_for_command_switch(void)
+{
+    // 1. 检查PPP是否已连接
+    if (!ppp_lwip_is_connected()) {
+        PPP_DEBUG_DEBUG("[SAFE_CHECK] Not safe: PPP not connected");
+        return false;
+    }
+    
+    uint32_t current_time = g_timer_timestamp_ms;
+    
+    // 2. 检查接收空闲时间
+    if (g_ppp_data_state.last_rx_time_ms == 0) {
+        // 从未接收过数据,认为是空闲
+        PPP_DEBUG_DEBUG("[SAFE_CHECK] No RX data yet, considered idle");
+    } else {
+        uint32_t idle_ms = current_time - g_ppp_data_state.last_rx_time_ms;
+        if (idle_ms < PPP_SAFE_SWITCH_IDLE_MS) {
+            PPP_DEBUG_DEBUG("[SAFE_CHECK] Not safe: RX idle=%ums < threshold=%ums", 
+                           idle_ms, PPP_SAFE_SWITCH_IDLE_MS);
+            return false;
+        }
+    }
+    
+    // 3. 检查接收速率
+    if (g_ppp_data_state.rx_rate_bps > PPP_LIGHT_THRESHOLD_BPS) {
+        PPP_DEBUG_DEBUG("[SAFE_CHECK] Not safe: RX rate=%u bps > threshold=%u bps", 
+                       g_ppp_data_state.rx_rate_bps, PPP_LIGHT_THRESHOLD_BPS);
+        return false;
+    }
+    
+    // 4. 检查所有buffer是否空闲
+    if (g_ping_pong_buffers != NULL) {
+        uint32_t non_empty_count = 0;
+        for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+            if (g_ping_pong_buffers[i].state != PPP_BUFFER_STATE_EMPTY) {
+                non_empty_count++;
+                PPP_DEBUG_DEBUG("[SAFE_CHECK] Buffer[%u] not empty (state=%d)", 
+                               i, g_ping_pong_buffers[i].state);
+            }
+        }
+        if (non_empty_count > 0) {
+            PPP_DEBUG_DEBUG("[SAFE_CHECK] Not safe: %u buffers not empty", non_empty_count);
+            return false;
+        }
+    }
+    
+    // 全部检查通过
+    uint32_t idle_ms = (g_ppp_data_state.last_rx_time_ms > 0) ?
+                       (current_time - g_ppp_data_state.last_rx_time_ms) : 0xFFFFFFFF;
+    PPP_DEBUG_INFO("[SAFE_CHECK] ✓ Safe for command switch (idle=%ums, rate=%u bps)", 
+                  idle_ms, g_ppp_data_state.rx_rate_bps);
+    return true;
+}
+
+/**
+ * @brief 等待安全切换窗口
+ * @param timeout_ms 超时时间(毫秒)
+ * @return true 找到安全窗口,false 超时
+ */
+bool ppp_interrupt_wait_for_safe_switch(uint32_t timeout_ms)
+{
+    uint32_t start_time = ppp_get_current_time_ms();
+    uint32_t elapsed = 0;
+    
+    PPP_DEBUG_INFO("[SAFE_WAIT] Waiting for safe switch window (timeout=%ums)...", timeout_ms);
+    
+    while (elapsed < timeout_ms) {
+        if (ppp_interrupt_is_safe_for_command_switch()) {
+            PPP_DEBUG_INFO("[SAFE_WAIT] ✓ Safe window found (waited %ums)", elapsed);
+            return true;
+        }
+        
+        // 短暂休眠,避免占用过多CPU
+        osal_msleep(100);
+        
+        elapsed = ppp_get_current_time_ms() - start_time;
+    }
+    
+    PPP_DEBUG_WARN("[SAFE_WAIT] Timeout after %ums, no safe window found", elapsed);
+    return false;
+}
+
+/**
+ * @brief 打印数据传输状态信息(调试用)
+ */
+void ppp_interrupt_print_data_state(void)
+{
+    uint32_t current_time = g_timer_timestamp_ms;
+    uint32_t idle_ms = (g_ppp_data_state.last_rx_time_ms > 0) ?
+                       (current_time - g_ppp_data_state.last_rx_time_ms) : 0xFFFFFFFF;
+    
+    PPP_DEBUG_WARN("╔═══════════════════════════════════════╗");
+    PPP_DEBUG_WARN("║  PPP Data Transfer State              ║");
+    PPP_DEBUG_WARN("╠═══════════════════════════════════════╣");
+    PPP_DEBUG_WARN("║ PPP Connected:  %s                    ║", 
+                   ppp_lwip_is_connected() ? "YES" : "NO ");
+    PPP_DEBUG_WARN("║ RX Idle Time:   %u ms                 ║", idle_ms);
+    PPP_DEBUG_WARN("║ RX Rate:        %u bytes/sec          ║", g_ppp_data_state.rx_rate_bps);
+    PPP_DEBUG_WARN("║ Safe for +++:   %s                    ║", 
+                   ppp_interrupt_is_safe_for_command_switch() ? "YES ✓" : "NO  ✗");
+    PPP_DEBUG_WARN("╠═══════════════════════════════════════╣");
+    
+    // Buffer状态
+    if (g_ping_pong_buffers != NULL) {
+        PPP_DEBUG_WARN("║ Buffer Status:                        ║");
+        for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+            const char *state_str = "?";
+            switch (g_ping_pong_buffers[i].state) {
+                case PPP_BUFFER_STATE_EMPTY:      state_str = "EMPTY     "; break;
+                case PPP_BUFFER_STATE_FILLING:    state_str = "FILLING   "; break;
+                case PPP_BUFFER_STATE_FULL:       state_str = "FULL      "; break;
+                case PPP_BUFFER_STATE_PROCESSING: state_str = "PROCESSING"; break;
+            }
+            PPP_DEBUG_WARN("║   Buffer[%u]: %s              ║", i, state_str);
+        }
+    } else {
+        PPP_DEBUG_WARN("║ Buffers: Not allocated                ║");
+    }
+    
+    PPP_DEBUG_WARN("╚═══════════════════════════════════════╝");
 } 
\ No newline at end of file