2026-04-10 19:28:20 +08:00
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include <app_event_manager.h>
|
|
|
|
|
|
|
|
|
|
#define MODULE ble_hid_module
|
|
|
|
|
#include <caf/events/module_state_event.h>
|
|
|
|
|
|
|
|
|
|
#include <caf/events/ble_common_event.h>
|
|
|
|
|
#include <bluetooth/services/hids.h>
|
|
|
|
|
#include <zephyr/logging/log.h>
|
|
|
|
|
|
|
|
|
|
#include "hid_led_event.h"
|
2026-04-15 15:47:14 +08:00
|
|
|
#include "hid_channel_state_event.h"
|
2026-04-10 19:28:20 +08:00
|
|
|
#include "hid_report_sent_event.h"
|
|
|
|
|
#include "hid_tx_report_event.h"
|
|
|
|
|
#include "keyboard_core.h"
|
2026-04-17 19:12:57 +08:00
|
|
|
#include "module_lifecycle.h"
|
2026-04-10 19:28:20 +08:00
|
|
|
#include "set_protocol_event.h"
|
|
|
|
|
|
|
|
|
|
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
|
|
|
|
|
|
|
|
|
#define BLE_HID_KEYS_REPORT_ID 0x01
|
|
|
|
|
#define BLE_HID_CONSUMER_REPORT_ID 0x02
|
|
|
|
|
#define BLE_HID_KEYS_REPORT_IDX 0
|
|
|
|
|
#define BLE_HID_CONSUMER_REPORT_IDX 1
|
|
|
|
|
#define BLE_HID_KEYS_LED_REPORT_SIZE 1U
|
|
|
|
|
#define BASE_USB_HID_SPEC_VERSION 0x0101
|
|
|
|
|
|
|
|
|
|
struct in_flight_report {
|
|
|
|
|
bool active;
|
|
|
|
|
enum keyboard_report_type report_type;
|
|
|
|
|
uint16_t sequence;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BT_HIDS_DEF(hids_obj,
|
|
|
|
|
KEYBOARD_NKRO_REPORT_SIZE,
|
|
|
|
|
KEYBOARD_CONSUMER_REPORT_SIZE,
|
|
|
|
|
BLE_HID_KEYS_LED_REPORT_SIZE);
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
struct ble_hid_module_ctx {
|
|
|
|
|
struct module_lifecycle_ctx lc;
|
|
|
|
|
struct bt_conn *active_conn;
|
|
|
|
|
struct in_flight_report in_flight;
|
|
|
|
|
enum keyboard_protocol_mode protocol_mode;
|
|
|
|
|
bool secured;
|
|
|
|
|
bool keyboard_report_notify_enabled;
|
|
|
|
|
bool consumer_report_notify_enabled;
|
|
|
|
|
bool boot_keyboard_notify_enabled;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int do_init(void);
|
|
|
|
|
static int do_start(void);
|
|
|
|
|
static int do_stop(void);
|
|
|
|
|
|
|
|
|
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
2026-04-18 14:17:23 +08:00
|
|
|
.mode = ML_MODE_NONE,
|
|
|
|
|
.stopped_state = MODULE_STATE_OFF,
|
2026-04-17 19:12:57 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
|
|
|
|
.do_init = do_init,
|
|
|
|
|
.do_start = do_start,
|
|
|
|
|
.do_stop = do_stop,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct ble_hid_module_ctx ctx = {
|
|
|
|
|
.lc = {
|
|
|
|
|
.state = LC_UNINIT,
|
|
|
|
|
.cfg = &lifecycle_cfg,
|
|
|
|
|
.ops = &lifecycle_ops,
|
|
|
|
|
},
|
|
|
|
|
.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT,
|
|
|
|
|
};
|
2026-04-10 19:28:20 +08:00
|
|
|
|
|
|
|
|
static const uint8_t hid_report_desc[] = {
|
|
|
|
|
0x05, 0x01, /* Usage Page (Generic Desktop) */
|
|
|
|
|
0x09, 0x06, /* Usage (Keyboard) */
|
|
|
|
|
0xA1, 0x01, /* Collection (Application) */
|
|
|
|
|
0x85, BLE_HID_KEYS_REPORT_ID,
|
|
|
|
|
0x05, 0x07, /* Usage Page (Keyboard/Keypad) */
|
|
|
|
|
0x19, 0xE0, /* Usage Minimum (0xE0) */
|
|
|
|
|
0x29, 0xE7, /* Usage Maximum (0xE7) */
|
|
|
|
|
0x15, 0x00, /* Logical Minimum (0) */
|
|
|
|
|
0x25, 0x01, /* Logical Maximum (1) */
|
|
|
|
|
0x75, 0x01, /* Report Size (1) */
|
|
|
|
|
0x95, 0x08, /* Report Count (8) */
|
|
|
|
|
0x81, 0x02, /* Input (Data,Var,Abs) */
|
|
|
|
|
0x05, 0x07, /* Usage Page (Keyboard/Keypad) */
|
|
|
|
|
0x19, 0x00, /* Usage Minimum (0x00) */
|
|
|
|
|
0x2A, 0xDF, 0x00, /* Usage Maximum (0x00DF) */
|
|
|
|
|
0x15, 0x00, /* Logical Minimum (0) */
|
|
|
|
|
0x25, 0x01, /* Logical Maximum (1) */
|
|
|
|
|
0x75, 0x01, /* Report Size (1) */
|
|
|
|
|
0x96, 0xE0, 0x00, /* Report Count (224) */
|
|
|
|
|
0x81, 0x02, /* Input (Data,Var,Abs) */
|
|
|
|
|
0x85, BLE_HID_KEYS_REPORT_ID,
|
|
|
|
|
0x05, 0x08, /* Usage Page (LEDs) */
|
|
|
|
|
0x19, 0x01, /* Usage Minimum (1) */
|
|
|
|
|
0x29, 0x05, /* Usage Maximum (5) */
|
|
|
|
|
0x15, 0x00, /* Logical Minimum (0) */
|
|
|
|
|
0x25, 0x01, /* Logical Maximum (1) */
|
|
|
|
|
0x75, 0x01, /* Report Size (1) */
|
|
|
|
|
0x95, 0x05, /* Report Count (5) */
|
|
|
|
|
0x91, 0x02, /* Output (Data,Var,Abs) */
|
|
|
|
|
0x75, 0x03, /* Report Size (3) */
|
|
|
|
|
0x95, 0x01, /* Report Count (1) */
|
|
|
|
|
0x91, 0x01, /* Output (Const,Array,Abs) */
|
|
|
|
|
0xC0, /* End Collection */
|
|
|
|
|
0x05, 0x0C, /* Usage Page (Consumer) */
|
|
|
|
|
0x09, 0x01, /* Usage (Consumer Control) */
|
|
|
|
|
0xA1, 0x01, /* Collection (Application) */
|
|
|
|
|
0x85, BLE_HID_CONSUMER_REPORT_ID,
|
|
|
|
|
0x15, 0x00, /* Logical Minimum (0) */
|
|
|
|
|
0x26, 0xFF, 0x03, /* Logical Maximum (1023) */
|
|
|
|
|
0x19, 0x00, /* Usage Minimum (0) */
|
|
|
|
|
0x2A, 0xFF, 0x03, /* Usage Maximum (1023) */
|
|
|
|
|
0x75, 0x10, /* Report Size (16) */
|
|
|
|
|
0x95, 0x01, /* Report Count (1) */
|
|
|
|
|
0x81, 0x00, /* Input (Data,Array,Abs) */
|
|
|
|
|
0xC0 /* End Collection */
|
|
|
|
|
};
|
|
|
|
|
|
2026-04-14 16:42:04 +08:00
|
|
|
static void submit_ble_transport_state_event(void)
|
2026-04-10 19:28:20 +08:00
|
|
|
{
|
2026-04-17 19:12:57 +08:00
|
|
|
bool ready = module_lifecycle_is_running(&ctx.lc) &&
|
|
|
|
|
ctx.secured && (ctx.active_conn != NULL);
|
2026-04-15 15:47:14 +08:00
|
|
|
uint8_t report_ready_bm = 0U;
|
2026-04-10 19:28:20 +08:00
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
if (ready && ((ctx.protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) ?
|
|
|
|
|
ctx.boot_keyboard_notify_enabled :
|
|
|
|
|
ctx.keyboard_report_notify_enabled)) {
|
2026-04-15 15:47:14 +08:00
|
|
|
report_ready_bm |= BIT(KEYBOARD_REPORT_TYPE_KEYS);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
if (ready && (ctx.protocol_mode == KEYBOARD_PROTOCOL_MODE_REPORT) &&
|
|
|
|
|
ctx.consumer_report_notify_enabled) {
|
2026-04-15 15:47:14 +08:00
|
|
|
report_ready_bm |= BIT(KEYBOARD_REPORT_TYPE_CONSUMER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
submit_hid_channel_state_event(
|
|
|
|
|
HID_SEND_CH_BLE_SHARED,
|
|
|
|
|
report_ready_bm,
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.protocol_mode);
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void input_report_notify_handler(uint8_t report_id, enum bt_hids_notify_evt evt)
|
|
|
|
|
{
|
|
|
|
|
bool enabled = (evt == BT_HIDS_CCCD_EVT_NOTIFY_ENABLED);
|
|
|
|
|
|
|
|
|
|
if (report_id == BLE_HID_KEYS_REPORT_ID) {
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.keyboard_report_notify_enabled = enabled;
|
2026-04-10 19:28:20 +08:00
|
|
|
} else if (report_id == BLE_HID_CONSUMER_REPORT_ID) {
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.consumer_report_notify_enabled = enabled;
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-14 16:42:04 +08:00
|
|
|
submit_ble_transport_state_event();
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void boot_keyboard_notify_handler(enum bt_hids_notify_evt evt)
|
|
|
|
|
{
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.boot_keyboard_notify_enabled = (evt == BT_HIDS_CCCD_EVT_NOTIFY_ENABLED);
|
2026-04-14 16:42:04 +08:00
|
|
|
submit_ble_transport_state_event();
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void hid_report_complete_cb(struct bt_conn *conn, void *user_data)
|
|
|
|
|
{
|
|
|
|
|
ARG_UNUSED(conn);
|
|
|
|
|
ARG_UNUSED(user_data);
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
if (!ctx.in_flight.active) {
|
2026-04-10 19:28:20 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-15 15:47:14 +08:00
|
|
|
submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED,
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.in_flight.report_type,
|
|
|
|
|
ctx.in_flight.sequence, false);
|
|
|
|
|
ctx.in_flight.active = false;
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void keyboard_led_report_common(struct bt_hids_rep *rep, bool write)
|
|
|
|
|
{
|
|
|
|
|
if (!write || (rep->data == NULL) || (rep->size < BLE_HID_KEYS_LED_REPORT_SIZE)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-14 16:42:04 +08:00
|
|
|
submit_hid_led_event(HID_TRANSPORT_BLE, rep->data[0]);
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void keyboard_led_report_handler(struct bt_hids_rep *rep,
|
|
|
|
|
struct bt_conn *conn,
|
|
|
|
|
bool write)
|
|
|
|
|
{
|
|
|
|
|
ARG_UNUSED(conn);
|
|
|
|
|
|
|
|
|
|
keyboard_led_report_common(rep, write);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void boot_keyboard_led_report_handler(struct bt_hids_rep *rep,
|
|
|
|
|
struct bt_conn *conn,
|
|
|
|
|
bool write)
|
|
|
|
|
{
|
|
|
|
|
ARG_UNUSED(conn);
|
|
|
|
|
|
|
|
|
|
keyboard_led_report_common(rep, write);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void pm_evt_handler(enum bt_hids_pm_evt evt, struct bt_conn *conn)
|
|
|
|
|
{
|
|
|
|
|
ARG_UNUSED(conn);
|
|
|
|
|
|
|
|
|
|
switch (evt) {
|
|
|
|
|
case BT_HIDS_PM_EVT_BOOT_MODE_ENTERED:
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_BOOT;
|
2026-04-10 19:28:20 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BT_HIDS_PM_EVT_REPORT_MODE_ENTERED:
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
|
2026-04-10 19:28:20 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
submit_set_protocol_event(HID_TRANSPORT_BLE, ctx.protocol_mode);
|
2026-04-14 16:42:04 +08:00
|
|
|
submit_ble_transport_state_event();
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
static int do_init(void)
|
2026-04-10 19:28:20 +08:00
|
|
|
{
|
|
|
|
|
struct bt_hids_init_param hids_init_param = { 0 };
|
|
|
|
|
struct bt_hids_inp_rep *input_report;
|
|
|
|
|
struct bt_hids_outp_feat_rep *output_report;
|
|
|
|
|
|
|
|
|
|
hids_init_param.info.bcd_hid = BASE_USB_HID_SPEC_VERSION;
|
|
|
|
|
hids_init_param.info.b_country_code = 0x00;
|
|
|
|
|
hids_init_param.info.flags = BT_HIDS_REMOTE_WAKE | BT_HIDS_NORMALLY_CONNECTABLE;
|
|
|
|
|
hids_init_param.rep_map.data = hid_report_desc;
|
|
|
|
|
hids_init_param.rep_map.size = sizeof(hid_report_desc);
|
|
|
|
|
hids_init_param.pm_evt_handler = pm_evt_handler;
|
|
|
|
|
hids_init_param.is_kb = true;
|
|
|
|
|
hids_init_param.boot_kb_notif_handler = boot_keyboard_notify_handler;
|
|
|
|
|
hids_init_param.boot_kb_outp_rep_handler = boot_keyboard_led_report_handler;
|
|
|
|
|
|
|
|
|
|
input_report = &hids_init_param.inp_rep_group_init.reports[BLE_HID_KEYS_REPORT_IDX];
|
|
|
|
|
input_report->id = BLE_HID_KEYS_REPORT_ID;
|
|
|
|
|
input_report->size = KEYBOARD_NKRO_REPORT_SIZE;
|
|
|
|
|
input_report->handler_ext = input_report_notify_handler;
|
|
|
|
|
hids_init_param.inp_rep_group_init.cnt++;
|
|
|
|
|
|
|
|
|
|
input_report = &hids_init_param.inp_rep_group_init.reports[BLE_HID_CONSUMER_REPORT_IDX];
|
|
|
|
|
input_report->id = BLE_HID_CONSUMER_REPORT_ID;
|
|
|
|
|
input_report->size = KEYBOARD_CONSUMER_REPORT_SIZE;
|
|
|
|
|
input_report->handler_ext = input_report_notify_handler;
|
|
|
|
|
hids_init_param.inp_rep_group_init.cnt++;
|
|
|
|
|
|
|
|
|
|
output_report = &hids_init_param.outp_rep_group_init.reports[0];
|
|
|
|
|
output_report->id = BLE_HID_KEYS_REPORT_ID;
|
|
|
|
|
output_report->size = BLE_HID_KEYS_LED_REPORT_SIZE;
|
|
|
|
|
output_report->handler = keyboard_led_report_handler;
|
|
|
|
|
hids_init_param.outp_rep_group_init.cnt = 1U;
|
|
|
|
|
|
|
|
|
|
return bt_hids_init(&hids_obj, &hids_init_param);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
static int do_start(void)
|
2026-04-10 19:28:20 +08:00
|
|
|
{
|
2026-04-17 19:12:57 +08:00
|
|
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
2026-04-10 19:28:20 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-14 16:42:04 +08:00
|
|
|
submit_ble_transport_state_event();
|
2026-04-10 19:28:20 +08:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
static int do_stop(void)
|
2026-04-10 19:28:20 +08:00
|
|
|
{
|
2026-04-17 19:12:57 +08:00
|
|
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
|
|
|
|
return 0;
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.in_flight.active = false;
|
2026-04-14 16:42:04 +08:00
|
|
|
submit_ble_transport_state_event();
|
2026-04-17 19:12:57 +08:00
|
|
|
|
|
|
|
|
return 0;
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void reset_connection_state(void)
|
|
|
|
|
{
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.active_conn = NULL;
|
|
|
|
|
ctx.secured = false;
|
|
|
|
|
ctx.keyboard_report_notify_enabled = false;
|
|
|
|
|
ctx.consumer_report_notify_enabled = false;
|
|
|
|
|
ctx.boot_keyboard_notify_enabled = false;
|
|
|
|
|
ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
|
|
|
|
|
ctx.in_flight.active = false;
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool handle_ble_peer_event(const struct ble_peer_event *event)
|
|
|
|
|
{
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
switch (event->state) {
|
|
|
|
|
case PEER_STATE_CONNECTED:
|
2026-04-17 19:12:57 +08:00
|
|
|
if (ctx.active_conn != NULL) {
|
2026-04-10 19:28:20 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.active_conn = event->id;
|
|
|
|
|
ctx.protocol_mode = KEYBOARD_PROTOCOL_MODE_REPORT;
|
|
|
|
|
submit_set_protocol_event(HID_TRANSPORT_BLE, ctx.protocol_mode);
|
2026-04-10 19:28:20 +08:00
|
|
|
err = bt_hids_connected(&hids_obj, event->id);
|
|
|
|
|
if (err) {
|
|
|
|
|
LOG_ERR("bt_hids_connected failed (%d)", err);
|
|
|
|
|
}
|
2026-04-14 16:42:04 +08:00
|
|
|
submit_ble_transport_state_event();
|
2026-04-10 19:28:20 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
case PEER_STATE_SECURED:
|
2026-04-17 19:12:57 +08:00
|
|
|
if (ctx.active_conn != event->id) {
|
2026-04-10 19:28:20 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.secured = true;
|
2026-04-14 16:42:04 +08:00
|
|
|
submit_ble_transport_state_event();
|
2026-04-10 19:28:20 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
case PEER_STATE_DISCONNECTED:
|
2026-04-17 19:12:57 +08:00
|
|
|
if (ctx.active_conn != event->id) {
|
2026-04-10 19:28:20 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = bt_hids_disconnected(&hids_obj, event->id);
|
|
|
|
|
if (err) {
|
|
|
|
|
LOG_WRN("bt_hids_disconnected failed (%d)", err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reset_connection_state();
|
2026-04-14 16:42:04 +08:00
|
|
|
submit_ble_transport_state_event();
|
2026-04-10 19:28:20 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool handle_hid_tx_report_event(const struct hid_tx_report_event *event)
|
|
|
|
|
{
|
|
|
|
|
int err;
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
if (!module_lifecycle_is_running(&ctx.lc) ||
|
|
|
|
|
(event->channel != HID_SEND_CH_BLE_SHARED) ||
|
|
|
|
|
ctx.in_flight.active) {
|
2026-04-10 19:28:20 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
if ((ctx.active_conn == NULL) || !ctx.secured) {
|
2026-04-10 19:28:20 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (event->report_type == KEYBOARD_REPORT_TYPE_KEYS) {
|
2026-04-17 19:12:57 +08:00
|
|
|
if (event->protocol_mode != ctx.protocol_mode) {
|
2026-04-10 19:28:20 +08:00
|
|
|
LOG_WRN("Drop BLE keys report due to protocol mismatch");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.in_flight.active = true;
|
|
|
|
|
ctx.in_flight.report_type = event->report_type;
|
|
|
|
|
ctx.in_flight.sequence = event->sequence;
|
2026-04-10 19:28:20 +08:00
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
if (ctx.protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) {
|
2026-04-10 19:28:20 +08:00
|
|
|
err = bt_hids_boot_kb_inp_rep_send(&hids_obj,
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.active_conn,
|
2026-04-10 19:28:20 +08:00
|
|
|
event->dyndata.data,
|
|
|
|
|
(uint8_t)event->dyndata.size,
|
|
|
|
|
hid_report_complete_cb);
|
|
|
|
|
} else {
|
|
|
|
|
err = bt_hids_inp_rep_send(&hids_obj,
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.active_conn,
|
2026-04-10 19:28:20 +08:00
|
|
|
BLE_HID_KEYS_REPORT_IDX,
|
|
|
|
|
event->dyndata.data,
|
|
|
|
|
(uint8_t)event->dyndata.size,
|
|
|
|
|
hid_report_complete_cb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (err) {
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.in_flight.active = false;
|
2026-04-10 19:28:20 +08:00
|
|
|
LOG_WRN("BLE keyboard report submit failed (%d)", err);
|
2026-04-15 15:47:14 +08:00
|
|
|
submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED,
|
2026-04-14 16:42:04 +08:00
|
|
|
KEYBOARD_REPORT_TYPE_KEYS,
|
2026-04-10 19:28:20 +08:00
|
|
|
event->sequence, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (event->report_type == KEYBOARD_REPORT_TYPE_CONSUMER) {
|
2026-04-17 19:12:57 +08:00
|
|
|
if (ctx.protocol_mode != KEYBOARD_PROTOCOL_MODE_REPORT) {
|
2026-04-10 19:28:20 +08:00
|
|
|
LOG_WRN("Drop BLE consumer report in boot mode");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.in_flight.active = true;
|
|
|
|
|
ctx.in_flight.report_type = event->report_type;
|
|
|
|
|
ctx.in_flight.sequence = event->sequence;
|
2026-04-10 19:28:20 +08:00
|
|
|
|
|
|
|
|
err = bt_hids_inp_rep_send(&hids_obj,
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.active_conn,
|
2026-04-10 19:28:20 +08:00
|
|
|
BLE_HID_CONSUMER_REPORT_IDX,
|
|
|
|
|
event->dyndata.data,
|
|
|
|
|
(uint8_t)event->dyndata.size,
|
|
|
|
|
hid_report_complete_cb);
|
|
|
|
|
if (err) {
|
2026-04-17 19:12:57 +08:00
|
|
|
ctx.in_flight.active = false;
|
2026-04-10 19:28:20 +08:00
|
|
|
LOG_WRN("BLE consumer report submit failed (%d)", err);
|
2026-04-15 15:47:14 +08:00
|
|
|
submit_hid_report_sent_event(HID_SEND_CH_BLE_SHARED,
|
2026-04-14 16:42:04 +08:00
|
|
|
KEYBOARD_REPORT_TYPE_CONSUMER,
|
2026-04-10 19:28:20 +08:00
|
|
|
event->sequence, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool app_event_handler(const struct app_event_header *aeh)
|
|
|
|
|
{
|
|
|
|
|
if (is_hid_tx_report_event(aeh)) {
|
|
|
|
|
return handle_hid_tx_report_event(cast_hid_tx_report_event(aeh));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_ble_peer_event(aeh)) {
|
|
|
|
|
return handle_ble_peer_event(cast_ble_peer_event(aeh));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_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)) {
|
2026-04-17 19:12:57 +08:00
|
|
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
APP_EVENT_LISTENER(MODULE, app_event_handler);
|
|
|
|
|
APP_EVENT_SUBSCRIBE_EARLY(MODULE, module_state_event);
|
|
|
|
|
APP_EVENT_SUBSCRIBE(MODULE, hid_tx_report_event);
|
|
|
|
|
APP_EVENT_SUBSCRIBE_EARLY(MODULE, ble_peer_event);
|