/* * usart_biz.c * * Created on: 2026-02-26 * Author: wangfq * Updated: 2026-07-02 — 使用 loop_uart_proto 帧解析器替代 timeout heuristic */ #include "config.h" #include "cmcng.h" #include "debug.h" /* DEBUG 宏: 4G 版本以 -DDEBUG=0 编译, 此时 printf 不占用 USART1 */ #include "loop_uart_proto.h" #include #include "dbn_ble_srv.h" #include "ota_srv.h" void USART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); void USART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); /*==================== UART2 RX DMA (2026-08-17 方案A) ==================== * 根因: PRINT 临界区(关中断 ~7.4ms)期间 USART2 RXNE 中断被屏蔽 → 丢字节 → checksum fail * 方案: DMA1_Ch6 循环模式硬件收字节 (不依赖 CPU 中断), 主循环轮询消费 * - 512B 环形缓冲: 能装 ~7 帧 (70B), 覆盖主循环长阻塞窗口 (SPI 擦除 45ms) * - 无新增中断 (关 RXNE, DMA 硬件接管) → 无优先级冲突; WCHNET 用独立 ETH DMA, * BLE 栈不用 DMA1 → Ch6 独占无冲突 * - lup_feed_byte 状态机移入主循环 (原中断上下文) → 无中断竞争更安全 *======================================================================*/ #define UART2_DMA_BUF_LEN 512 static uint8_t uart2_dma_buf[UART2_DMA_BUF_LEN] __attribute__((aligned(4))); static uint16_t uart2_dma_last = 0; /* 主循环消费位置 (DMA 写指针由硬件维护) */ static uint32_t uart2_dma_drop = 0; /* 溢出丢弃计数 (主循环消费不及时) */ static uint8_t uart2_dma_ota_mode = 0xFF; /* 上次 OTA 模式 (0xFF=未初始化, 首轮强制 reset) */ void uart2_dma_init(void) { DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_DeInit(DMA1_Channel6); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART2->DATAR); DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)uart2_dma_buf; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = UART2_DMA_BUF_LEN; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel6, &DMA_InitStructure); /* DMA 接管 USART2 RX: 硬件收字节, 打印关中断不丢 */ USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE); DMA_Cmd(DMA1_Channel6, ENABLE); /* 关闭 RXNE 中断 (DMA 接管后逐字节中断不再需要) */ USART_ITConfig(USART2, USART_IT_RXNE, DISABLE); uart2_dma_last = 0; } /* 主循环每轮调用: 消费 DMA 环形缓冲新字节 → 批量喂 lup_feed_byte 状态机 */ void uart2_dma_poll(void) { uint16_t cur = (uint16_t)(UART2_DMA_BUF_LEN - DMA_GetCurrDataCounter(DMA1_Channel6)); uint16_t n = (uint16_t)((cur + UART2_DMA_BUF_LEN - uart2_dma_last) & (UART2_DMA_BUF_LEN - 1)); if (n == 0) return; /* 溢出保护: 未消费 > 半缓冲 (256B) → 消费太慢被 DMA 覆盖, 重置解析器丢帧计数 2026-08-19: OTA 模式下 0x9F ACK 帧仅 7B, 停等协议同一时刻 Loop 至多回 1 帧, 放宽阈值到整缓冲 — 256B 阈值在 TX 阻塞窗口可能误杀 ACK */ { uint16_t drop_thr = g_flag_counter_ota.flag ? UART2_DMA_BUF_LEN : (UART2_DMA_BUF_LEN / 2); if (n > drop_thr) { uart2_dma_drop++; lup_frame_reset(); uart2_dma_last = cur; return; } } /* OTA 模式切换 (0x7F ↔ 0x9F) 时重置帧解析器, 防旧模式残留状态污染 */ if (g_flag_counter_ota.flag != uart2_dma_ota_mode) { lup_frame_reset(); uart2_dma_ota_mode = g_flag_counter_ota.flag; } while (n--) { uint8_t b = uart2_dma_buf[uart2_dma_last]; uart2_dma_last = (uint16_t)((uart2_dma_last + 1) & (UART2_DMA_BUF_LEN - 1)); /* OTA 模式走 0x9F 帧解析 (bootloader 的 pre_ok/addr_ok/data ACK), 非 OTA 保持 0x7F 协议解析 */ int done = g_flag_counter_ota.flag ? lup_feed_byte_ota(b) : lup_feed_byte(b); if (done) { /* 帧接收完成 → 复制到 g_pkg_uart_2 (与中断版同逻辑, 主循环无竞争) */ const uint8_t *frame = lup_frame_data(); uint16_t frame_len = lup_frame_len(); if (frame_len <= BUFF_STACK_SIZE) { memcpy(g_pkg_uart_2.pkg, frame, frame_len); g_pkg_uart_2.offset = frame_len; g_pkg_uart_2.flag = 1; g_pkg_uart_2.tick = 0; } lup_frame_reset(); } else if (g_lup_parser.state != LUP_FRAME_STATE_IDLE) { /* 收帧中 → tick 归零 (对齐中断版行为, 防 TIM3 半帧兜底误判) */ g_pkg_uart_2.tick = 0; } } } /*==================== UART1 <-> Air780 4G 通道 (协议 §6.1) ==================== * 定位: 4G 通道中 vd960DBN 只做"字节流透传", 零业务转换 —— * 上行: Loop 0x7F 帧(UART2) --校验通过后原样转发--> UART1 --> Air780 解析转 JSON * 下行: Air780 帧(UART1) --魔数分流--> 0x7F: 转发 UART2(给 vd960Loop) * 0x8F: DBN 本地处理 * * 硬约束: * 1) 只转发 lup_verify_checksum() 通过的完整帧。Air780 侧靠 loop_state 变化沿判车, * 转发一个残缺帧 = 凭空多判一台车。 * 2) 接收必须走 DMA (与 UART2 方案A 同理): PRINT 临界区 / BLE 栈回调 / SPI 擦除等 * 长阻塞窗口会屏蔽 RXNE 中断 -> 丢字节 -> 校验失败。本通道"不丢帧"是硬要求。 * 3) 帧装配器独立于 g_lup_parser: 后者专供 UART2(Loop) 通道, 两条流的字节绝不能 * 混进同一个状态机 (混了就是互相残杀)。 * * 帧格式 (与 Loop/BLE 协议完全一致): * [7F][Addr][LEN][CMD][Value: LEN-1B][XOR][SUM] 总长 = LEN + 5 * 校验覆盖 Addr..Value (不含 magic), 复用 lup_verify_checksum() * * 编译开关: * 调试版 (DEBUG != 0): printf 占用 USART1/PB6, 本通道不参与编译 -> 走空实现 * 4G 版 (DEBUG == 0): -DDEBUG=0 编译即自动启用 (PB6/PB7 由本文件接管) * 亦可 -DUART1_AIR780_EN=1/0 强制覆盖 *===========================================================================*/ #ifndef UART1_AIR780_EN #define UART1_AIR780_EN (DEBUG == 0) #endif #define UART1_MAGIC_LOOP LUP_MAGIC /* 0x7F: 转发给 vd960Loop */ #define UART1_MAGIC_LOCAL 0x8F /* 0x8F: DBN 本地处理 (BLE 侧同名魔数) */ #define UART1_DMA_BUF_LEN 512 #if (UART1_AIR780_EN) static uint8_t uart1_dma_buf[UART1_DMA_BUF_LEN] __attribute__((aligned(4))); static uint16_t uart1_dma_last = 0; /* 主循环消费位置 (DMA 写指针由硬件维护) */ /* 下行帧装配器 (独立实例, 不与 g_lup_parser 共享) */ static uint8_t uart1_rx_frame[LUP_MAX_PKG_LEN]; static uint16_t uart1_rx_idx = 0; /* 已收字节数 */ static uint16_t uart1_rx_need = 0; /* 本帧总长, 0 = 尚未定长 */ /* 通道计数: 现场核对"上行转发数 == Air780 实收数", 比翻日志可靠 */ uint32_t g_uart1_fwd_to_air = 0; /* 上行: UART2 -> UART1 转发帧数 */ uint32_t g_uart1_fwd_to_loop = 0; /* 下行: UART1 -> UART2 转发帧数 */ uint32_t g_uart1_local_cnt = 0; /* 下行: 本地处理帧数 (0x8F) */ uint32_t g_uart1_badchk = 0; /* 下行: 校验失败帧数 */ uint32_t g_uart1_drop = 0; /* 下行: DMA 溢出丢弃次数 */ /* ---- 下行分流 ---- */ static void uart1_dispatch_frame(uint8_t *pkg, uint16_t len) { if (pkg[0] == UART1_MAGIC_LOOP) { /* 0x7F -> 原样转发给 vd960Loop */ g_uart1_fwd_to_loop++; UART2_SendString(pkg, len); } else { /* 0x8F -> DBN 本地处理 (预留: 具体行为待协议细化, 先只计数) */ g_uart1_local_cnt++; } } /* ---- 坏帧回找魔数: 把 [1..len) 里第一个魔数起的残余搬到头部继续装配 ---- * 防"单帧损坏 -> 后续帧全部失步" */ static void uart1_resync(const uint8_t *buf, uint16_t len) { uint16_t i; for (i = 1; i < len; i++) { if (buf[i] == UART1_MAGIC_LOOP || buf[i] == UART1_MAGIC_LOCAL) { uint16_t k, n = 0; for (k = i; k < len; k++) { uart1_rx_frame[n++] = buf[k]; } uart1_rx_idx = n; uart1_rx_need = 0; if (n >= 3) { uint8_t lf = uart1_rx_frame[2]; uint16_t need = (uint16_t)lf + 5; if (lf >= 1 && need <= LUP_MAX_PKG_LEN) { uart1_rx_need = need; } else { uart1_rx_idx = 0; /* LEN 非法: 残余作废 */ } } return; } } /* 残余中没有魔数 -> 全部丢弃 */ } /* ---- 定长收满 -> 校验 -> 分流 ---- */ static void uart1_frame_ready(void) { uint16_t len = uart1_rx_idx; uart1_rx_idx = 0; uart1_rx_need = 0; if (lup_verify_checksum(uart1_rx_frame, len) == 0) { uart1_dispatch_frame(uart1_rx_frame, len); } else { g_uart1_badchk++; uart1_resync(uart1_rx_frame, len); } } /* ---- UART1 字节流装配 ---- */ static void uart1_feed_byte(uint8_t b) { uint8_t guard = 0; if (uart1_rx_idx == 0) { if (b == UART1_MAGIC_LOOP || b == UART1_MAGIC_LOCAL) { uart1_rx_frame[0] = b; uart1_rx_idx = 1; } return; /* 非魔数字节: 帧间空闲, 直接丢 */ } if (uart1_rx_idx >= LUP_MAX_PKG_LEN) { /* 防御: 正常流程到不了 */ uart1_rx_idx = 0; uart1_rx_need = 0; return; } uart1_rx_frame[uart1_rx_idx++] = b; if (uart1_rx_idx == 3) { /* [7F][Addr][LEN] 到手 -> 定长 */ uint8_t lf = uart1_rx_frame[2]; uint16_t need = (uint16_t)lf + 5; if (lf < 1 || need > LUP_MAX_PKG_LEN) { uart1_rx_idx = 0; /* LEN 非法 -> 重新找魔数 */ uart1_rx_need = 0; return; } uart1_rx_need = need; } /* 校验失败后 resync 可能让残余已够长, 故用 while (guard 防跑飞) */ while (uart1_rx_need != 0 && uart1_rx_idx >= uart1_rx_need && guard++ < 8) { uart1_frame_ready(); } } void uart1_dma_init(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; USART_InitTypeDef USART_InitStructure = {0}; DMA_InitTypeDef DMA_InitStructure; /* PB6 = USART1_TX / PB7 = USART1_RX (USART1 重映射) */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; /* Tx */ GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; /* Rx */ GPIO_Init(GPIOB, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 115200; /* 与 Air780 侧 uart1 一致 */ USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE); /* RX 用 DMA1_Ch5 循环缓冲 (UART2 占用 Ch6/Ch7, 通道不冲突) */ DMA_DeInit(DMA1_Channel5); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DATAR); DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)uart1_dma_buf; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = UART1_DMA_BUF_LEN; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel5, &DMA_InitStructure); USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); DMA_Cmd(DMA1_Channel5, ENABLE); USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); /* DMA 接管, 逐字节中断不再需要 */ uart1_dma_last = 0; uart1_rx_idx = 0; uart1_rx_need = 0; } /* 主循环每轮调用: 消费 DMA 环形缓冲新字节 -> 装配 -> 分流 */ void uart1_dma_poll(void) { uint16_t cur = (uint16_t)(UART1_DMA_BUF_LEN - DMA_GetCurrDataCounter(DMA1_Channel5)); uint16_t n = (uint16_t)((cur + UART1_DMA_BUF_LEN - uart1_dma_last) & (UART1_DMA_BUF_LEN - 1)); if (n == 0) return; /* 溢出保护: 未消费超过半缓冲 -> 已被 DMA 覆盖, 复位装配器重同步 */ if (n > (UART1_DMA_BUF_LEN / 2)) { g_uart1_drop++; uart1_rx_idx = 0; uart1_rx_need = 0; uart1_dma_last = cur; return; } while (n--) { uint8_t b = uart1_dma_buf[uart1_dma_last]; uart1_dma_last = (uint16_t)((uart1_dma_last + 1) & (UART1_DMA_BUF_LEN - 1)); uart1_feed_byte(b); } } #else /* !UART1_AIR780_EN: 调试版 printf 占用 USART1 -> 空实现, 保证链接一致 */ void uart1_dma_init(void) { } void uart1_dma_poll(void) { } uint32_t g_uart1_fwd_to_air = 0; uint32_t g_uart1_fwd_to_loop = 0; uint32_t g_uart1_local_cnt = 0; uint32_t g_uart1_badchk = 0; uint32_t g_uart1_drop = 0; #endif /* UART1_AIR780_EN */ void uart_init(void){ GPIO_InitTypeDef GPIO_InitStructure = {0}; USART_InitTypeDef USART_InitStructure = {0}; NVIC_InitTypeDef NVIC_InitStructure = {0}; // usart1 : peripheral / DEBUG //usart2 :loop mcu RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // Tx GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // Rx GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 192000; // Loop MCU 实际波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART2, &USART_InitStructure); /* RXNE 中断由 uart2_dma_init 关闭 (DMA 接管, 2026-08-17) */ NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_Cmd(USART2, ENABLE); uart2_dma_init(); /* DMA 循环接收接管 (2026-08-17) */ uart1_dma_init(); /* 4G 通道 UART1↔Air780 初始化 (协议 §6.1); DEBUG!=0 时为空实现 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化帧解析器 lup_frame_reset(); } /********************************************************************* * @fn USART1_IRQHandler * * @brief This function handles USART1 global interrupt request. * * @return none */ void USART1_IRQHandler(void) { } /********************************************************************* * @fn USART2_IRQHandler * * @brief USART2 RX — 使用 lup_feed_byte() 帧解析器 * 当解析出完整帧时,复制到 g_pkg_uart_2.pkg 并设置 flag * * @return none */ void USART2_IRQHandler(void) { /* 2026-08-17: RXNE 中断已关 (DMA 接管), 本 handler 不再触发。 保留空函数 + IDLE 中断注释: 若后续需要帧边界辅助, 在此加 USART_IT_IDLE 处理 (读 SR + 读 DR 清标志, 置标志由主循环消费)。 */ } void UART2_SendString(uint8_t *buf, uint16_t len) { uint16_t _len = len; while(_len){ while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET); USART_SendData(USART2, *buf++); _len--; } while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET); } void UART1_SendString(uint8_t *buf, uint16_t len) { uint16_t _len = len; while(_len){ while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); USART_SendData(USART1, *buf++); _len--; } } /* * uart_srv — 主循环中调用,处理已接收完整的 UART2 帧 * * 处理流程: * 1. 0x7F + 0xC0/0x0C → 传感器数据上报 * - 若无 BLE 连接 → 标记 `_report_flag`,在 TCP JSON 中处理 * - 若有 BLE 连接且 acs_enable → 转 0x8F 前缀发给 BLE * 2. 0x7F + 其他 CMD → 响应帧,交给 lup_process_frame() 匹配挂起命令 * 3. 非 0x7F → 调试打印(可能是字符串等) */ void uart_srv(void) { uint8_t i; uint8_t _report_flag = 0; uart2_dma_poll(); /* DMA 环形缓冲 → 帧解析 (2026-08-17) */ // 检查命令超时 lup_cmd_check_timeout(); if(g_pkg_uart_2.flag){ if(g_flag_counter_ota.flag == 0){ if(g_pkg_uart_2.pkg[0] == 0x7F){ uint8_t cmd = g_pkg_uart_2.pkg[3]; // --- 所有 0x7F 帧先经过 lup_process_frame 校验 --- // 0xC0: 校验后通过回调直接推送 TCP JSON // 其他: 校验后匹配挂起命令 lup_process_frame(g_pkg_uart_2.pkg, g_pkg_uart_2.offset); /* --- 4G 通道上行转发 (协议 §6.1) --- 校验通过的完整帧原样送 Air780; 必须置于下方 InitPkgUart 消费之前。 只转发 verify 通过的帧: Air780 靠 loop_state 变化沿判车, 残缺帧 = 多判一台车 */ if (lup_verify_checksum(g_pkg_uart_2.pkg, g_pkg_uart_2.offset) == 0) { g_uart1_fwd_to_air++; UART1_SendString(g_pkg_uart_2.pkg, g_pkg_uart_2.offset); } // --- 传感器上报 (0xC0) 分流 --- // 回调已处理 TCP 推送,此处仅处理 BLE 转发 if(cmd == LUP_CMD_SENSOR_REPORT) { if(g_dbn_ble_state_acs_enable.flag != 0){ // BLE ACS 已连接 → 改 Magic 为 0x8F 发给 BLE g_pkg_uart_2.pkg[0] = 0x8F; g_flag_notify_temp = set_response_tran_to_notify(g_pkg_uart_2.pkg, g_pkg_uart_2.offset, &g_notify_buftemp); // 保留给 BLE } /* 2026-08-13 修复: 0xC0 帧消费后必须清 flag — 原缺失, auth 未通过时 tcp_json_push_sensor 提前 return 也不清 → 坏帧/正常帧反复处理 (checksum fail 刷屏) */ InitPkgUart(&g_pkg_uart_2); } else { if(g_flag_bt_state){ g_flag_notify_temp = set_response_tran_to_notify(g_pkg_uart_2.pkg, g_pkg_uart_2.offset, &g_notify_buftemp); InitPkgUart(&g_pkg_uart_2); } else { /* 2026-08-13 修复: 非 0xC0 + 无 BLE 连接也清 flag (原缺失) */ InitPkgUart(&g_pkg_uart_2); } } // 调试打印 (2026-08-13: LUP Rx 已在 lup_process_frame 缓冲打印, // 此处重复逐字节打印冗余且高频 — 暂时关闭) #if 0 for(i = 0; i < g_pkg_uart_2.offset; i++){ PRINT(" %02X", g_pkg_uart_2.pkg[i]); } PRINT("\n"); #endif } else { // 非 0x7F 魔法字节 — hex 打印 (原 %s 会把二进制当字符串 → 乱码) PRINT("Rcv_len:%d,dat:", g_pkg_uart_2.offset); for(i = 0; i < g_pkg_uart_2.offset; i++){ PRINT(" %02X", g_pkg_uart_2.pkg[i]); } PRINT("\n"); } } else{ /* OTA 模式: Loop bootloader 回的 0x9F ACK 帧 (pre_ok/addr_ok/data ACK) 分发: - 本地远程 OTA (g_ota_flash_active, V1.08) → 交给 ota_srv 刷写状态机 - BLE 透传 (现状, V1.02.03) → 透传回 BLE 工具 否则停等协议 (0xA7 WITH_BACK) 永远等不到 ACK */ if(g_ota_flash_active){ ota_flash_feed_ack(g_pkg_uart_2.pkg, g_pkg_uart_2.offset); } else if(g_flag_bt_state){ g_flag_notify_temp = set_response_tran_to_notify(g_pkg_uart_2.pkg, g_pkg_uart_2.offset, &g_notify_buftemp); } /* OTA 模式同样清 flag — 残留帧会在 OTA 结束后被误处理 */ InitPkgUart(&g_pkg_uart_2); } if(g_flag_bt_state){ } else{ g_dbn_ble_state_acs_enable.flag = 0; } } }