# .tar Firmware 處理研究:KL630 / KL730 > 對應 research index §41 > 範圍:KL630 / KL730 firmware 是 `.tar` 格式(不是 .bin)、SDK 處理路徑、解壓策略、安裝包衝擊 > 撰寫日期:2026-05-24 > 限制:純 plan、不出 code、所有「需 SDK 文件驗證」段落都明標註 > 路徑使用相對路徑(相對於 `/Users/jimchen/visionA/local-tool/`) --- ## 0. TL;DR 1. KL520 / KL720 是 `fw_scpu.bin` + `fw_ncpu.bin` 兩個 raw binary、KL630 / KL730 是 `kp_firmware.tar` + `kp_loader.tar` 兩個 .tar 包 2. **.tar 裡面包什麼、SDK 怎麼吃,需要在 B 階段 M9-6 milestone 驗證**——我們現在無法從 warrenchen 程式碼推斷(他們沒實作) 3. 兩個候選策略: - **策略 X:runtime 解壓**(bridge.py 解 .tar 到 temp 目錄、餵解壓後的 .bin 給 SDK) - **策略 Y:build time 解壓**(build script 解壓進 `firmware//extracted/`、ship 解壓後的 .bin) - **策略 Z:直接餵 .tar 給 SDK**(如果 SDK 支援 `load_firmware_from_tar` 之類 API) 4. **推薦策略 Y + Z 二選一、視 SDK 驗證結果**——不推薦策略 X(每次 connect 解壓浪費時間 + temp file 管理麻煩) 5. 安裝包大小衝擊估算:策略 Y 約 +5MB、策略 Z 約 +5MB(一樣、因為 .tar 跟 .bin 解壓後大小接近、壓縮率不高) --- ## 1. 為什麼 KL630 / KL730 是 .tar、不是 .bin ### 1.1 從 warrenchen bundle 看到的事實 ``` local_service_win/firmware/ ├── KL520/ │ ├── fw_scpu.bin ← raw binary │ ├── fw_ncpu.bin ← raw binary │ ├── fw_loader.bin ← raw binary │ ├── dfw/minions.bin ← raw binary(DFUT 用) │ └── VERSION ← "2.2.0" ├── KL720/ │ ├── fw_scpu.bin │ ├── fw_ncpu.bin │ └── VERSION ← "2.2.0" ├── KL630/ │ ├── kp_firmware.tar ← tar 打包 │ ├── kp_loader.tar ← tar 打包 │ └── VERSION ← "SDK-v2.5.7"(命名規則不同) └── KL730/ ├── kp_firmware.tar ├── kp_loader.tar └── VERSION ← "SDK-v1.3.0" ``` ### 1.2 推測原因(**待 SDK 文件驗證**) 從命名規則、版號規則、SDK 版本看: | 觀察 | 推論 | |------|------| | KL520/KL720 VERSION 是 firmware 版本(2.2.0)、KL630/KL730 是 SDK 版本(SDK-v2.5.7)| KL630/KL730 是新世代 SDK(v2.x SDK release)、firmware 與 SDK 綁定打包 | | KL520/KL720 用 `fw_scpu.bin` / `fw_ncpu.bin` 命名、KL630/KL730 用 `kp_firmware.tar` 命名| KneronPLUS v2/v3 改用統一 packaging 格式、把 scpu + ncpu + metadata 整包到一個 .tar | | KL520/KL720 有 `fw_loader.bin`、KL630/KL730 有 `kp_loader.tar`| Loader 也用同樣的打包策略、可能裡面除了 binary 還含 manifest | | KL730 SDK-v1.3.0 比 KL630 SDK-v2.5.7 低、跟 chip 推出時間有關| KL730 可能還在較舊 SDK release(warrenchen 取樣時的版本快照)| ### 1.3 .tar 內容可能性(**未驗證、僅猜測**) `.tar` 通常會包: - `fw_scpu.bin` - `fw_ncpu.bin` - `manifest.json` 或 `metadata.txt`(含版本、checksum、target chip 等) - 可能含其他 firmware sub-module(FPP_FW 等視 chip 而異) **驗證方式**(M9-6 必做): ```bash mkdir -p /tmp/kl630_inspect cd /tmp/kl630_inspect tar -tvf /tmp/web_academy_prototype/local_service_win/firmware/KL630/kp_firmware.tar tar -tvf /tmp/web_academy_prototype/local_service_win/firmware/KL630/kp_loader.tar tar -tvf /tmp/web_academy_prototype/local_service_win/firmware/KL730/kp_firmware.tar tar -tvf /tmp/web_academy_prototype/local_service_win/firmware/KL730/kp_loader.tar # 紀錄每個 .tar 內含檔案清單、大小、結構 ``` **本份研究無法跑這個 inspect**(Architect Agent 不執行 shell 變動類指令、且這應該在實機驗證階段做)——M9-6 milestone 必做、結果回填到本檔 §3。 --- ## 2. KneronPLUS API 對 .tar 的處理(**全部待 SDK 文件驗證**) ### 2.1 可能的 API 設計 從 KneronPLUS Python SDK 既有 API pattern 推測: | API 候選 | 簽名 | 可能性 | |---------|------|-------| | `kp.core.load_firmware_from_file(dg, scpu_path, ncpu_path)` | 既有 API、接受兩個 .bin | KL630/KL730 是否能接受 .tar 內容路徑?需要先解壓?| | `kp.core.load_firmware_from_tar(dg, tar_path)` | 假設新 API | **未確認存在**——可能 SDK v3.x 才有 | | `kp.core.update_kdp2_firmware_from_tar(dg, tar_path, auto_reboot)` | 假設新 API(KDP2 寫 flash 用) | **未確認**、推測對應 KL630/KL730 升級 | | `kp.core.update_kdp_firmware_from_files(dg, scpu, ncpu, auto_reboot)` | 既有 API(A 階段用) | 對 KL630/KL730 可能不適用(KDP 是 KL520/KL720 老世代術語)| ### 2.2 從 warrenchen wheel 推斷 `local_service_win/KneronPLUS-3.1.2-py3-none-any.whl` 是 KneronPLUS 3.1.2、推測 API 命名應該已統一(v3.x 主版本)。 **驗證方式**(M9-6 必做): ```bash cd /tmp unzip /tmp/web_academy_prototype/local_service_win/KneronPLUS-3.1.2-py3-none-any.whl -d kneron_plus_inspect # 找 kp/core.py 或對應的 wrapper grep -rn "tar\|load_firmware\|update_kdp\|update_firmware" /tmp/kneron_plus_inspect/kp/ # 找所有 firmware-related 函數 grep -rn "^def " /tmp/kneron_plus_inspect/kp/core.py | grep -i "fw\|firmware" ``` **本份研究無法跑這個**——M9-6 必做。 ### 2.3 從 visionA-local 既有 KneronPLUS wheel 推斷 需要知道我們既有 wheel 版本(**待查**): ```bash # 假設安裝在 server/scripts/venv/ 或類似位置 ls server/scripts/*.whl 2>/dev/null # 如果是直接 ship wheel pip show kneronplus 2>/dev/null # 如果是 installed package ``` **重要**:如果我們既有 wheel 比 warrenchen 的 3.1.2 還舊(例如 2.x),可能: - 既有 wheel 不認 `KP_DEVICE_KL630` / `KP_DEVICE_KL730` enum → driver 升級必須先升 wheel - 既有 wheel 沒有 .tar 處理 API → 必須升 wheel 才能支援 KL630/KL730 → M9-6 評估「是否升級 KneronPLUS wheel」是 B 階段風險最高的決策點。 --- ## 3. 大小估算(warrenchen 提供的 .tar 各多大) ### 3.1 .tar 檔案大小(從 warrenchen bundle 推斷) ```bash # 在 M9-6 驗證階段執行(本份研究不執行 shell write 動作) ls -lh /tmp/web_academy_prototype/local_service_win/firmware/KL630/ ls -lh /tmp/web_academy_prototype/local_service_win/firmware/KL730/ ls -lh /tmp/web_academy_prototype/local_service_win/firmware/KL520/ ls -lh /tmp/web_academy_prototype/local_service_win/firmware/KL520_kdp/ ls -lh /tmp/web_academy_prototype/local_service_win/firmware/KL720/ ``` **預估值**(基於檔案類型常識): | 路徑 | 預估大小 | 註 | |------|---------|------| | `KL520/fw_scpu.bin` | ~52KB | TDD L3219 記錄 | | `KL520/fw_ncpu.bin` | ~40KB | TDD L3219 記錄 | | `KL520/fw_loader.bin` | ~10KB | KDP1→KDP2 升級用 | | `KL520/dfw/minions.bin` | ~50KB | DFUT 用、未來可能不 bundle | | `KL520_kdp/fw_scpu.bin` | ~50KB | KDP1 降版用 | | `KL520_kdp/fw_ncpu.bin` | ~40KB | KDP1 降版用 | | `KL720/fw_scpu.bin` | ~150KB | KDP2、更複雜 | | `KL720/fw_ncpu.bin` | ~100KB | | | `KL630/kp_firmware.tar` | ~2-3MB | tar 含多檔、新世代 firmware 較大 | | `KL630/kp_loader.tar` | ~500KB | loader | | `KL730/kp_firmware.tar` | ~3-4MB | | | `KL730/kp_loader.tar` | ~500KB | | **B 階段所有 firmware 合計增量**: - KL520_kdp(降版用):~90KB - KL630(升降版用):~2.5-3.5MB - KL730(升降版用):~3.5-4.5MB - 合計:**~6-8MB** **multi-version bundle(B2 階段)**: - 每 chip 額外 bundle 1 個舊版(v2.1.0 之類):~+1-2MB - 合計:**~7-10MB** ### 3.2 與 macOS dmg 既有 163MB 比 | 階段 | 累計新增 | 累計安裝包 | 衝擊 | |------|---------|----------|------| | 既有(含 KL520/KL720 firmware) | 0 | 163MB | baseline | | A 階段(+ KL520/fw_loader.bin) | +10KB | ~163MB | <0.01% | | B 階段(含 KL520_kdp + KL630 + KL730 firmware) | +6-8MB | ~170-171MB | +4-5% | | B2 階段(多版本,每 chip + 1 個舊版)| +7-10MB | ~170-173MB | +4-6% | → **使用者「+5MB 接受」的決策完全成立**——B 階段全做完約 +7-10MB、不超過 +6%。 ### 3.3 解壓後大小(估算) .tar 通常不會做壓縮(tar 預設無 compression、除非 .tar.gz)、解壓後大小 ≈ 原 .tar 大小: | 檔案 | 原始 .tar | 解壓後 | |------|----------|--------| | `KL630/kp_firmware.tar` (~3MB) | 3MB | ~3MB(內含多個 .bin、metadata、加總接近 .tar 大小) | | `KL730/kp_firmware.tar` (~4MB) | 4MB | ~4MB | → 採策略 Y(build time 解壓)vs 策略 Z(ship .tar)大小差異 **< 100KB**、可忽略。 --- ## 4. 解壓策略對比 ### 4.1 策略 X:runtime 解壓 **做法**: - bridge.py 每次 connect KL630/KL730 時、解壓 `.tar` 到 `tempfile.mkdtemp()` 暫存目錄 - 餵解壓後的 .bin 路徑給 `kp.core.load_firmware_from_file()` - 連線結束清理 temp 目錄 **優點**: - 安裝包不增加解壓後檔案、只 ship 一份 .tar - 解壓邏輯集中在 bridge.py、單一資料夾管理 **缺點**: - 每次 connect 多花 50-200ms 解壓時間 - temp 目錄管理:clean-up、permissions、tempfile 衝突 - macOS hardened runtime 對 temp 目錄寫入權限可能有限制 - Windows 上 `tempfile` 預設位置 `%TEMP%` 可能被防毒軟體掃描,慢 - KL630/KL730 如果類似 KL520(每次 connect 都要 load firmware),解壓會發生在 hot path **不推薦**——成本 vs 收益不划算。 ### 4.2 策略 Y:build time 解壓 **做法**: - `installer/` build script 在 wails build 之前、先解壓 `.tar` 到 `server/scripts/firmware//extracted/` - ship 解壓後的 .bin(不 ship 原始 .tar) - bridge.py 直接餵解壓後路徑、`_resolve_firmware_paths(chip)` 解析 `extracted/` 子目錄 **優點**: - runtime 零成本、connect 速度不受影響 - bridge.py 邏輯與 KL520/KL720 一致(都餵 .bin path) - 安裝包大小不變(.tar 跟解壓後 .bin 大小接近) **缺點**: - 需要修改 installer build script(單純做) - 開發環境第一次 clone repo 後、必須跑解壓 script 一次(或加進 `make setup` / npm postinstall) - 解壓後檔案進不進 git?建議**不進**(避免 binary diff、靠 build script 即時產生) **推薦條件**:如果 SDK 不支援 .tar 直接餵入、選此策略。 ### 4.3 策略 Z:直接餵 .tar 給 SDK **做法**: - SDK 提供 `kp.core.load_firmware_from_tar()` 或類似 API、bridge.py 直接傳 .tar 路徑 **優點**: - 最簡(不需解壓邏輯) - runtime 零成本 - 安裝包 ship 原始 .tar、與 warrenchen 一致 **缺點**: - **依賴 SDK 支援**——M9-6 必須驗證 API 存在 - 如果 SDK 接受的是「.tar 內 fw_scpu.bin 解出來的路徑」、那就退回策略 Y - bridge.py 內 KL520/KL720 vs KL630/KL730 firmware 路徑解析邏輯不一致(一邊兩個 .bin、一邊一個 .tar)、`_resolve_firmware_paths` 必須回 union type 或分支處理 **推薦條件**:如果 SDK 確認支援、選此策略(最乾淨)。 ### 4.4 決策樹 ``` M9-6 SDK 驗證結果 ├── SDK 支援 load_firmware_from_tar() / update_*_from_tar() │ └── 選策略 Z │ └── 改動:_resolve_firmware_paths 回 (tar_path, None) 或 union │ └── SDK 不支援、必須先解壓 └── 選策略 Y └── 改動: - installer build script 加 tar -xf 步驟 - .gitignore 加 firmware//extracted/ - 開發環境 setup 加解壓 step - _resolve_firmware_paths 找 extracted/fw_scpu.bin ``` **絕對不要選策略 X**(runtime 解壓)。 --- ## 5. SDK API 可用性驗證計畫(M9-6 必做) ### 5.1 驗證項目清單 | # | 驗證項目 | 方法 | 影響 | |---|---------|------|-----| | 1 | 既有 KneronPLUS wheel 版本 | `pip show kneronplus` / 找 wheel 檔案 | 決定要不要升級 wheel | | 2 | wheel 內 `kp.ProductId.KP_DEVICE_KL630` / `KL730` enum 存在 | `python -c "import kp; print(kp.ProductId.KP_DEVICE_KL630)"` | 不存在 → 升 wheel | | 3 | `kp.core.load_firmware_from_file` 對 .tar 路徑的行為 | 實機跑、傳 `.tar` 看回傳 | 決定策略 Y or Z | | 4 | `kp.core.update_kdp_firmware_from_files` 對 KL630/KL730 是否適用 | 實機跑(如果有 KL630/KL730)| FW 升降版實作策略 | | 5 | 是否有 `load_firmware_from_tar()` / `update_*_from_tar()` 新 API | grep wheel source / 查 SDK 文件 | 策略 Z 是否可行 | | 6 | KL630/KL730 firmware 字串可能值 | 實機 `kp.core.scan_devices()` 看 firmware 欄位 | FW badge 顯示邏輯 | | 7 | KL630/KL730 是否每次 connect 都要 load firmware | 實機 connect 兩次、看第二次需不需要 load | connect 流程設計 | | 8 | `kp.inference.generic_image_inference_send/receive` 對 KL630/KL730 NEF 是否能直接 work | 實機跑 sample inference | inference 流程是否要分支 | | 9 | .tar 內容(解壓看裡面有什麼)| `tar -tvf kp_firmware.tar` | bridge.py 解析策略 | | 10 | KneronPLUS wheel 升級對 KL520/KL720 的 regression 風險 | 升級後跑 既有 E2E | 是否值得升 wheel | ### 5.2 驗證所需資源 - 使用者手上要有: - 至少 1 個 KL630 dongle(理想) - 至少 1 個 KL730 dongle(理想) - 如果沒有、只能查 SDK 文件 + wheel source、無法做動態驗證、風險變高 - KneronPLUS SDK 官方文件(PDF / online docs) - Python REPL + 既有 venv ### 5.3 驗證結果回填位置 - 本檔 §1.3、§2、§3.3 的「未驗證」段落填實際結果 - 40-b-phase 檔 §3.2、§5.2、§7.1 對應段落 - 30-integration-plan 檔 §6 階段 B 評估提示更新 --- ## 6. .tar 解壓技術細節(如選策略 Y) ### 6.1 解壓工具選擇 **跨平台選 Python `tarfile` 模組**(標準庫、無外部依賴): ```python # 偽碼、給 installer build script 用 import tarfile import os import shutil def extract_firmware_tars(firmware_dir): """Walk firmware// dirs、解壓所有 .tar 到 extracted/ 子目錄""" for chip_dir in os.listdir(firmware_dir): chip_path = os.path.join(firmware_dir, chip_dir) if not os.path.isdir(chip_path): continue for fname in os.listdir(chip_path): if not fname.endswith(".tar"): continue tar_path = os.path.join(chip_path, fname) extract_to = os.path.join(chip_path, "extracted") os.makedirs(extract_to, exist_ok=True) with tarfile.open(tar_path, "r") as tar: tar.extractall(extract_to) ``` **不選 shell `tar -xf`**——Windows 上 `tar` 命令不一定存在(Win10+ 才有)、Python 標準庫穩定。 ### 6.2 何時跑 - **CI/CD build pipeline**:每次 build 安裝包前跑(保證 ship 出去的安裝包有解壓檔) - **開發環境 setup**:`scripts/setup-dev.sh` / `make setup` 加一步、或 npm postinstall - **首次 clone 後**:README 提醒「跑 `python3 scripts/extract-firmware.py`」 ### 6.3 .gitignore 規則 ``` # .gitignore 追加(B 階段 M9-8 milestone) server/scripts/firmware/*/extracted/ ``` → `.tar` 進 git、解壓後 `.bin` 不進 git(避免雙份 binary 進版控、減少 repo 大小) ### 6.4 衝突處理 如果使用者手動修改了 `extracted/` 內檔案、下次 build 會覆蓋。可接受、因為這個目錄不該手動改。 --- ## 7. 如果選策略 Z(直接餵 .tar)的細節 ### 7.1 bridge.py 簽名變化 ```python # _resolve_firmware_paths 偽碼變化 def _resolve_firmware_paths(chip="KL520"): base = os.path.dirname(os.path.abspath(__file__)) fw_dir = os.path.join(base, "firmware", chip) if chip in ("KL520", "KL720"): # 既有路徑 .bin scpu = os.path.join(fw_dir, "fw_scpu.bin") ncpu = os.path.join(fw_dir, "fw_ncpu.bin") if os.path.exists(scpu) and os.path.exists(ncpu): return {"format": "bin", "scpu": scpu, "ncpu": ncpu, "loader": ...} return None if chip in ("KL630", "KL730"): fw_tar = os.path.join(fw_dir, "kp_firmware.tar") loader_tar = os.path.join(fw_dir, "kp_loader.tar") if os.path.exists(fw_tar): return {"format": "tar", "firmware": fw_tar, "loader": loader_tar} return None return None ``` → 回 dict / union type 而不是 tuple、給 caller 判斷 format。 ### 7.2 firmware load 分支 ```python # handle_connect / handle_firmware_upgrade 內偽碼 fw_paths = _resolve_firmware_paths(chip) if fw_paths is None: return {"error": f"firmware not found for {chip}"} if fw_paths["format"] == "bin": kp.core.load_firmware_from_file(dg, fw_paths["scpu"], fw_paths["ncpu"]) elif fw_paths["format"] == "tar": # 假設 SDK 提供這個 API、待驗證 kp.core.load_firmware_from_tar(dg, fw_paths["firmware"]) ``` --- ## 8. 風險(針對 .tar 處理) ### 8.1 R-TAR-1:SDK 不接受 .tar 直接餵(中度,B 階段 M9-6 驗) **情境**:策略 Z 不可行、被迫退回策略 Y。 **緩解**:M9-6 預先驗證、選對策略才做 M9-8。 ### 8.2 R-TAR-2:build time 解壓步驟漏跑(中度) **情境**:CI/CD 流程沒加解壓 step、ship 出去的安裝包沒有解壓 .bin、KL630/KL730 連不上。 **緩解**: - installer build script 加 mandatory `extract-firmware.py` step - 加 build-time check:「`firmware/KL630/extracted/fw_scpu.bin` 不存在 → build fail」 - 安裝包 smoke test:解壓安裝包、grep `extracted/fw_scpu.bin` 必須存在 ### 8.3 R-TAR-3:解壓對 macOS notarization 影響(低度) **情境**:macOS notarization 對 dmg 內 binary file 要求 codesign、解壓出來的 .bin 是否需要簽? **研究**: - firmware .bin 不是 executable(是 NPU instruction binary)、預估不需 codesign - 但 Apple Gatekeeper / XProtect 可能誤判某些 binary pattern - M9-13 milestone 三平台驗證時必須跑 notarized dmg、確認沒被砍 ### 8.4 R-TAR-4:.tar 解壓路徑跨平台問題(低度) **情境**:Python `tarfile.extractall()` 在 Windows 上對絕對路徑 / `..` path entry 有警告(Python 3.12+ 預設拒絕)。 **緩解**: - 解壓前用 `tarfile.data_filter` 過濾(Python 3.12+ 內建) - 或預先驗證 .tar 內容、refuse 含 `..` / 絕對路徑的 .tar --- ## 9. 給 Orchestrator 的決策點 1. **A 階段 MVP 不涉 .tar**——不影響本檔 2. **B 階段啟動前 M9-6 必跑**——SDK 驗證、決定策略 Y/Z 3. **策略選定後本檔 §4.4 「決策樹」結果回填**到 progress.md「重要決策紀錄」 4. **如果使用者沒有 KL630/KL730 dongle**——降級驗證強度:只查 SDK 文件 + wheel source、不做動態驗證、風險 R-FW-8 提升 --- ## 10. 與其他研究檔的關係 | 連結 | 引用內容 | |------|---------| | `40-b-phase-kl630-kl730-extension.md` §6.3 | `_resolve_firmware_paths` 擴展偽碼(本檔詳化)| | `40-b-phase-kl630-kl730-extension.md` R-FW-9 | .tar 解壓對安裝包大小衝擊(本檔 §3 詳化)| | `40-b-phase-kl630-kl730-extension.md` R-FW-10 | KL630/KL730 是否有 Loader mode(本檔 §5.1 驗證 #6/#7 確認)| | `42-manual-downgrade-for-end-users.md` | 多版本 .tar 儲存結構(本檔 §6.3 .gitignore 規則延伸)|