功能概述
本文档描述了 NES 游戏模拟器的蓝牙手柄控制功能改造。通过 BluFi 协议,微信小程序可以作为虚拟手柄连接 ESP32 设备,控制 NES 游戏。
主要功能
- 蓝牙虚拟手柄:通过 BluFi BLE 协议发送按键信号
- 双玩家支持:支持两个玩家同时游戏
- 网络自动切换:进入游戏时暂停 WiFi、启动 BluFi;退出时自动恢复
- 物理按键备用:GPIO10 A 键作为物理输入备用
- 按键超时保护:断线或超时自动释放按键
架构设计
模块结构
main/game/
├── nes_button_bridge.h/cc # 按键桥梁:接收蓝牙事件,提供按键状态
├── nes_network_manager.h/cc # 网络管理:WiFi/BluFi 切换
└── game_manager.h/cc # 游戏管理:NES 模拟器控制
main/boards/common/
└── blufi.cpp # BluFi 协议处理:解析 nes_btn 命令
main/boards/rymcu-bigsmart/
└── rymcu_bigsmart_nes.cc # NES 游戏入口:网络切换和按键获取
数据流程
┌─────────────────┐ BluFi BLE ┌─────────────────┐
│ 微信小程序 │ ──────────────→ │ ESP32-S3 │
│ (虚拟手柄UI) │ nes_btn协议 │ │
└─────────────────┘ └────────┬────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ BluFi 模块 │
│ ESP_BLUFI_EVENT_RECV_CUSTOM_DATA │
│ ↓ 解析 nes_btn 协议 │
│ ↓ 调用 NesButtonBridge::HandleButtonEvent() │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ NesButtonBridge (按键桥梁) │
│ - 维护玩家按键状态 ButtonState[2] │
│ - 线程安全的状态管理 │
│ - 提供 GetButtonState(player) 接口 │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ GameManager (游戏管理) │
│ - 获取按键状态,传递给 NES 模拟器 │
│ - 支持双玩家控制器 │
└─────────────────────────────────────────────────────────┘
状态流转
┌──────────────┐ 长按Boot 3s ┌──────────────┐
│ │ ─────────────────→ │ │
│ Idle 状态 │ │ 游戏菜单 │
│ WiFi 连接 │ │ WiFi 暂停 │
│ BluFi 关闭 │ │ BluFi 开启 │
│ │ ←───────────────── │ │
└──────────────┘ Select+Start退出 └──────────────┘
命令示例
nes_btn:1:press:01 # 玩家1 按下 A 键
nes_btn:1:release:01 # 玩家1 松开 A 键
nes_btn:1:state:41 # 玩家1 状态同步 (A + 右键)
nes_btn:2:press:10 # 玩家2 按下 上键
nes_btn:1:press:03 # 玩家1 同时按下 A+B 键
nes_btn:1:release:FF # 玩家1 松开所有键
nes_btn:2:state:00 # 玩家2 清零所有按键
代码改动说明
新增文件
1. nes_button_bridge.h
按键桥梁头文件,定义了:
NesButtonState- 按键状态结构体NesButtonEvent- 按键事件结构体NesButtonEventType- 事件类型枚举NesButtonBridge- 按键桥梁类
2. nes_button_bridge.cc
按键桥梁实现:
Initialize()- 初始化互斥锁HandleButtonEvent()- 处理蓝牙按键事件GetButtonState()- 获取指定玩家按键状态ClearAllButtons()- 清零所有按键(BLE断开时调用)CheckButtonTimeout()- 检查按键超时
3. nes_network_manager.h
网络管理器头文件,定义了:
NesNetworkManager- 游戏网络管理类NesNetworkModeCallback- 网络模式变化回调
4. nes_network_manager.cc
网络管理器实现:
EnterGameNetworkMode()- 进入游戏网络模式(暂停WiFi,启动BluFi)ExitGameNetworkMode()- 退出游戏网络模式(关闭BluFi,恢复WiFi)PauseWifi()/ResumeWifi()- WiFi 控制StartBlufi()/StopBlufi()- BluFi 控制
修改文件
1. blufi.cpp
改动内容:
- 添加头文件引用
nes_button_bridge.h和nes_network_manager.h - 在
ESP_BLUFI_EVENT_RECV_CUSTOM_DATA中添加nes_btn协议解析 - 在
ESP_BLUFI_EVENT_BLE_DISCONNECT中清零按键状态
2. rymcu_bigsmart_nes.cc
改动内容:
- 添加头文件引用
nes_button_bridge.h和nes_network_manager.h TryEnterGameMode()调用NesNetworkManager::EnterGameNetworkMode()NesGameTask()从NesButtonBridge获取按键状态- 退出时调用
NesNetworkManager::ExitGameNetworkMode()
3. game_manager.h
改动内容:
- 添加
HandleButtonInput(int player, const ButtonState& state)重载方法 - 修改
ProcessGameInput签名支持玩家参数
4. game_manager.cc
改动内容:
- 实现
HandleButtonInput(int player, ...)多玩家版本 ProcessGameInput支持设置不同玩家的控制器
5. CMakeLists.txt
改动内容:
- 添加
game/nes_button_bridge.cc - 添加
game/nes_network_manager.cc
使用方法
进入游戏模式
- 设备处于 Idle 待机状态
- 长按 Boot 按钮 3 秒
- 设备自动:
- 暂停 WiFi 连接
- 启动 BluFi BLE 广播
- 显示游戏 ROM 选择菜单
小程序连接
- 微信小程序扫描蓝牙设备
- 连接设备(设备名包含 "Xiaozhi" 或 "BLUFI")
- 连接成功后即可发送按键命令
退出游戏模式
- 在游戏菜单中按 Select + Start
- 设备自动:
- 关闭 BluFi
- 恢复 WiFi 连接
- 返回主界面
容错机制
按键超时
- 超时时间:1 秒
- 触发条件:超过 1 秒无按键更新
- 处理方式:自动清零所有按键状态
- 配置方法:
NesButtonBridge::SetButtonTimeout(ms)
蓝牙断开
- 触发事件:
ESP_BLUFI_EVENT_BLE_DISCONNECT - 处理方式:自动清零所有玩家按键状态
- 用户体验:游戏暂停,显示"手柄已断开"
网络恢复
- 退出游戏时自动恢复 WiFi
- 如果恢复失败,设备进入 Idle 状态
- WiFi 连接信息在进入游戏前保存
日志关键词
# 正常流程
"NesNetworkMgr: Entering game network mode"
"NesNetworkMgr: WiFi paused"
"NesNetworkMgr: BluFi started"
"BLUFI_CLASS: NES button: player=1, event=press, btn=0x01"
# 异常情况
"NesNetworkMgr: Failed to start BluFi"
"NesBtnBridge: Player 1 button timeout, clearing"
版本信息
- 改造日期:2026-04-13
- ESP-IDF 版本:5.5.1
- 目标芯片:ESP32-S3
- 依赖组件:BluFi, WifiManager, GameManager
