Funpack3-1实现蓝牙鼠标键盘复合设备应用
该项目使用了XG24-EK2703A,实现了蓝牙键鼠的设计,它的主要功能为:两个按键分别短按模拟鼠标滚轮向前、向后滚动一格。两个按键一起长按2S模拟键盘输入 EETREE.COM。
标签
蓝牙
FunPack3-1
XG24-EK2703A
蓝牙鼠标键盘
蓝牙HID
GNTT
鲜de芒果
更新2024-03-05
295

一、项目介绍

本项目基于Silabs XG24-EK2703A 片上系统的开发套件实现的蓝牙HID鼠标+键盘的复合设备。


1.1 硬件介绍

XG24-EK2703A是一款基于EFR32MG24片上系统的开发套件,具备超低成本、低功耗和小巧的特点。该套件支持2.4GHz无线通信,兼容蓝牙LE、蓝牙mesh、Zigbee、Thread和Matter协议,为无线物联网产品的开发和原型制作提供了极大的便利。


1.2 需求说明

  • 模拟鼠标滚轮功能,实现上下翻页
  • 模拟键盘功能,实现按键输入


二、功能实现

2.1 原理说明

HID(Human Interface Device)人机接口设备,是生活中常见的输入设备,比如键盘鼠标游戏手柄等等。早期的HID是设备大部分都是通过USB接口来实现,蓝牙技术出现后,通过蓝牙作为传输层,实现了蓝牙无线HID设备。通过蓝牙实现的HID功能一般简称为HOGP(HID over Gatt Profile)。

要实现HID的功能,一般需满足如下两个条件:

  1. 在广播数据中广播HID的UUID,设备外观,设备名称等信息。HID服务的UUID是0x1812,键盘的外观是0x03C1,鼠标的外观是0x03C2,游戏手柄的外观是0x03C3。

  1. 在GATT中实现HID要求的服务和特性


2.2 设计思路

2.2.1 软件流程

如上图所示,设备蓝牙初始化完成后,电脑通过蓝牙可以搜索到本蓝牙设备。建立蓝牙通信连接后,设备上的按键如果被触发即可通过蓝牙HID协议向电脑发送按键指令。设备按键使用中断回调函数触发,触发后向电脑发送蓝牙HID按键事件,电脑端收到事件后即可触发Windows按键事件。剩下的就交由操作系统处理了,如果这时打开了编辑器,并处于焦点模式即可看到编辑器上会输入 eetree.cn 字符。


2.2.2 实现过程

本次应用使用的硬件基于Silabs XG24-EK2703A 片上系统的开发套件。软件部分实现过程:

  1. 编写蓝牙HID协议栈:在设备端编写蓝牙HID协议栈的部分,包括HID profile的实现,以支持设备与主机之间的通信和数据交换。详见章节:2.3.1 与 2.3.2
  2. 处理用户输入和数据传输:按键初始化,处理用户的输入事件(如按键、鼠标滚轮等),并通过蓝牙协议将数据传输到主机设备。详见章节:2.3.4
  3. 控制设备行为和状态,配对和连接等:根据需求,编写配对和连接管理的部分,实现设备的相关功能,确保设备能够安全地配对和连接到主机设备进行交互。详见章节:2.3.3


2.3 关键代码说明

2.3.1 Report Map & Report

蓝牙键鼠关键的就是 Report Map 的定义,定义好之后,按照定义的格式发送相应数据即可实现相应功能。这里给出我在该项目中的数据定义

/**
* HID 上报数据描述
* 0x05, 0x01, // Usage Page (Generic Desktop)
* 0x09, 0x06, // Usage (Keyboard)
* 0xA1, 0x01, // Collection (Application)
* 0x85, 0x01, // Report id (Keyboard)
* 0x05, 0x07, // Usage Page (Key Codes)
* 0x19, 0xe0, // Usage Minimum (224)
* 0x29, 0xe7, // Usage Maximum (231)
* 0x15, 0x00, // Logical Minimum (0)
* 0x25, 0x01, // Logical Maximum (1)
* 0x75, 0x01, // Report Size (1)
* 0x95, 0x08, // Report Count (8)
* 0x81, 0x02, // Input (Data, Variable, Absolute)
* 0x95, 0x01, // Report Count (1)
* 0x75, 0x08, // Report Size (8)
* 0x81, 0x01, // Input (Constant) reserved byte(1)
* 0x95, 0x06, // Report Count (6)
* 0x75, 0x08, // Report Size (8)
* 0x15, 0x00, // Logical Minimum (0)
* 0x25, 0x65, // Logical Maximum (101)
* 0x05, 0x07, // Usage Page (Key codes)
* 0x19, 0x00, // Usage Minimum (0)
* 0x29, 0x65, // Usage Maximum (101)
* 0x81, 0x00, // Input (Data, Array) Key array(6 bytes)
* 0x85, 0x01, // Output Report id (Caps LOCK)
* 0x95, 0x05, // Report Count (5)
* 0x75, 0x01, // Report Size (1)
* 0x05, 0x08, // Usage Page (Page# for LEDs)
* 0x19, 0x01, // Usage Minimum (1)
* 0x29, 0x05, // Usage Maximum (5)
* 0x91, 0x02, // Output (Data, Variable, Absolute),
* 0x95, 0x01, // Report Count (1)
* 0x75, 0x03, // Report Size (3)
* 0x91, 0x01, // Output (Data, Variable, Absolute), report padding
* 0xC0, // End Collection (Application) Keyboard
*
* 0x05, 0x01, // Usage Page (Generic Desktop)
* 0x09, 0x02, // Usage (Mouse)
* 0xA1, 0x01, // Collection (Application)
* 0x85, 0x02, // Report Id 2 (Mouse)
* 0x09, 0x01, // Usage (Pointer)
* 0xA1, 0x00, // Collection (Physical)
* 0x95, 0x05, // Report Count (5)
* 0x75, 0x01, // Report Size (1)
* 0x05, 0x09, // Usage Page (Buttons)
* 0x19, 0x01, // Usage Minimum (01)
* 0x29, 0x05, // Usage Maximum (05)
* 0x15, 0x00, // Logical Minimum (0)
* 0x25, 0x01, // Logical Maximum (1)
* 0x81, 0x02, // Input (Data, Variable, Absolute)
* 0x95, 0x01, // Report Count (1)
* 0x75, 0x03, // Report Size (3)
* 0x81, 0x01, // Input (Constant) for padding
* 0x05, 0x01, // Usage Page (Generic Desktop)
* 0x09, 0x30, // Usage (X Point)
* 0x09, 0x31, // Usage (Y Point)
* 0x09, 0x38, // Usage (Mouse Wheel)
* 0x15, 0x81, // Logical Minimum (-127)
* 0x25, 0x7F, // Logical Maximum (127)
* 0x75, 0x08, // Report Size (8)
* 0x95, 0x03, // Report Count (1)
* 0x81, 0x06, // Input (Data, Variable, Relative)
* 0xC0, // End Collection (Physical)
* 0xC0 // End Collection (Physical)
*/
/**
* 键盘上报数据为 8 字节
*/
static uint8_t input_report_data[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
/**
* 鼠标上报数据为 4 字节
*/
static uint8_t input_report_data_mouse[] = { 0, 0, 0, 0 };


2.3.2 GATT 配置截图

在官方 HID Keyboard 示例的 GATT 配置文件基础上,只需要新增一个鼠标的 Report 特征值即可。


2.3.3 蓝牙事件处理

...

case sl_bt_evt_system_external_signal_id:
if (notification_enabled == 1) {
if(1 == report_type) { // 上报按键事件
memset(input_report_data, 0, sizeof(input_report_data));
input_report_data[MODIFIER_INDEX] = CAPSLOCK_KEY_OFF;
for(int i = 0; i < sizeof(send_key_array); i ++) {
input_report_data[DATA_INDEX] = send_key_array[i];
app_log("report keyboard data: %d\r\n", send_key_array[i]);
// 键盘报告
sc = sl_bt_gatt_server_notify_all(gattdb_report,
sizeof(input_report_data),
input_report_data);
app_assert_status(sc);
}
report_type = 0; // 重置为上报鼠标事件
} else { // 上报鼠标事件
memset(input_report_data_mouse, 0, sizeof(input_report_data_mouse));
input_report_data_mouse[0] = 0x0;
input_report_data_mouse[3] = mouse_wheel;
app_log("report mouse data: %d\r\n", input_report_data_mouse[3]);
// 鼠标报告
sc = sl_bt_gatt_server_notify_all(gattdb_report_mouse,
sizeof(input_report_data_mouse),
input_report_data_mouse);
app_assert_status(sc);
mouse_wheel = 0; // 重置鼠标滚轮状态,避免按下时重复发送滚动数据
}

app_log("Key report was sent\r\n");
}
app_log("sl_bt_evt_system_external_signal_id event!");
break;

...


2.3.4 按键事件处理

按键事件逻辑,按键中断回调函数中,判断是哪个按键,按键事件回调时判断按键的状态进行逻辑处理。这里按下时会启动一个定时器。

...

// BTN0 按键事件
if (&sl_button_btn0 == handle) {
if (sl_button_get_state(handle) == SL_SIMPLE_BUTTON_PRESSED) { // 按下
app_log("Button pushed - callback\r\n");
// 启动按键0定时器
sl_sleeptimer_start_timer(&btn0_timer,
timeout_tick,
on_timeout, handle,
0,
SL_SLEEPTIMER_NO_HIGH_PRECISION_HF_CLOCKS_REQUIRED_FLAG);
} else { // 松开
sl_sleeptimer_stop_timer(&btn0_timer);

btn0_state = false;
if(1 == report_type) { // 报告按键事件

} else {
mouse_wheel = 1;
}
app_log("Button released - callback \r\n");
}
}

...


三、功能展示

3.1 鼠标滚轮效果

向下滚动一格


向上滚动一格


3.2 键盘按键模拟效果

长按两秒输入 eetree.com

这里为了避免模拟键盘输入与模拟鼠标滚轮时的按键冲突,这里设置为按下两秒后,松开按键时才触发键盘数据上报。


四、总结

Simplicity Studio 5 IDE初次使用时,有点摸不着头脑。但静下心来按照官方教程,一步步安装还是很容易成功的。使用体验上也是比较友好的,由于IDE是基于Eclipse系的使用上还是稍微有点复杂。官方教程也比较详细,基本上按照官方教程都能搞定,多摸索就好了。

第一次接触蓝牙应用,对蓝牙协议栈不了解,因此开发过程中走了不少弯路。尤其是HID协议,完全没概念。好在官方封装的比较好,其中GATT的图形化配置非常Nice。但也由于GATT配置工具封装的很好,导致配置HID ReportMap时一时不知道如何下手,摸索了很长时间才尝试出来。这点希望官方能加强这部分的文档输出。

最后感谢电子森林与得捷电子联合推出的 《Funpack》 系列活动,对于我来说是个很好的学习机会,理论结合实践。我们下期活动再见!


五、参考资料

附件下载
bt_soc_empty.zip
Simplicity Studio 5 工程源码
团队介绍
业余电子爱好者
团队成员
鲜de芒果
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号