fix(nginx): 调整企业微信回调代理路径 feat(gateway): 添加企业微信消息处理功能 docs: 更新项目规划文档和企业微信配置详情 refactor(XCamera): 重构LED检测和图像处理逻辑 test: 添加ONVIF抓图测试功能
441 lines
10 KiB
Markdown
441 lines
10 KiB
Markdown
# ESP32 虚拟键鼠实现方案
|
||
|
||
## 功能目标
|
||
通过 ESP32-S3 模拟键盘按键,实现虚拟键鼠功能
|
||
|
||
---
|
||
|
||
## 技术方案
|
||
|
||
| 方案 | 通信方式 | 延迟 | 适用场景 | 复杂度 |
|
||
|------|----------|------|----------|--------|
|
||
| **USB HID** | USB OTG 有线 | 极低 | 桌面设备、即插即用 | 中等 |
|
||
| **蓝牙 HID** | Bluetooth | 中等 | 移动设备、无线场景 | 较低 |
|
||
| **WiFi HID** | WiFi/UDP/HTTP | 中等 | 远程控制、IoT集成 | 较低 |
|
||
|
||
---
|
||
|
||
## 采用方案:ESP-IDF C + TinyUSB
|
||
|
||
### 开发环境
|
||
- **开发板**:ESP32-S3(支持 USB OTG)
|
||
- **框架**:ESP-IDF(乐鑫官方 C 框架)
|
||
- **USB 库**:TinyUSB(ESP-IDF 内置支持)
|
||
|
||
### 硬件要求
|
||
- ESP32-S3 开发板
|
||
- USB 数据线(ESP32-S3 的 USB 接口)
|
||
|
||
---
|
||
|
||
## ⚠️ 重要注意事项
|
||
|
||
### 问题1:键鼠 + WiFi + 蓝牙同时使用
|
||
|
||
ESP32-S3 支持 **WiFi 和蓝牙同时运行**,但需要注意:
|
||
|
||
| 模式 | WiFi | 蓝牙 | USB HID | 说明 |
|
||
|------|------|------|----------|------|
|
||
| **三模** | ✅ | ✅ | ✅ | 同时运行 |
|
||
| 双模 | ✅ | ❌ | ✅ | WiFi + USB HID |
|
||
| 双模 | ❌ | ✅ | ✅ | 蓝牙 + USB HID |
|
||
|
||
**配置要求:**
|
||
- 开启 WiFi Station 模式
|
||
- 开启 蓝牙 BLE 模式
|
||
- 开启 USB HID 设备模式
|
||
|
||
---
|
||
|
||
### 问题2:Rust 环境隔离(关键!)
|
||
|
||
**问题描述:**
|
||
用户同时进行普通 Rust 应用开发和 ESP32 开发,普通 Rust 使用 `std` target,ESP32 使用 `xtensa` 或 `riscv32` target。如果环境配置不当,会导致 `cargo` 命令冲突。
|
||
|
||
**解决方案:**
|
||
|
||
#### ✅ 推荐:使用 VS Code + esp-idf extension(完全隔离)
|
||
|
||
1. **安装 esp-idf VS Code 插件**
|
||
- 搜索 "Espressif IDF" 安装
|
||
- 自动管理 ESP-IDF 和工具链,不影响系统 Rust
|
||
|
||
2. **配置专用 VS Code 工作区**
|
||
- 为 ESP32 项目创建独立工作区
|
||
- 插件会自动激活 ESP 环境
|
||
|
||
#### ✅ 替代:使用 `espup` 创建独立工具链
|
||
|
||
```bash
|
||
# 安装到指定目录,不污染系统环境
|
||
cargo install espup
|
||
|
||
# 安装 ESP 工具链到指定目录
|
||
espup install -t ~/esp/esp-idf
|
||
|
||
# 在 ESP32 项目中激活(不影响全局)
|
||
source ~/esp/esp-idf/export.sh
|
||
```
|
||
|
||
#### ❌ 避免:不要修改系统默认 Rust
|
||
|
||
```bash
|
||
# 错误做法 - 会影响普通 Rust 开发
|
||
rustup default esp
|
||
|
||
# 正确做法 - 项目级指定 target
|
||
rustup target add xtensa-esp32s3-elf
|
||
cargo build --release -target xtensa-esp32s3-elf
|
||
```
|
||
|
||
#### 推荐的项目结构
|
||
|
||
```
|
||
ESP32 项目/
|
||
├── esp32_hid_keyboard/
|
||
│ ├── CMakeLists.txt
|
||
│ ├── main/
|
||
│ │ ├── CMakeLists.txt
|
||
│ │ └── main.c
|
||
│ └── sdkconfig
|
||
└── .vscode/
|
||
└── settings.json # esp-idf 插件配置
|
||
```
|
||
|
||
---
|
||
|
||
## ESP-IDF C 方案优势
|
||
|
||
✅ **官方成熟例程,直接可用**
|
||
✅ **功能丰富,一站式解决**
|
||
✅ **文档完善,调试方便**
|
||
|
||
| 功能 | 支持情况 |
|
||
|------|----------|
|
||
| USB 虚拟键盘 | ✅ 官方例程 |
|
||
| USB 虚拟鼠标 | ✅ 官方例程 |
|
||
| USB 虚拟网卡 | ✅ 官方例程 |
|
||
| USB 虚拟 U 盘 | ✅ 官方例程 |
|
||
| 蓝牙配网 (BLE) | ✅ 官方例程 |
|
||
| WiFi + 蓝牙同时 | ✅ 支持 |
|
||
|
||
---
|
||
|
||
## 实现步骤
|
||
|
||
### 1. 环境准备
|
||
|
||
**安装 ESP-IDF(独立安装,不影响 Rust):**
|
||
|
||
```bash
|
||
# Windows (PowerShell)
|
||
.\install.ps1
|
||
|
||
# 激活环境(每次开发 ESP32 时执行)
|
||
.\env.ps1
|
||
|
||
# 确认 ESP-IDF 版本
|
||
idf.py --version
|
||
# 推荐 ESP-IDF v5.0+
|
||
```
|
||
|
||
**或者使用 esp-idf VS Code 插件(推荐):**
|
||
- 安装 Espressif IDF 插件
|
||
- 在插件中配置 ESP-IDF 路径
|
||
- 打开项目自动切换环境
|
||
|
||
### 2. 创建项目
|
||
|
||
```bash
|
||
# 从官方示例创建 USB HID 项目
|
||
cp -r $IDF_PATH/examples/peripherals/usb/device/hid_device ./esp32_hid_keyboard
|
||
cd esp32_hid_keyboard
|
||
```
|
||
|
||
### 3. ESP-IDF 配置(关键!)
|
||
|
||
```bash
|
||
# 进入配置菜单
|
||
idf.py menuconfig
|
||
```
|
||
|
||
#### 3.1 开启 USB 支持
|
||
**→ Hardware Settings → USB CONFIG**
|
||
- [x] Enable USB OTG
|
||
- [x] Enable USB CDC
|
||
- [x] Force USB OTG mode as device
|
||
|
||
#### 3.2 开启 TinyUSB
|
||
**→ Component config → TinyUSB**
|
||
- [x] Enable TinyUSB
|
||
- [x] Support CDC (Serial)
|
||
- [x] Support HID (Keyboard/Mouse/Gamepad)
|
||
- [x] HID keyboard
|
||
- [x] HID mouse
|
||
- [x] Support MSC (Mass Storage)
|
||
- [x] Support Ethernet (RNDIS/ECM)
|
||
|
||
#### 3.3 开启 WiFi + 蓝牙(重点!)
|
||
**→ Component config → Wi-Fi**
|
||
- [x] Enable WiFi
|
||
- [x] WiFi Station
|
||
- [x] WiFi AP (可选)
|
||
|
||
**→ Component config → Bluetooth**
|
||
- [x] Enable Bluetooth
|
||
- [x] Bluetooth LE (BLE)
|
||
- [x] BLE GATT Server
|
||
|
||
#### 3.4 配置 Flash 和 RAM
|
||
**→ Serial flasher config**
|
||
- [x] Default flash size: 8MB
|
||
- [x] Partition table: Factory app, two OTA definitions
|
||
|
||
---
|
||
|
||
## 核心代码
|
||
|
||
### 1. WiFi + 蓝牙同时初始化
|
||
|
||
```c
|
||
#include "esp_bt.h"
|
||
#include "esp_wifi.h"
|
||
#include "esp_blufi_api.h"
|
||
#include "nvs_flash.h"
|
||
|
||
static void wifi_init(void)
|
||
{
|
||
ESP_ERROR_CHECK(esp_netif_init());
|
||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||
esp_netif_create_default_wifi_sta();
|
||
|
||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||
|
||
wifi_config_t wifi_config = {
|
||
.sta = {
|
||
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
|
||
},
|
||
};
|
||
|
||
// 设置 WiFi 名称和密码(可从 NVS 或配网获取)
|
||
memcpy(wifi_config.sta.ssid, "YourSSID", 7);
|
||
memcpy(wifi_config.sta.password, "YourPassword", 12);
|
||
|
||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
||
ESP_ERROR_CHECK(esp_wifi_start());
|
||
|
||
ESP_LOGI(TAG, "WiFi started");
|
||
}
|
||
|
||
static void ble_init(void)
|
||
{
|
||
// 初始化 NVS
|
||
esp_err_t ret = nvs_flash_init();
|
||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||
ret = nvs_flash_init();
|
||
}
|
||
ESP_ERROR_CHECK(ret);
|
||
|
||
// 释放经典蓝牙内存(只用 BLE)
|
||
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
|
||
|
||
// 初始化蓝牙控制器
|
||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||
ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
|
||
|
||
// 使能 BLE 模式
|
||
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
|
||
|
||
// 初始化 Bluedroid
|
||
ESP_ERROR_CHECK(esp_bluedroid_init());
|
||
ESP_ERROR_CHECK(esp_bluedroid_enable());
|
||
|
||
ESP_LOGI(TAG, "BLE started");
|
||
}
|
||
```
|
||
|
||
### 2. TinyUSB 初始化
|
||
|
||
```c
|
||
#include "tusb.h"
|
||
|
||
static const tusb_desc_device_t dev_desc = {
|
||
.bLength = sizeof(tusb_desc_device_t),
|
||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||
.bcdUSB = 0x0200,
|
||
.bDeviceClass = 0x00,
|
||
.bDeviceSubClass = 0x00,
|
||
.bDeviceProtocol = 0x00,
|
||
.bMaxPacketSize0 = 64,
|
||
.idVendor = 0x303A, // Espressif VID
|
||
.idProduct = 0x4002, // USB HID Keyboard PID
|
||
.bcdDevice = 0x0100,
|
||
.iManufacturer = 0x01,
|
||
.iProduct = 0x02,
|
||
.iSerialNumber = 0x03,
|
||
.bNumConfigurations = 0x01
|
||
};
|
||
|
||
static void tinyusb_init(void)
|
||
{
|
||
const tinyusb_config_t tusb_cfg = {
|
||
.device_descriptor = &dev_desc,
|
||
.string_descriptor = NULL,
|
||
.external_phy = false,
|
||
};
|
||
|
||
ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));
|
||
ESP_LOGI(TAG, "TinyUSB initialized");
|
||
}
|
||
```
|
||
|
||
### 3. 键盘发送函数
|
||
|
||
```c
|
||
// 键盘修饰键
|
||
#define HID_MOD_LEFTCTRL (1 << 0)
|
||
#define HID_MOD_LEFTSHIFT (1 << 1)
|
||
#define HID_MOD_LEFTALT (1 << 2)
|
||
#define HID_MOD_LEFTGUI (1 << 3)
|
||
|
||
// 常用键码
|
||
#define HID_KEY_A 0x04
|
||
#define HID_KEY_C 0x06
|
||
#define HID_KEY_ENTER 0x28
|
||
|
||
void hid_keyboard_send(uint8_t key, uint8_t modifier)
|
||
{
|
||
uint8_t report[8] = { modifier, 0, key, 0, 0, 0, 0, 0 };
|
||
tud_hid_n_report(0, 0, report, sizeof(report));
|
||
}
|
||
|
||
void hid_keyboard_release(void)
|
||
{
|
||
uint8_t report[8] = {0};
|
||
tud_hid_n_report(0, 0, report, sizeof(report));
|
||
}
|
||
|
||
void hid_keyboard_send_string(const char *str)
|
||
{
|
||
while (*str) {
|
||
if (*str >= 0x20 && *str <= 0x7E) {
|
||
hid_keyboard_send(*str, 0);
|
||
vTaskDelay(pdMS_TO_TICKS(10));
|
||
hid_keyboard_release();
|
||
vTaskDelay(pdMS_TO_TICKS(5));
|
||
}
|
||
str++;
|
||
}
|
||
}
|
||
|
||
void hid_keyboard_send_ctrl_c(void)
|
||
{
|
||
hid_keyboard_send(HID_KEY_C, HID_MOD_LEFTCTRL);
|
||
vTaskDelay(pdMS_TO_TICKS(10));
|
||
hid_keyboard_release();
|
||
}
|
||
```
|
||
|
||
### 4. 主程序
|
||
|
||
```c
|
||
#include "esp_log.h"
|
||
#include "freertos/FreeRTOS.h"
|
||
#include "freertos/task.h"
|
||
#include "tusb.h"
|
||
|
||
static const char *TAG = "USB_HID";
|
||
|
||
void app_main(void)
|
||
{
|
||
ESP_LOGI(TAG, "ESP32-S3 USB HID + WiFi + BLE Starting...");
|
||
|
||
// 1. 初始化 WiFi
|
||
wifi_init();
|
||
ESP_LOGI(TAG, "WiFi initialized");
|
||
|
||
// 2. 初始化蓝牙
|
||
ble_init();
|
||
ESP_LOGI(TAG, "BLE initialized");
|
||
|
||
// 3. 初始化 TinyUSB
|
||
tinyusb_init();
|
||
ESP_LOGI(TAG, "USB HID initialized, waiting for host...");
|
||
|
||
while (1) {
|
||
if (tud_mounted()) {
|
||
int c = getchar();
|
||
if (c != EOF) {
|
||
switch (c) {
|
||
case 'a': hid_keyboard_send(0x04, 0); break;
|
||
case 'c': hid_keyboard_send_ctrl_c(); break;
|
||
case '\n': hid_keyboard_send(0x28, 0); break;
|
||
default: break;
|
||
}
|
||
vTaskDelay(pdMS_TO_TICKS(10));
|
||
hid_keyboard_release();
|
||
}
|
||
}
|
||
|
||
vTaskDelay(pdMS_TO_TICKS(10));
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 常用键码参考
|
||
|
||
| 按键 | 键码 |
|
||
|------|------|
|
||
| A-Z | 0x04-0x1D |
|
||
| 0-9 | 0x1E-0x27 |
|
||
| Enter | 0x28 |
|
||
| ESC | 0x29 |
|
||
| Backspace | 0x2A |
|
||
| Tab | 0x2B |
|
||
| Space | 0x2C |
|
||
| F1-F12 | 0x3A-0x45 |
|
||
| ↑↓←→ | 0x52-0x4F |
|
||
|
||
---
|
||
|
||
## 官方例程参考
|
||
|
||
| 示例路径 | 功能 |
|
||
|----------|------|
|
||
| `examples/peripherals/usb/device/hid_device` | USB HID 键鼠 |
|
||
| `examples/peripherals/usb/device/cdc_serial` | USB 虚拟串口 |
|
||
| `examples/peripherals/usb/device/msc_disk` | USB 虚拟 U 盘 |
|
||
| `examples/wifi/ble_esp` | 蓝牙配网 |
|
||
| `examples/wifi/wps` | WiFi 配网 |
|
||
| `examples/bluetooth/blufi` | 蓝牙配网 + WiFi |
|
||
|
||
---
|
||
|
||
## 快速启动命令
|
||
|
||
```bash
|
||
# 进入 HID 示例
|
||
cd $IDF_PATH/examples/peripherals/usb/device/hid_device
|
||
|
||
# 配置(开启 WiFi + 蓝牙)
|
||
idf.py menuconfig
|
||
|
||
# 编译烧录
|
||
idf.py -p COMX flash monitor
|
||
```
|
||
|
||
---
|
||
|
||
## 参考资源
|
||
|
||
- TinyUSB 官方文档:https://github.com/hathach/tinyusb
|
||
- ESP-IDF USB 示例:https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb/device
|
||
- ESP-IDF 蓝牙文档:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32s3/api-reference/bluetooth/index.html
|
||
- ESP-IDF WiFi 文档:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32s3/api-reference/network/esp_wifi.html
|
||
- esp-idf VS Code 插件:https://marketplace.visualstudio.com/items?itemName=espressif.esp-idf-extension
|