# 研究摘要: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 ### 核心發現 1. **R5-Q9 砍 flash 的決策不阻擋本任務**——當時砍的是「使用者按按鈕去燒模型到 device flash」這條使用者旅程,**FW 升降版是不同的事**。Q9 砍掉的並不是 firmware 燒錄的技術能力(我們既有的 `Flash()` driver method 跟 bridge.py 都還有完整的 `kp.core.load_firmware_from_file` 邏輯,只是叫法叫「load_firmware」不叫「flash firmware」)。 2. **visionA-local 既有 code 已經有 70% 的 FW 偵測 + RAM-load 邏輯**: - `kneron_bridge.py:handle_connect()` 已會偵測 `Loader` mode、自動從 `firmware//fw_scpu.bin + fw_ncpu.bin` load firmware 到 RAM - `kneron_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) 3. **缺的核心是「持久化升降版」**: - 既有的 `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) 4. **跨平台選 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(兩個我們已支援的晶片)。 **做什麼**: 1. **被動偵測**:scan / connect 時已知道 firmware 字串、在前端 UI 顯示 FW 版本(綠/黃/紅 badge) 2. **主動升級**(單一動作):使用者按「升級到最新 KDP2」按鈕 → 走 warrenchen 的 legacy-upgrade flow → 進度回報 → 完成後 rescan 3. **不做手動降版**:階段 A 不暴露「給使用者選版本」UI、只有「升級到目前內建的最新版本」一個動作 **為什麼先做 A**: - 解決 90% 的真實痛點(拿到一根插上是 KDP1 legacy 的舊 dongle 沒辦法用) - 工時 ~3-5 人天、安裝包 +0KB(KL520/KL720 firmware 都已內建) - 風險低:失敗的話舊狀態還在、re-plug 重試 - 不踩 brick 風險(KDP2 是 Kneron 官方 SDK 的標準版本、不是改寫過的 binary) #### 階段 B(完整版,視 A 驗證結果決定要不要做):「手動降版 + 多裝置支援」 **做什麼**: 1. **手動降版 KDP2 → KDP1**(測試 / 復現舊 bug 用、僅內部) 2. **加入 KL630 / KL730 支援**(需要 KneronPLUS SDK 對應版本驗證) 3. **多版本 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 砍掉」) - 推測理由(需使用者確認): 1. visionA-local 是「local 推論工具」、不是「dongle 管理工具」、燒 flash 不屬核心使用旅程 2. 燒 flash 有 brick 風險、不想對使用者開放 3. 早期 MVP 範圍縮小、把非必要功能延後 4. 既有「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. 下一步建議 1. 給使用者 review 本份 plan(這個檔 + 10/20/30 三個附檔) 2. 使用者確認後: - **方案 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** → 我修 3. 文件完成後依 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 一次做完。新決策: 1. **手動降版面向一般使用者**(不只 dev mode、Settings 一般面板就要看得到) 2. **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 階段啟動前必確認 1. KneronPLUS wheel 版本與升級可能性(M9-6 第一件事) 2. KL630/KL730 是否有實機可測(沒有則 M9-6 降級為純文件研究) 3. Kneron 對 firmware re-distribution 的書面授權範圍是否含舊版 / KDP1(42 §7) 4. 使用者對多版本 bundle 策略的選擇(保守 / 完整 / 極簡,42 §4.3) 5. 多版本目錄結構選項(建議 C、42 §3.2) ### 下一步建議(更新版) 1. 給使用者 review 本份完整 plan(00 + 10/20/30 + 40/41/42 七個檔) 2. 使用者最終 confirm 整體範圍後: - **A 階段啟動**:M9-1 ~ M9-5(5 人天) - **B 階段預備**:M9-6 SDK 驗證(1 人天、可與 A 階段平行做 research) 3. A 階段 release / 驗證後評估 M9-6 結論、決定 B 階段全做或調整 scope 4. B 階段執行:M9-7 ~ M9-13(合計 ~9.5 人天) 5. 整體合計:**~15.5 人天**(A 5 + B 10.5)