feat(hid_tx_manager): 重构HID传输管理器以支持报告状态跟踪
- 引入原子标志位替换布尔变量,提高线程安全性 - 使用消息队列替代循环缓冲区实现传输队列 - 添加boot和NKRO报告状态管理功能 - 实现脏标记机制优化报告发送流程 - 改进传输完成事件处理逻辑
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user