firmwareloop 0.9.0__tar.gz → 0.9.1__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.9.0 → firmwareloop-0.9.1}/PKG-INFO +5 -3
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/README.md +2 -2
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/firmwareloop.egg-info/PKG-INFO +5 -3
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/firmwareloop.egg-info/SOURCES.txt +4 -1
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/firmwareloop.egg-info/requires.txt +3 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/pyproject.toml +12 -1
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/__init__.py +1 -1
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/fw_mcp_server.py +64 -29
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/setup-agent-mcp.ps1 +2 -2
- firmwareloop-0.9.1/tools/templates/lab.example.yaml +195 -0
- firmwareloop-0.9.1/tools/templates/skill-firmwareloop.md +37 -0
- firmwareloop-0.9.1/tools/templates/skill-fwloop-adapter.md +190 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/LICENSE +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/firmwareloop.egg-info/dependency_links.txt +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/firmwareloop.egg-info/entry_points.txt +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/firmwareloop.egg-info/top_level.txt +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/setup.cfg +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/acceptance-scenario.ps1 +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/build.ps1 +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/can.ps1 +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/check-qoder-mcp.ps1 +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/common/build-backends.psm1 +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/common/fw.psm1 +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/common/uart_probe.py +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/doctor.ps1 +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/flash.ps1 +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/instrument_cli.py +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/lib/__init__.py +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/lib/instruments.py +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/lib/ndtdbg.py +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/lib/serial_assistant.py +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/logic_capture.ps1 +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/logic_decode.ps1 +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/ndtdbg_bridge.ps1 +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/ndtdbg_cli.py +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/reset.ps1 +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/serial_cli.py +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/sigrok_csv_to_fwloop.py +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/test-backends.ps1 +0 -0
- {firmwareloop-0.9.0 → firmwareloop-0.9.1}/tools/test.ps1 +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: firmwareloop
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.1
|
|
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
|
|
@@ -24,6 +24,8 @@ Requires-Dist: pytest>=8.0.0
|
|
|
24
24
|
Requires-Dist: pyocd>=0.36.0
|
|
25
25
|
Requires-Dist: pyyaml>=6.0
|
|
26
26
|
Requires-Dist: agentic-hil>=0.14.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest-xdist>=3.6.0; extra == "dev"
|
|
27
29
|
Dynamic: license-file
|
|
28
30
|
|
|
29
31
|
# FirmwareLoop (`fwloop`)
|
|
@@ -385,7 +387,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
385
387
|
├── demo-firmware/ 示例固件(CMake;宿主编译模拟 MCU,闭环验证载体)
|
|
386
388
|
├── demo-make/ 示例固件(Make;构建测试载体)
|
|
387
389
|
├── docs/ DEPENDENCY_MATRIX / REUSE_PLAN / V0.0.2_GAP_VERIFICATION
|
|
388
|
-
├── pyproject.toml 标准 Python 包配置与 CLI 入口声明 (v0.9.
|
|
390
|
+
├── pyproject.toml 标准 Python 包配置与 CLI 入口声明 (v0.9.1)
|
|
389
391
|
├── .mcp.example.json 双层 MCP 配置模板(firmwareloop + agentic-hil)
|
|
390
392
|
├── AGENTS.md 通用智能体规范(Antigravity / Qoder / Cursor 等)
|
|
391
393
|
├── CLAUDE.md Claude Code CLI 指南
|
|
@@ -395,7 +397,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
395
397
|
|
|
396
398
|
---
|
|
397
399
|
|
|
398
|
-
## 能力验证状态(v0.9.
|
|
400
|
+
## 能力验证状态(v0.9.1)
|
|
399
401
|
|
|
400
402
|
> 状态定义:`Implemented`(已实现)/ `Simulator Validated`(模拟验证)/
|
|
401
403
|
> `Real Hardware Validated`(真机验证)/ `Experimental` / `Not Implemented`
|
|
@@ -357,7 +357,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
357
357
|
├── demo-firmware/ 示例固件(CMake;宿主编译模拟 MCU,闭环验证载体)
|
|
358
358
|
├── demo-make/ 示例固件(Make;构建测试载体)
|
|
359
359
|
├── docs/ DEPENDENCY_MATRIX / REUSE_PLAN / V0.0.2_GAP_VERIFICATION
|
|
360
|
-
├── pyproject.toml 标准 Python 包配置与 CLI 入口声明 (v0.9.
|
|
360
|
+
├── pyproject.toml 标准 Python 包配置与 CLI 入口声明 (v0.9.1)
|
|
361
361
|
├── .mcp.example.json 双层 MCP 配置模板(firmwareloop + agentic-hil)
|
|
362
362
|
├── AGENTS.md 通用智能体规范(Antigravity / Qoder / Cursor 等)
|
|
363
363
|
├── CLAUDE.md Claude Code CLI 指南
|
|
@@ -367,7 +367,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
367
367
|
|
|
368
368
|
---
|
|
369
369
|
|
|
370
|
-
## 能力验证状态(v0.9.
|
|
370
|
+
## 能力验证状态(v0.9.1)
|
|
371
371
|
|
|
372
372
|
> 状态定义:`Implemented`(已实现)/ `Simulator Validated`(模拟验证)/
|
|
373
373
|
> `Real Hardware Validated`(真机验证)/ `Experimental` / `Not Implemented`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: firmwareloop
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.1
|
|
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
|
|
@@ -24,6 +24,8 @@ Requires-Dist: pytest>=8.0.0
|
|
|
24
24
|
Requires-Dist: pyocd>=0.36.0
|
|
25
25
|
Requires-Dist: pyyaml>=6.0
|
|
26
26
|
Requires-Dist: agentic-hil>=0.14.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest-xdist>=3.6.0; extra == "dev"
|
|
27
29
|
Dynamic: license-file
|
|
28
30
|
|
|
29
31
|
# FirmwareLoop (`fwloop`)
|
|
@@ -385,7 +387,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
385
387
|
├── demo-firmware/ 示例固件(CMake;宿主编译模拟 MCU,闭环验证载体)
|
|
386
388
|
├── demo-make/ 示例固件(Make;构建测试载体)
|
|
387
389
|
├── docs/ DEPENDENCY_MATRIX / REUSE_PLAN / V0.0.2_GAP_VERIFICATION
|
|
388
|
-
├── pyproject.toml 标准 Python 包配置与 CLI 入口声明 (v0.9.
|
|
390
|
+
├── pyproject.toml 标准 Python 包配置与 CLI 入口声明 (v0.9.1)
|
|
389
391
|
├── .mcp.example.json 双层 MCP 配置模板(firmwareloop + agentic-hil)
|
|
390
392
|
├── AGENTS.md 通用智能体规范(Antigravity / Qoder / Cursor 等)
|
|
391
393
|
├── CLAUDE.md Claude Code CLI 指南
|
|
@@ -395,7 +397,7 @@ claude mcp remove --scope user agentic-hil
|
|
|
395
397
|
|
|
396
398
|
---
|
|
397
399
|
|
|
398
|
-
## 能力验证状态(v0.9.
|
|
400
|
+
## 能力验证状态(v0.9.1)
|
|
399
401
|
|
|
400
402
|
> 状态定义:`Implemented`(已实现)/ `Simulator Validated`(模拟验证)/
|
|
401
403
|
> `Real Hardware Validated`(真机验证)/ `Experimental` / `Not Implemented`
|
|
@@ -32,4 +32,7 @@ tools/common/uart_probe.py
|
|
|
32
32
|
tools/lib/__init__.py
|
|
33
33
|
tools/lib/instruments.py
|
|
34
34
|
tools/lib/ndtdbg.py
|
|
35
|
-
tools/lib/serial_assistant.py
|
|
35
|
+
tools/lib/serial_assistant.py
|
|
36
|
+
tools/templates/lab.example.yaml
|
|
37
|
+
tools/templates/skill-firmwareloop.md
|
|
38
|
+
tools/templates/skill-fwloop-adapter.md
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "firmwareloop"
|
|
7
|
-
version = "0.9.
|
|
7
|
+
version = "0.9.1"
|
|
8
8
|
description = "AI Agent Firmware Development and Lab Automation Platform (Dual-Tier MCP Server)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [
|
|
@@ -42,9 +42,20 @@ fwloop = "tools.fw_mcp_server:main"
|
|
|
42
42
|
fw-mcp = "tools.fw_mcp_server:main"
|
|
43
43
|
fw = "tools.fw_mcp_server:main"
|
|
44
44
|
|
|
45
|
+
# 开发/验收工具链 (不随 wheel 分发给使用者): 并行跑单测用
|
|
46
|
+
# uv pip install -e ".[dev]"
|
|
47
|
+
# python -m pytest tests/unit -n auto --dist=loadfile
|
|
48
|
+
[project.optional-dependencies]
|
|
49
|
+
dev = [
|
|
50
|
+
"pytest-xdist>=3.6.0",
|
|
51
|
+
]
|
|
52
|
+
|
|
45
53
|
[tool.setuptools.packages.find]
|
|
46
54
|
where = ["."]
|
|
47
55
|
include = ["tools*"]
|
|
48
56
|
|
|
49
57
|
[tool.setuptools.package-data]
|
|
50
58
|
"*" = ["*.ps1", "*.psm1", "*.yaml", "*.md", "*.json"]
|
|
59
|
+
# 随包分发的模板/资源 (v0.9.1): tools/templates/ 下的 lab.yaml 模板与 skill 副本。
|
|
60
|
+
# 仓库根的 lab/ 与 skills/ 不在 wheel 内, 安装态必须靠这些副本 (防漂移测试锁定一致)。
|
|
61
|
+
"tools" = ["templates/*.yaml", "templates/*.md"]
|
|
@@ -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.9.
|
|
3
|
+
fw_mcp_server.py - FirmwareLoop High-Level Workflow & Device MCP Server (v0.9.1).
|
|
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, DeepSeek Harness,
|
|
@@ -817,13 +817,47 @@ def _detect_hardware() -> Dict[str, Any]:
|
|
|
817
817
|
return detected
|
|
818
818
|
|
|
819
819
|
|
|
820
|
+
_PACKAGE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
def _lab_example_template_path() -> str:
|
|
824
|
+
"""lab.yaml 唯一模板定位 (v0.9.1 修复安装态 FileNotFoundError):
|
|
825
|
+
源码仓库态优先 lab/lab.example.yaml (开发真身); wheel 安装态
|
|
826
|
+
(REPO_ROOT=site-packages, 无 lab/ 目录) 回退随包分发的
|
|
827
|
+
tools/templates/lab.example.yaml——两份由防漂移测试逐行锁定一致。"""
|
|
828
|
+
repo = os.path.join(REPO_ROOT, "lab", "lab.example.yaml")
|
|
829
|
+
if os.path.isfile(repo):
|
|
830
|
+
return repo
|
|
831
|
+
return os.path.join(_PACKAGE_DIR, "templates", "lab.example.yaml")
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
def _skill_template_path(name: str) -> Optional[str]:
|
|
835
|
+
"""skill 源文件定位: 源码仓库 skills/<name>/SKILL.md 优先 (skills/ 不随 wheel
|
|
836
|
+
分发), 安装态回退包内 tools/templates/skill-<name>.md; 均缺失返回 None。"""
|
|
837
|
+
repo = os.path.join(REPO_ROOT, "skills", name, "SKILL.md")
|
|
838
|
+
if os.path.isfile(repo):
|
|
839
|
+
return repo
|
|
840
|
+
pkg = os.path.join(_PACKAGE_DIR, "templates", f"skill-{name}.md")
|
|
841
|
+
return pkg if os.path.isfile(pkg) else None
|
|
842
|
+
|
|
843
|
+
|
|
844
|
+
def _project_lab_yaml_path() -> str:
|
|
845
|
+
"""配置写入位置: 源码仓库态 (REPO_ROOT/lab 存在) 写仓库 lab/lab.yaml (工程习惯
|
|
846
|
+
与既有测试锚点不变); 安装态写调用方工程 CWD/lab/lab.yaml (IDE 以工程根为 CWD
|
|
847
|
+
启动 MCP), 避免把配置写进 site-packages 自身。"""
|
|
848
|
+
repo_lab = os.path.join(REPO_ROOT, "lab")
|
|
849
|
+
if os.path.isdir(repo_lab):
|
|
850
|
+
return os.path.join(repo_lab, "lab.yaml")
|
|
851
|
+
return os.path.join(os.getcwd(), "lab", "lab.yaml")
|
|
852
|
+
|
|
853
|
+
|
|
820
854
|
def _build_lab_yaml_from_example(target_dir: str, target_chip: str, build_backend: str,
|
|
821
855
|
detected_dll_dir: Optional[str]) -> str:
|
|
822
856
|
"""P1-5: lab/lab.example.yaml 为唯一模板 (example 加段 init 自动跟上);
|
|
823
857
|
仅替换 project.name/target_chip/build_backend/source_dir 与 dut.uart.port
|
|
824
858
|
(留空 + 注释 "用 fw_scan_hardware 探测", 去掉硬编码 COM3);
|
|
825
859
|
ndtdbg.dll_dir 按探测结果预填, 探测不到保持注释态 + 人工指引。"""
|
|
826
|
-
example_path =
|
|
860
|
+
example_path = _lab_example_template_path()
|
|
827
861
|
with open(example_path, encoding="utf-8") as fh:
|
|
828
862
|
lines = fh.read().splitlines()
|
|
829
863
|
out: List[str] = []
|
|
@@ -871,7 +905,7 @@ def _upgrade_lab_yaml(existing_path: str) -> List[str]:
|
|
|
871
905
|
import yaml as _yaml
|
|
872
906
|
with open(existing_path, encoding="utf-8") as fh:
|
|
873
907
|
existing = _yaml.safe_load(fh) or {}
|
|
874
|
-
example_path =
|
|
908
|
+
example_path = _lab_example_template_path()
|
|
875
909
|
with open(example_path, encoding="utf-8") as fh:
|
|
876
910
|
example = _yaml.safe_load(fh) or {}
|
|
877
911
|
added: List[str] = []
|
|
@@ -1231,8 +1265,8 @@ fw_serial_capture(power_cycle_off_ms=500) # 抓开机日志(窗口内自动
|
|
|
1231
1265
|
|
|
1232
1266
|
|
|
1233
1267
|
def handle_fw_configure_lab(args: Dict[str, Any]) -> Dict[str, Any]:
|
|
1234
|
-
lab_yaml_path =
|
|
1235
|
-
example_yaml_path =
|
|
1268
|
+
lab_yaml_path = _project_lab_yaml_path()
|
|
1269
|
+
example_yaml_path = _lab_example_template_path()
|
|
1236
1270
|
|
|
1237
1271
|
config: Dict[str, Any] = {}
|
|
1238
1272
|
if os.path.exists(lab_yaml_path):
|
|
@@ -2391,7 +2425,7 @@ def process_request(req: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
|
2391
2425
|
},
|
|
2392
2426
|
"serverInfo": {
|
|
2393
2427
|
"name": "firmwareloop",
|
|
2394
|
-
"version": "0.9.
|
|
2428
|
+
"version": "0.9.1"
|
|
2395
2429
|
}
|
|
2396
2430
|
}
|
|
2397
2431
|
}
|
|
@@ -2526,7 +2560,7 @@ def _settle_stashed_entrypoints(stashed) -> None:
|
|
|
2526
2560
|
def handle_cli_update() -> int:
|
|
2527
2561
|
"""Handle `firmwareloop update` command."""
|
|
2528
2562
|
print("============================================================")
|
|
2529
|
-
print(" FirmwareLoop Auto-Updater (v0.9.
|
|
2563
|
+
print(" FirmwareLoop Auto-Updater (v0.9.1)")
|
|
2530
2564
|
print("============================================================")
|
|
2531
2565
|
|
|
2532
2566
|
is_git_repo = os.path.exists(os.path.join(REPO_ROOT, ".git"))
|
|
@@ -3173,7 +3207,7 @@ def set_ndtdbg_dlldir(dll_path: str) -> str:
|
|
|
3173
3207
|
def handle_cli_setup() -> int:
|
|
3174
3208
|
"""Handle `firmwareloop setup` command: simultaneously configure Antigravity CLI, Claude Code CLI, Qoder IDE, CodeBuddy IDE, DeepSeek Harness (DSH), and ZCode IDE."""
|
|
3175
3209
|
print("============================================================")
|
|
3176
|
-
print(" FirmwareLoop Multi-Agent Global Setup Helper (v0.9.
|
|
3210
|
+
print(" FirmwareLoop Multi-Agent Global Setup Helper (v0.9.1)")
|
|
3177
3211
|
print("============================================================")
|
|
3178
3212
|
print("")
|
|
3179
3213
|
|
|
@@ -3288,27 +3322,28 @@ def handle_cli_setup() -> int:
|
|
|
3288
3322
|
print(f" - User MCP: [Warning] Could not write {zc_result['path']}: {zc_result.get('reason')}")
|
|
3289
3323
|
|
|
3290
3324
|
# 7. Global Skills Sync for Antigravity and Claude Code
|
|
3325
|
+
# 源解析 (v0.9.1): 源码仓库 skills/<name>/SKILL.md 优先, 安装态回退包内
|
|
3326
|
+
# tools/templates/skill-<name>.md (skills/ 不随 wheel 分发, 此前安装态静默 0 同步)。
|
|
3327
|
+
print(f"\n[7] Global Skills:")
|
|
3291
3328
|
ag_skills_dir = os.path.join(user_home, ".gemini", "antigravity-cli", "skills")
|
|
3292
3329
|
claude_skills_dir = os.path.join(user_home, ".claude", "skills")
|
|
3293
|
-
source_skills_dir = os.path.join(REPO_ROOT, "skills")
|
|
3294
3330
|
skills_synced = 0
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
print(f"\n[7] Global Skills:")
|
|
3331
|
+
for sk in ["firmwareloop", "fwloop-adapter"]:
|
|
3332
|
+
sk_src = _skill_template_path(sk)
|
|
3333
|
+
if not sk_src:
|
|
3334
|
+
print(f" - {sk}: [Warning] skill 源缺失 (仓库 skills/ 与包内 templates/ 均未找到)")
|
|
3335
|
+
continue
|
|
3336
|
+
try:
|
|
3337
|
+
ag_target = os.path.join(ag_skills_dir, sk)
|
|
3338
|
+
os.makedirs(ag_target, exist_ok=True)
|
|
3339
|
+
shutil.copyfile(sk_src, os.path.join(ag_target, "SKILL.md"))
|
|
3340
|
+
|
|
3341
|
+
cl_target = os.path.join(claude_skills_dir, sk)
|
|
3342
|
+
os.makedirs(cl_target, exist_ok=True)
|
|
3343
|
+
shutil.copyfile(sk_src, os.path.join(cl_target, "SKILL.md"))
|
|
3344
|
+
skills_synced += 1
|
|
3345
|
+
except Exception as exc: # noqa: BLE001
|
|
3346
|
+
print(f" - {sk}: [Warning] {exc}")
|
|
3312
3347
|
print(f" - Synchronized: [OK] {skills_synced} skills (firmwareloop, fwloop-adapter) to Antigravity & Claude Code")
|
|
3313
3348
|
|
|
3314
3349
|
# 8. Machine-level global lab.yaml (ndtdbg config for the globally installed tool)
|
|
@@ -3328,7 +3363,7 @@ def handle_cli_setup() -> int:
|
|
|
3328
3363
|
def handle_cli_init(chip: Optional[str] = None, upgrade: bool = False) -> int:
|
|
3329
3364
|
"""Handle `firmwareloop init [target_chip]` command."""
|
|
3330
3365
|
print("============================================================")
|
|
3331
|
-
print(" FirmwareLoop Multi-Agent Project Initializer (v0.9.
|
|
3366
|
+
print(" FirmwareLoop Multi-Agent Project Initializer (v0.9.1)")
|
|
3332
3367
|
print("============================================================")
|
|
3333
3368
|
cwd = os.getcwd()
|
|
3334
3369
|
print(f"[*] Initializing multi-agent guidelines & bench config in:\n {cwd}\n")
|
|
@@ -3361,7 +3396,7 @@ def handle_cli_init(chip: Optional[str] = None, upgrade: bool = False) -> int:
|
|
|
3361
3396
|
|
|
3362
3397
|
|
|
3363
3398
|
def print_cli_help() -> None:
|
|
3364
|
-
print("""FirmwareLoop (fwloop) — AI Agent Firmware Engineering & Lab Automation Platform (v0.9.
|
|
3399
|
+
print("""FirmwareLoop (fwloop) — AI Agent Firmware Engineering & Lab Automation Platform (v0.9.1)
|
|
3365
3400
|
|
|
3366
3401
|
Usage:
|
|
3367
3402
|
fwloop [command] (or: firmwareloop [command])
|
|
@@ -3407,7 +3442,7 @@ def main() -> None:
|
|
|
3407
3442
|
sys.exit(2)
|
|
3408
3443
|
sys.exit(handle_cli_ndtdebugtool(args[1]))
|
|
3409
3444
|
elif cmd in ["version", "-v", "--version"]:
|
|
3410
|
-
print("FirmwareLoop v0.9.
|
|
3445
|
+
print("FirmwareLoop v0.9.1")
|
|
3411
3446
|
sys.exit(0)
|
|
3412
3447
|
elif cmd in ["help", "-h", "--help"]:
|
|
3413
3448
|
print_cli_help()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<#
|
|
2
2
|
.SYNOPSIS
|
|
3
|
-
Dual-Tier MCP setup and registration helper (v0.9.
|
|
3
|
+
Dual-Tier MCP setup and registration helper (v0.9.1).
|
|
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.9.
|
|
245
|
+
Write-Host " FirmwareLoop Dual-Tier MCP & Agent Setup Helper (v0.9.1)" -ForegroundColor Green
|
|
246
246
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
247
247
|
Write-Host ""
|
|
248
248
|
Write-Host "[1] Google Antigravity / Gemini CLI:" -ForegroundColor Yellow
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# lab/lab.example.yaml - lab configuration template (Spec §6/§9/§20/§24/§25)
|
|
2
|
+
#
|
|
3
|
+
# REAL values (COM ports, probe serials, instrument IPs, fixture IDs, secrets)
|
|
4
|
+
# MUST NEVER be committed. Copy this file to lab/lab.yaml (gitignored) and fill
|
|
5
|
+
# in your bench. Everything here is a placeholder; the default mode is the
|
|
6
|
+
# simulator, which exercises the pipeline without silicon.
|
|
7
|
+
#
|
|
8
|
+
# Copy: Copy-Item lab\lab.example.yaml lab\lab.yaml
|
|
9
|
+
# Check: .\tools\doctor.ps1 -Json
|
|
10
|
+
# Run: .\tools\test.ps1 -Json
|
|
11
|
+
|
|
12
|
+
project:
|
|
13
|
+
name: open-embedder-demo
|
|
14
|
+
# Build backend hint for tools/build.ps1 auto-detection ("cmake", "keil",
|
|
15
|
+
# "iar", "zephyr", "esp-idf", "platformio", "make"). Leave empty for auto.
|
|
16
|
+
build_backend: cmake
|
|
17
|
+
source_dir: demo-firmware
|
|
18
|
+
|
|
19
|
+
# Device under test. UART mode: "simulator" (default, runs the compiled
|
|
20
|
+
# artifact as a subprocess) or "serial" (real COM port via pyserial).
|
|
21
|
+
dut:
|
|
22
|
+
target:
|
|
23
|
+
# Expected probe identity (Spec §9): when a probe is configured, an
|
|
24
|
+
# identity mismatch MUST abort immediately with TARGET_MISMATCH.
|
|
25
|
+
expected_target: null # e.g. "STM32F401RE" when real silicon
|
|
26
|
+
probe_serial: null # e.g. "000123456789"
|
|
27
|
+
reset:
|
|
28
|
+
# Command line used by tools/reset.ps1 / Agentic HIL when configured.
|
|
29
|
+
tool: null # "agentic-hil" | "openocd" | vendor CLI
|
|
30
|
+
uart:
|
|
31
|
+
mode: simulator # "simulator" | "serial"
|
|
32
|
+
port: COM5 # only used when mode=serial
|
|
33
|
+
baud: 115200
|
|
34
|
+
boot_expect: # Spec §11: expect() not sleep()
|
|
35
|
+
- pattern: "Bootloader"
|
|
36
|
+
timeout_ms: 2000
|
|
37
|
+
- pattern: "Application started"
|
|
38
|
+
timeout_ms: 3000
|
|
39
|
+
|
|
40
|
+
# 自研/自定义调试工具接入模板(可通过 fwloop-adapter skill 交互配置)
|
|
41
|
+
custom_tools:
|
|
42
|
+
flash:
|
|
43
|
+
enabled: false
|
|
44
|
+
command: "D:/Tools/my_flasher.exe --target {target_chip} --file {artifact_path}"
|
|
45
|
+
timeout_ms: 60000
|
|
46
|
+
reset:
|
|
47
|
+
enabled: false
|
|
48
|
+
command: "D:/Tools/my_reset.exe --port {uart_port}"
|
|
49
|
+
timeout_ms: 10000
|
|
50
|
+
log_capture:
|
|
51
|
+
enabled: false
|
|
52
|
+
command: "python D:/Tools/my_logger.py --port {uart_port} --out {output_file}"
|
|
53
|
+
timeout_ms: 30000
|
|
54
|
+
|
|
55
|
+
# NdtBox (USB->IIC) 调试/采集配置, 供 tools/ndtdbg_cli.py 使用 (芯海 Fxx 等)。
|
|
56
|
+
# dll_dir 指向 NdtDebugTool 分发包的 lib 目录 (含 USBIOX.DLL/x86-32, 由 32 位 PS 桥加载)。
|
|
57
|
+
# 使用前退出 STDataCollection.exe (USB 独占)。固件升级为二期能力, 本期不含。
|
|
58
|
+
ndtdbg:
|
|
59
|
+
dll_dir: "C:/path/to/NdtDebugTool/lib"
|
|
60
|
+
chip_type: 0 # 0=芯海Fxx 1=ST 2=Maxim 3=AW 4=芯海M68 (本期仅 0)
|
|
61
|
+
slave_addr: "0xA0" # IIC 从机地址 (0=0xA0 1=0x92 2=0xA0 3=0xB8 4=0xE4)
|
|
62
|
+
iic_speed: 1 # 0=20kHz 1=100kHz
|
|
63
|
+
timeout_ms: 60000
|
|
64
|
+
write_allowed: false # write-reg 还需 CLI --confirm 双确认; 保持 false 即永不写
|
|
65
|
+
stream: # fw_ndtdbg_stream 默认值 (均可省略)
|
|
66
|
+
default_interval_ms: 100
|
|
67
|
+
fail_threshold: 50
|
|
68
|
+
# regs: ["0xEE:8:ch"] # 目标数据寄存器表 (未显式传参时的项目级默认; 缺省且调用未传时 Fail-Closed)
|
|
69
|
+
# 协议 profile (产品协议知识沉淀, agent 无需考古固件源码):
|
|
70
|
+
# 纯读轮询 (continuous): 数据源为持续流, 不配 pre_write 即可
|
|
71
|
+
# 请求-响应 (request-response): 每帧先写命令再读, 配 pre_write 序列
|
|
72
|
+
# pre_write: ["0xEC:10"] # 每帧先写 0xEC=10 触发刷新 (请求-响应式产品示例)
|
|
73
|
+
# 交插写压力剖面 (P1-1, 需 write_allowed: true 且 MCP confirm: true):
|
|
74
|
+
# interleave_writes: ["0x56:cycle:00,01,02,03:every=8"] # 每 8 帧轮换写 (并发时序压力)
|
|
75
|
+
# interleave_writes: ["0xBE:once:01:frame=5"] # 第 5 帧写一次
|
|
76
|
+
# write_allowed 属于会话级临时态: true 用完即关, 不建议写入任何常驻配置文件
|
|
77
|
+
|
|
78
|
+
# 产品协议 profile (第三层知识的外置载体; 需根据目标固件协议配置):
|
|
79
|
+
# target_profile:
|
|
80
|
+
# stream_regs: ["0xEE:8:ch"] # stream 目标数据寄存器表 (P0-1)
|
|
81
|
+
# measure_frame: # fw_ndtdbg_measure 的帧解析 (P1-1)
|
|
82
|
+
# data_reg: "0xEE" # 数据帧寄存器
|
|
83
|
+
# checksum: "negated-sum-le16" # 校验算法: none | negated-sum-le16
|
|
84
|
+
# decode: "int16le" # 通道解码: int16le | uint16le | int8 | uint8 | raw
|
|
85
|
+
# min_len: 4 # 最短帧长度 (字节)
|
|
86
|
+
# write_loop: # selftest 写读回环自验序列 (P2-2)
|
|
87
|
+
# addr: "0xBE"
|
|
88
|
+
# write_data: "01"
|
|
89
|
+
# restore_data: "00"
|
|
90
|
+
|
|
91
|
+
# 串口助手 (fw_serial_* 工具族, 供 tools/serial_cli.py 使用) - 长驻会话收发/帧解析/采集。
|
|
92
|
+
# 端口参数均为 fw_serial_open 的缺省值; 会话 JSONL 日志 (带时间戳 RX/TX) 自动落 log_dir。
|
|
93
|
+
serial:
|
|
94
|
+
# port: COM5 # fw_serial_open 缺省端口 - 刻意留空 (Fail-Closed):
|
|
95
|
+
# # 未显式配置时 open real 直接 CONFIG_ERROR, 避免误开未知端口
|
|
96
|
+
baud: 115200
|
|
97
|
+
data_bits: 8
|
|
98
|
+
parity: "N"
|
|
99
|
+
stop_bits: 1
|
|
100
|
+
log_dir: artifacts/serial # 会话日志目录 (相对工程根, 自动创建)
|
|
101
|
+
parser: # fw_serial_parse 默认规则 (超级报文简化, 均可省略)
|
|
102
|
+
mode: none # none | delimiter | fixed_length
|
|
103
|
+
# delimiter: "0D 0A" # HEX 分隔符 (delimiter 模式)
|
|
104
|
+
# fixed_length: 16 # 帧长 (fixed_length 模式)
|
|
105
|
+
checksum: none # none | sum8 | crc16-modbus (帧尾校验)
|
|
106
|
+
fields: [] # [{name, offset, type: u8|i8|u16le|u32le|f32le|hex|text, len}]
|
|
107
|
+
# script: # simulator 后端可编程响应 (单测/离线演示用)
|
|
108
|
+
# - on_rx: "41 54" # 收到 "AT" 前缀时回复 "OK 42", 其余帧默认 echo
|
|
109
|
+
# reply: "4F 4B 20 34 32"
|
|
110
|
+
|
|
111
|
+
# Instruments for tools/instrument_cli.py (Spec §14-16). backend=simulator
|
|
112
|
+
# returns modelled values; backend=visa drives PyVISA/SCPI. Override SCPI
|
|
113
|
+
# commands per instrument when your device differs from the default recipes.
|
|
114
|
+
instruments:
|
|
115
|
+
scope1:
|
|
116
|
+
type: scope
|
|
117
|
+
backend: simulator # switch to "visa" for real hardware
|
|
118
|
+
resource: "TCPIP::192.168.1.50::INSTR" # VISA resource string
|
|
119
|
+
commands:
|
|
120
|
+
measure_frequency: ":MEASure:FREQuency? {ch}"
|
|
121
|
+
psu1:
|
|
122
|
+
type: power_supply
|
|
123
|
+
backend: simulator # switch to "visa" for real hardware
|
|
124
|
+
resource: "USB0::0x1AB1::0x0E11::DP832A0000::INSTR"
|
|
125
|
+
dmm1:
|
|
126
|
+
type: dmm
|
|
127
|
+
backend: simulator
|
|
128
|
+
resource: "USB0::0x1AB1::0x0E11::DM3058::INSTR"
|
|
129
|
+
awg1:
|
|
130
|
+
type: signal_generator
|
|
131
|
+
backend: simulator
|
|
132
|
+
resource: "TCPIP::192.168.1.51::INSTR"
|
|
133
|
+
relay1:
|
|
134
|
+
type: relay
|
|
135
|
+
backend: simulator
|
|
136
|
+
resource: "TCPIP::192.168.1.52::INSTR"
|
|
137
|
+
relay_channel: 1
|
|
138
|
+
|
|
139
|
+
# Simulated measurement values used by backend=simulator (dry runs).
|
|
140
|
+
simulated_measurements:
|
|
141
|
+
scope:
|
|
142
|
+
frequency: 20000.0 # Hz
|
|
143
|
+
duty: 50.0 # %
|
|
144
|
+
vpp: 3.3 # V
|
|
145
|
+
rms: 1.65 # V
|
|
146
|
+
rise_time: 0.000000005 # s
|
|
147
|
+
psu:
|
|
148
|
+
voltage: 3.3 # V
|
|
149
|
+
current: 0.035 # A
|
|
150
|
+
power: 0.1155 # W
|
|
151
|
+
|
|
152
|
+
# Autonomous repair loop policy (Spec §20). Arms the AI agent with hard stops.
|
|
153
|
+
agent_loop:
|
|
154
|
+
max_code_iterations: 3
|
|
155
|
+
max_flash_attempts_per_iteration: 2
|
|
156
|
+
stop_on_hardware_mismatch: true
|
|
157
|
+
stop_on_permission_denied: true
|
|
158
|
+
stop_on_safety_violation: true
|
|
159
|
+
|
|
160
|
+
# Permission model (Spec §24) - documented defaults; enforcement lives in the
|
|
161
|
+
# tools and the AI_DEV_GUIDE AGENT RULES.
|
|
162
|
+
permissions:
|
|
163
|
+
auto_allowed:
|
|
164
|
+
- build
|
|
165
|
+
- probe
|
|
166
|
+
- uart_rx
|
|
167
|
+
- can_rx
|
|
168
|
+
- read_register
|
|
169
|
+
- read_memory
|
|
170
|
+
- logic_capture
|
|
171
|
+
- scope_measure
|
|
172
|
+
- psu_measure
|
|
173
|
+
- pytest
|
|
174
|
+
- report_read
|
|
175
|
+
require_confirmation:
|
|
176
|
+
- flash
|
|
177
|
+
- reset
|
|
178
|
+
- uart_tx
|
|
179
|
+
- can_tx
|
|
180
|
+
- power_cycle
|
|
181
|
+
- relay
|
|
182
|
+
- psu_output
|
|
183
|
+
- awg_output
|
|
184
|
+
permanently_forbidden:
|
|
185
|
+
- mass_erase
|
|
186
|
+
- otp
|
|
187
|
+
- fuse
|
|
188
|
+
- option_bytes
|
|
189
|
+
- rdp
|
|
190
|
+
- secure_boot
|
|
191
|
+
- production_lock
|
|
192
|
+
- signing_key
|
|
193
|
+
- raw_debugger
|
|
194
|
+
- raw_scpi
|
|
195
|
+
- unbounded_voltage_current
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: firmwareloop
|
|
3
|
+
description: FirmwareLoop workflow skill for orchestrating firmware builds (Keil/CMake/Make/etc.), probe detection (ST-LINK/J-Link), interactive lab configuration, pytest HIL testing, I2C/SPI logic analyzer captures, PyVISA instrument measurements, and end-to-end hardware acceptance.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# FirmwareLoop Skill
|
|
7
|
+
|
|
8
|
+
Use this skill when developing, building, testing, or diagnosing embedded firmware within the FirmwareLoop repository.
|
|
9
|
+
|
|
10
|
+
## Capabilities & Tools
|
|
11
|
+
|
|
12
|
+
### Upper-Tier MCP Tools (`firmwareloop`)
|
|
13
|
+
- `fw_doctor`: Run environmental health check.
|
|
14
|
+
- `fw_configure_lab`: Interactively configure or update project parameters, target chip (e.g. STM32F103C8), build backend (e.g. keil), source directory, COM port, and debugger probe in `lab/lab.yaml`.
|
|
15
|
+
- `fw_scan_hardware`: Scan and identify attached hardware debuggers (ST-LINK, J-Link, CMSIS-DAP) and COM ports.
|
|
16
|
+
- `fw_build`: Compile firmware across 7 backends (Keil, CMake, Make, IAR, PlatformIO, Zephyr, ESP-IDF).
|
|
17
|
+
- `fw_flash`: Flash compiled firmware image into target MCU.
|
|
18
|
+
- `fw_reset`: Hardware or software reset of the target MCU.
|
|
19
|
+
- `fw_run_hil_test`: Run 12-item pytest HIL automated testing.
|
|
20
|
+
- `fw_acceptance_scenario`: Execute end-to-end acceptance scenario.
|
|
21
|
+
- `fw_measure`: Query PyVISA/SCPI instrument readings (frequency, duty cycle, Vpp, voltage, current).
|
|
22
|
+
- `fw_logic_capture` / `fw_logic_decode`: Digital protocol capture and verification (I2C, SPI, UART).
|
|
23
|
+
- `fw_get_evidence`: Retrieve audit run artifacts and reports.
|
|
24
|
+
|
|
25
|
+
### Standard CLI Fallback (when MCP is not connected)
|
|
26
|
+
```powershell
|
|
27
|
+
.\tools\doctor.ps1 -Json
|
|
28
|
+
.\tools\build.ps1 -Configuration Debug -Clean -Json
|
|
29
|
+
.\tools\test.ps1 -Json
|
|
30
|
+
.\tools\acceptance-scenario.ps1 -Json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Mandatory Rules
|
|
34
|
+
1. **Real-Hardware-First & Zero Fake Data**: Never fake or mock hardware results. When compilers, debuggers, or MCU targets are missing, fail closed immediately and output explicit error diagnostics and user setup guidance.
|
|
35
|
+
2. **Max 3 Code Iterations**: Never loop infinitely fixing code.
|
|
36
|
+
3. **Fail Closed on Safety**: Never bypass `limits.yaml`.
|
|
37
|
+
4. **Verify Evidence**: Ensure all evidence is captured in `artifacts/runs/<run_id>/`.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fwloop-adapter
|
|
3
|
+
description: 帮助用户将企业自研或第三方 Debug 探针、固件烧录工具、芯片复位脚本、串口/CAN Log 抓取工具或私有协议分析器快速接入 FirmwareLoop。当用户说"接入自研/自定义工具"、"配置私有烧录器"、"使用我们公司的 debug 脚本"或提供 GUI 上位机时触发。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# FirmwareLoop 自定义工具接入 Skill (fwloop-adapter)
|
|
7
|
+
|
|
8
|
+
当用户希望将公司内部自研的烧录器、复位工具、串口抓包脚本或私有硬件调试工具接入 FirmwareLoop 时,遵循以下标准化工程流程与小白用户引导规范。
|
|
9
|
+
|
|
10
|
+
## 适用场景
|
|
11
|
+
1. 用户拥有专属的命令行烧录工具(如 `my_flasher.exe`、`custom_flash.py`、J-Link 内部批处理脚本)。
|
|
12
|
+
2. 用户拥有专用的串口/CAN 抓包与日志采集工具。
|
|
13
|
+
3. 用户拥有私有的板卡供电或复位控制上位机。
|
|
14
|
+
4. **用户只有带界面(GUI)的 exe 上位机软件,不知道如何接入自动化工作流。**
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 面对纯 GUI 上位机软件的专项引导流程(小白友好,先探查后求助)
|
|
19
|
+
|
|
20
|
+
如果用户告知 **“我们只有一个带界面的 exe 上位机软件(需要用鼠标点按钮选择文件、点击下载/抓包),没有命令行”**,Agent **严禁直接报错或直接让用户去找人**,必须按以下**由近及远、先探查本地现场后求助同事的 4 级阶梯流程**主动引导用户:
|
|
21
|
+
|
|
22
|
+
### 阶梯 1:先让用户提供上位机所在文件夹路径(最先执行,探查本地现有资源)
|
|
23
|
+
Agent 首先引导用户提供上位机所在的本地目录:
|
|
24
|
+
> “请把您这个上位机所在的文件夹路径(如 `D:\tools\NdtDebugTool-v1.0.19`)发给我,我先帮您扫描一下目录内部的资源。”
|
|
25
|
+
* **Agent 内部执行动作**:
|
|
26
|
+
1. 扫描同目录下是否存在对应的命令行工具(如 `_cli.exe`、`_console.exe`);
|
|
27
|
+
2. 扫描同目录下是否有使用说明书(`shouce.md`、`readme.txt`、通信协议规范文档);
|
|
28
|
+
3. 扫描同目录下是否有底层通信动态库(如 `lib/USBIOX.DLL`、`FTD2XX.DLL`、`CH341.DLL`)或配置文件(`config.ini`);
|
|
29
|
+
4. 测试运行 `tool.exe --help`、`-h`、`-s` 探测是否存在隐藏的静默命令行开关。
|
|
30
|
+
|
|
31
|
+
### 阶梯 2:基于目录资源或引导用户提供协议/源码,Agent 编写 Python 脚本代打(无需改上位机)
|
|
32
|
+
如果阶梯 1 发现了底层通信库(如 `USBIOX.DLL`、`usb2io.dll`)或协议说明,或者用户能提供单片机端代码:
|
|
33
|
+
> “我在您的上位机目录下发现了底层通信库(如 `lib/USBIOX.DLL`)与使用手册。如果您能提供单片机端的 Bootloader 源码或通信协议,我可以直接为您编写一个纯 Python 脚本,直接与硬件通信完成烧录/抓包,完全不需要再打开那个界面软件!”
|
|
34
|
+
* **Agent 内部执行动作**:
|
|
35
|
+
在 `lab/adapters/` 下编写 Python 驱动脚本(利用 `ctypes` 调用 DLL 或通过串口发包),直接实现标准 JSON 接口,彻底解决接入。
|
|
36
|
+
|
|
37
|
+
### 阶梯 3:如果本地资源完全不足(真正黑盒),再生成对接说明去找上位机开发同事
|
|
38
|
+
只有当阶梯 1 和 2 确认该上位机没有任何文档、没有任何底层库、没有协议且是纯黑盒 GUI 时,Agent 才生成《致上位机开发同事的技术说明函》:
|
|
39
|
+
> “我检查了上位机目录,发现它是一个纯黑盒界面程序,且缺少通信协议。您可以将以下需求直接转发给开发该上位机的同事,请他协助加几行命令行调用支持:”
|
|
40
|
+
```text
|
|
41
|
+
【需求对接】为上位机增加静默命令行调用支持(适配自动化 AI Agent)
|
|
42
|
+
Hi 同事,我们正在引入 FirmwareLoop 自动化工作流。为了能通过终端自动调用您的上位机执行烧录/抓包,需要您协助提供以下轻量支持(任选其一即可):
|
|
43
|
+
1. 方案 A(推荐):在现有上位机程序中,增加启动参数判断(例如 `tool.exe --cli --file <固件路径> --port <COM口>`),当传入这些参数时直接在后台静默执行核心烧录/抓包函数,无需弹出窗口;
|
|
44
|
+
2. 方案 B:直接编译一个对应的控制台版本(如 `tool_cli.exe`);
|
|
45
|
+
3. 方案 C:如果方便,请分享一下上位机通信协议文档或底层通信动态库(DLL / Python SDK)。
|
|
46
|
+
执行要求:成功请 exit(0),失败请 exit(1) 并将报错信息打印至 stdout 或写入 log 文件。感谢支持!
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 阶梯 4:最终兜底方案(UI 自动化 pywinauto 后台点击)
|
|
50
|
+
如果上位机同事也无法修改,且无法获取协议,Agent 基于 `pywinauto` 编写后台自动化脚本模拟点击按钮完成烧录/抓包。
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 引导用户与内部工具开发工程师的对接清单(Checklist)
|
|
55
|
+
|
|
56
|
+
当用户的自研工具缺少 CLI 接口、需要弹窗点击或行为不明确时,**Agent 应当主动提醒并引导用户,向负责开发该工具的内部工程师提供以下 5 大对接需求**:
|
|
57
|
+
|
|
58
|
+
1. **提供无界面的静默命令行接口(Headless / Non-Interactive CLI)**:
|
|
59
|
+
- *说明*:Agent 无法通过屏幕点击 GUI 弹窗,工具必须支持纯命令行调用(如 `tool.exe --flash <固件路径> --chip <芯片型号>` 或提供 Python SDK/脚本),全程无需人工按键交互。
|
|
60
|
+
2. **严格规范退出码(Standard Exit Codes)**:
|
|
61
|
+
- *说明*:如果工具报错了但退出码仍返回 0,Agent 会误判为成功。要求成功时必须 `exit(0)`,任何失败(探针未连、校验失败、超时)必须返回**非 0 退出码**(如 `exit(1)`)。
|
|
62
|
+
3. **标准输出与日志重定向(Stdout / Log File Export)**:
|
|
63
|
+
- *说明*:Agent 需要根据工具打印的报错细节来排查代码。工具应将诊断信息输出到标准输出(stdout/stderr),或支持参数 `--log-file <path>` 导出文件。
|
|
64
|
+
4. **明确动态传参占位符(Parameter Mapping)**:
|
|
65
|
+
- 约定工具接收的参数格式:固件路径(`{artifact_path}`)、芯片型号(`{target_chip}`)、串口号(`{uart_port}`)、波特率(`{baud}`)、探针序列号(`{probe_serial}`)。
|
|
66
|
+
5. **内置操作超时与复位机制(Timeout & Auto-Reset)**:
|
|
67
|
+
- *说明*:工具在目标板卡无响应时需内置超时保护(防止进程死锁挂起 Agent);烧录完成后建议支持可选的自动复位启动(如 `--reset` 参数)。
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 标准化接入流程
|
|
72
|
+
|
|
73
|
+
### 第一步:分析自研工具的接口特征
|
|
74
|
+
先查看或向用户确认该工具的调用方式:
|
|
75
|
+
1. **调用形式**:是可执行文件(`.exe`)、Python 脚本(`.py`)、PowerShell 脚本(`.ps1`)还是 C/C++ 动态链接库。
|
|
76
|
+
2. **入参要求**:
|
|
77
|
+
- 固件烧录类:通常需要目标芯片型号(`{target_chip}`)、固件绝对路径(`{artifact_path}`)、探针序列号(`{probe_serial}`)。
|
|
78
|
+
- 串口/日志类:通常需要 COM 端口号(`{uart_port}`)、波特率(`{baud}`)、日志输出文件(`{output_file}`)、抓取时长(`{duration_ms}`)。
|
|
79
|
+
3. **退出码与输出规范**:
|
|
80
|
+
- 成功时返回退出码 `0`。
|
|
81
|
+
- 失败时返回非 0 退出码,并在 stdout/stderr 打印具体错误原因。
|
|
82
|
+
|
|
83
|
+
### 第二步:选择接入模式并实施
|
|
84
|
+
|
|
85
|
+
#### 模式 A:配置驱动型(针对标准 CLI 工具,最推荐)
|
|
86
|
+
如果用户工具能够直接通过命令行参数完成任务:
|
|
87
|
+
1. 打开或创建 `lab/lab.yaml`。
|
|
88
|
+
2. 在 `custom_tools` 节点下配置命令模板(支持占位符 `{artifact_path}`, `{target_chip}`, `{uart_port}`, `{output_file}`):
|
|
89
|
+
```yaml
|
|
90
|
+
custom_tools:
|
|
91
|
+
flash:
|
|
92
|
+
enabled: true
|
|
93
|
+
command: "D:/MyTools/flasher.exe -c {target_chip} -f {artifact_path}"
|
|
94
|
+
timeout_ms: 60000
|
|
95
|
+
reset:
|
|
96
|
+
enabled: true
|
|
97
|
+
command: "D:/MyTools/reset_tool.exe -p {uart_port}"
|
|
98
|
+
timeout_ms: 10000
|
|
99
|
+
log_capture:
|
|
100
|
+
enabled: true
|
|
101
|
+
command: "python D:/MyTools/logger.py --port {uart_port} --out {output_file}"
|
|
102
|
+
timeout_ms: 30000
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### 模式 B:脚本适配器型(针对复杂参数或前置处理)
|
|
106
|
+
如果自研工具有前置握手、环境依赖或格式转换要求:
|
|
107
|
+
1. 在 `lab/adapters/` 目录下创建轻量包装脚本(例如 `lab/adapters/flash_custom.py` 或 `lab/adapters/flash_custom.ps1`)。
|
|
108
|
+
2. 包装脚本负责:
|
|
109
|
+
- 接收标准参数并调用内部自研工具;
|
|
110
|
+
- 拦截并捕获原始日志,重定向落盘到 `artifacts/logs/`;
|
|
111
|
+
- 输出统一的结构化 JSON(包含 `schema`, `ok`, `error_class`, `log`)。
|
|
112
|
+
|
|
113
|
+
#### 模式 C:并联 MCP 服务型(针对复杂常驻服务或 SDK)
|
|
114
|
+
如果自研工具本身是完整的服务:
|
|
115
|
+
在工程根目录的 `.mcp.json` 中并联注册自研 MCP 服务:
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"mcpServers": {
|
|
119
|
+
"fwloop": {
|
|
120
|
+
"command": "uvx",
|
|
121
|
+
"args": ["firmwareloop"]
|
|
122
|
+
},
|
|
123
|
+
"custom-debug-tool": {
|
|
124
|
+
"command": "python",
|
|
125
|
+
"args": ["D:/MyTools/company_mcp_server.py"]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 第三步:真实物理联调验证(Dry-Run)
|
|
132
|
+
1. 严禁假跑!必须在真实连接硬件的前提下运行一次试运行。
|
|
133
|
+
2. 检查输出日志是否成功写入 `artifacts/logs/`。
|
|
134
|
+
3. 验证返回码与异常拦截机制(例如拔掉 USB 探针后,确认工具能正确报错并被 Agent 捕获)。
|
|
135
|
+
|
|
136
|
+
### 第四步:交付与提示
|
|
137
|
+
向用户展示配置位置,并说明后续在对话中可以直接使用自然语言调度:
|
|
138
|
+
- “*使用我们公司的烧录工具把固件刷入芯片*”
|
|
139
|
+
- “*启动自研抓包工具采集 5 秒串口日志*”
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 可选手法:目标侧"只读诊断插桩"(通用模式)
|
|
144
|
+
|
|
145
|
+
**适用**:目标固件"挂死 / 反复重启",没有可用串口输出(或写通道不可用),但工具族能读寄存器。
|
|
146
|
+
思路:让固件把**运行痕迹暴露成只读寄存器**,Agent 一次读回即可定位阶段与崩溃现场,
|
|
147
|
+
不必"改一处 → 烧一次 → 猜一次"。
|
|
148
|
+
|
|
149
|
+
> **⚠️ 归属规则(先看这条)**:本 skill 会**随包分发**(`fwloop init` / `fwloop setup` 会把它
|
|
150
|
+
> 复制到用户工程与各 Agent 的 skills 目录),因此**这里只放与具体项目、具体芯片无关的通用内容**。
|
|
151
|
+
> 每个项目的**地址约定、寄存器含义、现场案例属于项目资产**,请记录到:
|
|
152
|
+
> - 该项目仓库内的 `docs/<project>-probe-convention.md`,或该项目自建的 project skill;
|
|
153
|
+
>
|
|
154
|
+
> 本 skill 负责教你**怎么设计**这套插桩、以及**记录到哪里**,不承载任何单一项目的约定。
|
|
155
|
+
|
|
156
|
+
### 通用模式(由粗到细四件套)
|
|
157
|
+
|
|
158
|
+
1. **阶段编号**:最后到达的启动边界;
|
|
159
|
+
2. **阶段追踪环**:最近 N 步的环形缓冲(看清"路径",而不只是终点);
|
|
160
|
+
3. **计数器组**:主循环迭代数、可疑等待循环的自旋计数、崩溃现场(fault 状态字 / PC / LR / xPSR);
|
|
161
|
+
4. **运行时可调"停靠级别"**:写后断电即可逐级二分崩溃点。
|
|
162
|
+
|
|
163
|
+
### 通用约束(与芯片无关,都是踩出来的)
|
|
164
|
+
|
|
165
|
+
1. 插桩数组放 **NOINIT** 段:复位/软复位不清零,才看得到"重启前最后执行到哪";
|
|
166
|
+
2. 尽量**只读注册**,不要占用可写寄存器语义;
|
|
167
|
+
3. 注册表必须按**地址升序**:乱序会导致从机自检失败 / 初始化提前 `return`
|
|
168
|
+
⇒ 通信通道根本没起来,现象与"目标掉电"完全一样(极易误判);
|
|
169
|
+
4. **避开厂商协议占用的地址**:例——烧录工具会往某个固定地址写擦除/完成魔数,
|
|
170
|
+
插桩变量放在那里会污染工具的判据;
|
|
171
|
+
5. 采集遵守工具族的协议约束(升序读、单次长度上限、关键字节双读校验——见各工具描述);
|
|
172
|
+
6. 插桩代码用 `#if` 开关包裹:关闭时零成本、零 RAM。
|
|
173
|
+
|
|
174
|
+
### 固件侧两条"已知良方"(与芯片无关)
|
|
175
|
+
|
|
176
|
+
1. **"通道先行"**:把"能被工具读到的通道"(I2C 从机 / 串口)初始化提到所有可疑初始化**之前**
|
|
177
|
+
⇒ 之后无论哪里崩,设备仍然可读(把它写在最后,往往会被插桩本身锁死);
|
|
178
|
+
2. **fault handler 禁止裸自旋**(`B .`):其优先级高于一切可配置中断,死等会饿死通信中断,
|
|
179
|
+
目标"从总线上消失"(工具侧表现为 `BUS_TIMEOUT`)⇒ 应"记录现场 + 复位"。
|
|
180
|
+
(进阶手法"改写异常返回地址 → 恢复函数 → 重建通道 → 停靠"与芯片强相关,换目标需复测。)
|
|
181
|
+
|
|
182
|
+
### 最小闭环(通用)
|
|
183
|
+
|
|
184
|
+
```text
|
|
185
|
+
fw_ndtdbg_power_cycle(off_ms=500) # 复位(不需 write_allowed)
|
|
186
|
+
fw_ndtdbg_status # 分级结论 + 判据表
|
|
187
|
+
fw_ndtdbg_read_reg(reg=..., len=...) # 读"项目约定文档"里定义的诊断寄存器
|
|
188
|
+
fw_ndtdbg_flash(...) # 改完固件自助烧录(含烧后冷启动冒烟)
|
|
189
|
+
fw_serial_capture(power_cycle_off_ms=500) # 抓开机日志(窗口内自动复位)
|
|
190
|
+
```
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|