feat(hid): 实现HID通道状态管理和多通道支持
- 将原来的HID传输状态事件替换为新的HID通道状态事件,支持USB键盘、USB消费者和BLE共享通道 - 添加usb_hid_consumer_module.c模块来处理USB消费者HID报告 - 添加usb_hid_keyboard_module.c模块来处理USB键盘HID报告 - 修改CMakeLists.txt以包含新的HID模块源文件 - 更新事件系统中的transport字段为channel字段,并相应修改所有相关处理逻辑 - 在hid_flowctrl_module.c中实现多通道并发处理机制 - 删除过时的hid_transport_state_event相关代码 - 添加新的hid_channel_state_event用于报告各通道就绪状态
This commit is contained in:
@@ -10,8 +10,8 @@
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "hid_channel_state_event.h"
|
||||
#include "hid_report_sent_event.h"
|
||||
#include "hid_transport_state_event.h"
|
||||
#include "hid_tx_report_event.h"
|
||||
#include "keyboard_core.h"
|
||||
#include "keyboard_hid_report_event.h"
|
||||
@@ -37,25 +37,26 @@ struct queued_report {
|
||||
uint8_t data[HID_FLOWCTRL_REPORT_DATA_MAX];
|
||||
};
|
||||
|
||||
struct hid_transport_state_data {
|
||||
bool ready;
|
||||
bool keys_ready;
|
||||
bool consumer_ready;
|
||||
struct hid_channel_state_data {
|
||||
uint8_t report_ready_bm;
|
||||
enum keyboard_protocol_mode protocol_mode;
|
||||
};
|
||||
|
||||
struct in_flight_report {
|
||||
bool active;
|
||||
enum hid_transport transport;
|
||||
enum hid_send_channel channel;
|
||||
enum keyboard_report_type report_type;
|
||||
uint16_t sequence;
|
||||
};
|
||||
|
||||
static struct hid_transport_state_data transport_state[HID_TRANSPORT_COUNT] = {
|
||||
[HID_TRANSPORT_USB] = {
|
||||
static struct hid_channel_state_data channel_state[HID_SEND_CH_COUNT] = {
|
||||
[HID_SEND_CH_USB_KEYS] = {
|
||||
.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
|
||||
},
|
||||
[HID_TRANSPORT_BLE] = {
|
||||
[HID_SEND_CH_USB_CONSUMER] = {
|
||||
.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
|
||||
},
|
||||
[HID_SEND_CH_BLE_SHARED] = {
|
||||
.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
|
||||
},
|
||||
};
|
||||
@@ -65,21 +66,28 @@ static struct queued_report consumer_fifo[HID_FLOWCTRL_FIFO_DEPTH];
|
||||
static uint8_t consumer_fifo_head;
|
||||
static uint8_t consumer_fifo_tail;
|
||||
static uint8_t consumer_fifo_count;
|
||||
static struct in_flight_report in_flight;
|
||||
static struct in_flight_report in_flight[HID_SEND_CH_COUNT];
|
||||
static enum mode_switch_mode current_mode;
|
||||
static uint16_t next_sequence;
|
||||
static bool initialized;
|
||||
static bool running;
|
||||
|
||||
static bool mode_to_transport(enum mode_switch_mode mode, enum hid_transport *transport)
|
||||
static bool current_mode_to_channel(enum keyboard_report_type report_type,
|
||||
enum hid_send_channel *channel)
|
||||
{
|
||||
switch (mode) {
|
||||
if (channel == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (current_mode) {
|
||||
case MODE_SWITCH_USB:
|
||||
*transport = HID_TRANSPORT_USB;
|
||||
*channel = (report_type == KEYBOARD_REPORT_TYPE_KEYS) ?
|
||||
HID_SEND_CH_USB_KEYS :
|
||||
HID_SEND_CH_USB_CONSUMER;
|
||||
return true;
|
||||
|
||||
case MODE_SWITCH_BLE:
|
||||
*transport = HID_TRANSPORT_BLE;
|
||||
*channel = HID_SEND_CH_BLE_SHARED;
|
||||
return true;
|
||||
|
||||
default:
|
||||
@@ -131,102 +139,137 @@ static bool consumer_fifo_pop(struct queued_report *entry)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool transport_can_send_report(enum keyboard_report_type report_type)
|
||||
static bool channel_can_send_report(enum hid_send_channel channel,
|
||||
enum keyboard_report_type report_type,
|
||||
enum keyboard_protocol_mode protocol_mode)
|
||||
{
|
||||
enum hid_transport transport;
|
||||
struct hid_transport_state_data *state;
|
||||
const struct hid_channel_state_data *state = &channel_state[channel];
|
||||
|
||||
if (!mode_to_transport(current_mode, &transport) || in_flight.active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state = &transport_state[transport];
|
||||
|
||||
if (!state->ready) {
|
||||
if (in_flight[channel].active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (report_type == KEYBOARD_REPORT_TYPE_KEYS) {
|
||||
return state->keys_ready;
|
||||
return (state->report_ready_bm & BIT(KEYBOARD_REPORT_TYPE_KEYS)) &&
|
||||
(state->protocol_mode == protocol_mode);
|
||||
}
|
||||
|
||||
return state->consumer_ready;
|
||||
if (channel == HID_SEND_CH_BLE_SHARED) {
|
||||
return (state->report_ready_bm & BIT(KEYBOARD_REPORT_TYPE_CONSUMER)) &&
|
||||
(state->protocol_mode == KEYBOARD_PROTOCOL_MODE_REPORT);
|
||||
}
|
||||
|
||||
return (state->report_ready_bm & BIT(KEYBOARD_REPORT_TYPE_CONSUMER)) != 0U;
|
||||
}
|
||||
|
||||
static void try_send_keys(void)
|
||||
{
|
||||
enum hid_send_channel channel;
|
||||
|
||||
if (!pending_keys.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current_mode_to_channel(KEYBOARD_REPORT_TYPE_KEYS, &channel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel_can_send_report(channel, pending_keys.report_type,
|
||||
pending_keys.protocol_mode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
in_flight[channel].active = true;
|
||||
in_flight[channel].channel = channel;
|
||||
in_flight[channel].report_type = pending_keys.report_type;
|
||||
in_flight[channel].sequence = next_sequence++;
|
||||
(void)submit_hid_tx_report_event(channel, pending_keys.report_type,
|
||||
pending_keys.protocol_mode,
|
||||
in_flight[channel].sequence,
|
||||
pending_keys.data, pending_keys.size);
|
||||
pending_keys.valid = false;
|
||||
}
|
||||
|
||||
static void try_send_consumer_fifo(void)
|
||||
{
|
||||
struct queued_report queued;
|
||||
enum hid_send_channel channel;
|
||||
|
||||
if (consumer_fifo_count == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current_mode_to_channel(KEYBOARD_REPORT_TYPE_CONSUMER, &channel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!consumer_fifo_pop(&queued)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel_can_send_report(channel, queued.report_type,
|
||||
queued.protocol_mode)) {
|
||||
if (queued.protocol_mode == channel_state[channel].protocol_mode) {
|
||||
consumer_fifo_push(queued.report_type, queued.protocol_mode,
|
||||
queued.data, queued.size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
in_flight[channel].active = true;
|
||||
in_flight[channel].channel = channel;
|
||||
in_flight[channel].report_type = queued.report_type;
|
||||
in_flight[channel].sequence = next_sequence++;
|
||||
(void)submit_hid_tx_report_event(channel, queued.report_type,
|
||||
queued.protocol_mode,
|
||||
in_flight[channel].sequence,
|
||||
queued.data, queued.size);
|
||||
}
|
||||
|
||||
static void try_send_consumer_latest(void)
|
||||
{
|
||||
enum hid_send_channel channel;
|
||||
|
||||
if (!pending_consumer_latest.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current_mode_to_channel(KEYBOARD_REPORT_TYPE_CONSUMER, &channel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel_can_send_report(channel,
|
||||
pending_consumer_latest.report_type,
|
||||
pending_consumer_latest.protocol_mode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
in_flight[channel].active = true;
|
||||
in_flight[channel].channel = channel;
|
||||
in_flight[channel].report_type = pending_consumer_latest.report_type;
|
||||
in_flight[channel].sequence = next_sequence++;
|
||||
(void)submit_hid_tx_report_event(channel,
|
||||
pending_consumer_latest.report_type,
|
||||
pending_consumer_latest.protocol_mode,
|
||||
in_flight[channel].sequence,
|
||||
pending_consumer_latest.data,
|
||||
pending_consumer_latest.size);
|
||||
pending_consumer_latest.valid = false;
|
||||
}
|
||||
|
||||
static void try_send_next(void)
|
||||
{
|
||||
struct queued_report queued;
|
||||
enum hid_transport transport;
|
||||
struct hid_transport_state_data *state;
|
||||
|
||||
if (!running || in_flight.active || !mode_to_transport(current_mode, &transport)) {
|
||||
if (!running) {
|
||||
return;
|
||||
}
|
||||
|
||||
state = &transport_state[transport];
|
||||
|
||||
if (!state->ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pending_keys.valid && transport_can_send_report(KEYBOARD_REPORT_TYPE_KEYS)) {
|
||||
if (pending_keys.protocol_mode != state->protocol_mode) {
|
||||
LOG_WRN("Drop stale keys report after protocol change");
|
||||
pending_keys.valid = false;
|
||||
} else {
|
||||
in_flight.active = true;
|
||||
in_flight.transport = transport;
|
||||
in_flight.report_type = pending_keys.report_type;
|
||||
in_flight.sequence = next_sequence++;
|
||||
(void)submit_hid_tx_report_event(
|
||||
transport, pending_keys.report_type,
|
||||
pending_keys.protocol_mode, in_flight.sequence,
|
||||
pending_keys.data, pending_keys.size);
|
||||
pending_keys.valid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((consumer_fifo_count > 0U) &&
|
||||
transport_can_send_report(KEYBOARD_REPORT_TYPE_CONSUMER) &&
|
||||
consumer_fifo_pop(&queued)) {
|
||||
if (queued.protocol_mode != state->protocol_mode) {
|
||||
LOG_WRN("Drop stale consumer report after protocol change");
|
||||
} else {
|
||||
in_flight.active = true;
|
||||
in_flight.transport = transport;
|
||||
in_flight.report_type = queued.report_type;
|
||||
in_flight.sequence = next_sequence++;
|
||||
(void)submit_hid_tx_report_event(
|
||||
transport, queued.report_type,
|
||||
queued.protocol_mode, in_flight.sequence,
|
||||
queued.data, queued.size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pending_consumer_latest.valid &&
|
||||
transport_can_send_report(KEYBOARD_REPORT_TYPE_CONSUMER)) {
|
||||
if (pending_consumer_latest.protocol_mode != state->protocol_mode) {
|
||||
LOG_WRN("Drop stale latest consumer report after protocol change");
|
||||
pending_consumer_latest.valid = false;
|
||||
} else {
|
||||
in_flight.active = true;
|
||||
in_flight.transport = transport;
|
||||
in_flight.report_type = pending_consumer_latest.report_type;
|
||||
in_flight.sequence = next_sequence++;
|
||||
(void)submit_hid_tx_report_event(
|
||||
transport, pending_consumer_latest.report_type,
|
||||
pending_consumer_latest.protocol_mode,
|
||||
in_flight.sequence,
|
||||
pending_consumer_latest.data,
|
||||
pending_consumer_latest.size);
|
||||
pending_consumer_latest.valid = false;
|
||||
}
|
||||
}
|
||||
try_send_keys();
|
||||
try_send_consumer_fifo();
|
||||
try_send_consumer_latest();
|
||||
}
|
||||
|
||||
static bool handle_keyboard_hid_report_event(const struct keyboard_hid_report_event *event)
|
||||
static bool handle_keyboard_hid_report_event(
|
||||
const struct keyboard_hid_report_event *event)
|
||||
{
|
||||
if (!running ||
|
||||
((event->mode != MODE_SWITCH_USB) && (event->mode != MODE_SWITCH_BLE))) {
|
||||
@@ -257,41 +300,18 @@ static bool handle_keyboard_hid_report_event(const struct keyboard_hid_report_ev
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool handle_hid_transport_state_event(const struct hid_transport_state_event *event)
|
||||
static bool handle_hid_channel_state_event(
|
||||
const struct hid_channel_state_event *event)
|
||||
{
|
||||
enum hid_transport active_transport;
|
||||
struct hid_transport_state_data *state;
|
||||
|
||||
if (event->transport >= HID_TRANSPORT_COUNT) {
|
||||
if (event->channel >= HID_SEND_CH_COUNT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state = &transport_state[event->transport];
|
||||
channel_state[event->channel].report_ready_bm = event->report_ready_bm;
|
||||
channel_state[event->channel].protocol_mode = event->protocol_mode;
|
||||
|
||||
state->ready = event->ready;
|
||||
state->keys_ready = event->keys_ready;
|
||||
state->consumer_ready = event->consumer_ready;
|
||||
|
||||
if (state->protocol_mode != event->protocol_mode) {
|
||||
state->protocol_mode = event->protocol_mode;
|
||||
|
||||
if (mode_to_transport(current_mode, &active_transport) &&
|
||||
(active_transport == event->transport)) {
|
||||
pending_keys.valid = false;
|
||||
pending_consumer_latest.valid = false;
|
||||
consumer_fifo_head = 0U;
|
||||
consumer_fifo_tail = 0U;
|
||||
consumer_fifo_count = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
if (!state->ready &&
|
||||
mode_to_transport(current_mode, &active_transport) &&
|
||||
(active_transport == event->transport)) {
|
||||
consumer_fifo_head = 0U;
|
||||
consumer_fifo_tail = 0U;
|
||||
consumer_fifo_count = 0U;
|
||||
in_flight.active = false;
|
||||
if (event->report_ready_bm == 0U) {
|
||||
in_flight[event->channel].active = false;
|
||||
}
|
||||
|
||||
try_send_next();
|
||||
@@ -300,17 +320,21 @@ static bool handle_hid_transport_state_event(const struct hid_transport_state_ev
|
||||
|
||||
static bool handle_hid_report_sent_event(const struct hid_report_sent_event *event)
|
||||
{
|
||||
if (!in_flight.active || (event->transport != in_flight.transport)) {
|
||||
if (event->channel >= HID_SEND_CH_COUNT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event->sequence != in_flight.sequence) {
|
||||
if (!in_flight[event->channel].active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event->sequence != in_flight[event->channel].sequence) {
|
||||
LOG_WRN("Unexpected HID sent sequence %u (expected %u)",
|
||||
event->sequence, in_flight.sequence);
|
||||
event->sequence, in_flight[event->channel].sequence);
|
||||
return false;
|
||||
}
|
||||
|
||||
in_flight.active = false;
|
||||
in_flight[event->channel].active = false;
|
||||
|
||||
if (event->error) {
|
||||
LOG_WRN("HID report send failed for seq %u", event->sequence);
|
||||
@@ -339,18 +363,14 @@ static int module_init(void)
|
||||
{
|
||||
clear_pending_reports();
|
||||
current_mode = MODE_SWITCH_USB;
|
||||
transport_state[HID_TRANSPORT_USB].ready = false;
|
||||
transport_state[HID_TRANSPORT_USB].keys_ready = false;
|
||||
transport_state[HID_TRANSPORT_USB].consumer_ready = false;
|
||||
transport_state[HID_TRANSPORT_USB].protocol_mode =
|
||||
memset(channel_state, 0, sizeof(channel_state));
|
||||
channel_state[HID_SEND_CH_USB_KEYS].protocol_mode =
|
||||
KEYBOARD_PROTOCOL_MODE_REPORT;
|
||||
transport_state[HID_TRANSPORT_BLE].ready = false;
|
||||
transport_state[HID_TRANSPORT_BLE].keys_ready = false;
|
||||
transport_state[HID_TRANSPORT_BLE].consumer_ready = false;
|
||||
transport_state[HID_TRANSPORT_BLE].protocol_mode =
|
||||
channel_state[HID_SEND_CH_USB_CONSUMER].protocol_mode =
|
||||
KEYBOARD_PROTOCOL_MODE_REPORT;
|
||||
channel_state[HID_SEND_CH_BLE_SHARED].protocol_mode =
|
||||
KEYBOARD_PROTOCOL_MODE_REPORT;
|
||||
next_sequence = 1U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -362,7 +382,6 @@ static int module_start(void)
|
||||
|
||||
running = true;
|
||||
try_send_next();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -379,15 +398,18 @@ static void module_pause(void)
|
||||
static bool app_event_handler(const struct app_event_header *aeh)
|
||||
{
|
||||
if (is_keyboard_hid_report_event(aeh)) {
|
||||
return handle_keyboard_hid_report_event(cast_keyboard_hid_report_event(aeh));
|
||||
return handle_keyboard_hid_report_event(
|
||||
cast_keyboard_hid_report_event(aeh));
|
||||
}
|
||||
|
||||
if (is_hid_transport_state_event(aeh)) {
|
||||
return handle_hid_transport_state_event(cast_hid_transport_state_event(aeh));
|
||||
if (is_hid_channel_state_event(aeh)) {
|
||||
return handle_hid_channel_state_event(
|
||||
cast_hid_channel_state_event(aeh));
|
||||
}
|
||||
|
||||
if (is_hid_report_sent_event(aeh)) {
|
||||
return handle_hid_report_sent_event(cast_hid_report_sent_event(aeh));
|
||||
return handle_hid_report_sent_event(
|
||||
cast_hid_report_sent_event(aeh));
|
||||
}
|
||||
|
||||
if (is_mode_switch_event(aeh)) {
|
||||
@@ -395,7 +417,8 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
||||
}
|
||||
|
||||
if (is_module_state_event(aeh)) {
|
||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||
const struct module_state_event *event =
|
||||
cast_module_state_event(aeh);
|
||||
|
||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||
int err;
|
||||
@@ -450,7 +473,7 @@ static bool app_event_handler(const struct app_event_header *aeh)
|
||||
|
||||
APP_EVENT_LISTENER(MODULE, app_event_handler);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, keyboard_hid_report_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, hid_transport_state_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, hid_channel_state_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, hid_report_sent_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, mode_switch_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, module_state_event);
|
||||
|
||||
Reference in New Issue
Block a user