feat: 添加HID传输管理和旋转编码器支持

添加了hid_tx_event和hid_tx_done_event事件类型,用于统一管理HID
数据传输,并在ble_hid_module和usb_hid_module中实现相应的处理逻辑。

新增qdec_module模块来处理旋转编码器输入,将旋转事件转换为步进事件,
并在keyboard_module中集成音量控制功能。

更新CMakeLists.txt以包含新的事件和模块文件,在app.overlay中启
用qdec设备,并在prj.conf中添加SENSOR配置。

BREAKING CHANGE: 将原有的hid_boot_event和hid_report_event替换
为统一的hid_tx_event事件系统。
This commit is contained in:
2026-03-20 11:04:48 +08:00
parent 2a389ef19b
commit 579dc35a36
14 changed files with 698 additions and 76 deletions

View File

@@ -15,7 +15,8 @@
#include "hid_report_descriptor.h"
#include "hid_boot_event.h"
#include "hid_protocol_event.h"
#include "hid_report_event.h"
#include "hid_tx_done_event.h"
#include "hid_tx_event.h"
#include "keyboard_led_event.h"
#include "mode_event.h"
@@ -67,6 +68,11 @@ static struct usb_hid_ctx g_usb_hid = {
.current_protocol = HID_PROTO_REPORT,
};
static void submit_usb_tx_done(enum hid_tx_kind kind, bool success)
{
hid_tx_done_event_submit(kind, success);
}
USBD_DEVICE_DEFINE(new_kbd_usbd,
DEVICE_DT_GET(DT_NODELABEL(usbd)),
APP_USB_VID, APP_USB_PID);
@@ -242,6 +248,9 @@ static void hid_stub_input_done(const struct device *dev, const uint8_t *report)
if (iface) {
iface->in_flight = false;
submit_usb_tx_done((dev == g_usb_hid.boot.dev) ?
HID_TX_KIND_BOOT : HID_TX_KIND_REPORT,
true);
return;
}
@@ -596,73 +605,76 @@ static bool handle_wake_up_event(void)
return false;
}
static bool handle_hid_boot_event(const struct hid_boot_event *event)
static bool handle_hid_tx_event(const struct hid_tx_event *event)
{
if (!g_usb_hid.policy.usb_mode_selected || !usb_hid_stack_is_active()) {
return false;
}
if (g_usb_hid.current_protocol != HID_PROTO_BOOT) {
if (event->kind == HID_TX_KIND_BOOT) {
const uint8_t *payload = hid_tx_event_get_data(event);
size_t payload_len = hid_tx_event_get_size(event);
int err;
if (g_usb_hid.current_protocol != HID_PROTO_BOOT) {
return false;
}
if (!g_usb_hid.boot.iface_ready || !g_usb_hid.boot.dev) {
submit_usb_tx_done(HID_TX_KIND_BOOT, false);
return false;
}
if (g_usb_hid.boot.in_flight) {
LOG_WRN("Drop boot tx: previous report not sent");
submit_usb_tx_done(HID_TX_KIND_BOOT, false);
return false;
}
err = hid_device_submit_report(g_usb_hid.boot.dev,
payload_len,
payload);
if (err) {
LOG_WRN("USB boot report send failed err=%d", err);
submit_usb_tx_done(HID_TX_KIND_BOOT, false);
} else {
g_usb_hid.boot.in_flight = true;
}
return false;
}
const uint8_t *payload = hid_boot_event_get_data(event);
size_t payload_len = hid_boot_event_get_size(event);
if (!g_usb_hid.boot.iface_ready || !g_usb_hid.boot.dev) {
return false;
}
if (g_usb_hid.boot.in_flight) {
LOG_WRN("Drop boot report: previous report not sent");
return false;
}
int err = hid_device_submit_report(g_usb_hid.boot.dev,
payload_len,
payload);
if (err) {
LOG_WRN("USB boot report send failed err=%d", err);
} else {
g_usb_hid.boot.in_flight = true;
}
return false;
}
static bool handle_hid_report_event(const struct hid_report_event *event)
{
/*
* USB 侧仅在 active 条件满足时发送:
* - 当前 mode 为 USB
* - USB HID 栈已启用且对应接口 ready。
*/
if (!g_usb_hid.policy.usb_mode_selected || !usb_hid_stack_is_active()) {
return false;
}
if (g_usb_hid.current_protocol != HID_PROTO_REPORT) {
return false;
}
const uint8_t *data = hid_report_event_get_data(event);
size_t data_len = hid_report_event_get_size(event);
const uint8_t *data = hid_tx_event_get_data(event);
size_t data_len = hid_tx_event_get_size(event);
uint8_t report_id;
if (data_len < 1U) {
submit_usb_tx_done(HID_TX_KIND_REPORT, false);
return false;
}
report_id = data[0];
if (!g_usb_hid.nkro.iface_ready || !g_usb_hid.nkro.dev) {
submit_usb_tx_done(HID_TX_KIND_REPORT, false);
return false;
}
if ((report_id != REPORT_ID_KEYBOARD) && (report_id != REPORT_ID_CONSUMER)) {
submit_usb_tx_done(HID_TX_KIND_REPORT, false);
return false;
}
if (g_usb_hid.nkro.in_flight) {
LOG_WRN("Drop report id=0x%02x: previous report not sent", report_id);
LOG_WRN("Drop tx report id=0x%02x: previous report not sent", report_id);
submit_usb_tx_done(HID_TX_KIND_REPORT, false);
return false;
}
@@ -670,6 +682,7 @@ static bool handle_hid_report_event(const struct hid_report_event *event)
int err = hid_device_submit_report(g_usb_hid.nkro.dev, data_len, data);
if (err) {
LOG_WRN("USB report send failed id=0x%02x err=%d", report_id, err);
submit_usb_tx_done(HID_TX_KIND_REPORT, false);
} else {
g_usb_hid.nkro.in_flight = true;
}
@@ -695,12 +708,8 @@ static bool app_event_handler(const struct app_event_header *aeh)
return handle_wake_up_event();
}
if (is_hid_report_event(aeh)) {
return handle_hid_report_event(cast_hid_report_event(aeh));
}
if (is_hid_boot_event(aeh)) {
return handle_hid_boot_event(cast_hid_boot_event(aeh));
if (is_hid_tx_event(aeh)) {
return handle_hid_tx_event(cast_hid_tx_event(aeh));
}
__ASSERT_NO_MSG(false);
@@ -712,5 +721,4 @@ APP_EVENT_SUBSCRIBE(MODULE, module_state_event);
APP_EVENT_SUBSCRIBE(MODULE, mode_event);
APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event);
APP_EVENT_SUBSCRIBE(MODULE, wake_up_event);
APP_EVENT_SUBSCRIBE_EARLY(MODULE, hid_boot_event);
APP_EVENT_SUBSCRIBE_EARLY(MODULE, hid_report_event);
APP_EVENT_SUBSCRIBE_EARLY(MODULE, hid_tx_event);