tools: self-contained portable production package
- tools/python-embed/: embedded Python 3.12.10 runtime with bleak/pyserial preinstalled (git-ignored, fetched from the huaweicloud mirror); bats resolve Python in order: python-embed -> .venv-ble -> system - NSpyocd.exe + DFP pack copied into tools/ (git-ignored); flash_package.py prefers the in-tools copies - make_release.bat/ps1: one-click zip to out/mothercup_tools_<ts>.zip (staged in TEMP to avoid self-inclusion; zip excluded from git) - all bats converted to CRLF (LF-only breaks cmd block parsing and %~dp0) - verified: zip extracted outside the repo runs ble_ota --uart end-to-end (PASS, 27 kB/s) and flash_package via the bundled NSpyocd - docs: dev log section 49, AGENTS.md tools section + heap 18KB fix
This commit is contained in:
parent
dd218addce
commit
57762e50be
6
.gitignore
vendored
6
.gitignore
vendored
@ -5,3 +5,9 @@ mcm-ddc-ble/MDK-ARM/Objects
|
||||
mcm-ddc-ble/MDK-ARM/build.log
|
||||
mcm-ddc-ble/MDK-ARM/build-app2.log
|
||||
mcm-ddc-ble/MDK-ARM/Objects-app2
|
||||
|
||||
# portable production runtime (bundled, not committed)
|
||||
tools/python-embed/
|
||||
tools/NSpyocd/
|
||||
tools/N32WB03x_DFP.1.4.0.pack
|
||||
tools/out/mothercup_tools_*.zip
|
||||
|
||||
10
AGENTS.md
10
AGENTS.md
@ -148,17 +148,19 @@ mcm-ddc-ble/
|
||||
|
||||
## PC 工具(tools/)
|
||||
|
||||
- `merge_image.py` — 纯 Python 无三方依赖;合并 boot+bootsetting(缺省记录,脚本生成)+APP 为整片 hex/bin,同时产出 `_ota.bin`/`_ota.json`(bank1 载荷);`--ota-app2` 追加 bank2 载荷 `_ota_app2.bin/.json`;`--app2 <bin> --with-appdata` 生成双 bank 整包(make_dual_package.bat 使用);自动从 `app_version.h` 取 `APP_FW_VERSION_NUM` 写入清单(含 `target_bank` 字段)
|
||||
- `make_package.bat` / `flash_package.bat` — 一键出包 / NSpyocd 整片烧录(脚本会自动找 Python312 全路径,本机 `python` 可能是商店占位 stub)
|
||||
**自包含生产包(§49)**:tools/ 内嵌 Python 运行时(`python-embed/`,bleak+pyserial 预装)+ NSpyocd 烧录器副本 + DFP pack,`make_release.bat` 一键打 zip 到 `out/mothercup_tools_<时间戳>.zip`——解压到任何 Windows 电脑即可用,无需安装 Python/任何环境。三件套不入库(gitignore):`python-embed/`、`NSpyocd/`、`N32WB03x_DFP.1.4.0.pack`;**bat 文件必须保持 CRLF 行尾**(LF 会导致 cmd 解析错乱)。Python 解析优先级:`python-embed` → `.venv-ble`(开发机自动建)→ 系统 Python。
|
||||
|
||||
- `merge_image.py` — 纯 Python 无三方依赖;合并 boot+bootsetting(缺省记录,脚本生成)+APP 为整片 hex/bin,同时产出 `_ota.bin`/`_ota.json`(bank1 载荷);`--ota-app2` 追加 bank2 载荷 `_ota_app2.bin/.json`;`--app2 <bin> --with-appdata` 生成双 bank 整包(make_dual_package.bat 使用);自动从 `app_version.h` 取 `APP_FW_VERSION_NUM` 写入清单(含 `target_bank` 字段);**出包硬卡:镜像初始 SP 必须在 (0x20004000, 0x2000C000](SRAM 悬崖,§47)**
|
||||
- `make_package.bat` / `flash_package.bat` — 一键出包 / NSpyocd 整片烧录(flash_package.py 流式转发输出并把厂商横幅替换为 "CAIIC NSLINK UMP")
|
||||
- `make_dual_package.bat` — 双 APP 整包(Boot+bootsetting 双 bank+APP_DATA+APP1+APP2,APP2 升一版链接 0x01024000),用于 appsw 切换测试
|
||||
- `ble_cli_test.py` + `ble_cli.bat` — PC 端 bleak 蓝牙 CLI 测试客户端(帧协议模式 + `-rw` 读写特征模式,交互模式 `-i`,venv 在 `tools/.venv-ble`,不入库;首次运行 bat 按 `tools/requirements-ble.txt`(bleak+pyserial)自动创建)
|
||||
- `ble_ota_update.py` + `ble_ota.bat` — BLE OTA 升级器(解析单文件升级包 `mothercup_ble_ota.bin`、按 CUR_BANK 选对侧 bank 载荷、经 OTA 特征 `...e0005` 逐帧锁步、复位检测+重连校验;`--uart COMx` 走串口二进制模式:握手标记进入/ABORT 退出;V1.00.24 起默认流式(8KB 窗口+扇区 ack+go-back-N),`--lockstep` 或旧固件自动回退锁步)。**BLE 与 UART 双通道均已实测通过(§42/§44),流式见 §47**
|
||||
- `ble_ota_update.py` + `ble_ota.bat` — BLE OTA 升级器(解析单文件升级包 `mothercup_ble_ota.bin`、按 CUR_BANK 选对侧 bank 载荷、经 OTA 特征 `...e0005` 逐帧锁步、复位检测+重连校验;`--uart COMx` 走串口二进制模式(460800 8N1,V1.00.26 起):握手标记进入/ABORT 退出;V1.00.24 起默认流式(8KB 窗口+扇区 ack+go-back-N),`--lockstep` 或旧固件自动回退锁步)。**BLE 与 UART 双通道均已实测通过(§42/§44),流式见 §47/§48**
|
||||
- `ble_temp_watch.py` — 温度监测小工具
|
||||
|
||||
## 实时架构约定(固件)
|
||||
|
||||
- 使用 FreeRTOS V9.0.0 原生 API,**不使用 cmsis_os 封装**。
|
||||
- 任务:BLE 调度任务(栈 512 字,优先级 2,循环 `rwip_schedule(); vTaskDelay(1ms);`——**ke_msg/ke_timer 只允许在该任务上下文运行**);LED 任务(LED1 闪烁半周期读 APP_DATA 参数 `led1_blink_ms`);CliTask(优先级 3);CLI 输出经环形缓冲由 BLE 任务上下文发 notify(`ble_up.c`)。`configTOTAL_HEAP_SIZE = 20KB`(heap_4)。
|
||||
- 任务:BLE 调度任务(栈 512 字,优先级 2,循环 `rwip_schedule(); vTaskDelay(1ms);`——**ke_msg/ke_timer 只允许在该任务上下文运行**);LED 任务(LED1 闪烁半周期读 APP_DATA 参数 `led1_blink_ms`);CliTask(优先级 3);CLI 输出经环形缓冲由 BLE 任务上下文发 notify(`ble_up.c`)。`configTOTAL_HEAP_SIZE = 18KB`(heap_4;SRAM 悬崖约束见 Flash/RAM 布局铁律)。
|
||||
- SysTick 由 FreeRTOS port 接管:`main` 中不要手动 `SysTick_Config`,`n32wb03x_it.c` 中不要重复定义 SVC/PendSV/SysTick_Handler。
|
||||
- USART1_IRQn 优先级为 3(最低),因 ISR 内调用 FreeRTOS FromISR API,必须 ≥ `configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY`(=3)。BLE_SW/FIFO IRQ 优先级 0,其 ISR 内禁止调用 FromISR API。
|
||||
- 串口输出并发:多任务/CLI 输出分别持有 `bsp_usart_tx_lock()` 互斥锁;调度器启动前为空操作。不要在中断或多个任务里直接 printf。
|
||||
|
||||
19
docs/开发日志.md
19
docs/开发日志.md
@ -1245,3 +1245,22 @@ APP2 链接的镜像发向 APP1 区。设备端 END 校验(向量表 Reset PC
|
||||
在 460800 下正常(devinfo/ota 握手/复位后复核全走文本 CLI)。
|
||||
- 对比:115200 锁步 39s → 115200 流式 5.9s → 460800 流式 2.6s。
|
||||
- 注意:串口终端/工具必须同步改 460800,否则 CLI 全是乱码。
|
||||
|
||||
## 49. tools 自包含生产包(2026-09-05,无固件改动)
|
||||
|
||||
- 目标:tools/ 打包即可发布到任何 Windows 产线电脑,无需安装任何环境。
|
||||
- **内嵌 Python 运行时**:`tools/python-embed/`(python-3.12.10-embed-amd64,
|
||||
华为云镜像下载;python312._pth 启用 Lib/site-packages + import site,
|
||||
bleak 3.0.2/pyserial 3.5 用 pip --target 预装,29MB)。bat 优先级:
|
||||
python-embed → .venv-ble(开发机自动建)→ 系统 Python。
|
||||
- **烧录器收编**:NSpyocd.exe + DFP pack 复制进 tools/(flash_package.py
|
||||
优先用 tools 内副本,找不到才回退仓库 nations-tec 路径)。
|
||||
- **一键打包**:`make_release.bat`(PowerShell Compress-Archive,排除
|
||||
.venv-ble/__pycache__,zip 暂存 %TEMP% 再移入 out/——直接写 out/ 会
|
||||
自读自写报错)。
|
||||
- **坑**:bat 必须 CRLF 行尾——LF-only 时 cmd 对括号块/%~dp0 的解析会
|
||||
错乱(standalone 复测时 venv 分支被误触发且 PYREAL 为空),本次全部
|
||||
转 CRLF。zip 用 Windows 资源管理器/Expand-Archive 解压(Info-ZIP
|
||||
unzip 对 Compress-Archive 的反斜杠分隔符不兼容)。
|
||||
- 验证:zip 解到仓库外独立目录,ble_ota.bat --uart COM4 全流程 PASS
|
||||
(2.2s,27 kB/s,0 重传);flash_package.bat 用包内 NSpyocd 烧录 PASS。
|
||||
|
||||
@ -13,8 +13,10 @@ rem Requires tools\.venv-ble (created automatically on first run).
|
||||
rem ============================================================
|
||||
setlocal
|
||||
set TOOLS=%~dp0
|
||||
set PYEXE=%TOOLS%.venv-ble\Scripts\python.exe
|
||||
|
||||
rem 优先使用随包内嵌的 Python 运行时(tools\python-embed,免安装);
|
||||
rem 没有则回退到自动创建的 .venv-ble(开发机)
|
||||
set PYEXE=%TOOLS%python-embed\python.exe
|
||||
if not exist "%PYEXE%" set PYEXE=%TOOLS%.venv-ble\Scripts\python.exe
|
||||
if not exist "%PYEXE%" (
|
||||
echo [setup] creating venv %TOOLS%.venv-ble ...
|
||||
set PYREAL=
|
||||
|
||||
@ -13,8 +13,10 @@ rem Requires tools\.venv-ble (created automatically on first run).
|
||||
rem ============================================================
|
||||
setlocal
|
||||
set TOOLS=%~dp0
|
||||
set PYEXE=%TOOLS%.venv-ble\Scripts\python.exe
|
||||
|
||||
rem 优先使用随包内嵌的 Python 运行时(tools\python-embed,免安装);
|
||||
rem 没有则回退到自动创建的 .venv-ble(开发机)
|
||||
set PYEXE=%TOOLS%python-embed\python.exe
|
||||
if not exist "%PYEXE%" set PYEXE=%TOOLS%.venv-ble\Scripts\python.exe
|
||||
if not exist "%PYEXE%" (
|
||||
echo [setup] creating venv %TOOLS%.venv-ble ...
|
||||
set PYREAL=
|
||||
|
||||
@ -9,8 +9,12 @@ rem and CLOSE Keil (it holds the probe).
|
||||
rem ============================================================
|
||||
setlocal
|
||||
|
||||
set PYEXE=
|
||||
python --version >nul 2>&1 && set PYEXE=python
|
||||
rem 优先使用随包内嵌的 Python 运行时(tools\python-embed,免安装)
|
||||
set PYEXE=%~dp0python-embed\python.exe
|
||||
if not exist "%PYEXE%" (
|
||||
set PYEXE=
|
||||
python --version >nul 2>&1 && set PYEXE=python
|
||||
)
|
||||
if not defined PYEXE (
|
||||
if exist "%LOCALAPPDATA%\Programs\Python\Python312\python.exe" (
|
||||
set PYEXE="%LOCALAPPDATA%\Programs\Python\Python312\python.exe"
|
||||
|
||||
@ -26,12 +26,20 @@ BANNER_PATTERNS = [
|
||||
]
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
PYOCD = os.path.join(ROOT, "nations-tec", "N32WB03x_SDK_V2.0.0",
|
||||
"utilities", "dfu", "NSpyocd", "NSpyocd.exe")
|
||||
TOOLS = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# Prefer the copies shipped inside tools/ (portable production package);
|
||||
# fall back to the repo's nations-tec/ SDK layout (developer machine).
|
||||
_local_pyocd = os.path.join(TOOLS, "NSpyocd", "NSpyocd.exe")
|
||||
_local_pack = os.path.join(TOOLS, "N32WB03x_DFP.1.4.0.pack")
|
||||
PYOCD = _local_pyocd if os.path.isfile(_local_pyocd) else \
|
||||
os.path.join(ROOT, "nations-tec", "N32WB03x_SDK_V2.0.0",
|
||||
"utilities", "dfu", "NSpyocd", "NSpyocd.exe")
|
||||
# The builtin "n32wb031" target only maps 256KB of flash (fails at
|
||||
# 0x01040000 on the dual-bank package); the DFP pack target
|
||||
# "n32wb031keq6_2" maps the full 512KB of the KEQ6-2 we actually use.
|
||||
PACK = os.path.join(ROOT, "nations-tec", "N32WB03x_DFP.1.4.0.pack")
|
||||
PACK = _local_pack if os.path.isfile(_local_pack) else \
|
||||
os.path.join(ROOT, "nations-tec", "N32WB03x_DFP.1.4.0.pack")
|
||||
TARGET = "n32wb031keq6_2"
|
||||
|
||||
|
||||
|
||||
@ -26,8 +26,12 @@ if errorlevel 1 goto :fail
|
||||
findstr /C:"0 Error(s), 0 Warning(s)" "%ROOT%\mcm-ddc-ble\MDK-ARM\build-app2.log" >nul || goto :fail
|
||||
|
||||
echo [4/4] Merging images...
|
||||
rem 优先随包内嵌的 Python 运行时(merge_image.py 只需标准库)
|
||||
set PYEXE=
|
||||
python --version >nul 2>&1 && set PYEXE=python
|
||||
if exist "%~dp0python-embed\python.exe" set PYEXE="%~dp0python-embed\python.exe"
|
||||
if not defined PYEXE (
|
||||
python --version >nul 2>&1 && set PYEXE=python
|
||||
)
|
||||
if not defined PYEXE (
|
||||
if exist "%LOCALAPPDATA%\Programs\Python\Python312\python.exe" (
|
||||
set PYEXE="%LOCALAPPDATA%\Programs\Python\Python312\python.exe"
|
||||
|
||||
11
tools/make_release.bat
Normal file
11
tools/make_release.bat
Normal file
@ -0,0 +1,11 @@
|
||||
@echo off
|
||||
rem ============================================================
|
||||
rem make_release.bat - pack tools\ into out\mothercup_tools_<ts>.zip
|
||||
rem Self-contained production package: embedded Python runtime
|
||||
rem (python-embed\) + NSpyocd flasher included - the target PC
|
||||
rem needs nothing installed. Unzip anywhere and run the .bat files.
|
||||
rem ============================================================
|
||||
setlocal
|
||||
set PS=powershell
|
||||
%PS% -noprofile -command "exit 0" >nul 2>&1 || set PS=%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe
|
||||
%PS% -noprofile -executionpolicy bypass -file "%~dp0make_release.ps1"
|
||||
14
tools/make_release.ps1
Normal file
14
tools/make_release.ps1
Normal file
@ -0,0 +1,14 @@
|
||||
# make_release.ps1 - pack tools/ into a self-contained production zip.
|
||||
# The zip holds the embedded Python runtime (python-embed/, bleak+pyserial
|
||||
# preinstalled) and NSpyocd, so the target PC needs NO installation.
|
||||
# Excludes the dev-only venv and caches; keeps out/ (the firmware images).
|
||||
# NOTE: the zip is staged in $TEMP first - writing it into out/ while
|
||||
# reading out/ would make Compress-Archive read its own half-written file.
|
||||
$tools = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$stamp = Get-Date -Format "yyyyMMdd_HHmm"
|
||||
$stage = Join-Path $env:TEMP "mothercup_tools_$stamp.zip"
|
||||
$final = Join-Path $tools "out\mothercup_tools_$stamp.zip"
|
||||
$items = Get-ChildItem $tools | Where-Object { $_.Name -notin @('.venv-ble', '__pycache__') }
|
||||
Compress-Archive -Path ($items | ForEach-Object { $_.FullName }) -DestinationPath $stage -Force -ErrorAction Stop
|
||||
Move-Item $stage $final -Force
|
||||
Write-Output "packed: $final"
|
||||
Loading…
x
Reference in New Issue
Block a user