feat(usb_hid): 重构USB HID模块状态管理并优化电源管理

- 修改USB HID事件结构,将enable字段替换为stack_state枚举,
  区分VBUS连接状态和协议栈启用状态
- 更新日志和分析器中的字段映射,正确显示栈状态而非布尔使能值
- 添加电源管理限制功能,在USB连接时保持系统活跃状态
- 重构LED输入报告处理逻辑,支持引导和NKRO设备的报告解析
- 调整USB连接状态变更逻辑,仅反映VBUS连接情况
- 将power_manager超时配置从300秒调整为30秒以优化响应速度

BREAKING CHANGE: USB HID事件结构中的enable字段已替换为stack_state枚举类型
This commit is contained in:
2026-03-16 15:22:10 +08:00
parent 7587df7553
commit 4e8bb71f83
4 changed files with 118 additions and 50 deletions

View File

@@ -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,

View File

@@ -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;
};

View File

@@ -8,6 +8,7 @@
#include <app_event_manager.h>
#include <caf/events/power_event.h>
#include <caf/events/power_manager_event.h>
#define MODULE usb_hid
#include <caf/events/module_state_event.h>
@@ -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;