V1.00.26: UART baud 115200 -> 460800

- firmware BSP_USART_BAUDRATE 460800 (divider error +0.03%); uartrst/
  uartinfo follow the macro
- RX DMA ring 2KB -> 3KB: at 460800 2KB only covers 44ms, less than the
  ~45ms flash-erase interrupt-off window; stack top now 0x2000BDE8
  (guard warns <1KB from the 0x2000C000 cliff, by design)
- tools: ble_ota_update.py UartTransport and uart_cap.py default baud
- Verified: stream OTA 55832B in 2.6s @23kB/s (one lost frame recovered
  by go-back-N), PASS after reboot; text CLI fine at 460800
- docs: ble_protocol.md, design spec, AGENTS.md, dev log section 48
This commit is contained in:
evan.liu 2026-09-05 10:01:23 +08:00
parent f729d16ff2
commit 8a7cebcf77
22 changed files with 3999 additions and 3981 deletions

View File

@ -5,7 +5,7 @@
本仓库是 **mothercup(母乳杯)** 产品的完整代码仓库,包含三大部分: 本仓库是 **mothercup(母乳杯)** 产品的完整代码仓库,包含三大部分:
1. **设备固件** — 基于国民技术(Nations)**N32WB031 BLE SoC**(Cortex-M0,64MHz HSI,**板载硅片实测 256KB Flash**(0x01000000~0x0103FFFF,开发日志 §37),RAM 48KB+16KB): 1. **设备固件** — 基于国民技术(Nations)**N32WB031 BLE SoC**(Cortex-M0,64MHz HSI,**板载硅片实测 256KB Flash**(0x01000000~0x0103FFFF,开发日志 §37),RAM 48KB+16KB):
- **`mcm-ddc-ble/`** — 唯一活跃的应用固件工程(APP,链接在 APP1 bank `0x01008000`/112KB)。以 SDK rdtss 例程为蓝本,集成 FreeRTOS、UART CLI、BLE 自定义 GATT 服务(CLI 透传 / 设备信息查询 / BLE OTA 双 bank 直写升级)、bootsetting 与 APP_DATA 参数区结构化读写命令。当前版本 **V1.00.25**(`mcm-ddc-ble/inc/app_version.h`)。历史上曾有 `mcm-ddc-04/` 主工程,**已删除**,其功能已全部并入本工程。 - **`mcm-ddc-ble/`** — 唯一活跃的应用固件工程(APP,链接在 APP1 bank `0x01008000`/112KB)。以 SDK rdtss 例程为蓝本,集成 FreeRTOS、UART CLI、BLE 自定义 GATT 服务(CLI 透传 / 设备信息查询 / BLE OTA 双 bank 直写升级)、bootsetting 与 APP_DATA 参数区结构化读写命令。当前版本 **V1.00.26**(`mcm-ddc-ble/inc/app_version.h`)。历史上曾有 `mcm-ddc-04/` 主工程,**已删除**,其功能已全部并入本工程。
- **`Boot/`** — 自写精简 bootloader(链接在 `0x01000000`/16KB):校验 bootsetting 记录自身完整性(magic + 结构体 CRC32)后按 active bank 的 `start_address` 直接跳转;**不校验镜像 CRC(CRC 校验在 OTA 升级过程中完成)**;记录无效或地址越界回退 APP1。 - **`Boot/`** — 自写精简 bootloader(链接在 `0x01000000`/16KB):校验 bootsetting 记录自身完整性(magic + 结构体 CRC32)后按 active bank 的 `start_address` 直接跳转;**不校验镜像 CRC(CRC 校验在 OTA 升级过程中完成)**;记录无效或地址越界回退 APP1。
2. **手机 App `SmartAssiter/`** — uni-app **Vue3 + TypeScript** 工程(HBuilderX 项目管理,无 package.json),通过 BLE 连接设备:查看运行参数(温度/电压/转速/bank/堆等)、CLI 终端、参数读写(appget/appset)、OTA 升级页(e0005 锁步,已恢复)。另有登录/注册/用户信息等云端业务页面。 2. **手机 App `SmartAssiter/`** — uni-app **Vue3 + TypeScript** 工程(HBuilderX 项目管理,无 package.json),通过 BLE 连接设备:查看运行参数(温度/电压/转速/bank/堆等)、CLI 终端、参数读写(appget/appset)、OTA 升级页(e0005 锁步,已恢复)。另有登录/注册/用户信息等云端业务页面。
3. **PC 工具 `tools/`** — 整片烧录包制作/烧录脚本 + bleak 蓝牙测试客户端。 3. **PC 工具 `tools/`** — 整片烧录包制作/烧录脚本 + bleak 蓝牙测试客户端。
@ -55,7 +55,7 @@ mcm-ddc-ble/
├── src/ ├── src/
│ ├── main.c # 入口:VTOR 预置 → USART+banner → LED → app_ble_init → app_params_init │ ├── main.c # 入口:VTOR 预置 → USART+banner → LED → app_ble_init → app_params_init
│ │ # → ns_sleep_lock_acquire(锁睡眠保 SWD) → 建 BLE 调度/LED/CLI 任务 → vTaskStartScheduler │ │ # → ns_sleep_lock_acquire(锁睡眠保 SWD) → 建 BLE 调度/LED/CLI 任务 → vTaskStartScheduler
│ ├── bsp_usart.c # USART1(PB6/PB7, 115200 8N1):fputc 重定向 + DMA TX(CH1) + RX DMA 循环环形缓冲(CH2, 2KB, IDLE 中断唤醒;擦扇区关中断期间不丢字节) + TX 互斥锁 │ ├── bsp_usart.c # USART1(PB6/PB7, 460800 8N1, V1.00.26 起):fputc 重定向 + DMA TX(CH1) + RX DMA 循环环形缓冲(CH2, 3KB, IDLE 中断唤醒;擦扇区关中断期间不丢字节) + TX 互斥锁
│ ├── app_gpio.c # LED1(PB0)/LED2(PA6) │ ├── app_gpio.c # LED1(PB0)/LED2(PA6)
│ ├── app_cli.c # CLI UART 前端:CliTask 行接收/编辑/历史/Tab/Ctrl+Z,提示符 caiic-> │ ├── app_cli.c # CLI UART 前端:CliTask 行接收/编辑/历史/Tab/Ctrl+Z,提示符 caiic->
│ ├── cli_core.c # CLI 核心(命令表 s_cmds[]/handler/分词执行),输出经可切换 cli_out_fn │ ├── cli_core.c # CLI 核心(命令表 s_cmds[]/handler/分词执行),输出经可切换 cli_out_fn
@ -95,7 +95,7 @@ mcm-ddc-ble/
"D:\Keil_v5\UV4\UV4.exe" -b caiic_boot.uvprojx -j0 -o build.log # Boot 增量构建 "D:\Keil_v5\UV4\UV4.exe" -b caiic_boot.uvprojx -j0 -o build.log # Boot 增量构建
``` ```
要求保持 **0 Error(s), 0 Warning(s)**。当前基线(V1.00.25):`Code=48992 RO-data=4980 RW-data=2088 ZI-data=29120`。 要求保持 **0 Error(s), 0 Warning(s)**。当前基线(V1.00.26):`Code=48996 RO-data=4980 RW-data=2088 ZI-data=30144`。
**固件版本号约定(重要)**:每次修改固件代码必须递增 `mcm-ddc-ble/inc/app_version.h` 中的 `APP_FW_VERSION` 与 `APP_FW_VERSION_NUM`(格式 `0x00MMmmpp`,通常补丁位 +1),用于识别板上实际运行的固件;工程名与出包文件名保持不变。 **固件版本号约定(重要)**:每次修改固件代码必须递增 `mcm-ddc-ble/inc/app_version.h` 中的 `APP_FW_VERSION` 与 `APP_FW_VERSION_NUM`(格式 `0x00MMmmpp`,通常补丁位 +1),用于识别板上实际运行的固件;工程名与出包文件名保持不变。
@ -113,7 +113,7 @@ mcm-ddc-ble/
3. 日常开发调试:Keil F7 编译、F8 下载即可(Boot 不校验镜像 CRC,可直接下载 APP 调试);**Keil 下载选项必须是 "Erase Sectors",整片擦除会杀掉 Boot/bootsetting**(杀掉后需重烧整片包恢复)。板子上烧过其他 0x01000000 起步的程序同样会覆盖 Boot,恢复也是重烧整片包。 3. 日常开发调试:Keil F7 编译、F8 下载即可(Boot 不校验镜像 CRC,可直接下载 APP 调试);**Keil 下载选项必须是 "Erase Sectors",整片擦除会杀掉 Boot/bootsetting**(杀掉后需重烧整片包恢复)。板子上烧过其他 0x01000000 起步的程序同样会覆盖 Boot,恢复也是重烧整片包。
4. 日常固件升级设计路径是 BLE OTA(手机 App 或 PC bleak 客户端)。 4. 日常固件升级设计路径是 BLE OTA(手机 App 或 PC bleak 客户端)。
验证运行:串口助手接 PB6(TX)/PB7(RX),115200 8N1,复位后应看到 banner 与 `caiic->` 提示符(`help` 查看命令);手机应能搜到广播名 `CAIIC-MCM-20260902`。 验证运行:串口助手接 PB6(TX)/PB7(RX),460800 8N1(V1.00.26 起),复位后应看到 banner 与 `caiic->` 提示符(`help` 查看命令);手机应能搜到广播名 `CAIIC-MCM-20260902`。
## BLE 接口与协议 ## BLE 接口与协议

View File

@ -2,8 +2,8 @@
Rebuild target 'caiic_boot' Rebuild target 'caiic_boot'
assembling startup_n32wb03x.s... assembling startup_n32wb03x.s...
compiling boot_crc32.c... compiling boot_crc32.c...
compiling system_n32wb03x.c...
compiling main.c... compiling main.c...
compiling system_n32wb03x.c...
linking... linking...
Program Size: Code=1320 RO-data=680 RW-data=0 ZI-data=2104 Program Size: Code=1320 RO-data=680 RW-data=0 ZI-data=2104
FromELF: creating hex file... FromELF: creating hex file...

View File

@ -149,7 +149,7 @@ OTA 会话(§6 的 BEGIN/DATA/END/ABORT → OTA_RSP)跑在 0xCA 帧上,帧
| 通道 | 下行(主机→设备) | 上行(设备→主机) | | 通道 | 下行(主机→设备) | 上行(设备→主机) |
|---|---|---| |---|---|---|
| **BLE OTA 特征** `...e0005` | 每次"写带响应"携带一帧(≤ att_mtu−3) | 写完**读同一特征**取回 OTA_RSP 帧;读应答可能先于设备处理完成返回空,**读需轮询至非空**(擦扇区时数十 ms) | | **BLE OTA 特征** `...e0005` | 每次"写带响应"携带一帧(≤ att_mtu−3) | 写完**读同一特征**取回 OTA_RSP 帧;读应答可能先于设备处理完成返回空,**读需轮询至非空**(擦扇区时数十 ms) |
| **UART 串口**(115200 8N1) | CLI 先发文本命令 `ota`,**等到设备回标记行 `[ota] binary mode ON` 再发帧**(握手,防帧被当文本命令吃掉),随后原始帧字节流 | OTA_RSP 帧直接从 TX 发出;**OTA_ABORT 立即退出**回 CLI,10s 无帧兜底退出 | | **UART 串口**(460800 8N1,V1.00.26 起;之前为 115200) | CLI 先发文本命令 `ota`,**等到设备回标记行 `[ota] binary mode ON` 再发帧**(握手,防帧被当文本命令吃掉),随后原始帧字节流 | OTA_RSP 帧直接从 TX 发出;**OTA_ABORT 立即退出**回 CLI,10s 无帧兜底退出 |
UART 模式切换与容错(V1.00.21 起): UART 模式切换与容错(V1.00.21 起):
@ -184,8 +184,9 @@ PC 参考实现:`tools\ble_ota_update.py`(`ble_ota.bat`;BLE 默认,
## 6.7 UART 流式传输模式(V1.00.24 起) ## 6.7 UART 流式传输模式(V1.00.24 起)
动机:逐帧锁步在 115200 下实测只有 ~1.5 kB/s(每帧一个 RTT + 主机调度 动机:逐帧锁步在 115200 下实测只有 ~1.5 kB/s(每帧一个 RTT + 主机调度
抖动)。流式模式让 DATA 帧在窗口内连续下发,**实测 9.5 kB/s(55.8KB 抖动)。流式模式让 DATA 帧在窗口内连续下发:**115200 下实测 9.5 kB/s
约 5.9s,0 重传)**,只受波特率与扇区擦除时间限制。 (55.8KB 约 5.9s,0 重传);460800(V1.00.26 起默认)下实测 23 kB/s
(约 2.6s)**,只受波特率与扇区擦除时间限制。
**前提(固件侧)**:UART RX 改为 **DMA 环形缓冲**(2KB,循环模式)—— **前提(固件侧)**:UART RX 改为 **DMA 环形缓冲**(2KB,循环模式)——
DMA 在关中断的扇区擦除窗口内继续接收字节,这是流式不丢包的关键; DMA 在关中断的扇区擦除窗口内继续接收字节,这是流式不丢包的关键;
@ -231,7 +232,7 @@ bootsetting 与 APP_DATA 保留区(0x01006000/8KB)的读写以 CLI 命令形
| `appsw [1\|2]` | 切换运行 bank 并复位(V1.00.15 起):无参切对侧 bank;切前校验 bootsetting 记录、目标 bank 记录一致性,并复算目标镜像 CRC32 与记录比对,不匹配拒绝(坏 bank 需先跑 OTA 写入有效镜像) | | `appsw [1\|2]` | 切换运行 bank 并复位(V1.00.15 起):无参切对侧 bank;切前校验 bootsetting 记录、目标 bank 记录一致性,并复算目标镜像 CRC32 与记录比对,不匹配拒绝(坏 bank 需先跑 OTA 写入有效镜像) |
| `reset` | 复位单板:应答后延时 200ms 执行 `NVIC_SystemReset()`,Boot 按 active bank 跳转 | | `reset` | 复位单板:应答后延时 200ms 执行 `NVIC_SystemReset()`,Boot 按 active bank 跳转 |
| `factory` | 恢复出厂设置:APP_DATA 参数区恢复缺省值并落盘后复位(**不动 bootsetting**) | | `factory` | 恢复出厂设置:APP_DATA 参数区恢复缺省值并落盘后复位(**不动 bootsetting**) |
| `uartrst` | 复位串口:USART1 按 115200 8N1 重新初始化并清空 RX 队列 | | `uartrst` | 复位串口:USART1 按 460800 8N1 重新初始化并清空 RX 队列 |
| `uartinfo` | 查询串口参数:引脚(PB6/PB7 AF4)、波特率/数据位/校验/停止位、TX DMA/RX 中断形态 | | `uartinfo` | 查询串口参数:引脚(PB6/PB7 AF4)、波特率/数据位/校验/停止位、TX DMA/RX 中断形态 |
参数记录(APP_DATA 区头,52B):magic `0xCA12DA7A` + layout_ver + 参数字段 + 参数记录(APP_DATA 区头,52B):magic `0xCA12DA7A` + layout_ver + 参数字段 +

View File

@ -1231,3 +1231,17 @@ APP2 链接的镜像发向 APP1 区。设备端 END 校验(向量表 Reset PC
- 附:flash_package 改 python 包装(tools/flash_package.py)流式转发 - 附:flash_package 改 python 包装(tools/flash_package.py)流式转发
NSpyocd 输出并替换横幅为 "CAIIC NSLINK UMP";块状读取修进度条 \r NSpyocd 输出并替换横幅为 "CAIIC NSLINK UMP";块状读取修进度条 \r
不刷新问题;模式替换需在拼接缓冲上做(跨块边界会劈开模式串)。 不刷新问题;模式替换需在拼接缓冲上做(跨块边界会劈开模式串)。
## 48. UART 波特率提升 115200→460800(2026-09-05,V1.00.26)
- 固件 `BSP_USART_BAUDRATE` 460800(64MHz/460800 分频误差 +0.03%);
`uartrst`/`uartinfo` 走宏自动跟随,帮助文本同步。
- **环形缓冲 2KB→3KB**:460800 下 2KB 只能覆盖 44ms,小于擦扇区关中断
窗口(~45ms);3KB ≈ 69ms。注意 SRAM 悬崖(§47):栈顶上移 1KB 至
0x2000BDE8,merge_image.py 硬卡给出 <1KB 告警(属预期内)。
- PC 工具默认波特率同步(ble_ota_update.py UartTransport、uart_cap.py)。
- 实测:流式 OTA 55832B **2.6s(23 kB/s)**,途中丢 1 帧由 go-back-N
自动回退续传( rewind 45360→38160),复位复核 PASS;CLI 文本模式
在 460800 下正常(devinfo/ota 握手/复位后复核全走文本 CLI)。
- 对比:115200 锁步 39s → 115200 流式 5.9s → 460800 流式 2.6s。
- 注意:串口终端/工具必须同步改 460800,否则 CLI 全是乱码。

View File

@ -38,7 +38,7 @@ V1.0 / 2026-09-05
- **RAM 铁律**:低 16KB(0x20000000~0x20003FFF)被芯片 ROM/BLE 子系统占用, - **RAM 铁律**:低 16KB(0x20000000~0x20003FFF)被芯片 ROM/BLE 子系统占用,
任何工程 IRAM 执行区必须从 **0x20004000** 起(否则 BLE init 必 HardFault) 任何工程 IRAM 执行区必须从 **0x20004000** 起(否则 BLE init 必 HardFault)
- **SWD 引脚 SWCLK=PA4 / SWDIO=PA5,应用程序绝对禁止占用** - **SWD 引脚 SWCLK=PA4 / SWDIO=PA5,应用程序绝对禁止占用**
- 板载 LED:LED1=PB0、LED2=PA6;USART1:TX=PB6 / RX=PB7(AF4,115200 8N1) - 板载 LED:LED1=PB0、LED2=PA6;USART1:TX=PB6 / RX=PB7(AF4,460800 8N1,V1.00.26 起)
- 新增 GPIO 前核对开发日志 §4 引脚分配表 - 新增 GPIO 前核对开发日志 §4 引脚分配表
- **不要直接写寄存器**;勘误修复必须先在 SDK 源码交叉验证地址用途 - **不要直接写寄存器**;勘误修复必须先在 SDK 源码交叉验证地址用途
(曾按勘误表写 AFEC 寄存器导致 BLE 射频挂死,开发日志 §28) (曾按勘误表写 AFEC 寄存器导致 BLE 射频挂死,开发日志 §28)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -9,12 +9,12 @@
#define __APP_VERSION_H__ #define __APP_VERSION_H__
#ifndef APP_FW_VERSION #ifndef APP_FW_VERSION
#define APP_FW_VERSION "V1.00.25" #define APP_FW_VERSION "V1.00.26"
#endif #endif
/* Numeric form used by the BLE info query / OTA records: 0x00MMmmpp */ /* Numeric form used by the BLE info query / OTA records: 0x00MMmmpp */
#ifndef APP_FW_VERSION_NUM #ifndef APP_FW_VERSION_NUM
#define APP_FW_VERSION_NUM 0x00010019u #define APP_FW_VERSION_NUM 0x0001001Au
#endif #endif
#endif /* __APP_VERSION_H__ */ #endif /* __APP_VERSION_H__ */

View File

@ -1,7 +1,7 @@
/** /**
* @file bsp_usart.h * @file bsp_usart.h
* @brief USART1 support: printf retarget (polling TX), DMA TX, RX DMA * @brief USART1 support: printf retarget (polling TX), DMA TX, RX DMA
* circular ring + IDLE interrupt. TX=PB6, RX=PB7, 115200 8N1. * circular ring + IDLE interrupt. TX=PB6, RX=PB7, 460800 8N1.
*/ */
#ifndef __BSP_USART_H__ #ifndef __BSP_USART_H__
#define __BSP_USART_H__ #define __BSP_USART_H__
@ -20,7 +20,7 @@ extern "C" {
#define BSP_USART_RX_PIN GPIO_PIN_7 #define BSP_USART_RX_PIN GPIO_PIN_7
#define BSP_USART_TX_GPIO_AF GPIO_AF4_USART1 #define BSP_USART_TX_GPIO_AF GPIO_AF4_USART1
#define BSP_USART_RX_GPIO_AF GPIO_AF4_USART1 #define BSP_USART_RX_GPIO_AF GPIO_AF4_USART1
#define BSP_USART_BAUDRATE 115200 #define BSP_USART_BAUDRATE 460800
/* USART1 TX DMA channel (remap required on this chip) */ /* USART1 TX DMA channel (remap required on this chip) */
#define BSP_USART_TX_DMA_CH DMA_CH1 #define BSP_USART_TX_DMA_CH DMA_CH1

View File

@ -12,9 +12,12 @@
#include "semphr.h" #include "semphr.h"
#define RX_INJECT_QUEUE_LEN 64 /* BLE downlink -> CLI injection */ #define RX_INJECT_QUEUE_LEN 64 /* BLE downlink -> CLI injection */
#define RX_RING_SIZE 2048u /* DMA circular ring: ~173ms @115200, #define RX_RING_SIZE 3072u /* DMA circular ring: ~69ms @460800,
* covers flash-erase interrupt-off * covers flash-erase interrupt-off
* windows during OTA streaming */ * windows (~45ms) during OTA streaming.
* NOTE: keep the stack top below the
* 0x2000C000 SRAM cliff (dev log §47) -
* merge_image.py hard-fails otherwise */
#define RX_WAIT_SLICE_MS 20u /* semaphore wait granularity (also the #define RX_WAIT_SLICE_MS 20u /* semaphore wait granularity (also the
* poll period when the IDLE interrupt * poll period when the IDLE interrupt
* does not fire during a back-to-back * does not fire during a back-to-back
@ -65,7 +68,7 @@ static uint16_t bsp_usart_rx_head(void)
} }
/** /**
* @brief Initialize USART1 (115200 8N1) on PB6(TX)/PB7(RX), * @brief Initialize USART1 (460800 8N1) on PB6(TX)/PB7(RX),
* DMA TX channel and the RX DMA ring. * DMA TX channel and the RX DMA ring.
*/ */
void bsp_usart_init(void) void bsp_usart_init(void)

View File

@ -340,7 +340,7 @@ static const CliCmd_t s_cmds[] = {
{"ota", "ota: UART enters OTA binary frame mode (see help ota)", CmdOta}, {"ota", "ota: UART enters OTA binary frame mode (see help ota)", CmdOta},
{"reset", "reset: system reset (reboot)", CmdReset}, {"reset", "reset: system reset (reboot)", CmdReset},
{"factory", "factory: restore params to defaults and reboot", CmdFactory}, {"factory", "factory: restore params to defaults and reboot", CmdFactory},
{"uartrst", "uartrst: re-init USART1 (115200 8N1), flush rx queue", CmdUartRst}, {"uartrst", "uartrst: re-init USART1 (460800 8N1), flush rx queue", CmdUartRst},
{"uartinfo", "uartinfo: show USART1 pins/baud/format", CmdUartInfo}, {"uartinfo", "uartinfo: show USART1 pins/baud/format", CmdUartInfo},
}; };

View File

@ -168,7 +168,7 @@ class UartTransport:
MARKER_ON = b"[ota] binary mode ON" MARKER_ON = b"[ota] binary mode ON"
PROMPT = b"caiic->" PROMPT = b"caiic->"
def __init__(self, port, baud=115200): def __init__(self, port, baud=460800):
import serial import serial
self.ser = serial.Serial(port, baud, timeout=0.1) self.ser = serial.Serial(port, baud, timeout=0.1)
self.dec = FrameDecoder() self.dec = FrameDecoder()

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -1,7 +1,7 @@
{ {
"file": "mothercup_ble_prod_ota.bin", "file": "mothercup_ble_prod_ota.bin",
"target_bank": 1, "target_bank": 1,
"size": 55528, "size": 55532,
"crc32": "0x83A6B3FA", "crc32": "0x6AC3C102",
"version": 65561 "version": 65562
} }

View File

@ -1,7 +1,7 @@
{ {
"file": "mothercup_ble_prod_ota_app2.bin", "file": "mothercup_ble_prod_ota_app2.bin",
"target_bank": 2, "target_bank": 2,
"size": 55828, "size": 55832,
"crc32": "0x2DD68645", "crc32": "0xCA9651B0",
"version": 65561 "version": 65562
} }

View File

@ -9,7 +9,7 @@ port = sys.argv[1] if len(sys.argv) > 1 else r"\\.\COM4"
out = sys.argv[2] out = sys.argv[2]
dur = float(sys.argv[3]) if len(sys.argv) > 3 else 120 dur = float(sys.argv[3]) if len(sys.argv) > 3 else 120
ser = serial.Serial(port, 115200, timeout=0.2) ser = serial.Serial(port, 460800, timeout=0.2)
t0 = time.time() t0 = time.time()
with open(out, "wb") as f: with open(out, "wb") as f:
while time.time() - t0 < dur: while time.time() - t0 < dur: