打开主菜单

谷雨文档中心 β

更改

NRF52832DK协议栈高级实验

添加12,705字节2019年10月12日 (六) 11:53
实验简介
==== 实验简介 ====
HID(human Interface device),即人机交互设备,常见的有鼠标,键盘,游戏手柄,等等。一般有线方式都是通过USB连线连接到机器设备,作为用户输入设备。在蓝牙技术中,HID设备的接入就是无线的了。但 BLE HID 规范是以 USB HID 规范为基础的 ,不然设备驱动,兼容等问题都会有很多麻烦了。蓝牙中有HID, HOGP profile,但是只是在蓝牙数据通信上做的规范,HID具体含义相关,还是需要看USB相关的HID文档。profile,但是只是在蓝牙数据通信上做的规范,HID具体含义相关,还是需要看USB相关的HID文档。提供的HID示例均符合USB HID使用表:http://www.usb.org/developers/hidpage
所有提供的HID示例均符合USB HID使用表:http://www.usb.org/developers/hidpage注意:原本的HID协议,鼠标作为输入端设备,PC电脑作为接入端。而在BLE上,蓝牙开发板是作为输入端,手机是作为接入端,这样的方式,就导致蓝牙开发板发送数据给手机都是作为input数据。
==== 硬件说明 ====
==== 源码讲解 ====
源码讲解部分,我们主要围绕HID服务部分的处理来介绍。分别是hid服务的初始化,mouse控制数据的说明,以及hid服务发送数据的方式。
===== mian.c =====
首先我们找到工程的服务初始化函数,在里面包含了我们的qwr初始化,以及我们的hid服务的初始化。<syntaxhighlight lang="c" line="1" start="593">
//******************************************************************
// fn : services_init
//
// brief : 由应用层调用的初始化服务的函数
//
// param : none
//
// return : none
static void services_init(void)
{
qwr_init();
hids_init();
}
</syntaxhighlight>然后我们追踪到我们的hid初始化函数,可以看到里面的代码处理可以分为3个部分。
'''第一部分:'''rep_map_data数组,这个数组中定义了3个报告(report)
 
Report ID 1:描述的是鼠标按键以及滚轮的控制
 
Report ID 2:描述的是鼠标(指针)的控制
 
Report ID 3:描述的是音乐播放按键的控制,包含了音量的加减、上一首、下一首的切换,以及暂停/恢复等。
 
'''第二部分:'''p_input_report起头的代码,分别对上面的3个报告进行了初始化,这边都是配置的简易加密(just work),也就是配对的时候不需要加密。并且均配置为BLE_HIDS_REP_TYPE_INPUT,也就是由开发板发送数据给手机。
 
'''第三部分:'''最后是ble_hids_init_t起头的代码,也就是对hid服务的结构体进行初始化,由于我们是要用鼠标按键的功能,所以配置mouse为true,keyfob为flase,同样的也都是简单加密。
 
由于我们这个例程是自拍功能(也就是控制手机的音量加减按键),所以我们仅针对Report ID 3进行讲解。具体的HID协议这边我们就不给大家说明了,可以查看实验简介中提供的USB HID链接说明。在report3中,我们用户使用一个字节的数据进行音乐播放的控制,这个字节的8个bit位控制的内容分别如下:
{| class="wikitable"
!bit
!功能
|-
|0
|开始/暂停
|-
|1
|一键启动
|-
|2
|下一首
|-
|3
|上一首
|-
|4
|音量减
|-
|5
|音量加
|-
|6
|应用控制
|-
|7
|返回
|}
<syntaxhighlight lang="c" line="1" start="432">
//******************************************************************
// fn : hids_init
//
// brief : 初始化HID服务
//
// param : none
//
// return : none
static void hids_init(void)
{
ret_code_t err_code;
ble_hids_init_t hids_init_obj;
ble_hids_inp_rep_init_t * p_input_report;
uint8_t hid_info_flags;
 
static ble_hids_inp_rep_init_t inp_rep_array[INPUT_REPORT_COUNT];
static uint8_t rep_map_data[] =
{
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x02, // Usage (Mouse)
 
0xA1, 0x01, // Collection (Application)
 
// Report ID 1: Mouse buttons + scroll/pan
0x85, 0x01, // Report Id 1
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x95, 0x05, // Report Count (3)
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
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x38, // Usage (Wheel)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x81, 0x06, // Input (Data, Variable, Relative)
0x05, 0x0C, // Usage Page (Consumer)
0x0A, 0x38, 0x02, // Usage (AC Pan)
0x95, 0x01, // Report Count (1)
0x81, 0x06, // Input (Data,Value,Relative,Bit Field)
0xC0, // End Collection (Physical)
 
// Report ID 2: Mouse motion
0x85, 0x02, // Report Id 2
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x75, 0x0C, // Report Size (12)
0x95, 0x02, // Report Count (2)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x16, 0x01, 0xF8, // Logical maximum (2047)
0x26, 0xFF, 0x07, // Logical minimum (-2047)
0x81, 0x06, // Input (Data, Variable, Relative)
0xC0, // End Collection (Physical)
0xC0, // End Collection (Application)
 
// Report ID 3: Advanced buttons
0x05, 0x0C, // Usage Page (Consumer)
0x09, 0x01, // Usage (Consumer Control)
0xA1, 0x01, // Collection (Application)
0x85, 0x03, // Report Id (3)
0x15, 0x00, // Logical minimum (0)
0x25, 0x01, // Logical maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x01, // Report Count (1)
 
0x09, 0xCD, // Usage (Play/Pause)
0x81, 0x06, // Input (Data,Value,Relative,Bit Field)
0x0A, 0x83, 0x01, // Usage (AL Consumer Control Configuration)
0x81, 0x06, // Input (Data,Value,Relative,Bit Field)
0x09, 0xB5, // Usage (Scan Next Track)
0x81, 0x06, // Input (Data,Value,Relative,Bit Field)
0x09, 0xB6, // Usage (Scan Previous Track)
0x81, 0x06, // Input (Data,Value,Relative,Bit Field)
 
0x09, 0xEA, // Usage (Volume Down)
0x81, 0x06, // Input (Data,Value,Relative,Bit Field)
0x09, 0xE9, // Usage (Volume Up)
0x81, 0x06, // Input (Data,Value,Relative,Bit Field)
0x0A, 0x25, 0x02, // Usage (AC Forward)
0x81, 0x06, // Input (Data,Value,Relative,Bit Field)
0x0A, 0x24, 0x02, // Usage (AC Back)
0x81, 0x06, // Input (Data,Value,Relative,Bit Field)
0xC0 // End Collection
};
 
memset(inp_rep_array, 0, sizeof(inp_rep_array));
// Initialize HID Service.
p_input_report = &inp_rep_array[INPUT_REP_BUTTONS_INDEX];
p_input_report->max_len = INPUT_REP_BUTTONS_LEN;
p_input_report->rep_ref.report_id = INPUT_REP_REF_BUTTONS_ID;
p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;
 
p_input_report->sec.cccd_wr = SEC_JUST_WORKS;
p_input_report->sec.wr = SEC_JUST_WORKS;
p_input_report->sec.rd = SEC_JUST_WORKS;
 
p_input_report = &inp_rep_array[INPUT_REP_MOVEMENT_INDEX];
p_input_report->max_len = INPUT_REP_MOVEMENT_LEN;
p_input_report->rep_ref.report_id = INPUT_REP_REF_MOVEMENT_ID;
p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;
 
p_input_report->sec.cccd_wr = SEC_JUST_WORKS;
p_input_report->sec.wr = SEC_JUST_WORKS;
p_input_report->sec.rd = SEC_JUST_WORKS;
 
p_input_report = &inp_rep_array[INPUT_REP_MPLAYER_INDEX];
p_input_report->max_len = INPUT_REP_MEDIA_PLAYER_LEN;
p_input_report->rep_ref.report_id = INPUT_REP_REF_MPLAYER_ID;
p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;
 
p_input_report->sec.cccd_wr = SEC_JUST_WORKS;
p_input_report->sec.wr = SEC_JUST_WORKS;
p_input_report->sec.rd = SEC_JUST_WORKS;
 
hid_info_flags = HID_INFO_FLAG_REMOTE_WAKE_MSK | HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK;
 
memset(&hids_init_obj, 0, sizeof(hids_init_obj));
 
hids_init_obj.error_handler = service_error_handler;
hids_init_obj.is_kb = false;
hids_init_obj.is_mouse = true;
hids_init_obj.inp_rep_count = INPUT_REPORT_COUNT;
hids_init_obj.p_inp_rep_array = inp_rep_array;
hids_init_obj.outp_rep_count = 0;
hids_init_obj.p_outp_rep_array = NULL;
hids_init_obj.feature_rep_count = 0;
hids_init_obj.p_feature_rep_array = NULL;
hids_init_obj.rep_map.data_len = sizeof(rep_map_data);
hids_init_obj.rep_map.p_data = rep_map_data;
hids_init_obj.hid_information.bcd_hid = BASE_USB_HID_SPEC_VERSION;
hids_init_obj.hid_information.b_country_code = 0;
hids_init_obj.hid_information.flags = hid_info_flags;
hids_init_obj.included_services_count = 0;
hids_init_obj.p_included_services_array = NULL;
 
hids_init_obj.rep_map.rd_sec = SEC_JUST_WORKS;
hids_init_obj.hid_information.rd_sec = SEC_JUST_WORKS;
 
hids_init_obj.boot_mouse_inp_rep_sec.cccd_wr = SEC_JUST_WORKS;
hids_init_obj.boot_mouse_inp_rep_sec.wr = SEC_JUST_WORKS;
hids_init_obj.boot_mouse_inp_rep_sec.rd = SEC_JUST_WORKS;
 
hids_init_obj.protocol_mode_rd_sec = SEC_JUST_WORKS;
hids_init_obj.protocol_mode_wr_sec = SEC_JUST_WORKS;
hids_init_obj.ctrl_point_wr_sec = SEC_JUST_WORKS;
 
err_code = ble_hids_init(&m_hids, &hids_init_obj);
APP_ERROR_CHECK(err_code);
}
</syntaxhighlight>看完了hid服务的初始化之后,我们来看下如何发送hid服务的数据,也就是mouse控制的数据,这里我们以开发板上的按键S1和S2来作为mouse音量键控制的展示。
 
首先是按键S1,我们按下后,进入到如下处理函数。我们定义一个buffer,并且给它赋值0x10(0001 0000),也就是bit4赋值为1,然后调用ble_hids_inp_rep_send函数将这个数据发送给手机,此时控制的是手机的音量减按键。
 
然后是按键S1,我们按下后,进入到如下处理函数。我们定义一个buffer,并且给它赋值0x20(0010 0000),也就是bit5赋值为1,然后调用ble_hids_inp_rep_send函数将这个数据发送给手机,此时控制的是手机的音量加按键。
 
而如果我们打开手机的照相机功能,音量的加减按键都是控制照相机拍照。<syntaxhighlight lang="c" line="1" start="1012">
//******************************************************************
// fn : bsp_event_handler
//
// brief : 处理来自BSP模块的事件的函数
//
// param : event -> 事件按下按钮产生的事件
//
// return : none
static void bsp_event_handler(bsp_event_t event)
{
ret_code_t err_code;
 
switch (event)
{
case BSP_EVENT_KEY_0:
if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
{
//mouse_movement_send(-MOVEMENT_SPEED, 0);
uint8_t buffer[INPUT_REP_MEDIA_PLAYER_LEN];
 
APP_ERROR_CHECK_BOOL(INPUT_REP_MEDIA_PLAYER_LEN == 1);
 
buffer[0] = 0x10;
err_code = ble_hids_inp_rep_send(&m_hids,
INPUT_REP_MPLAYER_INDEX,
INPUT_REP_MEDIA_PLAYER_LEN,
buffer,
m_conn_handle);
if (err_code != NRF_ERROR_INVALID_STATE)
{
APP_ERROR_CHECK(err_code);
}
}
break;
 
case BSP_EVENT_KEY_1:
if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
{
//mouse_movement_send(0, -MOVEMENT_SPEED);
uint8_t buffer[INPUT_REP_MEDIA_PLAYER_LEN];
 
APP_ERROR_CHECK_BOOL(INPUT_REP_MEDIA_PLAYER_LEN == 1);
 
buffer[0] = 0x20;
err_code = ble_hids_inp_rep_send(&m_hids,
INPUT_REP_MPLAYER_INDEX,
INPUT_REP_MEDIA_PLAYER_LEN,
buffer,
m_conn_handle);
if (err_code != NRF_ERROR_INVALID_STATE)
{
APP_ERROR_CHECK(err_code);
}
}
break;
default:
break;
}
}
</syntaxhighlight>
[[分类:NRF52832DK]]
[[分类:实验手册]]
510
个编辑