feat(led): 添加键盘LED状态管理模块
- 新增keyboard_led_state_event事件用于处理USB/BLE HID输出报告中的LED状态 - 实现led_state_module模块,管理Num Lock指示灯和BLE状态指示灯 - 定义LED状态效果映射,包括熄灭、常亮、慢闪、快闪等效果 - 将hid_keymap_def.h从configuration目录移至inc目录 - 在BLE和USB HID模块中添加对输出报告LED掩码的解析和处理 - 配置DTS中的led_1为可用状态,更新CMakeLists.txt构建配置
This commit is contained in:
@@ -10,7 +10,6 @@ project(new_kbd)
|
||||
|
||||
zephyr_include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)
|
||||
zephyr_include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/events)
|
||||
zephyr_include_directories(${CMAKE_CURRENT_SOURCE_DIR}/configuration/atguigu_mini_keyboard_nrf52840)
|
||||
|
||||
target_compile_definitions(app PRIVATE
|
||||
APP_HID_KEYMAP_DEF_PATH=\"hid_keymap_def.h\"
|
||||
@@ -22,12 +21,14 @@ target_sources(app PRIVATE
|
||||
src/events/config_event.c
|
||||
src/events/hid_protocol_event.c
|
||||
src/events/hid_report_event.c
|
||||
src/events/keyboard_led_state_event.c
|
||||
src/events/mode_event.c
|
||||
src/events/usb_hid_event.c
|
||||
src/modules/battery_module.c
|
||||
src/modules/ble_adv_ctrl_module.c
|
||||
src/modules/ble_bond_module.c
|
||||
src/modules/keyboard_module.c
|
||||
src/modules/led_state_module.c
|
||||
src/modules/mode_switch_module.c
|
||||
src/modules/usb_hid_module.c
|
||||
src/modules/ble_hid_module.c
|
||||
|
||||
@@ -53,6 +53,10 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&led_1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* 使能 SAADC,mode_switch_module 使用 channel 7 采样模式拨码电压。 */
|
||||
&adc {
|
||||
status = "okay";
|
||||
@@ -63,7 +67,6 @@
|
||||
|
||||
ip5305: pmic@75 {
|
||||
status = "okay";
|
||||
/* 试验项:调整 IP5305 KEY 保活周期,观察 I2C 失败窗口是否随周期移动。 */
|
||||
keepalive-interval-ms = <10000>;
|
||||
};
|
||||
};
|
||||
|
||||
29
inc/led_state.h
Normal file
29
inc/led_state.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef NEW_KBD_LED_STATE_H__
|
||||
#define NEW_KBD_LED_STATE_H__
|
||||
|
||||
#include <zephyr/types.h>
|
||||
|
||||
/* 模块内系统状态:只用于本项目的 LED 映射,不对外暴露协议语义。 */
|
||||
enum led_ble_state {
|
||||
LED_BLE_STATE_OFF = 0,
|
||||
LED_BLE_STATE_WAIT_RECONNECT,
|
||||
LED_BLE_STATE_PAIRING,
|
||||
LED_BLE_STATE_CONNECTED,
|
||||
LED_BLE_STATE_COUNT,
|
||||
};
|
||||
|
||||
enum led_num_lock_state {
|
||||
LED_NUM_LOCK_STATE_OFF = 0,
|
||||
LED_NUM_LOCK_STATE_ON,
|
||||
LED_NUM_LOCK_STATE_COUNT,
|
||||
};
|
||||
|
||||
enum led_id_new_kbd {
|
||||
LED_ID_NUM_LOCK = 0,
|
||||
LED_ID_BLE_STATE,
|
||||
LED_ID_COUNT,
|
||||
};
|
||||
|
||||
#define LED_UNAVAILABLE 0xFF
|
||||
|
||||
#endif /* NEW_KBD_LED_STATE_H__ */
|
||||
39
inc/led_state_def.h
Normal file
39
inc/led_state_def.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "led_state.h"
|
||||
#include <caf/led_effect.h>
|
||||
|
||||
/*
|
||||
* 该文件仅被 led_state_module.c 包含一次,用于定义:
|
||||
* 1) 逻辑 LED 到 CAF LED 实例编号映射;
|
||||
* 2) 每个逻辑状态对应的 LED 效果。
|
||||
*/
|
||||
const struct {} led_state_def_include_once;
|
||||
|
||||
/*
|
||||
* CAF LED 实例编号来源于 DTS 中 status=okay 的 gpio-leds 顺序:
|
||||
* - led_0 -> 0(Num Lock)
|
||||
* - led_1 -> 1(BLE 状态)
|
||||
*/
|
||||
static const uint8_t led_map[LED_ID_COUNT] = {
|
||||
[LED_ID_NUM_LOCK] = 0,
|
||||
[LED_ID_BLE_STATE] = 1,
|
||||
};
|
||||
|
||||
/* Num Lock 指示:灭=关闭,常亮=开启。 */
|
||||
static const struct led_effect led_num_lock_state_effect[LED_NUM_LOCK_STATE_COUNT] = {
|
||||
[LED_NUM_LOCK_STATE_OFF] = LED_EFFECT_LED_OFF(),
|
||||
[LED_NUM_LOCK_STATE_ON] = LED_EFFECT_LED_ON(LED_COLOR(255, 255, 255)),
|
||||
};
|
||||
|
||||
/*
|
||||
* BLE 指示灯策略:
|
||||
* - OFF: 熄灭(USB 连接或 BLE 非活动模式)
|
||||
* - WAIT_RECONNECT: 慢闪(1s toggle)
|
||||
* - PAIRING: 快闪(0.5s toggle)
|
||||
* - CONNECTED: 常亮
|
||||
*/
|
||||
static const struct led_effect led_ble_state_effect[LED_BLE_STATE_COUNT] = {
|
||||
[LED_BLE_STATE_OFF] = LED_EFFECT_LED_OFF(),
|
||||
[LED_BLE_STATE_WAIT_RECONNECT] = LED_EFFECT_LED_BLINK(1000, LED_COLOR(255, 255, 255)),
|
||||
[LED_BLE_STATE_PAIRING] = LED_EFFECT_LED_BLINK(500, LED_COLOR(255, 255, 255)),
|
||||
[LED_BLE_STATE_CONNECTED] = LED_EFFECT_LED_ON(LED_COLOR(255, 255, 255)),
|
||||
};
|
||||
31
src/events/keyboard_led_state_event.c
Normal file
31
src/events/keyboard_led_state_event.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "keyboard_led_state_event.h"
|
||||
|
||||
static void log_keyboard_led_state_event(const struct app_event_header *aeh)
|
||||
{
|
||||
const struct keyboard_led_state_event *event =
|
||||
cast_keyboard_led_state_event(aeh);
|
||||
|
||||
APP_EVENT_MANAGER_LOG(aeh, "mask=0x%02x num_lock=%u",
|
||||
event->led_mask, event->num_lock);
|
||||
}
|
||||
|
||||
static void profile_keyboard_led_state_event(struct log_event_buf *buf,
|
||||
const struct app_event_header *aeh)
|
||||
{
|
||||
const struct keyboard_led_state_event *event =
|
||||
cast_keyboard_led_state_event(aeh);
|
||||
|
||||
nrf_profiler_log_encode_uint8(buf, event->led_mask);
|
||||
nrf_profiler_log_encode_uint8(buf, event->num_lock);
|
||||
}
|
||||
|
||||
APP_EVENT_INFO_DEFINE(keyboard_led_state_event,
|
||||
ENCODE(NRF_PROFILER_ARG_U8,
|
||||
NRF_PROFILER_ARG_U8),
|
||||
ENCODE("led_mask", "num_lock"),
|
||||
profile_keyboard_led_state_event);
|
||||
|
||||
APP_EVENT_TYPE_DEFINE(keyboard_led_state_event,
|
||||
log_keyboard_led_state_event,
|
||||
&keyboard_led_state_event_info,
|
||||
APP_EVENT_FLAGS_CREATE(APP_EVENT_TYPE_FLAGS_INIT_LOG_ENABLE));
|
||||
24
src/events/keyboard_led_state_event.h
Normal file
24
src/events/keyboard_led_state_event.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef KEYBOARD_LED_STATE_EVENT_H__
|
||||
#define KEYBOARD_LED_STATE_EVENT_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <app_event_manager.h>
|
||||
#include <app_event_manager_profiler_tracer.h>
|
||||
|
||||
/*
|
||||
* 键盘 LED 状态事件:
|
||||
* - 由 USB/BLE HID 接收主机输出报告后上报;
|
||||
* - 当前仅消费 Num Lock 位,保留 led_mask 便于后续扩展 Caps/Scroll。
|
||||
*/
|
||||
struct keyboard_led_state_event {
|
||||
struct app_event_header header;
|
||||
|
||||
uint8_t led_mask;
|
||||
bool num_lock;
|
||||
};
|
||||
|
||||
APP_EVENT_TYPE_DECLARE(keyboard_led_state_event);
|
||||
|
||||
#endif /* KEYBOARD_LED_STATE_EVENT_H__ */
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "hid_protocol_event.h"
|
||||
#include "hid_report_event.h"
|
||||
#include "hid_report_descriptor.h"
|
||||
#include "keyboard_led_state_event.h"
|
||||
#include "mode_event.h"
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
@@ -27,6 +28,8 @@ BT_HIDS_DEF(hids_obj, INPUT_REPORT_COUNT, OUTPUT_REPORT_COUNT, 0);
|
||||
static struct bt_conn *active_conn;
|
||||
static enum bt_hids_pm current_pm = BT_HIDS_PM_REPORT;
|
||||
static bool ble_mode_selected;
|
||||
static bool num_lock_known;
|
||||
static bool num_lock_on;
|
||||
|
||||
static enum hid_protocol_type pm_to_protocol(enum bt_hids_pm pm)
|
||||
{
|
||||
@@ -42,6 +45,25 @@ static void publish_hid_protocol_event(enum hid_protocol_type protocol)
|
||||
APP_EVENT_SUBMIT(event);
|
||||
}
|
||||
|
||||
/* BLE 输出报告的 bit0 对应 Num Lock。仅在状态变化时上报,避免重复通知。 */
|
||||
static void publish_num_lock_state_from_led_mask(uint8_t led_mask)
|
||||
{
|
||||
bool new_num_lock = (led_mask & BIT(0)) != 0U;
|
||||
|
||||
if (num_lock_known && (num_lock_on == new_num_lock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
num_lock_known = true;
|
||||
num_lock_on = new_num_lock;
|
||||
|
||||
struct keyboard_led_state_event *event = new_keyboard_led_state_event();
|
||||
|
||||
event->led_mask = led_mask;
|
||||
event->num_lock = new_num_lock;
|
||||
APP_EVENT_SUBMIT(event);
|
||||
}
|
||||
|
||||
static void pm_evt_handler(enum bt_hids_pm_evt evt, struct bt_conn *conn)
|
||||
{
|
||||
ARG_UNUSED(conn);
|
||||
@@ -86,6 +108,7 @@ static void boot_keyboard_output_report_handler(struct bt_hids_rep *rep,
|
||||
return;
|
||||
}
|
||||
|
||||
publish_num_lock_state_from_led_mask(rep->data[0]);
|
||||
LOG_DBG("Boot KB out report 0x%02x", rep->data[0]);
|
||||
}
|
||||
|
||||
@@ -99,6 +122,7 @@ static void keyboard_output_report_handler(struct bt_hids_rep *rep,
|
||||
return;
|
||||
}
|
||||
|
||||
publish_num_lock_state_from_led_mask(rep->data[0]);
|
||||
LOG_DBG("Report KB out report 0x%02x", rep->data[0]);
|
||||
}
|
||||
|
||||
|
||||
180
src/modules/led_state_module.c
Normal file
180
src/modules/led_state_module.c
Normal file
@@ -0,0 +1,180 @@
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#include <app_event_manager.h>
|
||||
|
||||
#define MODULE led_state
|
||||
#include <caf/events/module_state_event.h>
|
||||
#include <caf/events/ble_common_event.h>
|
||||
#include <caf/events/led_event.h>
|
||||
|
||||
#include "keyboard_led_state_event.h"
|
||||
#include "led_state.h"
|
||||
#include "mode_event.h"
|
||||
#include "led_state_def.h"
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||||
|
||||
static uint8_t connected_peer_count;
|
||||
static bool ble_mode_selected;
|
||||
static bool peer_search_active;
|
||||
static enum peer_operation peer_op = PEER_OPERATION_CANCEL;
|
||||
static bool num_lock_on;
|
||||
|
||||
/* 根据当前聚合上下文决定 BLE 状态灯的逻辑状态。 */
|
||||
static enum led_ble_state resolve_ble_led_state(void)
|
||||
{
|
||||
if (!ble_mode_selected)
|
||||
return LED_BLE_STATE_OFF;
|
||||
|
||||
switch (peer_op) {
|
||||
case PEER_OPERATION_SELECT:
|
||||
case PEER_OPERATION_ERASE:
|
||||
case PEER_OPERATION_ERASE_ADV:
|
||||
return LED_BLE_STATE_PAIRING;
|
||||
|
||||
case PEER_OPERATION_SELECTED:
|
||||
case PEER_OPERATION_ERASE_ADV_CANCEL:
|
||||
case PEER_OPERATION_ERASED:
|
||||
case PEER_OPERATION_CANCEL:
|
||||
case PEER_OPERATION_SCAN_REQUEST:
|
||||
if (peer_search_active)
|
||||
return LED_BLE_STATE_PAIRING;
|
||||
|
||||
if (connected_peer_count > 0U)
|
||||
return LED_BLE_STATE_CONNECTED;
|
||||
|
||||
return LED_BLE_STATE_WAIT_RECONNECT;
|
||||
|
||||
default:
|
||||
__ASSERT_NO_MSG(false);
|
||||
return LED_BLE_STATE_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* 发布 Num Lock 灯效。 */
|
||||
static void submit_num_lock_led(void)
|
||||
{
|
||||
if (led_map[LED_ID_NUM_LOCK] == LED_UNAVAILABLE)
|
||||
return;
|
||||
|
||||
enum led_num_lock_state state =
|
||||
num_lock_on ? LED_NUM_LOCK_STATE_ON : LED_NUM_LOCK_STATE_OFF;
|
||||
struct led_event *event = new_led_event();
|
||||
|
||||
event->led_id = led_map[LED_ID_NUM_LOCK];
|
||||
event->led_effect = &led_num_lock_state_effect[state];
|
||||
APP_EVENT_SUBMIT(event);
|
||||
}
|
||||
|
||||
/* 发布 BLE 状态灯效。 */
|
||||
static void submit_ble_led(void)
|
||||
{
|
||||
if (led_map[LED_ID_BLE_STATE] == LED_UNAVAILABLE)
|
||||
return;
|
||||
|
||||
enum led_ble_state state = resolve_ble_led_state();
|
||||
struct led_event *event = new_led_event();
|
||||
|
||||
event->led_id = led_map[LED_ID_BLE_STATE];
|
||||
event->led_effect = &led_ble_state_effect[state];
|
||||
APP_EVENT_SUBMIT(event);
|
||||
}
|
||||
|
||||
static bool handle_mode_event(const struct mode_event *event)
|
||||
{
|
||||
ble_mode_selected = (event->mode_type == MODE_TYPE_BLE);
|
||||
submit_ble_led();
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool handle_ble_peer_event(const struct ble_peer_event *event)
|
||||
{
|
||||
switch (event->state) {
|
||||
case PEER_STATE_CONNECTED:
|
||||
__ASSERT_NO_MSG(connected_peer_count < UINT8_MAX);
|
||||
connected_peer_count++;
|
||||
break;
|
||||
|
||||
case PEER_STATE_DISCONNECTED:
|
||||
__ASSERT_NO_MSG(connected_peer_count > 0U);
|
||||
connected_peer_count--;
|
||||
break;
|
||||
|
||||
case PEER_STATE_SECURED:
|
||||
case PEER_STATE_CONN_FAILED:
|
||||
case PEER_STATE_DISCONNECTING:
|
||||
break;
|
||||
|
||||
default:
|
||||
__ASSERT_NO_MSG(false);
|
||||
break;
|
||||
}
|
||||
|
||||
submit_ble_led();
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool handle_ble_peer_search_event(const struct ble_peer_search_event *event)
|
||||
{
|
||||
peer_search_active = event->active;
|
||||
submit_ble_led();
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool handle_ble_peer_operation_event(const struct ble_peer_operation_event *event)
|
||||
{
|
||||
peer_op = event->op;
|
||||
submit_ble_led();
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool handle_keyboard_led_state_event(const struct keyboard_led_state_event *event)
|
||||
{
|
||||
num_lock_on = event->num_lock;
|
||||
submit_num_lock_led();
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||
submit_num_lock_led();
|
||||
submit_ble_led();
|
||||
module_set_state(MODULE_STATE_READY);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_mode_event(aeh))
|
||||
return handle_mode_event(cast_mode_event(aeh));
|
||||
|
||||
if (is_keyboard_led_state_event(aeh))
|
||||
return handle_keyboard_led_state_event(cast_keyboard_led_state_event(aeh));
|
||||
|
||||
if (IS_ENABLED(CONFIG_CAF_BLE_COMMON_EVENTS) && is_ble_peer_event(aeh))
|
||||
return handle_ble_peer_event(cast_ble_peer_event(aeh));
|
||||
|
||||
if (IS_ENABLED(CONFIG_CAF_BLE_COMMON_EVENTS) && is_ble_peer_search_event(aeh))
|
||||
return handle_ble_peer_search_event(cast_ble_peer_search_event(aeh));
|
||||
|
||||
if (IS_ENABLED(CONFIG_CAF_BLE_COMMON_EVENTS) && is_ble_peer_operation_event(aeh))
|
||||
return handle_ble_peer_operation_event(cast_ble_peer_operation_event(aeh));
|
||||
|
||||
__ASSERT_NO_MSG(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
APP_EVENT_LISTENER(MODULE, app_event_handler);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, module_state_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, mode_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, keyboard_led_state_event);
|
||||
#ifdef CONFIG_CAF_BLE_COMMON_EVENTS
|
||||
APP_EVENT_SUBSCRIBE(MODULE, ble_peer_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, ble_peer_search_event);
|
||||
APP_EVENT_SUBSCRIBE(MODULE, ble_peer_operation_event);
|
||||
#endif
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "hid_report_descriptor.h"
|
||||
#include "hid_protocol_event.h"
|
||||
#include "hid_report_event.h"
|
||||
#include "keyboard_led_state_event.h"
|
||||
#include "mode_event.h"
|
||||
#include "usb_hid_event.h"
|
||||
|
||||
@@ -55,6 +56,8 @@ struct usb_hid_ctx {
|
||||
|
||||
enum usb_hid_usbd_state usbd_state;
|
||||
enum hid_protocol_type current_protocol;
|
||||
bool num_lock_known;
|
||||
bool num_lock_on;
|
||||
};
|
||||
|
||||
static struct usb_hid_ctx g_usb_hid = {
|
||||
@@ -85,6 +88,25 @@ static void publish_usb_hid_state(void)
|
||||
APP_EVENT_SUBMIT(event);
|
||||
}
|
||||
|
||||
/* 从主机输出报告同步 Num Lock 位,并在状态变化时发布事件。 */
|
||||
static void publish_num_lock_state_from_led_mask(uint8_t led_mask)
|
||||
{
|
||||
bool new_num_lock = (led_mask & BIT(0)) != 0U;
|
||||
|
||||
if (g_usb_hid.num_lock_known && (g_usb_hid.num_lock_on == new_num_lock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_usb_hid.num_lock_known = true;
|
||||
g_usb_hid.num_lock_on = new_num_lock;
|
||||
|
||||
struct keyboard_led_state_event *event = new_keyboard_led_state_event();
|
||||
|
||||
event->led_mask = led_mask;
|
||||
event->num_lock = new_num_lock;
|
||||
APP_EVENT_SUBMIT(event);
|
||||
}
|
||||
|
||||
static void recompute_hid_state(void)
|
||||
{
|
||||
/* 兼容现有调用点:对外仅发布 enable + usbd 状态。 */
|
||||
@@ -118,8 +140,11 @@ static int hid_stub_set_report(const struct device *dev,
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(type);
|
||||
ARG_UNUSED(id);
|
||||
ARG_UNUSED(len);
|
||||
ARG_UNUSED(buf);
|
||||
|
||||
if ((len > 0U) && (buf != NULL)) {
|
||||
publish_num_lock_state_from_led_mask(buf[0]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -188,8 +213,10 @@ static void hid_stub_input_done(const struct device *dev, const uint8_t *report)
|
||||
static void hid_stub_output_report(const struct device *dev, uint16_t len, const uint8_t *buf)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(len);
|
||||
ARG_UNUSED(buf);
|
||||
|
||||
if ((len > 0U) && (buf != NULL)) {
|
||||
publish_num_lock_state_from_led_mask(buf[0]);
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_iface_ready_cb(const struct device *dev, bool ready)
|
||||
|
||||
Reference in New Issue
Block a user