版本:v1.0.0 状态:已实现(Python CLI 工具,约 70% 设计覆盖率) 适用范围:C 语言嵌入式工程(STM32 / 51 / ESP32 / Linux / 裸机) 实现路径:.trae/skills/keyflow-integrator/keyflow_integrator.py(1019 行)
1. Skill 定位与目标
Skill 名称:keyflow-integrator
核心能力:让 Agent 在任意嵌入式/C 工程中,一键完成:
设计原则:
- ✅ 零破坏性:不会删除/重写用户代码,仅在必要处追加最小补丁
- ✅ 可回滚:所有修改前自动备份关键文件为 .bak
- ✅ 显式决策:存在歧义时(如引脚选择、按键数量),必须通过对话明确而非猜测
- ✅ 幂等:同一项目多次执行不产生重复代码
2. 输入 / 输出契约
2.1 用户输入(自然语言或结构化描述)
project:
path: /absolute/path/to/project # 用户工程根目录
build_system: make|cmake|keil|iar|other # 构建系统
platform: stm32|51|esp32|linux|baremetal
compiler: armcc|gcc|sdcc|other
button_count: <N> # 按键数量
button_list: # (可选)按键描述列表
– name: "KEY_OK"
pin: "GPIOA,5" # 或自定义描述
active_level: low # low / high
debounce_ms: 15
long_press_ms: 1000
event_handler: "on_ok_pressed" # 业务回调函数名
– …
scan_period_ms: 10 # 主循环扫描周期
features: # 需要启用的扩展模块
– matrix_keypad: {rows: 4, cols: 4} # (可选)矩阵键盘
– exti_driven # (可选)中断驱动
– event_queue # (可选)事件队列
– combo_keys # (可选)组合键
integration_style: table_driven # table_driven(推荐) | manual
code_output_dir: src/app/buttons # 生成文件输出目录
business_hooks: # 业务层回调映射
– event: PRESSED
handler: "app_on_button_pressed(idx)"
– event: LONG_PRESS
handler: "app_on_button_long_press(idx)"
2.2 Skill 输出
files_created:
– /project/src/app/buttons/keyflow_config.h # 按键配置表 + 回调声明
– /project/src/app/buttons/keyflow_integration.c # glue code(初始化 + 扫描循环)
– /project/src/app/buttons/keyflow_port.c # 平台端口实现(GPIO 读写)
– /project/src/app/buttons/README.md # 说明文档(中文,自动生成)
files_modified:
– Makefile 或 CMakeLists.txt # 追加 keyflow 源码路径
– main.c / xxx_init.c # 追加初始化调用
verification:
– build_status: success|failed
– test_output: "7/7 tests passed"
3. 核心流程设计(5 阶段)
阶段 1:项目探查(Exploration)
目标:在不修改任何文件的前提下,识别工程结构与约定。
探查内容:
| 构建系统 | ls *.c Makefile CMakeLists.txt project.uvprojx | 识别为 Make / CMake / Keil |
| 源码目录结构 | find . -name "*.c" -type d | head -30 | src/ app/ main hw/ 等 |
| 头文件目录 | 定位 #include 模式 | #include "stm32f1xx_hal.h" / #include "main.h" |
| GPIO HAL 接口类型 | grep -rn "HAL_GPIO|digitalRead|P1\\s*&\\s*(1|PORT_WritePin" src 等 | 判断 STM32 HAL / Arduino / 51 / ESP-IDF / Linux sysfs |
| 主循环入口 | grep -n "while\\s*(\\s*1\\s*)|main\\s*(" src/main* | 定位扫描代码放入何处 |
| 已有按键代码 | grep -rn "button|key|按键" src/ | 判断是否需要迁移已有按键 |
| 编译器/平台 | 从 Makefile / CMakeLists.txt 中提取 | arm-none-eabi-gcc / sdcc / gcc |
输出:结构化 JSON project_profile.json(仅内存使用,不写文件)
阶段 2:安装(Installation)
目标:把 keyflow 源码按工程约定放置。
安装策略(二选一):
| A. Git 子模块 | Git 仓库已初始化 | git submodule add keyflow 仓库到 third_party/keyflow/ |
| B. 文件拷贝 | 非 Git / 简单工程 | 拷贝 include/button/*.h 和 src/button/*.c 到 third_party/keyflow/ |
安装产物位置约定:
project/
├── third_party/
│ └── keyflow/ ← keyflow 完整仓库或仅需要的文件
│ ├── include/button/*.h
│ └── src/button/*.c
└── src/app/buttons/ ← Skill 生成的 glue code(见阶段 4)
CMake/Makefile 修改策略:
- CMake 工程:在顶层 CMakeLists.txt 追加 add_subdirectory(third_party/keyflow/src/button) 并 target_link_libraries(your_app keyflow::button)(demo 可选项,与 keyflow 当前项目类似)
- Makefile 工程:定义 BUTTON_DIR := third_party/keyflow,在 SRCS += … 追加 $(BUTTON_DIR)/src/button/*.c,并 CFLAGS += -I$(BUTTON_DIR)/include
- Keil/IAR:基于 .uvprojx / .ewp 添加源文件条目(XML 解析/追加)
阶段 3:配置(Configuration)
目标:根据探查结果,生成 keyflow_port.c。
平台判定规则:
| STM32 | 包含 stm32fxxx_hal.h 头文件 | ButtonPort_ReadPin 实现 → HAL_GPIO_ReadPin;GetTickMs → HAL_GetTick |
| 51 单片机 | 包含 reg51.h / stc*.h,且编译器为 sdcc/keil c51 | P1 & (1 << pin) 方式;GetTickMs → 基于定时器 systick |
| ESP32 | 包含 freertos/FreeRTOS.h / driver/gpio.h | gpio_get_level(pin);GetTickMs → xTaskGetTickCount * portTICK_PERIOD_MS |
| Linux | 包含 unistd.h 且无 MCU 头文件 | Linux sysfs GPIO 或 /dev/gpiochipN |
| 裸机 | 以上均不满足 | 生成模板 + extern uint32_t SystemTick; |
引脚抽象约定:
引脚编码 port_pin_code 为 uint16_t,高 8 位为 port(如 A=0, B=1, …),低 8 位为 pin 编号。
阶段 4:对接(Integration)
核心生成策略:
A. 生成配置表(keyflow_config.h + keyflow_integration.c)
/* 示例(STM32) */
static ButtonManager g_keyflow_mgr;
/* 按键配置表 — 从用户输入的 button_list 转换而成 */
static const KeyflowEntry s_keyflow_keys[] = {
{
.cfg = {
.pin = KEYFLOW_MAKE_PIN(KEYFLOW_PORT_A, 5), /* GPIOA,5 */
.active_level = 0, /* 低电平有效 */
.debounce_ms = 15,
.release_debounce_ms = 15,
.long_press_ms = 1000,
.double_click_ms = 250,
.stable_cnt_required = 2,
.long_press_repeat_ms = 0,
},
.name = "KEY_OK",
.on_pressed = app_on_key_ok_pressed,
.on_long_press = app_on_key_ok_long_press,
.on_clicked = app_on_key_ok_clicked,
},
/* … more keys … */
};
/* 统一事件分发回调 */
static void keyflow_event_cb(Button *btn, ButtonEventType ev, void *ud) {
const KeyflowEntry *entry = (const KeyflowEntry *)ud;
switch (ev) {
case BUTTON_EVENT_PRESSED:
if (entry->on_pressed) entry->on_pressed(entry->idx);
break;
case BUTTON_EVENT_LONG_PRESS:
if (entry->on_long_press) entry->on_long_press(entry->idx);
break;
/* … other events … */
}
}
/* 初始化 */
void keyflow_init(void) {
ButtonManager_Init(&g_keyflow_mgr);
for (int i = 0; i < ARRAY_SIZE(s_keyflow_keys); ++i) {
ButtonManager_AddButton(&g_keyflow_mgr,
s_keyflow_keys[i].cfg,
keyflow_event_cb,
&s_keyflow_keys[i]);
}
}
/* 主循环扫描 — 用户在主循环调用 */
void keyflow_task(void) {
ButtonManager_UpdateAuto(&g_keyflow_mgr);
}
B. 矩阵键盘 / 中断驱动 / 事件队列 / 组合键
若用户在 features 中声明启用,分别生成:
| 矩阵键盘 | keyflow_matrix.c | MatrixKeyScanner 初始化 + MatrixKey_Scan 在扫描任务内调用 |
| 中断驱动 | keyflow_exti.c | ExtiButton_OnInterrupt() 在 EXTI ISR 中调用,ExtiButton_Dispatch() 在主循环调用 |
| 事件队列 | keyflow_queue.c | ButtonEventQueue_Push 回调 + 主循环 ButtonEventQueue_Pop |
| 组合键 | keyflow_combo.c | ComboKeyDetector 初始化 + 修饰键掩码匹配表 |
C. 业务层对接
在 business_hooks 中列出的业务函数,生成弱符号(__attribute__((weak)))或 extern 声明,让业务层自行实现:
/* keyflow_integration.h — 业务层需实现的回调 */
extern void app_on_key_ok_pressed(uint8_t idx);
extern void app_on_key_ok_long_press(uint8_t idx);
/* … */
阶段 5:验证(Verification)
验证步骤:
3.6 实现状态对照
| Phase 1: 项目探查 | ✅ 完全实现 | explore_project() 扫描构建系统/平台/GPIO HAL/main 入口 |
| Phase 2: 源码安装 | ✅ 实现 | 支持 copy-local 和 git-submodule 两种方式 |
| Phase 3: 端口生成 | ✅ 完全实现 | 5 个平台模板(STM32/51/ESP32/Linux/baremetal) |
| Phase 4a: 配置表生成 | ✅ 完全实现 | 动态生成按键配置表 + 弱符号回调声明 |
| Phase 4b: 集成代码 | ✅ 完全实现 | 模板包含 init + 循环注册 + 统一事件分发 |
| Phase 4c: 扩展模块 | ✅ 完全实现 | matrix/exti/queue/combo 4 个独立模板 |
| Phase 4d: Demo 示例 | ✅ 完全实现 | mock 端口注入 + 短按/长按自测试 |
| Phase 5: 编译验证 | ⚠️ 部分实现 | Linux/baremetal 执行 gcc 语法检查,其他平台仅文件检查 |
| Phase 0: Git 分支隔离 | ✅ 完全实现 | 自动创建 feature 分支,失败可回滚 |
| CMake/Makefile 修改 | ❌ 未实现 | 需用户手动将生成的 .c 文件添加到编译列表 |
| main.c 注入调用 | ❌ 未实现 | 需用户手动在 main 中添加 keyflow_init() 和 keyflow_task() |
| .bak 备份策略 | ❌ 未实现 | 改用 Git 分支隔离替代 |
| 交互式模式 | ❌ 未实现 | 当前仅支持命令行参数 |
| 幂等性检测 | ⚠️ 部分实现 | 检测已存在目录时警告并覆盖,但不检测重复注册 |
当前版本使用须知:集成完成后,用户需手动完成两步:
3.7 实际文件结构
.trae/skills/keyflow-integrator/
├── SKILL.md # Skill 使用说明
├── keyflow_integrator.py # 核心实现(1019 行)
└── templates/
├── keyflow_config_template.h # 按键配置表模板
├── keyflow_integration_template.c # init + task 集成模板
├── keyflow_port_stm32_template.c # STM32 HAL 端口
├── keyflow_port_51_template.c # 51 单片机端口
├── keyflow_port_esp32_template.c # ESP32 IDF 端口
├── keyflow_port_linux_template.c # Linux sysfs GPIO 端口
├── keyflow_port_baremetal_template.c # 裸机/自定义端口
├── keyflow_matrix_template.c # 矩阵键盘扩展
├── keyflow_exti_template.c # 中断驱动扩展
├── keyflow_queue_template.c # 事件队列扩展
├── keyflow_combo_template.c # 组合键/序列键扩展
└── keyflow_demo_template.c # 最小可运行示例
4. 安全性与幂等性设计
| 重复安装 | third_party/keyflow/ 已存在时跳过安装,仅提示更新 |
| 重复生成 | src/app/buttons/ 已存在时先 .bak 备份再覆盖,或提示用户选择覆盖/跳过 |
| 破坏已有按键实现 | 先扫描 grep -rn "button|key",若已存在按键代码,不删除仅追加补丁:把新实现放在独立目录,并在 README 中说明迁移建议 |
| 路径不完整 | 所有路径相对 project.path |
| Git 未初始化 | B 策略(文件拷贝)自动降级 |
| 平台识别失败 | 生成模板占位符代码 + 在验证阶段提供多平台模板,让用户手动选择 |
| 业务回调不存在 | 弱符号 + 编译链接警告,验证阶段输出缺失列表 |
5. 示例运行流程(伪代码)
┌────────────────────────────────────────────┐
│ 用户输入:"把 keyflow 装到 /my_project" │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ Phase 1: 项目探查(read-only) │
│ – ls /my_project │
│ – grep 构建系统 / GPIO 头文件 / 按键关键字 │
│ 输出: project_profile = { │
│ build_system: cmake, │
│ platform: stm32, │
│ compiler: arm-none-eabi-gcc │
│ } │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ Phase 2: 安装 keyflow │
│ – git submodule add keyflow 到 third_party/│
│ 或: cp keyflow/include/button/*.{h,c} │
│ – CMakeLists.txt 追加 add_subdirectory │
│ 或: Makefile 追加 BUTTON_DIR + CFLAGS │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ Phase 3: 生成端口 │
│ – 生成 keyflow_port.c(基于 platform) │
│ – 生成 keyflow_config.h(按键配置表) │
│ – 生成 keyflow_integration.c(主循环扫描) │
│ – 生成 keyflow_<feature>.c(扩展模块) │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ Phase 4: 业务对接 │
│ – 生成 business_hooks → 弱符号 extern │
│ – 让用户实现业务回调 │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ Phase 5: 验证 │
│ – cmake –build . │
│ – 语法检查 │
│ – 生成验证报告 keyflow_integration_report.md │
└────────────────────────────────────────────┘
│
▼
┌────────────────┐
│ 完成! │
└────────────────┘
6. 文件命名约定(与当前 keyflow 项目保持一致)
| keyflow_config.h | src/app/buttons/ | 按键配置表 + 回调声明 |
| keyflow_port.c | src/app/buttons/ | GPIO 读写 + 时间戳 |
| keyflow_integration.c | src/app/buttons/ | 初始化 + 主循环扫描 |
| keyflow_demo.c | src/app/buttons/ | 最小可运行示例 |
| keyflow_integration_report.md | src/app/buttons/ | 中文验证报告 |
7. 与当前 keyflow 项目的接口映射
| ButtonConfig | keyflow_config.h → 结构体数组 |
| ButtonManager_Init | keyflow_integration.c → keyflow_init() |
| ButtonManager_AddButton | keyflow_integration.c → 循环注册 |
| ButtonManager_UpdateAuto | keyflow_task() |
| MatrixKey_Init / Scan | keyflow_matrix.c → 矩阵键盘 |
| ExtiButton_OnInterrupt / Dispatch | keyflow_exti.c → 中断驱动 |
| ButtonEventQueue_Init / Push / Pop | keyflow_queue.c → 事件队列 |
| ComboKey_Init / Detect | keyflow_combo.c → 组合键 / 序列键 |
8. 错误处理与用户交互策略
| 无法识别构建系统 | 停止并询问 | “你的工程使用什么构建系统?(make/cmake/keil/…)” |
| 无法识别平台 | 停止并询问 | “你的目标硬件平台是?(stm32/51/esp32/linux/baremetal)” |
| button_list 为空 | 询问并生成参考 | “请描述你的按键列表(名称/引脚/有效电平/消抖/长按阈值/回调函数名)”,或默认 3 按键示例 |
| GPIO 语法无法解析 | 把 pin 标记为"需手动确认" | 在报告中列出所有"需手动确认的 pin 映射" |
| 编译失败 | 不修改代码,打印完整编译日志 | “编译失败,错误日志已输出” |
9. 回滚策略
-
每次执行前自动:
- 备份 CMakeLists.txt / Makefile → .bak
- 备份 src/app/buttons/ 若已存在 → .bak/
- 记录操作日志 keyflow_integration.log
-
回滚命令(Skill 可执行):若用户说"撤销刚才的操作",执行 git checkout — <files> 或 mv .bak 文件恢复
10. Skill 元数据
skill:
name: keyflow–integrator
version: 1.0.0
description: 将 keyflow 按键模块安装到目标 C/嵌入式工程,并生成配置表、端口抽象、业务对接代码与验证报告
inputs:
– 项目路径(绝对路径)
– 构建系统(make/cmake/keil/iar/other)
– 平台(stm32/51/esp32/linux/baremetal)
– 按键数量 + 按键描述列表(可选)
– 启用的扩展功能(矩阵/中断/事件队列/组合键)
– 业务回调函数映射(可选)
outputs:
– third_party/keyflow/ 源码
– src/app/buttons/*.{h,c} 业务对接代码
– 修改后的构建文件(CMake/Makefile)
– 中文集成报告 keyflow_integration_report.md
11. 与 keyflow 当前代码的关联
Skill 在生成代码时,严格遵循 keyflow 当前项目中 include/button/button.h 的 API 契约,不做任何 API 扩展或修改。生成的 glue code 仅做三件事:
实际实现中的关键映射:
| ButtonConfig | keyflow_config_template.h → 结构体数组 | keyflow_config_template.h |
| ButtonManager_Init | keyflow_integration_template.c → keyflow_init() | keyflow_integration_template.c |
| ButtonManager_AddButton | 循环注册 + keyflow_event_cb 统一分发 | keyflow_integration_template.c |
| ButtonManager_UpdateAuto | keyflow_task() 中调用 | keyflow_integration_template.c |
| ButtonPort_ReadPin/WritePin/GetTickMs | 5 个平台模板分别实现 | keyflow_port_*.c |
| MatrixKey_* / ExtiButton_* / ButtonEventQueue_* / ComboKey_* | 4 个扩展模块独立实现 | keyflow_*_template.c |
12. 设计确认记录
以下为设计阶段提出的待确认事项及其最终处理结果:
| 1 | Skill 名称 | keyflow-integrator ✅ | 已采用 |
| 2 | 生成文件位置 | src/third_party/keyflow/(源码)+ src/app/buttons/(glue code)✅ | 已调整路径约定 |
| 3 | 业务回调策略 | 弱符号 extern 声明 ✅ | 已实现 |
| 4 | 扩展模块策略 | 用户声明时才生成 ✅ | 已实现(4 个独立模板) |
| 5 | 验证深度 | 仅编译 + 日志输出 ✅ | 已实现(gcc 语法检查) |
| 6 | 备份策略 | Git 分支隔离替代 .bak ✅ | 已实现(feature/keyflow-integration-<timestamp>) |
尚未实现的设计项(待后续版本补充):
- CMake/Makefile 自动修改
- main.c 自动注入 keyflow_init() / keyflow_task()
- 交互式参数收集模式
项目仓库
- GitCode 仓库:https://gitcode.com/AZE-BlackCore/keyflow
免责声明
本文内容仅作为技术研究与学习交流之用,不构成任何形式的产品设计建议、电子工程建议或商业推荐。文中涉及的代码片段、状态机模型、消抖策略等技术方案,基于特定嵌入式场景与硬件条件设计,直接用于生产环境前请务必进行充分的测试与验证。
使用本文内容所导致的任何直接或间接后果(包括但不限于设备损坏、数据丢失、商业损失等),作者及 AZE-BlackCore 不承担任何责任。 请根据你的实际项目需求,结合硬件手册、行业规范与最佳实践进行独立判断和决策。
版权声明:本文版权归 AZE-BlackCore 所有,转载请注明出处。封面与示意图由 AI 生成,仅供示意参考。
