内容
# 硬件持续集成
**您的AI代理可以独立开发固件 — 因为硬件持续集成(HardCI)通过与真实硬件的闭环交互实现此功能。**
```
+--> 构建 --> 烧录 --> 刺激 --> 观察 --+
| |
+<-------------- 诊断与修复 -----------------+
```
您的代理程序,无需人工干预 — 您只需审查拉取请求
HardCI 是一个Python包,提供了一系列受限的MCP工具,用于探测、烧录、重置、验证固件、串口和CAN总线刺激/反馈、测试适配器、报告和日志 — 而无需给予代理任意的主机或调试器访问权限。项目本地的策略文件(`.hardci/config.yaml`)精确定义了允许的设备、操作、路径和限制。这种策略门控机制使得无人值守的硬件访问成为可能。
## 为什么
在嵌入式开发中,仅仅获得一个“绿色构建”是不够的:固件必须在真实的硬件板上正确运行。经典工具自动化了单个步骤 — 例如,在此处烧录,在那里读取日志 — 但是当需要真实硬件响应时,人又回到了循环中。给代理一个原始的调试器shell或直接的串口访问权限是不安全且不可复制的。HardCI通过一个小型的、可审计的门控机制填补了这一空白:
```
AI 代理 / 持续集成 ──MCP(标准输入/输出)──▶ 硬件持续集成 ──策略检查──▶ OpenOCD / pyOCD / STM32CubeProgrammer
│ 串口(pyserial)
│ CAN总线(PEAK / SocketCAN / 桥接)
▼
结构化结果、报告、日志
```
每个硬件操作都根据项目策略进行验证,执行时带有超时限制,日志记录到 `.hardci/logs/`,并以结构化的JSON结果(`ok`、`error_type`、`summary`、`likely_causes`、`report_path`、`log_path`)回应,代理可以据此采取行动。
## 安装
最简单的途径:告诉您的AI代理
> 从 https://github.com/hp-8472/hardci 安装硬件持续集成(HardCI)并为此项目设置。
代理遵循 [AI_AGENT_QUICKSTART.md](AI_AGENT_QUICKSTART.md) — 所有内容都安装在用户本地,**无需管理员权限**。
手动安装,无需安装任何内容(无需更改`PATH`;需要 [uv](https://docs.astral.sh/uv/) 或 pipx):
```bash
uvx hardci --version # 从PyPI
uvx --from git+https://github.com/hp-8472/hardci hardci --version # 从仓库
```
持久的用户本地安装(推荐用于MCP服务器入口):
```bash
uv tool install hardci # 或:pipx install hardci
hardci init
hardci doctor
hardci mcp-config --output .mcp.json
```
对于直接的PEAK/SocketCAN访问,安装CAN额外包:`uv tool install 'hardci[can]'`。如果出现问题,请参阅 [TROUBLESHOOTING.md](TROUBLESHOOTING.md)。
## MCP 入口
项目本地的 `.mcp.json`:
```json
{
"mcpServers": {
"hardci": {
"command": "hardci",
"args": ["mcp-stdio", "--config", ".hardci/config.yaml"]
}
}
}
```
## 配置
`hardci init` 会生成一个初始的 `.hardci/config.yaml`。该文件是策略 — 它指定了目标、调试器后端、允许的固件根目录、命名的串口和CAN总线,以及每个操作的权限:
```yaml
target:
name: "传感器板"
controller: "stm32f4"
debugger:
type: "openocd" # 或 "pyocd"(大多数Cortex-M目标),或 "stlink"(STM32CubeProgrammer CLI)
interface_cfg: "interface/stlink.cfg"
target_cfg: "target/stm32f4x.cfg"
timeout_s: 60
artifacts:
allowed_roots: ["build"] # 固件只能从此处烧录
allowed_extensions: [".elf", ".hex", ".bin"]
com_ports:
dut_uart:
device: "/dev/ttyACM0"
baudrate: 115200
can_buses:
dut_can:
adapter: "socketcan" # 或 "peak",或 "process" 用于自定义桥接
channel: "can0"
bitrate: 500000
adapters:
ntc_sim: # 传感器/执行器/故障模拟桥接
executable: "examples/adapters/sim_ntc_adapter.py"
channels: ["temperature", "resistance"]
faults: ["open", "short_to_gnd", "short_to_vcc"]
permissions:
allow_flash: true
allow_com_write: true
allow_can_write: true
allow_adapter_write: true
allow_raw_debugger_commands: false
allow_mass_erase: false
```
使用 `hardci schema --output hardci-config.schema.json` 导出完整的JSON模式。
## MCP 工具
| 组 | 工具 | 备注 |
|-------|-------|-------|
| 调试器 | `hardci_debugger_info`, `hardci_probe_target`, `hardci_reset_target` | OpenOCD, pyOCD, 或 STM32CubeProgrammer CLI |
| 固件 | `hardci_flash_firmware`, `hardci_artifact_upload` | 在烧录前验证固件(路径、扩展名、格式、SHA-256) |
| 串口 | `hardci_com_ports_list`, `hardci_com_session_start`, `hardci_com_session_stop`, `hardci_com_write`, `hardci_com_read` | 仅限命名端口,带缓冲的后台读取器 |
| CAN总线 | `hardci_can_buses_list`, `hardci_can_session_start`, `hardci_can_session_stop`, `hardci_can_send`, `hardci_can_read` | PEAK, SocketCAN, 或进程桥接 |
| 测试适配器 | `hardci_adapters_list`, `hardci_adapter_session_start`, `hardci_adapter_session_stop`, `hardci_adapter_set_value`, `hardci_adapter_inject_fault`, `hardci_adapter_clear_fault`, `hardci_adapter_measure` | 通过 [适配器桥接协议](examples/adapters/README.md) 进行传感器/执行器/故障模拟 |
| 诊断 | `hardci_get_last_report`, `hardci_classify_last_error` | 带可能原因的结构化错误分类 |
| 调试会话 | `hardci_debug_*`(启动/停止/状态,断点,继续/暂停,符号信息,内存转储) | 通过OpenOCD后端gdbserver的输入GDB/MI会话;来自 `debug:` 策略部分的符号允许列表和转储大小限制 |
典型的循环:构建固件 → `hardci_flash_firmware` → `hardci_com_session_start` → 通过 `hardci_com_write`/`hardci_can_send`/`hardci_adapter_set_value` 刺激 → 断言 `hardci_com_read`/`hardci_can_read`/`hardci_adapter_measure` → 失败时,`hardci_classify_last_error`。
## 测试适配器
现实世界的固件错误出现在标准实验室工具无法按需重现的电气条件下:打开或短路的传感器,漂移的NTC,缺少负载,弹跳的接触点。`adapters:` 部分将HardCI连接到测试适配器,这些适配器模拟这些状态 — 物理适配器硬件或纯软件模拟器,都使用相同的 [JSON桥接协议](examples/adapters/README.md)。
使用捆绑的NTC模拟器(`examples/adapters/sim_ntc_adapter.py`)的诊断循环示例:烧录固件,将模拟传感器设置为25°C并断言标称行为,注入`open`故障并断言固件报告传感器故障,清除故障并断言恢复 — 每个步骤都是自动的,可复制的,并受策略控制。
## 安全模型
- 代理永远不会获得shell、原始调试器或设备路径 — 只有命名的、配置的资源。
- 固件工件必须位于 `artifacts.allowed_roots` 下,匹配允许的扩展名,通过格式合理性检查,并经过哈希后才能烧录。拒绝路径遍历。
- 每个操作类都有自己的权限开关;`permission_denied` 结果是权威的,代理被指示停止(参见 [AGENTS.md](AGENTS.md))。
- 故意互锁:在启用 `allow_raw_debugger_commands` 或 `allow_mass_erase` 时,拒绝烧录 — 验证的烧录和不受限制的调试器访问是相互排斥的策略。
- 串口/CAN总线写入有大小限制(`max_write_bytes`、`max_frame_data_bytes`);读取有缓冲区限制。调试器调用在超时限制和禁用TCP服务器(OpenOCD `gdb_port`/`tcl_port`/`telnet_port` 禁用);只有输入的调试会话打开 `gdb_port`,绑定到 `localhost` 的临时端口,仅用于该会话,并在会话结束后关闭。
- 测试适配器通道和故障名称是明确的允许列表 — 在到达适配器桥接之前,HardCI拒绝任何未命名的配置。
- 所有操作都记录到 `.hardci/logs/` 并写入 `.hardci/reports/` 的结构化报告。
## pytest 插件
安装 `hardci` 会注册一个pytest插件,因此CI回归套件可以在没有MCP客户端的情况下驱动相同的策略控制工具:
```python
def test_open_sensor_diagnosis(hardci):
started = hardci.call("hardci_adapter_session_start", {"adapter_id": "ntc_sim"})
assert started["ok"] is True
injected = hardci.call("hardci_adapter_inject_fault", {"adapter_id": "ntc_sim", "fault": "open"})
assert injected["ok"] is True
# ... 使用 hardci_com_read 断言固件的反应 ...
```
`hardci` 固定装置加载相对于pytest rootdir的 `.hardci/config.yaml`(使用 `--hardci-config` 或 `hardci_config` ini选项覆盖)。如果不存在配置文件,则跳过测试,但存在无效配置文件会报错 — 配置错误不应在CI中静默禁用硬件套件。测试期间打开的适配器、串口和CAN会话在测试结束后停止,因此刺激状态不会在测试之间泄漏。有关完整的诊断循环示例,请参阅 [examples/pytest/](examples/pytest/),有关真实硬件上的完整循环,请参阅 [examples/nucleo-f446re_demo/](examples/nucleo-f446re_demo/):一个裸金属STM32固件,构建、烧录、重置,并通过其UART启动横幅进行断言。
## 常用命令
```text
hardci init
hardci doctor
hardci com-ports
hardci mcp-config --output .mcp.json
hardci mcp-stdio --config .hardci/config.yaml
hardci com-stdio --config .hardci/config.yaml --port dut_uart
hardci schema --output hardci-config.schema.json
hardci skill-install --agent opencode
```
## 平台支持
Linux、macOS和Windows(在Python 3.10–3.13上进行CI测试)。调试器后端:OpenOCD、pyOCD(`hardci[pyocd]` — 通过CMSIS包和CMSIS-DAP/ST-Link/J-Link探针覆盖大多数ARM Cortex-M目标,设置 `debugger.target_type`),和STM32CubeProgrammer CLI(在Windows上自动发现)。直接CAN访问需要 `hardci[can]`(python-can);任何其他适配器都可以通过 `process` 桥接协议连接。
## 开发
```bash
python -m pip install -e '.[dev]'
ruff check src tests
pytest
python -m build
twine check dist/*
```
该包通过 `.github/workflows/workflow.yml` 中的GitHub信任发布配置用于PyPI发布。
## 安全
策略绕过被视为漏洞 — 参见 [SECURITY.md](SECURITY.md)。
## 许可证
Apache-2.0 — 参见 [LICENSE](LICENSE)。