firmwareloop 0.1.6__tar.gz → 0.1.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/PKG-INFO +6 -4
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/README.md +5 -3
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/firmwareloop.egg-info/PKG-INFO +6 -4
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/pyproject.toml +1 -1
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/__init__.py +1 -1
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/fw_mcp_server.py +61 -7
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/lib/ndtdbg.py +127 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/ndtdbg_bridge.ps1 +44 -1
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/ndtdbg_cli.py +24 -1
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/setup-agent-mcp.ps1 +2 -2
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/LICENSE +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/firmwareloop.egg-info/SOURCES.txt +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/firmwareloop.egg-info/dependency_links.txt +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/firmwareloop.egg-info/entry_points.txt +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/firmwareloop.egg-info/requires.txt +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/firmwareloop.egg-info/top_level.txt +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/setup.cfg +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/acceptance-scenario.ps1 +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/build.ps1 +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/can.ps1 +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/check-qoder-mcp.ps1 +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/common/build-backends.psm1 +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/common/fw.psm1 +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/common/uart_probe.py +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/doctor.ps1 +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/flash.ps1 +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/instrument_cli.py +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/lib/__init__.py +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/lib/instruments.py +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/logic_capture.ps1 +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/logic_decode.ps1 +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/reset.ps1 +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/sigrok_csv_to_fwloop.py +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/test-backends.ps1 +0 -0
- {firmwareloop-0.1.6 → firmwareloop-0.1.7}/tools/test.ps1 +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: firmwareloop
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: AI Agent Firmware Development and Lab Automation Platform (Dual-Tier MCP Server)
|
|
5
5
|
Author-email: WeilinZhang <19523330249@163.com>
|
|
6
6
|
License: MIT
|
|
@@ -134,7 +134,8 @@ fwloop ndtdebugtool "C:/Users/weilin.zhang/Desktop/zwl/NdtDebugTool-v1.0.19"
|
|
|
134
134
|
> 完成以上两步后,Agent 侧即可直接调用 NdtBox 相关工具:
|
|
135
135
|
> `fw_ndtdbg_status`(版本/连通性/模组通断)、`fw_ndtdbg_measure`(数据轮询采集)、
|
|
136
136
|
> `fw_ndtdbg_read_reg` / `fw_ndtdbg_write_reg`(任意寄存器读写,写需 `write_allowed` + `confirm` 双门控)、
|
|
137
|
-
> `fw_ndtdbg_capture_seq`(寄存器序列 + Saleae
|
|
137
|
+
> `fw_ndtdbg_capture_seq`(寄存器序列 + Saleae 波形同窗口取证)、
|
|
138
|
+
> `fw_ndtdbg_flash`(.bin/.nfw 整片擦写烧录,需 `write_allowed` + `confirm` 双门控,默认拒绝)。
|
|
138
139
|
> 前置硬件要求:NdtBox 已装 CH341 驱动;如需 Saleae 波形证据,另装 sigrok-cli 并配置
|
|
139
140
|
> `libusb-win32` 驱动(详见 `docs/` 交付说明)。测试时请退出 STDataCollection.exe 上位机(USB 独占)。
|
|
140
141
|
|
|
@@ -362,7 +363,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
362
363
|
├── demo-firmware/ 示例固件(CMake;宿主编译模拟 MCU,闭环验证载体)
|
|
363
364
|
├── demo-make/ 示例固件(Make;构建测试载体)
|
|
364
365
|
├── docs/ DEPENDENCY_MATRIX / REUSE_PLAN / V0.0.2_GAP_VERIFICATION
|
|
365
|
-
├── pyproject.toml 标准 Python 包配置与 CLI 入口声明 (v0.1.
|
|
366
|
+
├── pyproject.toml 标准 Python 包配置与 CLI 入口声明 (v0.1.7)
|
|
366
367
|
├── .mcp.example.json 双层 MCP 配置模板(firmwareloop + agentic-hil)
|
|
367
368
|
├── AGENTS.md 通用智能体规范(Antigravity / Qoder / Cursor 等)
|
|
368
369
|
├── CLAUDE.md Claude Code CLI 指南
|
|
@@ -372,7 +373,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
372
373
|
|
|
373
374
|
---
|
|
374
375
|
|
|
375
|
-
## 能力验证状态(v0.1.
|
|
376
|
+
## 能力验证状态(v0.1.7)
|
|
376
377
|
|
|
377
378
|
> 状态定义:`Implemented`(已实现)/ `Simulator Validated`(模拟验证)/
|
|
378
379
|
> `Real Hardware Validated`(真机验证)/ `Experimental` / `Not Implemented`
|
|
@@ -393,6 +394,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
393
394
|
| Safety Policy(limits.yaml) | Implemented(simulator 校验)-> 外置权威配置 |
|
|
394
395
|
| 自动修复闭环(M6 载体) | Simulator Validated -> Real Hardware Validated 待 DUT |
|
|
395
396
|
| NdtBox 数据采集/调试(fw_ndtdbg_status / fw_ndtdbg_measure, ChipSea Fxx IIC) | Implemented(无硬件 Fail-Closed 已验证)-> Real Hardware Validated 待 NdtBox |
|
|
397
|
+
| NdtBox IIC 固件烧录(fw_ndtdbg_flash, .bin/.nfw 整片擦写, 芯海 Fxx) | Implemented(时序对齐原厂 UpdateFW, 双闸门 Fail-Closed 已验证)-> Real Hardware 待烧录验收 |
|
|
396
398
|
|
|
397
399
|
---
|
|
398
400
|
|
|
@@ -106,7 +106,8 @@ fwloop ndtdebugtool "C:/Users/weilin.zhang/Desktop/zwl/NdtDebugTool-v1.0.19"
|
|
|
106
106
|
> 完成以上两步后,Agent 侧即可直接调用 NdtBox 相关工具:
|
|
107
107
|
> `fw_ndtdbg_status`(版本/连通性/模组通断)、`fw_ndtdbg_measure`(数据轮询采集)、
|
|
108
108
|
> `fw_ndtdbg_read_reg` / `fw_ndtdbg_write_reg`(任意寄存器读写,写需 `write_allowed` + `confirm` 双门控)、
|
|
109
|
-
> `fw_ndtdbg_capture_seq`(寄存器序列 + Saleae
|
|
109
|
+
> `fw_ndtdbg_capture_seq`(寄存器序列 + Saleae 波形同窗口取证)、
|
|
110
|
+
> `fw_ndtdbg_flash`(.bin/.nfw 整片擦写烧录,需 `write_allowed` + `confirm` 双门控,默认拒绝)。
|
|
110
111
|
> 前置硬件要求:NdtBox 已装 CH341 驱动;如需 Saleae 波形证据,另装 sigrok-cli 并配置
|
|
111
112
|
> `libusb-win32` 驱动(详见 `docs/` 交付说明)。测试时请退出 STDataCollection.exe 上位机(USB 独占)。
|
|
112
113
|
|
|
@@ -334,7 +335,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
334
335
|
├── demo-firmware/ 示例固件(CMake;宿主编译模拟 MCU,闭环验证载体)
|
|
335
336
|
├── demo-make/ 示例固件(Make;构建测试载体)
|
|
336
337
|
├── docs/ DEPENDENCY_MATRIX / REUSE_PLAN / V0.0.2_GAP_VERIFICATION
|
|
337
|
-
├── pyproject.toml 标准 Python 包配置与 CLI 入口声明 (v0.1.
|
|
338
|
+
├── pyproject.toml 标准 Python 包配置与 CLI 入口声明 (v0.1.7)
|
|
338
339
|
├── .mcp.example.json 双层 MCP 配置模板(firmwareloop + agentic-hil)
|
|
339
340
|
├── AGENTS.md 通用智能体规范(Antigravity / Qoder / Cursor 等)
|
|
340
341
|
├── CLAUDE.md Claude Code CLI 指南
|
|
@@ -344,7 +345,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
344
345
|
|
|
345
346
|
---
|
|
346
347
|
|
|
347
|
-
## 能力验证状态(v0.1.
|
|
348
|
+
## 能力验证状态(v0.1.7)
|
|
348
349
|
|
|
349
350
|
> 状态定义:`Implemented`(已实现)/ `Simulator Validated`(模拟验证)/
|
|
350
351
|
> `Real Hardware Validated`(真机验证)/ `Experimental` / `Not Implemented`
|
|
@@ -365,6 +366,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
365
366
|
| Safety Policy(limits.yaml) | Implemented(simulator 校验)-> 外置权威配置 |
|
|
366
367
|
| 自动修复闭环(M6 载体) | Simulator Validated -> Real Hardware Validated 待 DUT |
|
|
367
368
|
| NdtBox 数据采集/调试(fw_ndtdbg_status / fw_ndtdbg_measure, ChipSea Fxx IIC) | Implemented(无硬件 Fail-Closed 已验证)-> Real Hardware Validated 待 NdtBox |
|
|
369
|
+
| NdtBox IIC 固件烧录(fw_ndtdbg_flash, .bin/.nfw 整片擦写, 芯海 Fxx) | Implemented(时序对齐原厂 UpdateFW, 双闸门 Fail-Closed 已验证)-> Real Hardware 待烧录验收 |
|
|
368
370
|
|
|
369
371
|
---
|
|
370
372
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: firmwareloop
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: AI Agent Firmware Development and Lab Automation Platform (Dual-Tier MCP Server)
|
|
5
5
|
Author-email: WeilinZhang <19523330249@163.com>
|
|
6
6
|
License: MIT
|
|
@@ -134,7 +134,8 @@ fwloop ndtdebugtool "C:/Users/weilin.zhang/Desktop/zwl/NdtDebugTool-v1.0.19"
|
|
|
134
134
|
> 完成以上两步后,Agent 侧即可直接调用 NdtBox 相关工具:
|
|
135
135
|
> `fw_ndtdbg_status`(版本/连通性/模组通断)、`fw_ndtdbg_measure`(数据轮询采集)、
|
|
136
136
|
> `fw_ndtdbg_read_reg` / `fw_ndtdbg_write_reg`(任意寄存器读写,写需 `write_allowed` + `confirm` 双门控)、
|
|
137
|
-
> `fw_ndtdbg_capture_seq`(寄存器序列 + Saleae
|
|
137
|
+
> `fw_ndtdbg_capture_seq`(寄存器序列 + Saleae 波形同窗口取证)、
|
|
138
|
+
> `fw_ndtdbg_flash`(.bin/.nfw 整片擦写烧录,需 `write_allowed` + `confirm` 双门控,默认拒绝)。
|
|
138
139
|
> 前置硬件要求:NdtBox 已装 CH341 驱动;如需 Saleae 波形证据,另装 sigrok-cli 并配置
|
|
139
140
|
> `libusb-win32` 驱动(详见 `docs/` 交付说明)。测试时请退出 STDataCollection.exe 上位机(USB 独占)。
|
|
140
141
|
|
|
@@ -362,7 +363,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
362
363
|
├── demo-firmware/ 示例固件(CMake;宿主编译模拟 MCU,闭环验证载体)
|
|
363
364
|
├── demo-make/ 示例固件(Make;构建测试载体)
|
|
364
365
|
├── docs/ DEPENDENCY_MATRIX / REUSE_PLAN / V0.0.2_GAP_VERIFICATION
|
|
365
|
-
├── pyproject.toml 标准 Python 包配置与 CLI 入口声明 (v0.1.
|
|
366
|
+
├── pyproject.toml 标准 Python 包配置与 CLI 入口声明 (v0.1.7)
|
|
366
367
|
├── .mcp.example.json 双层 MCP 配置模板(firmwareloop + agentic-hil)
|
|
367
368
|
├── AGENTS.md 通用智能体规范(Antigravity / Qoder / Cursor 等)
|
|
368
369
|
├── CLAUDE.md Claude Code CLI 指南
|
|
@@ -372,7 +373,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
372
373
|
|
|
373
374
|
---
|
|
374
375
|
|
|
375
|
-
## 能力验证状态(v0.1.
|
|
376
|
+
## 能力验证状态(v0.1.7)
|
|
376
377
|
|
|
377
378
|
> 状态定义:`Implemented`(已实现)/ `Simulator Validated`(模拟验证)/
|
|
378
379
|
> `Real Hardware Validated`(真机验证)/ `Experimental` / `Not Implemented`
|
|
@@ -393,6 +394,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
393
394
|
| Safety Policy(limits.yaml) | Implemented(simulator 校验)-> 外置权威配置 |
|
|
394
395
|
| 自动修复闭环(M6 载体) | Simulator Validated -> Real Hardware Validated 待 DUT |
|
|
395
396
|
| NdtBox 数据采集/调试(fw_ndtdbg_status / fw_ndtdbg_measure, ChipSea Fxx IIC) | Implemented(无硬件 Fail-Closed 已验证)-> Real Hardware Validated 待 NdtBox |
|
|
397
|
+
| NdtBox IIC 固件烧录(fw_ndtdbg_flash, .bin/.nfw 整片擦写, 芯海 Fxx) | Implemented(时序对齐原厂 UpdateFW, 双闸门 Fail-Closed 已验证)-> Real Hardware 待烧录验收 |
|
|
396
398
|
|
|
397
399
|
---
|
|
398
400
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""
|
|
3
|
-
fw_mcp_server.py - FirmwareLoop High-Level Workflow & Device MCP Server (v0.1.
|
|
3
|
+
fw_mcp_server.py - FirmwareLoop High-Level Workflow & Device MCP Server (v0.1.7).
|
|
4
4
|
|
|
5
5
|
Exposes high-level firmware engineering and hardware management tools to AI Coding
|
|
6
6
|
Agents (Antigravity CLI, Claude Code CLI, Qoder IDE, CodeBuddy IDE, Cursor) via the Model Context
|
|
@@ -19,6 +19,7 @@ Tools provided:
|
|
|
19
19
|
- fw_ndtdbg_read_reg: NdtBox IIC register read (ndtdbg_cli.py)
|
|
20
20
|
- fw_ndtdbg_write_reg: NdtBox IIC register write, double-gated (ndtdbg_cli.py)
|
|
21
21
|
- fw_ndtdbg_capture_seq: NdtBox register sequence + concurrent I2C capture for waveform evidence (ndtdbg_cli.py)
|
|
22
|
+
- fw_ndtdbg_flash: NdtBox IIC firmware flash (.bin/.nfw, full-chip erase, double-gated) (ndtdbg_cli.py)
|
|
22
23
|
- fw_logic_capture: Logic analyzer protocol capture (logic_capture.ps1)
|
|
23
24
|
- fw_logic_decode: Logic analyzer protocol decoding & assertion (logic_decode.ps1)
|
|
24
25
|
- fw_get_evidence: Read structured audit run evidence (artifacts/runs/)
|
|
@@ -306,6 +307,18 @@ def handle_fw_ndtdbg_write_reg(args: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
306
307
|
return res
|
|
307
308
|
|
|
308
309
|
|
|
310
|
+
def handle_fw_ndtdbg_flash(args: Dict[str, Any]) -> Dict[str, Any]:
|
|
311
|
+
"""Erase + flash a .bin/.nfw image onto the NdtBox target chip (ChipSea Fxx) over IIC."""
|
|
312
|
+
cli_script = os.path.join(REPO_ROOT, "tools", "ndtdbg_cli.py")
|
|
313
|
+
cmd = [PYTHON_EXE, cli_script, "flash-bin", "--file", str(args.get("file_path")),
|
|
314
|
+
"--erase-ms", str(int(args.get("erase_ms", 2000)))]
|
|
315
|
+
if args.get("confirm"):
|
|
316
|
+
cmd.append("--confirm")
|
|
317
|
+
_ndtdbg_reg_args(args, cmd)
|
|
318
|
+
timeout_s = min(max(int(args.get("timeout_seconds", 300)), 30), 900)
|
|
319
|
+
return run_process(cmd, timeout=timeout_s)
|
|
320
|
+
|
|
321
|
+
|
|
309
322
|
def handle_fw_ndtdbg_capture_seq(args: Dict[str, Any]) -> Dict[str, Any]:
|
|
310
323
|
"""单次调用内并发: 逻辑分析仪抓取与 NdtBox 寄存器序列同时进行。
|
|
311
324
|
|
|
@@ -1265,6 +1278,47 @@ TOOLS_REGISTRY = {
|
|
|
1265
1278
|
},
|
|
1266
1279
|
"handler": handle_fw_ndtdbg_write_reg,
|
|
1267
1280
|
},
|
|
1281
|
+
"fw_ndtdbg_flash": {
|
|
1282
|
+
"description": "Erase and flash a .bin/.nfw firmware image onto the NdtBox target chip (ChipSea Fxx) over IIC via NdtDebugTool (power-cycle reset into boot -> erase magic AA 55 A5 5A -> 128B page writes -> 256B read-back verify -> finish 'PASs'). DESTRUCTIVE full-chip erase: requires lab.yaml ndtdbg.write_allowed: true AND confirm: true, otherwise PERMISSION_DENIED.",
|
|
1283
|
+
"inputSchema": {
|
|
1284
|
+
"type": "object",
|
|
1285
|
+
"properties": {
|
|
1286
|
+
"file_path": {
|
|
1287
|
+
"type": "string",
|
|
1288
|
+
"description": "Firmware image path (.bin auto-padded to 128-byte alignment with 0xFF; .nfw stripped of its 256-byte header)",
|
|
1289
|
+
},
|
|
1290
|
+
"confirm": {
|
|
1291
|
+
"type": "boolean",
|
|
1292
|
+
"description": "Acknowledge the destructive full-chip erase (double-gated with lab.yaml ndtdbg.write_allowed)",
|
|
1293
|
+
"default": False,
|
|
1294
|
+
},
|
|
1295
|
+
"erase_ms": {
|
|
1296
|
+
"type": "integer",
|
|
1297
|
+
"description": "Erase wait in ms (align with factory UpdateFW: 2000)",
|
|
1298
|
+
"default": 2000,
|
|
1299
|
+
},
|
|
1300
|
+
"timeout_seconds": {
|
|
1301
|
+
"type": "integer",
|
|
1302
|
+
"description": "CLI process timeout; budget ~30s per 64KB image (page writes paced at 30ms)",
|
|
1303
|
+
"default": 300,
|
|
1304
|
+
},
|
|
1305
|
+
"dll_dir": {
|
|
1306
|
+
"type": "string",
|
|
1307
|
+
"description": "NdtDebugTool lib directory containing USBIOX.DLL and usb2io.dll; default from lab.yaml ndtdbg.dll_dir",
|
|
1308
|
+
},
|
|
1309
|
+
"slave_addr": {
|
|
1310
|
+
"type": "string",
|
|
1311
|
+
"description": "IIC slave address (e.g. 0xA0); default from lab.yaml ndtdbg.slave_addr",
|
|
1312
|
+
},
|
|
1313
|
+
"speed": {
|
|
1314
|
+
"type": "integer",
|
|
1315
|
+
"description": "IIC speed 0=20kHz 1=100kHz; default from lab.yaml ndtdbg.iic_speed",
|
|
1316
|
+
},
|
|
1317
|
+
},
|
|
1318
|
+
"required": ["file_path"],
|
|
1319
|
+
},
|
|
1320
|
+
"handler": handle_fw_ndtdbg_flash,
|
|
1321
|
+
},
|
|
1268
1322
|
"fw_ndtdbg_capture_seq": {
|
|
1269
1323
|
"description": "One-call protocol evidence: concurrently runs a NdtBox register write sequence (default 0xBE=01, 0x01=BE 42, poll 0x01, readback 0xBE) and a 3s Saleae/sigrok I2C capture, returning the capture path for fw_logic_decode.",
|
|
1270
1324
|
"inputSchema": {
|
|
@@ -1433,7 +1487,7 @@ def process_request(req: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
|
1433
1487
|
},
|
|
1434
1488
|
"serverInfo": {
|
|
1435
1489
|
"name": "firmwareloop",
|
|
1436
|
-
"version": "0.1.
|
|
1490
|
+
"version": "0.1.7"
|
|
1437
1491
|
}
|
|
1438
1492
|
}
|
|
1439
1493
|
}
|
|
@@ -1525,7 +1579,7 @@ def process_request(req: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
|
1525
1579
|
def handle_cli_update() -> int:
|
|
1526
1580
|
"""Handle `firmwareloop update` command."""
|
|
1527
1581
|
print("============================================================")
|
|
1528
|
-
print(" FirmwareLoop Auto-Updater (v0.1.
|
|
1582
|
+
print(" FirmwareLoop Auto-Updater (v0.1.7)")
|
|
1529
1583
|
print("============================================================")
|
|
1530
1584
|
|
|
1531
1585
|
is_git_repo = os.path.exists(os.path.join(REPO_ROOT, ".git"))
|
|
@@ -1795,7 +1849,7 @@ def set_ndtdbg_dlldir(dll_path: str) -> str:
|
|
|
1795
1849
|
def handle_cli_setup() -> int:
|
|
1796
1850
|
"""Handle `firmwareloop setup` command: simultaneously configure Antigravity CLI, Claude Code CLI, Qoder IDE, and CodeBuddy IDE."""
|
|
1797
1851
|
print("============================================================")
|
|
1798
|
-
print(" FirmwareLoop Multi-Agent Global Setup Helper (v0.1.
|
|
1852
|
+
print(" FirmwareLoop Multi-Agent Global Setup Helper (v0.1.7)")
|
|
1799
1853
|
print("============================================================")
|
|
1800
1854
|
print("")
|
|
1801
1855
|
|
|
@@ -1920,7 +1974,7 @@ def handle_cli_setup() -> int:
|
|
|
1920
1974
|
def handle_cli_init() -> int:
|
|
1921
1975
|
"""Handle `firmwareloop init` command."""
|
|
1922
1976
|
print("============================================================")
|
|
1923
|
-
print(" FirmwareLoop Multi-Agent Project Initializer (v0.1.
|
|
1977
|
+
print(" FirmwareLoop Multi-Agent Project Initializer (v0.1.7)")
|
|
1924
1978
|
print("============================================================")
|
|
1925
1979
|
cwd = os.getcwd()
|
|
1926
1980
|
print(f"[*] Initializing multi-agent guidelines & bench config in:\n {cwd}\n")
|
|
@@ -1941,7 +1995,7 @@ def handle_cli_init() -> int:
|
|
|
1941
1995
|
|
|
1942
1996
|
|
|
1943
1997
|
def print_cli_help() -> None:
|
|
1944
|
-
print("""FirmwareLoop (fwloop) — AI Agent Firmware Engineering & Lab Automation Platform (v0.1.
|
|
1998
|
+
print("""FirmwareLoop (fwloop) — AI Agent Firmware Engineering & Lab Automation Platform (v0.1.7)
|
|
1945
1999
|
|
|
1946
2000
|
Usage:
|
|
1947
2001
|
fwloop [command] (or: firmwareloop [command])
|
|
@@ -1981,7 +2035,7 @@ def main() -> None:
|
|
|
1981
2035
|
sys.exit(2)
|
|
1982
2036
|
sys.exit(handle_cli_ndtdebugtool(args[1]))
|
|
1983
2037
|
elif cmd in ["version", "-v", "--version"]:
|
|
1984
|
-
print("FirmwareLoop v0.1.
|
|
2038
|
+
print("FirmwareLoop v0.1.7")
|
|
1985
2039
|
sys.exit(0)
|
|
1986
2040
|
elif cmd in ["help", "-h", "--help"]:
|
|
1987
2041
|
print_cli_help()
|
|
@@ -92,6 +92,53 @@ def pad_bin_128(file_bytes: bytes) -> bytes:
|
|
|
92
92
|
return file_bytes + b"\xFF" * pad
|
|
93
93
|
|
|
94
94
|
|
|
95
|
+
# ---------------------------------------------------------------------------
|
|
96
|
+
# 固件烧录 (对齐 ChipSea.cs UpdateFW: 断电复位 -> 整片擦除 -> 页写 -> 回读校验 -> 完成魔数)
|
|
97
|
+
# ---------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
FLASH_WRITE_PAGE = 128 # WriteFw 每事务 128 字节负载 (IIC 写共 130B = 2B 页地址 + 负载)
|
|
100
|
+
FLASH_READ_WINDOW = 256 # ReadFwAndCheck 每窗回读 256 字节
|
|
101
|
+
ERASE_MAGIC = b"\xAA\x55\xA5\x5A" # EreaseChipCmd 写 @0x0000
|
|
102
|
+
FINISH_MAGIC = b"\x50\x41\x53\x73" # UpgradeFinishCmd "PASs" 写 @0x0000
|
|
103
|
+
BOOT_READY_MS = 100 # VBRTOFF 上电后到发擦除命令的等待 (UpdateFW Thread.Sleep(100))
|
|
104
|
+
PAGE_WRITE_GAP_MS = 30 # 页写间隔 (WriteFw Thread.Sleep(30))
|
|
105
|
+
PAGE_READ_GAP_MS = 10 # 回读窗口间隔 (ReadFwAndCheck Thread.Sleep(10))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def load_firmware(file_path: str) -> tuple[str, bytes]:
|
|
109
|
+
"""读取固件: .nfw 去 256 头 / .bin 128 对齐 0xFF 补齐 (ChipSea.cs LoadFile)。返回 (类型, 载荷)。"""
|
|
110
|
+
if not os.path.isfile(file_path):
|
|
111
|
+
raise NdtBoxError("CONFIG_ERROR", "固件文件不存在", file_path)
|
|
112
|
+
ext = os.path.splitext(file_path)[1].lower()
|
|
113
|
+
try:
|
|
114
|
+
with open(file_path, "rb") as fh:
|
|
115
|
+
raw = fh.read()
|
|
116
|
+
except OSError as exc:
|
|
117
|
+
raise NdtBoxError("CONFIG_ERROR", "固件文件读取失败", str(exc)) from exc
|
|
118
|
+
if ext == ".nfw":
|
|
119
|
+
return "nfw", strip_nfw(raw)
|
|
120
|
+
if ext == ".bin":
|
|
121
|
+
if not raw:
|
|
122
|
+
raise NdtBoxError("CONFIG_ERROR", ".bin 固件为空", file_path)
|
|
123
|
+
return "bin", pad_bin_128(raw)
|
|
124
|
+
raise NdtBoxError("CONFIG_ERROR", "仅支持 .bin / .nfw 固件文件", ext or "(无后缀)")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def build_page_write_frame(offset: int, page: bytes) -> bytes:
|
|
128
|
+
"""页写帧: 页地址大端 2 字节 + <=128 字节负载 (ChipSea.cs WriteFw 逐页自 0x0000 递增)。"""
|
|
129
|
+
if len(page) > FLASH_WRITE_PAGE:
|
|
130
|
+
raise NdtBoxError("CONFIG_ERROR", "页负载超过 128 字节", str(len(page)))
|
|
131
|
+
if not 0 <= offset <= 0xFFFF:
|
|
132
|
+
raise NdtBoxError("CONFIG_ERROR", "页地址越界 (0..0xFFFF)", hex(offset))
|
|
133
|
+
return offset.to_bytes(2, "big") + page
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def expected_read_window(fw: bytes, offset: int) -> bytes:
|
|
137
|
+
"""回读期望窗口: 256 字节, 末窗不足部分 0xFF 补齐 (ChipSea.cs ReadFwAndCheck)。"""
|
|
138
|
+
window = fw[offset:offset + FLASH_READ_WINDOW]
|
|
139
|
+
return window + b"\xFF" * (FLASH_READ_WINDOW - len(window))
|
|
140
|
+
|
|
141
|
+
|
|
95
142
|
# ---------------------------------------------------------------------------
|
|
96
143
|
# 桥调用层
|
|
97
144
|
# ---------------------------------------------------------------------------
|
|
@@ -156,6 +203,24 @@ class NdtBoxIo:
|
|
|
156
203
|
raise NdtBoxError("CONFIG_ERROR", "写入数据过长 (<=128)", str(len(data)))
|
|
157
204
|
self._bridge("write", RegAddr=reg, Data=data.hex())
|
|
158
205
|
|
|
206
|
+
def raw_write_read(self, write: bytes, read_len: int = 0) -> bytes | None:
|
|
207
|
+
"""原始 IIC 事务 (对齐 IIC.WriteRead): 写 write 字节(不含从机地址) 再读 read_len 字节。
|
|
208
|
+
|
|
209
|
+
覆盖 ChipSea 烧录的多字节地址形态 (页写 130B / 页读 [hi,lo]+256)。
|
|
210
|
+
"""
|
|
211
|
+
if not write:
|
|
212
|
+
raise NdtBoxError("CONFIG_ERROR", "raw 写字节为空", None)
|
|
213
|
+
if 1 + len(write) > 256:
|
|
214
|
+
raise NdtBoxError("CONFIG_ERROR", "raw 写事务过长 (含从机地址须 <=256)", str(len(write)))
|
|
215
|
+
if not 0 <= read_len <= 256:
|
|
216
|
+
raise NdtBoxError("CONFIG_ERROR", "raw 读长度越界 (0..256)", str(read_len))
|
|
217
|
+
data = self._bridge("raw", WriteHex=write.hex(), ReadLen=read_len)
|
|
218
|
+
return bytes.fromhex(data["hex"].replace(" ", "")) if read_len > 0 else None
|
|
219
|
+
|
|
220
|
+
def vbrt_reset(self, off_ms: int = 200) -> dict:
|
|
221
|
+
"""模组断电 off_ms 后恢复上电 (usb2io.dll IO10)——复位进入 IIC boot (IOoperation.VBRTOFF)。"""
|
|
222
|
+
return self._bridge("vbrt", OffMs=off_ms)
|
|
223
|
+
|
|
159
224
|
def close(self) -> dict:
|
|
160
225
|
return self._bridge("close")
|
|
161
226
|
|
|
@@ -220,3 +285,65 @@ class ChipSeaFxx:
|
|
|
220
285
|
raise NdtBoxError("CONFIG_ERROR", "poll 时长必须 > 0", str(duration_ms))
|
|
221
286
|
return self._io._bridge("poll", DurationMs=int(duration_ms), IntervalMs=int(interval_ms),
|
|
222
287
|
ReadyTimeoutMs=int(ready_timeout_ms))
|
|
288
|
+
|
|
289
|
+
# -- 固件烧录 (对齐 ChipSea.cs UpdateFW: 仅芯海 Fxx, 整片擦写) --
|
|
290
|
+
|
|
291
|
+
def flash_bin(self, file_path: str, erase_ms: int = 2000,
|
|
292
|
+
progress=None) -> dict:
|
|
293
|
+
"""经 NdtBox IIC 烧录 .bin/.nfw 固件到芯海 Fxx。
|
|
294
|
+
|
|
295
|
+
时序逐行对齐 ChipSea.cs UpdateFW:
|
|
296
|
+
LoadFile -> VBRTOFF(200) 断电复位进 boot -> 100ms -> 擦除魔数 -> erase_ms ->
|
|
297
|
+
逐 128B 页写(30ms 间隔) -> 200ms -> 逐 256B 窗回读校验(10ms 间隔) ->
|
|
298
|
+
完成魔数 "PASs" -> VBRTOFF(200) 复位加载新固件。
|
|
299
|
+
|
|
300
|
+
progress(phase, done, total) 在 write/verify 阶段回调。
|
|
301
|
+
校验不匹配抛 TARGET_MISMATCH (Fail-Closed, 不伪造成功)。
|
|
302
|
+
"""
|
|
303
|
+
import time
|
|
304
|
+
|
|
305
|
+
fw_type, fw = load_firmware(file_path)
|
|
306
|
+
started = time.monotonic()
|
|
307
|
+
pages = [fw[i:i + FLASH_WRITE_PAGE] for i in range(0, len(fw), FLASH_WRITE_PAGE)]
|
|
308
|
+
windows = list(range(0, len(fw), FLASH_READ_WINDOW))
|
|
309
|
+
|
|
310
|
+
self._io.vbrt_reset(200)
|
|
311
|
+
time.sleep(BOOT_READY_MS / 1000.0)
|
|
312
|
+
self._io.raw_write_read(b"\x00\x00" + ERASE_MAGIC, 0)
|
|
313
|
+
time.sleep(0.010)
|
|
314
|
+
time.sleep(erase_ms / 1000.0)
|
|
315
|
+
|
|
316
|
+
for i, page in enumerate(pages):
|
|
317
|
+
self._io.raw_write_read(build_page_write_frame(i * FLASH_WRITE_PAGE, page), 0)
|
|
318
|
+
time.sleep(PAGE_WRITE_GAP_MS / 1000.0)
|
|
319
|
+
if progress:
|
|
320
|
+
progress("write", i + 1, len(pages))
|
|
321
|
+
|
|
322
|
+
time.sleep(0.200)
|
|
323
|
+
for i, off in enumerate(windows):
|
|
324
|
+
expect = expected_read_window(fw, off)
|
|
325
|
+
got = self._io.raw_write_read(off.to_bytes(2, "big"), FLASH_READ_WINDOW)
|
|
326
|
+
if got != expect:
|
|
327
|
+
diff = next(k for k in range(FLASH_READ_WINDOW) if got[k] != expect[k])
|
|
328
|
+
raise NdtBoxError(
|
|
329
|
+
"TARGET_MISMATCH",
|
|
330
|
+
f"烧录校验失败 @0x{off + diff:04X}",
|
|
331
|
+
f"expect={expect[diff:diff + 8].hex()} got={got[diff:diff + 8].hex()}")
|
|
332
|
+
time.sleep(PAGE_READ_GAP_MS / 1000.0)
|
|
333
|
+
if progress:
|
|
334
|
+
progress("verify", i + 1, len(windows))
|
|
335
|
+
|
|
336
|
+
self._io.raw_write_read(b"\x00\x00" + FINISH_MAGIC, 0)
|
|
337
|
+
time.sleep(0.010)
|
|
338
|
+
self._io.vbrt_reset(200)
|
|
339
|
+
|
|
340
|
+
return {
|
|
341
|
+
"file": file_path,
|
|
342
|
+
"file_type": fw_type,
|
|
343
|
+
"fw_len": len(fw),
|
|
344
|
+
"pages_written": len(pages),
|
|
345
|
+
"read_windows": len(windows),
|
|
346
|
+
"erase_ms": erase_ms,
|
|
347
|
+
"verify": "pass",
|
|
348
|
+
"duration_ms": int((time.monotonic() - started) * 1000),
|
|
349
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# 输出: stdout 单行 JSON {ok, action, data} 或 {ok:false, error_class, error, detail}。
|
|
5
5
|
param(
|
|
6
6
|
[Parameter(Mandatory = $true)]
|
|
7
|
-
[ValidateSet("open", "read", "write", "version", "connect", "poll", "close")]
|
|
7
|
+
[ValidateSet("open", "read", "write", "version", "connect", "poll", "close", "raw", "vbrt")]
|
|
8
8
|
[string]$Action,
|
|
9
9
|
|
|
10
10
|
[string]$DllDir,
|
|
@@ -16,6 +16,11 @@ param(
|
|
|
16
16
|
[int]$Len = 1,
|
|
17
17
|
[string]$Data = "", # 十六进制字符串, 空格或连续皆可: "A5 01 02"
|
|
18
18
|
|
|
19
|
+
[string]$WriteHex = "", # raw: 写事务字节 (不含从机地址, 桥负责前置), 对齐 IIC.WriteRead(wBuf[0]=slave)
|
|
20
|
+
[int]$ReadLen = 0, # raw: 读字节数 (0=纯写)
|
|
21
|
+
|
|
22
|
+
[int]$OffMs = 200, # vbrt: 模组断电时长 ms (IO10 拉高), 结束后恢复上电
|
|
23
|
+
|
|
19
24
|
[int]$DurationMs = 1000, # poll 时长
|
|
20
25
|
[int]$IntervalMs = 10, # poll 采样间隔
|
|
21
26
|
[int]$ReadyTimeoutMs = 2000 # poll 数据就绪轮询超时
|
|
@@ -55,6 +60,16 @@ namespace STDataCollection {
|
|
|
55
60
|
[DllImport("USBIOX.DLL", CallingConvention = CallingConvention.StdCall)]
|
|
56
61
|
public static extern bool USBIO_StreamI2C(uint iIndex, uint iWriteLength, IntPtr iWriteBuffer, uint iReadLength, IntPtr oReadBuffer);
|
|
57
62
|
}
|
|
63
|
+
public static class U2io {
|
|
64
|
+
[DllImport("USB2IO.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
|
|
65
|
+
public static extern IntPtr USB2IO_Open(int Nbr);
|
|
66
|
+
[DllImport("USB2IO.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
|
|
67
|
+
public static extern int USB2IO_SetIoCfg(IntPtr h, int IoNbr, int IoCfg);
|
|
68
|
+
[DllImport("USB2IO.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
|
|
69
|
+
public static extern int USB2IO_SetIoOut(IntPtr h, int IoNbr, int IoOut);
|
|
70
|
+
[DllImport("USB2IO.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
|
|
71
|
+
public static extern int USB2IO_Close(IntPtr h);
|
|
72
|
+
}
|
|
58
73
|
}
|
|
59
74
|
"@
|
|
60
75
|
}
|
|
@@ -228,6 +243,34 @@ try {
|
|
|
228
243
|
Write-Output (@{ ok = $true; action = "poll"; data = @{ frame_count = $frames.Count; checksum_errors = $checksumErrors; ready_timeouts = $deadFrames; interval_ms = $IntervalMs; frames = $frames } } | ConvertTo-Json -Compress -Depth 6)
|
|
229
244
|
exit 0
|
|
230
245
|
}
|
|
246
|
+
"raw" {
|
|
247
|
+
# 对齐 ChipSea.cs 的多字节地址事务: 写 [slave, wBuf...] 再读 ReadLen 字节 (IIC.WriteRead 语义)
|
|
248
|
+
$wb = Parse-Hex $WriteHex
|
|
249
|
+
if ($wb.Count -eq 0) { Fail "CONFIG_ERROR" "raw 需要 -WriteHex (不含从机地址的写事务字节)" $null }
|
|
250
|
+
if (($wb.Count + 1) -gt 256) { Fail "CONFIG_ERROR" "raw 写事务过长 (含从机地址须 <=256)" $wb.Count }
|
|
251
|
+
if ($ReadLen -lt 0 -or $ReadLen -gt 256) { Fail "CONFIG_ERROR" "raw -ReadLen 越界 (0..256)" $ReadLen }
|
|
252
|
+
$h = Open-Device 0
|
|
253
|
+
$rb = New-Object byte[] $ReadLen
|
|
254
|
+
if (-not (Invoke-WriteRead $h $wb $rb)) { Fail "TARGET_MISMATCH" ("IIC raw 事务无应答 (w={0}B r={1}B)" -f $wb.Count, $ReadLen) (($wb | ForEach-Object { $_.ToString("X2") }) -join " ") }
|
|
255
|
+
[STDataCollection.Icb]::USBIO_CloseDevice([uint32]0) | Out-Null
|
|
256
|
+
$dataOut = @{ written = $wb.Count; read = $ReadLen }
|
|
257
|
+
if ($ReadLen -gt 0) { $dataOut.hex = (($rb | ForEach-Object { $_.ToString("X2") }) -join " ") }
|
|
258
|
+
Write-Output (@{ ok = $true; action = "raw"; data = $dataOut } | ConvertTo-Json -Compress -Depth 4)
|
|
259
|
+
exit 0
|
|
260
|
+
}
|
|
261
|
+
"vbrt" {
|
|
262
|
+
# 模组供电脚 (IO10) 对齐 IOoperation.VBRTON/VBRTOFF: usb2io.dll 设备号 1, IO10 配置 3=输出, 1=断电 0=上电
|
|
263
|
+
$h2 = [STDataCollection.U2io]::USB2IO_Open(1)
|
|
264
|
+
if ([int]$h2 -eq -1) { Fail "PROBE_NOT_FOUND" "USB2IO 打开失败 (设备 1); 确认 DllDir 含 usb2io.dll 且 NdtBox 已连接" $null }
|
|
265
|
+
[STDataCollection.U2io]::USB2IO_SetIoCfg($h2, 10, 3) | Out-Null
|
|
266
|
+
[STDataCollection.U2io]::USB2IO_SetIoOut($h2, 10, 1) | Out-Null
|
|
267
|
+
Start-Sleep -Milliseconds $OffMs
|
|
268
|
+
[STDataCollection.U2io]::USB2IO_SetIoOut($h2, 10, 0) | Out-Null
|
|
269
|
+
Start-Sleep -Milliseconds 50
|
|
270
|
+
[STDataCollection.U2io]::USB2IO_Close($h2) | Out-Null
|
|
271
|
+
Write-Output (@{ ok = $true; action = "vbrt"; data = @{ off_ms = $OffMs; powered_on = $true } } | ConvertTo-Json -Compress -Depth 4)
|
|
272
|
+
exit 0
|
|
273
|
+
}
|
|
231
274
|
}
|
|
232
275
|
} catch {
|
|
233
276
|
Fail "UNKNOWN_ERROR" "bridge 异常: $($_.Exception.Message)" $_.ScriptStackTrace
|
|
@@ -135,6 +135,21 @@ def cmd_poll(io: NdtBoxIo, duration_ms: int, interval_ms: int, max_frames: int,
|
|
|
135
135
|
ok("poll", result, log=f"poll({duration_ms}ms, {interval_ms}ms): {len(frames)} frames")
|
|
136
136
|
|
|
137
137
|
|
|
138
|
+
def cmd_flash_bin(io: NdtBoxIo, config: dict, file_path: str, erase_ms: int, confirm: bool) -> None:
|
|
139
|
+
# 烧录 = 整片擦除 + 页写, 破坏性高于 write-reg, 同款双闸门
|
|
140
|
+
if not confirm or not (config.get("ndtdbg") or {}).get("write_allowed", False):
|
|
141
|
+
fail("PERMISSION_DENIED",
|
|
142
|
+
"固件烧录被默认禁止",
|
|
143
|
+
detail="flash-bin 为整片擦写: 需 lab.yaml ndtdbg.write_allowed: true 且 CLI 传 --confirm")
|
|
144
|
+
|
|
145
|
+
def progress(phase: str, done: int, total: int) -> None:
|
|
146
|
+
print(f"[flash-bin] {phase} {done}/{total}", file=sys.stderr, flush=True)
|
|
147
|
+
|
|
148
|
+
result = ChipSeaFxx(io).flash_bin(file_path, erase_ms=erase_ms, progress=progress)
|
|
149
|
+
ok("flash-bin", result,
|
|
150
|
+
log=f"UpdateFW({file_path}): {result['fw_len']}B, {result['pages_written']} pages, verify={result['verify']}")
|
|
151
|
+
|
|
152
|
+
|
|
138
153
|
# --------------------------------------------------------------------------- main
|
|
139
154
|
|
|
140
155
|
def build_parser() -> argparse.ArgumentParser:
|
|
@@ -145,7 +160,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
145
160
|
common.add_argument("--slave-addr", help="IIC 从机地址, 默认 0xA0 (支持 0x 前缀)")
|
|
146
161
|
common.add_argument("--speed", help="IIC 速度 0=20kHz 1=100kHz, 默认 1")
|
|
147
162
|
common.add_argument("--lab-config", help="显式指定 lab.yaml 路径")
|
|
148
|
-
common.add_argument("--confirm", action="store_true", help="write-reg 需与 lab.yaml write_allowed 双确认")
|
|
163
|
+
common.add_argument("--confirm", action="store_true", help="write-reg / flash-bin 需与 lab.yaml write_allowed 双确认")
|
|
149
164
|
sub = p.add_subparsers(dest="cmd", required=True)
|
|
150
165
|
|
|
151
166
|
sub.add_parser("status", parents=[common], help="连通性 + 固件版本 + 模组通断")
|
|
@@ -165,6 +180,12 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
165
180
|
p_poll.add_argument("--interval-ms", type=int, default=10)
|
|
166
181
|
p_poll.add_argument("--max-frames", type=int, default=4, help="非 --full 时保留的帧样本数")
|
|
167
182
|
p_poll.add_argument("--full", action="store_true", help="输出全部帧 (可能较大)")
|
|
183
|
+
|
|
184
|
+
f = sub.add_parser("flash-bin", parents=[common],
|
|
185
|
+
help="烧录 .bin/.nfw 固件 (整片擦写, 默认禁止, 需网关+--confirm)")
|
|
186
|
+
f.add_argument("--file", required=True,
|
|
187
|
+
help="固件文件 (.bin 自动 128 对齐补 0xFF; .nfw 去 256 头)")
|
|
188
|
+
f.add_argument("--erase-ms", type=int, default=2000, help="擦除等待 ms (对齐原厂 2000)")
|
|
168
189
|
return p
|
|
169
190
|
|
|
170
191
|
|
|
@@ -187,6 +208,8 @@ def main(argv=None) -> None:
|
|
|
187
208
|
cmd_write_reg(io, config, args.addr, args.data, args.confirm)
|
|
188
209
|
elif args.cmd == "poll":
|
|
189
210
|
cmd_poll(io, args.duration_ms, args.interval_ms, args.max_frames, args.full)
|
|
211
|
+
elif args.cmd == "flash-bin":
|
|
212
|
+
cmd_flash_bin(io, config, args.file, args.erase_ms, args.confirm)
|
|
190
213
|
else: # pragma: no cover
|
|
191
214
|
fail("CONFIG_ERROR", f"unknown cmd: {args.cmd}")
|
|
192
215
|
except NdtBoxError as exc:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<#
|
|
2
2
|
.SYNOPSIS
|
|
3
|
-
Dual-Tier MCP setup and registration helper (v0.1.
|
|
3
|
+
Dual-Tier MCP setup and registration helper (v0.1.7).
|
|
4
4
|
Inspects installed AI coding agents (Qoder, Claude Code, Antigravity, Cursor)
|
|
5
5
|
and configures global MCP / skills or prints exact registration commands.
|
|
6
6
|
|
|
@@ -242,7 +242,7 @@ if ($Json) {
|
|
|
242
242
|
Write-FwJson ([pscustomobject]$report)
|
|
243
243
|
} else {
|
|
244
244
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
245
|
-
Write-Host " FirmwareLoop Dual-Tier MCP & Agent Setup Helper (v0.1.
|
|
245
|
+
Write-Host " FirmwareLoop Dual-Tier MCP & Agent Setup Helper (v0.1.7)" -ForegroundColor Green
|
|
246
246
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
247
247
|
Write-Host ""
|
|
248
248
|
Write-Host "[1] Google Antigravity / Gemini CLI:" -ForegroundColor Yellow
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|