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

@@ -63,7 +63,7 @@ CONFIG_CAF_LEDS_GPIO=y
CONFIG_CAF_LEDS_PM_EVENTS=y CONFIG_CAF_LEDS_PM_EVENTS=y
CONFIG_CAF_POWER_MANAGER=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_CAF_POWER_MANAGER_ERROR_TIMEOUT=10
CONFIG_REBOOT=y CONFIG_REBOOT=y
CONFIG_CAF_KEEP_ALIVE_EVENTS=y CONFIG_CAF_KEEP_ALIVE_EVENTS=y

View File

@@ -5,9 +5,13 @@ static const char *const usb_hid_evt_type_name[] = {
}; };
static const char *const usb_hid_usbd_state_name[] = { static const char *const usb_hid_usbd_state_name[] = {
[USB_HID_USBD_DISCONNECTED] = "DISCONNECTED", [USB_HID_USBD_VBUS_DISCONNECTED] = "VBUS_DISCONNECTED",
[USB_HID_USBD_CONNECTED] = "CONNECTED", [USB_HID_USBD_VBUS_CONNECTED] = "VBUS_CONNECTED",
[USB_HID_USBD_SUSPENDED] = "SUSPENDED", };
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) 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->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->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], 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]); 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); 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->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); 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, ENCODE(NRF_PROFILER_ARG_U8,
NRF_PROFILER_ARG_U8, 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); profile_usb_hid_event);
APP_EVENT_TYPE_DEFINE(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_HID_EVT_STATE_REPORT = 0,
}; };
/* USB 连接状态(偏“链路可用性”) */ /* 仅反映 VBUS 连接状态 */
enum usb_hid_usbd_state { enum usb_hid_usbd_state {
USB_HID_USBD_DISCONNECTED = 0, USB_HID_USBD_VBUS_DISCONNECTED = 0,
USB_HID_USBD_CONNECTED, USB_HID_USBD_VBUS_CONNECTED,
USB_HID_USBD_SUSPENDED, };
/* USB HID 协议栈启停状态。 */
enum usb_hid_stack_state {
USB_HID_STACK_DISABLED = 0,
USB_HID_STACK_ENABLED,
}; };
struct usb_hid_event { struct usb_hid_event {
struct app_event_header header; struct app_event_header header;
enum usb_hid_event_type evt_type; enum usb_hid_event_type evt_type;
bool enable; enum usb_hid_stack_state stack_state;
enum usb_hid_usbd_state usbd_state; enum usb_hid_usbd_state usbd_state;
}; };

View File

@@ -8,6 +8,7 @@
#include <app_event_manager.h> #include <app_event_manager.h>
#include <caf/events/power_event.h> #include <caf/events/power_event.h>
#include <caf/events/power_manager_event.h>
#define MODULE usb_hid #define MODULE usb_hid
#include <caf/events/module_state_event.h> #include <caf/events/module_state_event.h>
@@ -56,13 +57,13 @@ struct usb_hid_ctx {
enum usb_hid_usbd_state usbd_state; enum usb_hid_usbd_state usbd_state;
enum hid_protocol_type current_protocol; enum hid_protocol_type current_protocol;
bool num_lock_known; enum power_manager_level pm_restrict_level;
bool num_lock_on;
}; };
static struct usb_hid_ctx g_usb_hid = { 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, .current_protocol = HID_PROTO_REPORT,
.pm_restrict_level = POWER_MANAGER_LEVEL_MAX,
}; };
USBD_DEVICE_DEFINE(new_kbd_usbd, 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(); struct usb_hid_event *event = new_usb_hid_event();
event->evt_type = USB_HID_EVT_STATE_REPORT; 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; event->usbd_state = g_usb_hid.usbd_state;
APP_EVENT_SUBMIT(event); APP_EVENT_SUBMIT(event);
} }
/* 从主机输出报告同步 Num Lock 位,并在状态变化时发布事件。 */ /* 统一入口仅处理单字节 LED 报告并发布事件。 */
static void publish_num_lock_state_from_led_mask(uint8_t led_mask) 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(); struct keyboard_led_state_event *event = new_keyboard_led_state_event();
event->led_mask = led_mask; event->led_mask = led_report;
event->num_lock = new_num_lock; event->num_lock = (led_report & BIT(0)) != 0U;
APP_EVENT_SUBMIT(event); 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) static void recompute_hid_state(void)
{ {
/* 兼容现有调用点:对外仅发布 enable + usbd 状态。 */ /* 兼容现有调用点:对外仅发布 enable + usbd 状态。 */
publish_usb_hid_state(); 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) static void set_usbd_state(enum usb_hid_usbd_state state)
{ {
if (g_usb_hid.usbd_state != state) { if (g_usb_hid.usbd_state != state) {
g_usb_hid.usbd_state = state; g_usb_hid.usbd_state = state;
refresh_usb_power_restrict();
publish_usb_hid_state(); publish_usb_hid_state();
} }
} }
@@ -137,14 +186,22 @@ static int hid_stub_set_report(const struct device *dev,
uint8_t type, uint8_t id, uint8_t type, uint8_t id,
uint16_t len, const uint8_t *buf) uint16_t len, const uint8_t *buf)
{ {
ARG_UNUSED(dev);
ARG_UNUSED(type); ARG_UNUSED(type);
ARG_UNUSED(id); ARG_UNUSED(id);
if ((len > 0U) && (buf != NULL)) { if (!should_handle_led_input_from_dev(dev)) {
publish_num_lock_state_from_led_mask(buf[0]); 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; 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) static void hid_stub_output_report(const struct device *dev, uint16_t len, const uint8_t *buf)
{ {
ARG_UNUSED(dev); if (!should_handle_led_input_from_dev(dev)) {
return;
if ((len > 0U) && (buf != NULL)) {
publish_num_lock_state_from_led_mask(buf[0]);
} }
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) 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) { if (ready) {
set_usbd_state(USB_HID_USBD_CONNECTED);
/* 连接可用后同步一次当前协议,让 keyboard_module 与传输侧编码一致。 */ /* 连接可用后同步一次当前协议,让 keyboard_module 与传输侧编码一致。 */
struct hid_protocol_event *event = new_hid_protocol_event(); 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) { switch (msg->type) {
case USBD_MSG_VBUS_READY: case USBD_MSG_VBUS_READY:
set_usbd_state(USB_HID_USBD_CONNECTED); set_usbd_state(USB_HID_USBD_VBUS_CONNECTED);
/* /*
* 只有在 USB 模式下才允许拉起 USB 栈。 * 只有在 USB 模式下才允许拉起 USB 栈。
* 这样即使插着线,只要用户切到 BLE/2.4G,也不会强制进入 USB HID。 * 这样即使插着线,只要用户切到 BLE/2.4G,也不会强制进入 USB HID。
@@ -296,19 +359,19 @@ static void usbd_msg_cb(struct usbd_context *const usbd_ctx,
break; break;
case USBD_MSG_VBUS_REMOVED: case USBD_MSG_VBUS_REMOVED:
set_usbd_state(USB_HID_USBD_DISCONNECTED); set_usbd_state(USB_HID_USBD_VBUS_DISCONNECTED);
break; break;
case USBD_MSG_SUSPEND: case USBD_MSG_SUSPEND:
set_usbd_state(USB_HID_USBD_SUSPENDED); publish_usb_hid_state();
break; break;
case USBD_MSG_RESUME: case USBD_MSG_RESUME:
set_usbd_state(USB_HID_USBD_CONNECTED); publish_usb_hid_state();
break; break;
case USBD_MSG_CONFIGURATION: case USBD_MSG_CONFIGURATION:
set_usbd_state(USB_HID_USBD_CONNECTED); publish_usb_hid_state();
break; break;
case USBD_MSG_UDC_ERROR: 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.raw_iface_ready = false;
g_usb_hid.boot_in_flight = false; g_usb_hid.boot_in_flight = false;
g_usb_hid.nkro_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)) { if (err && (err != -EALREADY)) {
@@ -504,7 +567,6 @@ static int usb_hid_set_enabled(bool enable)
} }
recompute_hid_state(); recompute_hid_state();
publish_usb_hid_state();
return 0; return 0;
} }
@@ -538,6 +600,7 @@ static bool handle_module_state_event(const struct module_state_event *event)
return false; return false;
} }
refresh_usb_power_restrict();
module_set_state(MODULE_STATE_READY); module_set_state(MODULE_STATE_READY);
publish_usb_hid_state(); publish_usb_hid_state();
return false; 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; const uint8_t *payload = event->dyndata.data;
size_t payload_len = event->dyndata.size; size_t payload_len = event->dyndata.size;
report_id = REPORT_ID_KEYBOARD;
if (!g_usb_hid.boot_iface_ready || !g_usb_hid.boot_dev) { if (!g_usb_hid.boot_iface_ready || !g_usb_hid.boot_dev) {
return false; return false;
} }
if (report_id != REPORT_ID_KEYBOARD) {
return false;
}
if (g_usb_hid.boot_in_flight) { if (g_usb_hid.boot_in_flight) {
LOG_WRN("Drop boot report: previous report not sent"); LOG_WRN("Drop boot report: previous report not sent");
return false; return false;