#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" #include "tinyusb.h" #include "tusb.h" #include "rust_app_wrapper.h" static const char *TAG = "USB"; #define REPORT_ID_KEYBOARD 1 #define REPORT_ID_MOUSE 2 #define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + 2 * TUD_HID_DESC_LEN) #define USB_VID 0x30D8 #define USB_PID 0x50A6 #define USB_BCD 0x0200 enum { ITF_NUM_KEYBOARD, // 0 ITF_NUM_MOUSE, // 1 ITF_NUM_TOTAL }; static tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, .bcdUSB = USB_BCD, .bDeviceClass = 0x00, .bDeviceSubClass = 0x00, .bDeviceProtocol = 0x00, .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, .idVendor = USB_VID, .idProduct = USB_PID, .bcdDevice = 0x0100, .iManufacturer = 0x01, .iProduct = 0x02, .iSerialNumber = 0x03, .bNumConfigurations = 0x01 }; // 独立键盘描述符(去掉 Report ID,使用单 Report 模式) uint8_t const desc_hid_report_kb[] = { TUD_HID_REPORT_DESC_KEYBOARD() }; // 独立鼠标描述符(去掉 Report ID,使用单 Report 模式) uint8_t const desc_hid_report_mouse[] = { TUD_HID_REPORT_DESC_MOUSE() }; // 按接口返回正确描述符 uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance) { if (instance == ITF_NUM_KEYBOARD) { return desc_hid_report_kb; } if (instance == ITF_NUM_MOUSE) { return desc_hid_report_mouse; } return NULL; } static char const *hid_string_descriptor[] = { (char[]){0x09, 0x04}, // 0: 语言ID "久鼎智控", // 1: 厂商 "智控键鼠套装", // 2: 产品 "1", // 3: 序列号 "HID 智控键盘", // 4: 键盘接口 "HID 智控鼠标", // 5: 鼠标接口 }; #define EPNUM_KEYBOARD 0x81 #define EPNUM_MOUSE 0x82 // ============================== // 🔥 这里是修复重点!!! // ============================== static uint8_t const hid_configuration_descriptor[] = { TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), // 键盘 HID 接口 TUD_HID_DESCRIPTOR( ITF_NUM_KEYBOARD, // 接口号 4, // 字符串索引 0, // 协议 = 0(必须!) sizeof(desc_hid_report_kb), EPNUM_KEYBOARD, CFG_TUD_HID_EP_BUFSIZE, 10 ), // 鼠标 HID 接口 TUD_HID_DESCRIPTOR( ITF_NUM_MOUSE, // 接口号 5, // 字符串索引 0, // 协议 = 0(必须!不能用 MOUSE 协议) sizeof(desc_hid_report_mouse), EPNUM_MOUSE, CFG_TUD_HID_EP_BUFSIZE, 10 ) }; uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) { (void) instance; (void) report_id; (void) report_type; (void) buffer; (void) reqlen; return 0; } void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) { (void) instance; (void) report_id; (void) report_type; (void) buffer; (void) bufsize; } // 暴露给 Rust 的函数 bool rust_is_usb_mounted() { bool mounted = tud_mounted(); ESP_LOGD(TAG, "USB mounted state: %d", mounted); return mounted; } //==================================================================== // 键盘函数(修复:去掉 Report ID) //==================================================================== void rust_send_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t const* keycode) { // 描述符现在没有 Report ID,所以传入 0 tud_hid_keyboard_report(0, modifier, keycode); } //==================================================================== // 鼠标函数(修复:使用 tud_hid_n_mouse_report 指定 instance) //==================================================================== void rust_send_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t wheel, int8_t pan) { ESP_LOGI(TAG, "Mouse report: btn=%d, x=%d, y=%d", buttons, x, y); // 关键修复:使用 tud_hid_n_mouse_report 并指定正确的 instance // ITF_NUM_KEYBOARD = 0 (键盘), ITF_NUM_MOUSE = 1 (鼠标) // 描述符没有 Report ID,所以 report_id 传 0 bool result = tud_hid_n_mouse_report(ITF_NUM_MOUSE, 0, buttons, x, y, wheel, pan); ESP_LOGI(TAG, "tud_hid_n_mouse_report result: %s", result ? "success" : "failed"); } // 暴露 FreeRTOS 函数给 Rust void rust_vTaskDelay(uint32_t xTicksToDelay) { vTaskDelay(xTicksToDelay); } // 暴露日志函数给 Rust void rust_esp_log_i(const char* tag, const char* message) { ESP_LOGI(tag, "%s", message); } void app_main(void) { ESP_LOGI(TAG, "USB 初始化"); const tinyusb_config_t tusb_cfg = { .port = TINYUSB_PORT_FULL_SPEED_0, .phy = { .skip_setup = false, .self_powered = false, .vbus_monitor_io = 0, }, .task = { .size = 3500, .priority = 14, .xCoreID = 0, }, .descriptor = { .device = &desc_device, .qualifier = NULL, .string = hid_string_descriptor, .string_count = sizeof(hid_string_descriptor)/sizeof(hid_string_descriptor[0]), .full_speed_config = hid_configuration_descriptor, .high_speed_config = NULL, }, .event_cb = NULL, .event_arg = NULL, }; ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); ESP_LOGI(TAG, "✅ USB HID 设备启动成功"); ESP_LOGI(TAG, "请连接 USB OTG 线到电脑"); rust_app_wrapper_init(); int count = 0; bool last_mounted = false; while (1) { vTaskDelay(1000 / portTICK_PERIOD_MS); bool mounted = tud_mounted(); if (mounted != last_mounted) { if (mounted) { ESP_LOGI(TAG, "🔌 USB 已连接到主机"); } else { ESP_LOGI(TAG, "🔌 USB 已断开"); } last_mounted = mounted; } if (count % 10 == 0) { ESP_LOGI(TAG, "USB 设备运行中... 挂载状态: %s", mounted ? "已连接" : "未连接"); } count++; } }