feat(hid_tx_manager): 重构HID传输管理器以支持报告状态跟踪

- 引入原子标志位替换布尔变量,提高线程安全性
- 使用消息队列替代循环缓冲区实现传输队列
- 添加boot和NKRO报告状态管理功能
- 实现脏标记机制优化报告发送流程
- 改进传输完成事件处理逻辑
This commit is contained in:
2026-03-20 13:47:54 +08:00
parent 579dc35a36
commit 9b29910299

View File

@@ -1,10 +1,14 @@
#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/atomic.h>
#include <app_event_manager.h>
#define MODULE hid_tx_manager
#include <caf/events/module_state_event.h>
#include "hid_report_descriptor.h"
#include "hid_boot_event.h"
#include "hid_report_event.h"
#include "hid_tx_done_event.h"
@@ -17,6 +21,15 @@ LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
#define HID_TX_QUEUE_SIZE 16
#define HID_TX_MAX_DATA 32
enum hid_tx_flag {
HID_TX_FLAG_INITIALIZED = 0,
HID_TX_FLAG_IN_FLIGHT,
HID_TX_FLAG_BOOT_VALID,
HID_TX_FLAG_BOOT_DIRTY,
HID_TX_FLAG_NKRO_VALID,
HID_TX_FLAG_NKRO_DIRTY,
};
struct hid_tx_item {
enum hid_tx_kind kind;
size_t len;
@@ -24,86 +37,92 @@ struct hid_tx_item {
};
struct hid_tx_ctx {
struct hid_tx_item queue[HID_TX_QUEUE_SIZE];
uint8_t head;
uint8_t tail;
uint8_t count;
bool initialized;
bool in_flight;
atomic_t flags;
struct hid_tx_item boot_state;
struct hid_tx_item nkro_state;
struct hid_tx_item inflight_item;
mode_type_t active_mode;
enum hid_tx_kind inflight_kind;
};
static struct hid_tx_ctx tx = {
.active_mode = MODE_TYPE_COUNT,
};
static bool hid_tx_queue_push(enum hid_tx_kind kind, const uint8_t *data, size_t len)
{
struct hid_tx_item *item;
K_MSGQ_DEFINE(hid_tx_queue_msgq, sizeof(struct hid_tx_item), HID_TX_QUEUE_SIZE, 4);
static bool hid_tx_item_store(struct hid_tx_item *item,
enum hid_tx_kind kind,
const uint8_t *data,
size_t len)
{
if (len > HID_TX_MAX_DATA) {
LOG_WRN("Drop HID tx kind=%u len=%u: too large", kind, len);
return false;
}
if (tx.count >= HID_TX_QUEUE_SIZE) {
LOG_WRN("Drop HID tx kind=%u len=%u: queue full", kind, len);
return false;
}
item = &tx.queue[tx.tail];
item->kind = kind;
item->len = len;
if ((len > 0U) && (data != NULL)) {
memcpy(item->data, data, len);
}
tx.tail = (tx.tail + 1U) % HID_TX_QUEUE_SIZE;
tx.count++;
return true;
}
static struct hid_tx_item *hid_tx_queue_front(void)
static bool hid_tx_queue_push(enum hid_tx_kind kind, const uint8_t *data, size_t len)
{
if (tx.count == 0U) {
return NULL;
struct hid_tx_item item;
if (!hid_tx_item_store(&item, kind, data, len)) {
return false;
}
return &tx.queue[tx.head];
if (k_msgq_put(&hid_tx_queue_msgq, &item, K_NO_WAIT)) {
LOG_WRN("Drop HID tx kind=%u len=%u: queue full", kind, len);
return false;
}
static void hid_tx_queue_pop(void)
return true;
}
static bool hid_tx_dispatch_item(const struct hid_tx_item *item)
{
__ASSERT_NO_MSG(tx.count > 0U);
tx.head = (tx.head + 1U) % HID_TX_QUEUE_SIZE;
tx.count--;
tx.inflight_item = *item;
atomic_set_bit(&tx.flags, HID_TX_FLAG_IN_FLIGHT);
hid_tx_event_submit(item->kind, item->data, item->len);
return true;
}
static void dispatch_next_if_possible(void)
{
struct hid_tx_item *item;
struct hid_tx_item item;
if (!tx.initialized || tx.in_flight) {
return;
}
item = hid_tx_queue_front();
if (item == NULL) {
if (!atomic_test_bit(&tx.flags, HID_TX_FLAG_INITIALIZED) ||
atomic_test_bit(&tx.flags, HID_TX_FLAG_IN_FLIGHT)) {
return;
}
if ((tx.active_mode != MODE_TYPE_USB) && (tx.active_mode != MODE_TYPE_BLE)) {
LOG_WRN("Drop HID tx kind=%u: unsupported mode=%u",
item->kind, tx.active_mode);
hid_tx_queue_pop();
dispatch_next_if_possible();
return;
}
tx.in_flight = true;
tx.inflight_kind = item->kind;
hid_tx_event_submit(item->kind, item->data, item->len);
if (atomic_test_bit(&tx.flags, HID_TX_FLAG_NKRO_DIRTY) &&
atomic_test_bit(&tx.flags, HID_TX_FLAG_NKRO_VALID)) {
atomic_clear_bit(&tx.flags, HID_TX_FLAG_NKRO_DIRTY);
(void)hid_tx_dispatch_item(&tx.nkro_state);
return;
}
if (atomic_test_bit(&tx.flags, HID_TX_FLAG_BOOT_DIRTY) &&
atomic_test_bit(&tx.flags, HID_TX_FLAG_BOOT_VALID)) {
atomic_clear_bit(&tx.flags, HID_TX_FLAG_BOOT_DIRTY);
(void)hid_tx_dispatch_item(&tx.boot_state);
return;
}
if (!k_msgq_get(&hid_tx_queue_msgq, &item, K_NO_WAIT)) {
(void)hid_tx_dispatch_item(&item);
}
}
static bool handle_module_state_event(const struct module_state_event *event)
@@ -112,8 +131,8 @@ static bool handle_module_state_event(const struct module_state_event *event)
return false;
}
__ASSERT_NO_MSG(!tx.initialized);
tx.initialized = true;
__ASSERT_NO_MSG(!atomic_test_bit(&tx.flags, HID_TX_FLAG_INITIALIZED));
atomic_set_bit(&tx.flags, HID_TX_FLAG_INITIALIZED);
module_set_state(MODULE_STATE_READY);
dispatch_next_if_possible();
@@ -129,42 +148,44 @@ static bool handle_mode_event(const struct mode_event *event)
static bool handle_hid_boot_request_event(const struct hid_boot_event *event)
{
(void)hid_tx_queue_push(HID_TX_KIND_BOOT,
(void)hid_tx_item_store(&tx.boot_state,
HID_TX_KIND_BOOT,
hid_boot_event_get_data(event),
hid_boot_event_get_size(event));
atomic_set_bit(&tx.flags, HID_TX_FLAG_BOOT_VALID);
atomic_set_bit(&tx.flags, HID_TX_FLAG_BOOT_DIRTY);
dispatch_next_if_possible();
return true;
}
static bool handle_hid_report_request_event(const struct hid_report_event *event)
{
(void)hid_tx_queue_push(HID_TX_KIND_REPORT,
hid_report_event_get_data(event),
hid_report_event_get_size(event));
const uint8_t *data = hid_report_event_get_data(event);
size_t len = hid_report_event_get_size(event);
if ((len > 0U) && (data[0] == REPORT_ID_KEYBOARD)) {
(void)hid_tx_item_store(&tx.nkro_state, HID_TX_KIND_REPORT, data, len);
atomic_set_bit(&tx.flags, HID_TX_FLAG_NKRO_VALID);
atomic_set_bit(&tx.flags, HID_TX_FLAG_NKRO_DIRTY);
} else {
(void)hid_tx_queue_push(HID_TX_KIND_REPORT, data, len);
}
dispatch_next_if_possible();
return true;
}
static bool handle_hid_tx_done_event(const struct hid_tx_done_event *event)
{
struct hid_tx_item *item;
if (!tx.in_flight) {
if (!atomic_test_bit(&tx.flags, HID_TX_FLAG_IN_FLIGHT)) {
return false;
}
if (event->kind != tx.inflight_kind) {
if (event->kind != tx.inflight_item.kind) {
return false;
}
item = hid_tx_queue_front();
if (item == NULL) {
tx.in_flight = false;
return false;
}
hid_tx_queue_pop();
tx.in_flight = false;
atomic_clear_bit(&tx.flags, HID_TX_FLAG_IN_FLIGHT);
dispatch_next_if_possible();
return false;