From 4e8bb71f83308adacd7968dfd4aac4abd3001afd Mon Sep 17 00:00:00 2001 From: skiinder Date: Mon, 16 Mar 2026 15:22:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(usb=5Fhid):=20=E9=87=8D=E6=9E=84USB=20HID?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E7=8A=B6=E6=80=81=E7=AE=A1=E7=90=86=E5=B9=B6?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=94=B5=E6=BA=90=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改USB HID事件结构,将enable字段替换为stack_state枚举, 区分VBUS连接状态和协议栈启用状态 - 更新日志和分析器中的字段映射,正确显示栈状态而非布尔使能值 - 添加电源管理限制功能,在USB连接时保持系统活跃状态 - 重构LED输入报告处理逻辑,支持引导和NKRO设备的报告解析 - 调整USB连接状态变更逻辑,仅反映VBUS连接情况 - 将power_manager超时配置从300秒调整为30秒以优化响应速度 BREAKING CHANGE: USB HID事件结构中的enable字段已替换为stack_state枚举类型 --- prj.conf | 2 +- src/events/usb_hid_event.c | 19 +++-- src/events/usb_hid_event.h | 15 ++-- src/modules/usb_hid_module.c | 132 +++++++++++++++++++++++++---------- 4 files changed, 118 insertions(+), 50 deletions(-) diff --git a/prj.conf b/prj.conf index ca7e54f..fb8396b 100644 --- a/prj.conf +++ b/prj.conf @@ -63,7 +63,7 @@ CONFIG_CAF_LEDS_GPIO=y CONFIG_CAF_LEDS_PM_EVENTS=y CONFIG_CAF_POWER_MANAGER=y -CONFIG_CAF_POWER_MANAGER_TIMEOUT=300 +CONFIG_CAF_POWER_MANAGER_TIMEOUT=30 CONFIG_CAF_POWER_MANAGER_ERROR_TIMEOUT=10 CONFIG_REBOOT=y CONFIG_CAF_KEEP_ALIVE_EVENTS=y diff --git a/src/events/usb_hid_event.c b/src/events/usb_hid_event.c index fcf5bd2..442967f 100644 --- a/src/events/usb_hid_event.c +++ b/src/events/usb_hid_event.c @@ -5,9 +5,13 @@ static const char *const usb_hid_evt_type_name[] = { }; static const char *const usb_hid_usbd_state_name[] = { - [USB_HID_USBD_DISCONNECTED] = "DISCONNECTED", - [USB_HID_USBD_CONNECTED] = "CONNECTED", - [USB_HID_USBD_SUSPENDED] = "SUSPENDED", + [USB_HID_USBD_VBUS_DISCONNECTED] = "VBUS_DISCONNECTED", + [USB_HID_USBD_VBUS_CONNECTED] = "VBUS_CONNECTED", +}; + +static const char *const usb_hid_stack_state_name[] = { + [USB_HID_STACK_DISABLED] = "DISABLED", + [USB_HID_STACK_ENABLED] = "ENABLED", }; static void log_usb_hid_event(const struct app_event_header *aeh) @@ -16,10 +20,11 @@ static void log_usb_hid_event(const struct app_event_header *aeh) __ASSERT_NO_MSG(event->evt_type < ARRAY_SIZE(usb_hid_evt_type_name)); __ASSERT_NO_MSG(event->usbd_state < ARRAY_SIZE(usb_hid_usbd_state_name)); + __ASSERT_NO_MSG(event->stack_state < ARRAY_SIZE(usb_hid_stack_state_name)); - APP_EVENT_MANAGER_LOG(aeh, "type=%s en=%u usbd=%s", + APP_EVENT_MANAGER_LOG(aeh, "type=%s stack=%s usbd=%s", usb_hid_evt_type_name[event->evt_type], - event->enable, + usb_hid_stack_state_name[event->stack_state], usb_hid_usbd_state_name[event->usbd_state]); } @@ -29,7 +34,7 @@ static void profile_usb_hid_event(struct log_event_buf *buf, const struct usb_hid_event *event = cast_usb_hid_event(aeh); nrf_profiler_log_encode_uint8(buf, (uint8_t)event->evt_type); - nrf_profiler_log_encode_uint8(buf, (uint8_t)event->enable); + nrf_profiler_log_encode_uint8(buf, (uint8_t)event->stack_state); nrf_profiler_log_encode_uint8(buf, (uint8_t)event->usbd_state); } @@ -37,7 +42,7 @@ APP_EVENT_INFO_DEFINE(usb_hid_event, ENCODE(NRF_PROFILER_ARG_U8, NRF_PROFILER_ARG_U8, NRF_PROFILER_ARG_U8), - ENCODE("evt_type", "enable", "usbd"), + ENCODE("evt_type", "stack", "usbd"), profile_usb_hid_event); APP_EVENT_TYPE_DEFINE(usb_hid_event, diff --git a/src/events/usb_hid_event.h b/src/events/usb_hid_event.h index cb8bfc5..296b035 100644 --- a/src/events/usb_hid_event.h +++ b/src/events/usb_hid_event.h @@ -11,18 +11,23 @@ enum usb_hid_event_type { USB_HID_EVT_STATE_REPORT = 0, }; -/* USB 连接层状态(偏“链路可用性”) */ +/* 仅反映 VBUS 连接状态。 */ enum usb_hid_usbd_state { - USB_HID_USBD_DISCONNECTED = 0, - USB_HID_USBD_CONNECTED, - USB_HID_USBD_SUSPENDED, + USB_HID_USBD_VBUS_DISCONNECTED = 0, + USB_HID_USBD_VBUS_CONNECTED, +}; + +/* USB HID 协议栈启停状态。 */ +enum usb_hid_stack_state { + USB_HID_STACK_DISABLED = 0, + USB_HID_STACK_ENABLED, }; struct usb_hid_event { struct app_event_header header; enum usb_hid_event_type evt_type; - bool enable; + enum usb_hid_stack_state stack_state; enum usb_hid_usbd_state usbd_state; }; diff --git a/src/modules/usb_hid_module.c b/src/modules/usb_hid_module.c index 0aa122c..7bf785b 100644 --- a/src/modules/usb_hid_module.c +++ b/src/modules/usb_hid_module.c @@ -8,6 +8,7 @@ #include #include +#include #define MODULE usb_hid #include @@ -56,13 +57,13 @@ struct usb_hid_ctx { enum usb_hid_usbd_state usbd_state; enum hid_protocol_type current_protocol; - bool num_lock_known; - bool num_lock_on; + enum power_manager_level pm_restrict_level; }; static struct usb_hid_ctx g_usb_hid = { - .usbd_state = USB_HID_USBD_DISCONNECTED, + .usbd_state = USB_HID_USBD_VBUS_DISCONNECTED, .current_protocol = HID_PROTO_REPORT, + .pm_restrict_level = POWER_MANAGER_LEVEL_MAX, }; USBD_DEVICE_DEFINE(new_kbd_usbd, @@ -83,40 +84,88 @@ static void publish_usb_hid_state(void) struct usb_hid_event *event = new_usb_hid_event(); event->evt_type = USB_HID_EVT_STATE_REPORT; - event->enable = g_usb_hid.stack_enabled; + event->stack_state = g_usb_hid.stack_enabled ? + USB_HID_STACK_ENABLED : USB_HID_STACK_DISABLED; event->usbd_state = g_usb_hid.usbd_state; APP_EVENT_SUBMIT(event); } -/* 从主机输出报告同步 Num Lock 位,并在状态变化时发布事件。 */ -static void publish_num_lock_state_from_led_mask(uint8_t led_mask) +/* 统一入口仅处理单字节 LED 报告并发布事件。 */ +static void process_usb_led_input_report(uint8_t led_report) { - bool new_num_lock = (led_mask & BIT(0)) != 0U; - - if (g_usb_hid.num_lock_known && (g_usb_hid.num_lock_on == new_num_lock)) { - return; - } - - g_usb_hid.num_lock_known = true; - g_usb_hid.num_lock_on = new_num_lock; - struct keyboard_led_state_event *event = new_keyboard_led_state_event(); - event->led_mask = led_mask; - event->num_lock = new_num_lock; + event->led_mask = led_report; + event->num_lock = (led_report & BIT(0)) != 0U; APP_EVENT_SUBMIT(event); } +static bool should_handle_led_input_from_dev(const struct device *dev) +{ + if (g_usb_hid.current_protocol == HID_PROTO_BOOT) + return (dev == g_usb_hid.boot_dev); + + return (dev == g_usb_hid.nkro_dev); +} + +static bool try_extract_led_mask(const struct device *dev, + uint16_t len, + const uint8_t *buf, + uint8_t *led_mask) +{ + if ((buf == NULL) || (len == 0U)) + return false; + + if (dev == g_usb_hid.boot_dev) { + *led_mask = buf[0]; + return true; + } + + if (dev != g_usb_hid.nkro_dev) + return false; + + if (len >= 2U) { + if (buf[0] != REPORT_ID_KEYBOARD) + return false; + + *led_mask = buf[1]; + return true; + } + + *led_mask = buf[0]; + return true; +} + static void recompute_hid_state(void) { /* 兼容现有调用点:对外仅发布 enable + usbd 状态。 */ publish_usb_hid_state(); } +/* + * USB 自动休眠策略: + * - 只要检测到 USB 线已连接(USBD 状态非 DISCONNECTED),限制系统保持 ALIVE; + * - USB 线断开后,恢复为 MAX,允许系统按原有超时策略自动休眠。 + */ +static void refresh_usb_power_restrict(void) +{ + enum power_manager_level target = + (g_usb_hid.usbd_state == USB_HID_USBD_VBUS_DISCONNECTED) ? + POWER_MANAGER_LEVEL_MAX : POWER_MANAGER_LEVEL_ALIVE; + + if (g_usb_hid.pm_restrict_level == target) { + return; + } + + g_usb_hid.pm_restrict_level = target; + power_manager_restrict(MODULE_IDX(MODULE), target); +} + static void set_usbd_state(enum usb_hid_usbd_state state) { if (g_usb_hid.usbd_state != state) { g_usb_hid.usbd_state = state; + refresh_usb_power_restrict(); publish_usb_hid_state(); } } @@ -137,14 +186,22 @@ static int hid_stub_set_report(const struct device *dev, uint8_t type, uint8_t id, uint16_t len, const uint8_t *buf) { - ARG_UNUSED(dev); ARG_UNUSED(type); ARG_UNUSED(id); - if ((len > 0U) && (buf != NULL)) { - publish_num_lock_state_from_led_mask(buf[0]); + if (!should_handle_led_input_from_dev(dev)) { + return 0; } + uint8_t led_mask; + + if (!try_extract_led_mask(dev, len, buf, &led_mask)) { + return 0; + } + + LOG_INF("hid_stub_set_report led_mask=0x%02x", led_mask); + process_usb_led_input_report(led_mask); + return 0; } @@ -212,11 +269,18 @@ static void hid_stub_input_done(const struct device *dev, const uint8_t *report) static void hid_stub_output_report(const struct device *dev, uint16_t len, const uint8_t *buf) { - ARG_UNUSED(dev); - - if ((len > 0U) && (buf != NULL)) { - publish_num_lock_state_from_led_mask(buf[0]); + if (!should_handle_led_input_from_dev(dev)) { + return; } + + uint8_t led_mask; + + if (!try_extract_led_mask(dev, len, buf, &led_mask)) { + return; + } + + LOG_INF("hid_stub_output_report led_mask=0x%02x", led_mask); + process_usb_led_input_report(led_mask); } static void hid_iface_ready_cb(const struct device *dev, bool ready) @@ -236,7 +300,6 @@ static void hid_iface_ready_cb(const struct device *dev, bool ready) } if (ready) { - set_usbd_state(USB_HID_USBD_CONNECTED); /* 连接可用后同步一次当前协议,让 keyboard_module 与传输侧编码一致。 */ struct hid_protocol_event *event = new_hid_protocol_event(); @@ -285,7 +348,7 @@ static void usbd_msg_cb(struct usbd_context *const usbd_ctx, { switch (msg->type) { case USBD_MSG_VBUS_READY: - set_usbd_state(USB_HID_USBD_CONNECTED); + set_usbd_state(USB_HID_USBD_VBUS_CONNECTED); /* * 只有在 USB 模式下才允许拉起 USB 栈。 * 这样即使插着线,只要用户切到 BLE/2.4G,也不会强制进入 USB HID。 @@ -296,19 +359,19 @@ static void usbd_msg_cb(struct usbd_context *const usbd_ctx, break; case USBD_MSG_VBUS_REMOVED: - set_usbd_state(USB_HID_USBD_DISCONNECTED); + set_usbd_state(USB_HID_USBD_VBUS_DISCONNECTED); break; case USBD_MSG_SUSPEND: - set_usbd_state(USB_HID_USBD_SUSPENDED); + publish_usb_hid_state(); break; case USBD_MSG_RESUME: - set_usbd_state(USB_HID_USBD_CONNECTED); + publish_usb_hid_state(); break; case USBD_MSG_CONFIGURATION: - set_usbd_state(USB_HID_USBD_CONNECTED); + publish_usb_hid_state(); break; case USBD_MSG_UDC_ERROR: @@ -493,7 +556,7 @@ static int usb_hid_set_enabled(bool enable) g_usb_hid.raw_iface_ready = false; g_usb_hid.boot_in_flight = false; g_usb_hid.nkro_in_flight = false; - set_usbd_state(USB_HID_USBD_DISCONNECTED); + publish_usb_hid_state(); } if (err && (err != -EALREADY)) { @@ -504,7 +567,6 @@ static int usb_hid_set_enabled(bool enable) } recompute_hid_state(); - publish_usb_hid_state(); return 0; } @@ -538,6 +600,7 @@ static bool handle_module_state_event(const struct module_state_event *event) return false; } + refresh_usb_power_restrict(); module_set_state(MODULE_STATE_READY); publish_usb_hid_state(); return false; @@ -596,14 +659,9 @@ static bool handle_hid_report_event(const struct hid_report_event *event) const uint8_t *payload = event->dyndata.data; size_t payload_len = event->dyndata.size; - report_id = REPORT_ID_KEYBOARD; - if (!g_usb_hid.boot_iface_ready || !g_usb_hid.boot_dev) { return false; } - if (report_id != REPORT_ID_KEYBOARD) { - return false; - } if (g_usb_hid.boot_in_flight) { LOG_WRN("Drop boot report: previous report not sent"); return false;