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>
240 lines
13 KiB
Markdown
240 lines
13 KiB
Markdown
# 研究摘要: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/<chip>/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)
|