L 級新功能、PRD/Design/TDD/ADR 三方協作 + 互審 + M9-6 SDK 雙驗證、總計 ~9000 行文件。
範圍:
- A 階段(MVP、5 人天):KL520 + KL720 自動升級 KDP1 → KDP2
- B 階段(10.5 人天):手動降版面向一般使用者 + KL630 / KL730 擴展
- 合計 15.5 人天、安裝包 +7MB(保守 bundle 策略)
關鍵決策:
- 翻案 R5-Q9(progress.md 第二輪使用者決策「韌體燒錄 flash → B 砍掉」)
- 跨平台用 KneronPLUS Python C API、不用 DFUT.exe
- 多版本目錄結構選 C metadata(firmware/<chip>/{version}/ + CURRENT_VERSION)
- Kneron firmware redistribution 授權與 R5-B4 預置模型同性質、發佈前評估
文件產出:
- PRD v2.2(PRD-v2.md 495 行 + features/feature-firmware-management.md 599 行)
- Design v2.2(firmware-management.md 948 行 + control-panel.md §6a graceful shutdown)
- TDD v2.2(v2/firmware-management.md 823 行 + ADR-001 218 行)
- 8 份 research(含 M9-6 弱驗證 + 強驗證、~3200 行)
- 3 份三方互審報告(PM/Design/Architect cross-review)
M9-6 強驗證重大發現(影響 B 階段):
- KL730 product_id 實際是 0x732(不是 0x0730)
- KL630/KL730 firmware 是 embedded Linux rootfs(不是 .bin、不同代設計)
- KneronPLUS Python 沒 update_kdp_firmware_from_files 公開 API、warrenchen 走 ctypes
- 不影響 A 階段、B 階段 M9-8 需 spike
下一步:派 backend M9-1 起跑(bridge.py handle_firmware_upgrade)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
13 KiB
研究摘要:visionA-local Kneron Dongle FW 偵測 + 升降版
作者:Architect Agent 日期:2026-05-24 範圍:純研究 plan、不出 code、不改任何既有檔案 目標:在 visionA-local(Wails 桌面 app)新增「自動偵測 Kneron Dongle FW 版本 + 升級 / 降版」功能 參考:同事 warrenchen 雲端版實作於
/tmp/web_academy_prototype/
1. Executive Summary
核心發現
- R5-Q9 砍 flash 的決策不阻擋本任務——當時砍的是「使用者按按鈕去燒模型到 device flash」這條使用者旅程,FW 升降版是不同的事。Q9 砍掉的並不是 firmware 燒錄的技術能力(我們既有的
Flash()driver method 跟 bridge.py 都還有完整的kp.core.load_firmware_from_file邏輯,只是叫法叫「load_firmware」不叫「flash firmware」)。 - visionA-local 既有 code 已經有 70% 的 FW 偵測 + RAM-load 邏輯:
kneron_bridge.py:handle_connect()已會偵測Loadermode、自動從firmware/<chip>/fw_scpu.bin + fw_ncpu.binload firmware 到 RAMkneron_bridge.py:handle_connect()已處理 KL720 KDP legacy (pid=0x0200) → 強制 load KDP2 firmware 到 RAM 的路徑DeviceInfo.FirmwareVer已在 driver interface 內、bridge 連線時也已回傳firmware欄位- bundled firmware 已存在於
server/scripts/firmware/{KL520,KL720}/fw_{scpu,ncpu}.bin(合計約 ~360KB)
- 缺的核心是「持久化升降版」:
- 既有的
load_firmware_from_file是 RAM-load(裝置重新上電就消失) - 真正的 FW 升降版需要呼叫
kp_update_kdp_firmware_from_files(C API、會寫 flash) - warrenchen 雲端版用兩條路徑:(a)
kp.core.install_driver_for_windows風格的 Python 包裝;(b)KneronDFUT.exe(Windows-only Qt GUI 工具的 CLI mode)
- 既有的
- 跨平台選 KneronPLUS C API、不選 DFUT.exe:
- DFUT.exe 是 Windows-only Qt5 binary、~30MB 依賴、不能用
libkplus.{dll,so,dylib}三平台都有、我們既有 bundle 已含、增加成本約 0KB(已在 KneronPLUS wheel 內)- 對應 Python API 是
kp.core.update_kdp_firmware_from_files、不需要走 ctypes(除非舊 KDP1 → KDP2 那條超 legacy 路徑需要kp_connect_devices_with_magic_pass、那段才必須 ctypes)
推薦方案:兩階段
階段 A(MVP,建議先做):「FW 偵測 + 自動升級 KDP1 → KDP2」
範圍:KL520 + KL720(兩個我們已支援的晶片)。
做什麼:
- 被動偵測:scan / connect 時已知道 firmware 字串、在前端 UI 顯示 FW 版本(綠/黃/紅 badge)
- 主動升級(單一動作):使用者按「升級到最新 KDP2」按鈕 → 走 warrenchen 的 legacy-upgrade flow → 進度回報 → 完成後 rescan
- 不做手動降版:階段 A 不暴露「給使用者選版本」UI、只有「升級到目前內建的最新版本」一個動作
為什麼先做 A:
- 解決 90% 的真實痛點(拿到一根插上是 KDP1 legacy 的舊 dongle 沒辦法用)
- 工時 ~3-5 人天、安裝包 +0KB(KL520/KL720 firmware 都已內建)
- 風險低:失敗的話舊狀態還在、re-plug 重試
- 不踩 brick 風險(KDP2 是 Kneron 官方 SDK 的標準版本、不是改寫過的 binary)
階段 B(完整版,視 A 驗證結果決定要不要做):「手動降版 + 多裝置支援」
做什麼:
- 手動降版 KDP2 → KDP1(測試 / 復現舊 bug 用、僅內部)
- 加入 KL630 / KL730 支援(需要 KneronPLUS SDK 對應版本驗證)
- 多版本 firmware 並存(讓使用者選擇 firmware 版本)
為什麼分開:
- 手動降版主要是「給開發者測試用」、不是真實使用者場景
- KL630 / KL730 我們目前 driver 沒驗證過、要先升級 driver code 才能加 FW 支援
- 安裝包 + 5-10MB(KL630/KL730 firmware 是 .tar 約 2-4MB / 套)
工時 / 範圍對照
| 項目 | MVP(A) | 完整版(A + B) |
|---|---|---|
| 裝置範圍 | KL520 + KL720 | + KL630 + KL730 |
| 操作範圍 | 自動升級 KDP1 → KDP2 | + 手動降版 + 多版本選擇 |
| 新增 API | 3 個(/api/devices/:id/firmware, /api/devices/:id/firmware/upgrade, WebSocket progress room) |
+ 2 個(/firmware/downgrade, /firmware/versions) |
| 新增 UI | 1 個 Devices 頁面卡片擴充(FW badge + 升級按鈕 + progress modal) | + Settings 內的「進階:FW 版本管理」面板 |
| bridge.py 新增 handler | firmware_upgrade |
+ firmware_downgrade + firmware_list_versions |
| driver 改動 | 加 UpgradeFirmware() method |
+ DowngradeFirmware(version) |
| 新文件 | TDD 補 §5.4 FW 升級子節 + 1 個新 ADR | + 1 個新 ADR |
| 預估工時 | 3-5 人天 | + 5-7 人天 = 8-12 人天合計 |
| 安裝包衝擊 | +0KB(既有 KL520/KL720 已 bundle) | +5-10MB(KL630/KL730 firmware + 可能的舊版 KL520_kdp) |
R5-Q9 翻案分析
Q9 原文:「韌體燒錄 flash → B 砍掉」(progress.md L776)。
當時為何砍:
- progress.md 沒留下原因(只有「B 砍掉」)
- 推測理由(需使用者確認):
- visionA-local 是「local 推論工具」、不是「dongle 管理工具」、燒 flash 不屬核心使用旅程
- 燒 flash 有 brick 風險、不想對使用者開放
- 早期 MVP 範圍縮小、把非必要功能延後
- 既有「load_firmware 到 RAM」夠用(KL520 USB Boot 每次都重 load、KL720 已預燒 KDP2)
現在為何要翻案:
- 「拿到舊 dongle 完全不能用」是真實痛點(progress.md L29 已有 Error 15 SEND_DATA_TOO_LARGE 經驗)
- 使用者明確要求做(聯合決策已收齊)
- 同事 warrenchen 雲端版已驗證可做、且安全
- 階段 A 範圍小、風險可控、工時可估
翻案是否合理:✅ 合理。
- Q9 的擔憂仍有效(brick 風險、不是核心旅程),但範圍縮小到「自動升級到內建 KDP2 標準版本」就能避開大部分風險
- 不開放使用者「燒任意 binary」、只開放「升級到 Kneron 官方 KDP2 標準版本」
- 加 progress.md 留下決策痕跡(新 ADR 引用 Q9 + 標註翻案理由)
裝置範圍建議
強烈建議 MVP 階段只做 KL520 + KL720:
| 晶片 | 現有 driver 支援 | warrenchen 提供 firmware | 建議 |
|---|---|---|---|
| KL520 | ✅ | ✅ KL520(KDP2)+ KL520_kdp(KDP1 降版用) | MVP 必做 |
| KL720 | ✅ | ✅ KL720(KDP2) | MVP 必做 |
| KL630 | ❌(driver 沒處理 product_id 0x0630) | ✅ kp_firmware.tar / kp_loader.tar | 延後(要先擴 driver) |
| KL730 | ❌(driver 沒處理 product_id 0x0730) | ✅ kp_firmware.tar / kp_loader.tar | 延後(要先擴 driver) |
KL630 / KL730 的 firmware 是 .tar 格式(不是 .bin),代表 SDK 的 load_firmware API 對它們的處理流程也不同、需要先讓 Python bridge 能載這兩種、再做 FW 升降版。強行加入 KL630 / KL730 會把 MVP 範圍翻倍。
安裝包大小衝擊預估
目前 macOS dmg:163MB(progress.md 確認)
| 階段 | 新增內容 | 大小 |
|---|---|---|
| MVP(A) | 0(既有 KL520/KL720 已 bundle) | +0KB |
| 完整版(B) | KL520_kdp(~92KB)+ KL630 .tar(~2MB)+ KL730 .tar(~3MB) | +5MB |
→ MVP 階段不衝擊安裝包大小、完整版約 +3%(接受範圍內)。
2. 與既有架構衝突點
2.1 與 TDD v2.1「watchServer Error state」機制的銜接
TDD v2.1 已決定 watchServer 失敗 → 切 ServerStateError、不再 os.Exit。
FW 升級失敗該怎麼處理:
- 建議:FW 升級是「device 層」失敗、不是「server 層」失敗、不應該讓 server 進 Error state
- 失敗時:device 層回 Error state(既有
driver.StatusError)、推 WebSocket 失敗訊息給 UI、server 繼續正常運行 - 這跟 watchServer 機制是平行的、不衝突
2.2 與 KL520 reset bug(2026-04-21)的銜接
bridge.py 已加 fresh_firmware_loaded flag、避免雙重 firmware load 浪費 60s。
FW 升級流程要避免踩同樣坑:
- 升級成功後 device 會 re-enumerate(裝置脫離 USB → 重新出現)
- 必須等 USB stable(建議 5-8 秒)+ 主動 rescan、不要立刻 reconnect
- 升級流程內部需要
kp.core.reset_device(KP_RESET_REBOOT)、跟我們既有的restartBridge()流程重疊,要小心 race
2.3 與 R5-E 60s 啟動上限的銜接
FW 升級是使用者主動觸發、不在啟動 pipeline 內、跟 60s 上限無關。
但:升級可能需要 30-60 秒(warrenchen 的 KL520 升級 timeout 設 30 秒、KL720 設 180 秒)、UI 必須給 progress bar、不能 block。
2.4 既有 Flash() method 的角色重新定位
flash/service.go:StartFlash() 目前的語意是「load model 到 device RAM」、不是「燒 firmware」。
建議:保持 flash/ 模組原意(load model)、新建 firmware/ 模組(升降版)、不混用。
具體模組劃分:
server/internal/flash/— 既有:load model 到 device RAM(語意保持)server/internal/firmware/(新)— FW 偵測 + 升級 + 降版
2.5 文件命名包袱
server/internal/driver/kneron/kl720_driver.go 檔名其實是 KL520 + KL720 共用 driver(progress.md 已標註)、本任務不改檔名(範圍外)、但新文件不要再用 kl720_* 命名、用 kneron_* 或 device_firmware_*。
3. 下一步建議
- 給使用者 review 本份 plan(這個檔 + 10/20/30 三個附檔)
- 使用者確認後:
- 方案 A 通過 → 啟動 PM 補 PRD「FW 管理」章節(記錄 Q9 翻案 + MVP 範圍)→ Architect 補 TDD v2.1 §5.4 firmware 子節 + 新 ADR-009-firmware-management → Design 補 Devices 頁面 FW badge + 升級 modal 設計
- 方案 B 通過 → 同上 + 補 KL630/KL730 driver 擴展 plan(多一份 research)
- 要求修改 plan → 我修
- 文件完成後依 milestone 進入開發(建議拆 M9-1 ~ M9-5)
Milestone 建議拆法(MVP 階段)
| # | Milestone | 預估 | 平行性 |
|---|---|---|---|
| M9-1 | bridge.py 新增 firmware_upgrade handler(KneronPLUS C API) |
1 人天 | 獨立 |
| M9-2 | Go driver + service:UpgradeFirmware() + firmware/service.go |
1 人天 | 依賴 M9-1 |
| M9-3 | API handler + WebSocket progress room | 0.5 人天 | 依賴 M9-2 |
| M9-4 | 前端 Devices 頁 FW badge + 升級按鈕 + progress modal | 1.5 人天 | 依賴 M9-3 |
| M9-5 | 三平台實機驗證(macOS / Windows / Linux) | 1 人天 | 全部後 |
| 合計 | 5 人天 |
每個 milestone 都走 Reviewer 審查、最後 Testing E2E 驗收。
附錄:B 階段研究索引(2026-05-24 追加)
使用者最新決策(2026-05-24)
使用者拍板採方案 A + B 一次做完。新決策:
- 手動降版面向一般使用者(不只 dev mode、Settings 一般面板就要看得到)
- FW 全部內嵌進安裝包、+5MB 接受、不做線上更新通道
本附錄涵蓋的新研究檔
| 檔案 | 主題 |
|---|---|
40-b-phase-kl630-kl730-extension.md |
KL630/KL730 driver 擴展研究主檔(warrenchen 實作分析、既有 driver 擴點、SDK 落差、milestone M9-6 ~ M9-13) |
41-tar-firmware-handling.md |
.tar firmware 處理細節(為什麼是 .tar、SDK API、解壓策略 X/Y/Z、大小估算) |
42-manual-downgrade-for-end-users.md |
手動降版面向一般使用者(driver/bridge/API 細節、多版本儲存結構、Design Agent 需求清單) |
與主檔(00 ~ 30)的關係
| 主檔內容 | B 階段研究檔位置 |
|---|---|
| §1 範圍對照表「階段 B 工時」5-7 人天 | 更新為 ~10.5 人天(B 階段拆三層 + 手動降版面向一般使用者 + SDK 驗證)詳見 40 §10 |
| §1 安裝包衝擊「+5-10MB」 | 更新為 +6-8MB(保守 bundle 策略)詳見 42 §4 |
| §1 「KL630/KL730 延後」 | 變更:A 階段做完後啟動 M9-6 SDK 驗證 → 決定 B 階段是否全做、見 40 §11 |
| §3 「手動降版主要是給開發者測試用」 | 翻案:使用者決策面向一般使用者、見 42 §1.1 |
B 階段風險清單擴增
承前 R-FW-1 ~ R-FW-7、本研究新增:
- R-FW-8:KneronPLUS SDK 對 KL630/KL730 API 不可預測(高度)
- R-FW-9:.tar 解包對安裝包大小衝擊(低度)
- R-FW-10:KL630/KL730 沒有 Loader mode 概念(中度)
- R-FW-11:一般使用者誤觸降版 brick 風險(高度,B2)
- R-FW-12:多版本管理 UX 複雜度(中度,B2)
- R-TAR-1 ~ R-TAR-4:.tar 解壓特定風險(41 檔 §8)
B 階段啟動前必確認
- KneronPLUS wheel 版本與升級可能性(M9-6 第一件事)
- KL630/KL730 是否有實機可測(沒有則 M9-6 降級為純文件研究)
- Kneron 對 firmware re-distribution 的書面授權範圍是否含舊版 / KDP1(42 §7)
- 使用者對多版本 bundle 策略的選擇(保守 / 完整 / 極簡,42 §4.3)
- 多版本目錄結構選項(建議 C、42 §3.2)
下一步建議(更新版)
- 給使用者 review 本份完整 plan(00 + 10/20/30 + 40/41/42 七個檔)
- 使用者最終 confirm 整體範圍後:
- A 階段啟動:M9-1 ~ M9-5(5 人天)
- B 階段預備:M9-6 SDK 驗證(1 人天、可與 A 階段平行做 research)
- A 階段 release / 驗證後評估 M9-6 結論、決定 B 階段全做或調整 scope
- B 階段執行:M9-7 ~ M9-13(合計 ~9.5 人天)
- 整體合計:~15.5 人天(A 5 + B 10.5)