From 9ab74a92857e7946ec06870e0371328e10874276 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=AD=99=E6=98=A5=E9=98=B3?= Date: Wed, 15 Oct 2025 11:28:42 +0800 Subject: [PATCH] =?utf8?q?=E7=BB=99ppp=E7=9A=84AT=E6=8C=87=E4=BB=A4?= =?utf8?q?=E5=88=87=E6=8D=A2=EF=BC=8C=E5=8A=A0=E4=B8=8A=E7=A9=BA=E9=97=B2?= =?utf8?q?=E5=88=A4=E5=AE=9A=E3=80=82=E5=B0=BD=E9=87=8F=E4=BF=9D=E8=AF=81?= =?utf8?q?=E4=BC=A0=E8=BE=93=E6=AD=A3=E5=B8=B8=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- code/sdk/zhihui/ppp/include/ppp_interrupt.h | 24 +++ code/sdk/zhihui/ppp/src/ppp_api.c | 21 ++- code/sdk/zhihui/ppp/src/ppp_interrupt.c | 167 +++++++++++++++++++- 3 files changed, 207 insertions(+), 5 deletions(-) diff --git a/code/sdk/zhihui/ppp/include/ppp_interrupt.h b/code/sdk/zhihui/ppp/include/ppp_interrupt.h index 4f1483f3b..9fddb4a4c 100644 --- a/code/sdk/zhihui/ppp/include/ppp_interrupt.h +++ b/code/sdk/zhihui/ppp/include/ppp_interrupt.h @@ -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 diff --git a/code/sdk/zhihui/ppp/src/ppp_api.c b/code/sdk/zhihui/ppp/src/ppp_api.c index e5a4b8ca7..ebff75625 100644 --- a/code/sdk/zhihui/ppp/src/ppp_api.c +++ b/code/sdk/zhihui/ppp/src/ppp_api.c @@ -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; diff --git a/code/sdk/zhihui/ppp/src/ppp_interrupt.c b/code/sdk/zhihui/ppp/src/ppp_interrupt.c index b09a3b064..4f62eff8f 100644 --- a/code/sdk/zhihui/ppp/src/ppp_interrupt.c +++ b/code/sdk/zhihui/ppp/src/ppp_interrupt.c @@ -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 -- 2.17.1