打印
[应用相关]

AN0174—AT32WB415 Custom HID over BLE开发指南

[复制链接]
747|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
AN, BLE, HID, ov
本帖最后由 ArterySW 于 2023-8-8 19:34 编辑

AT32WB415 Custom HID over BLE开发指南
前言
在AN0145我们实现了通用的媒体键盘与鼠标, HOGP使用了 USB的 HID规范,自然也可以建立自定义的 HID装置。
本应用笔记将以 AN0097的 Custom HID device为蓝本,将其功能移植到 BLE界面上,以期望能帮助使用者了解
如何使用 BLE建立属于自己的 HID装置。

支持型号列表:
AT32WB415

1 HOGP概述
有关HID的细节及 HOGP的内容,请参阅 AN0097, AN0145及 USB和 Bluetooth SIG的官方文件,
在这些文件中,使用者可以得到更加丰富的信息,在本应用笔记中不再赘述。

2 例 Custom HID装置实做
本应用指南是以BSP中的 Custom HID Device为原型,将其通讯接口改为 BLE, 具体实现的功能有
LED控制 , 按键状态接收及用户数据的自发自收 (使用 Loopback), 目前受限于上位机的架构,还无法
使用雅特力的官方工具,因此使用第三方的工具来演示这个范例程序。 以下各个小节会描述在开发过
程中需要修改及注意的细节,使用者可以根据自己的需求修改这些部份。

2.1 报告映射讨论
与AN0145相同, Custom HID一样需要在 gHIDReportDescriptor填入对应的 HID report, 基本上与
BSP的 Custom HID相同,但需要对 Report ID 5的内容进行修改,避免找不到装置,完整内容如下
 HID Report
0x06, 0xFF, 0x00, /* USAGE_PAGE(Vendor Page:0xFF00) */
0x09, 0x01, /* USAGE (Demo Kit) */
0xa1, 0x01, /* COLLECTION (Application) */
/* Led 2 */
0x85, HID_REPORT_ID_2, /* REPORT_ID 2 */
0x09, 0x02, /* USAGE (LED 2) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x95, 0x3F, /* REPORT_COUNT (1) */
0xB1, 0x82, /* FEATURE (Data,Var,Abs,Vol) */
0x85, 0x02, /* REPORT_ID (2) */
0x09, 0x02, /* USAGE (LED 2) */
0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vol) */
/* Led 3 */
0x85, HID_REPORT_ID_3, /* REPORT_ID (3) */
0x09, 0x03, /* USAGE (LED 3) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x95, 0x3F, /* REPORT_COUNT (1) */
0xB1, 0x82, /* FEATURE (Data,Var,Abs,Vol) */
0x85, 0x03, /* REPORT_ID (3) */

2.2 修改装置类型
只有当开发者正确地填入装置类型参数,主机端才能显示出合适的装置图标,即便在广播的时候能够
正确辨识出装置的类型,但如果没有修改 GAP中的 Appearance数值,联机后的装置图标依然会显
示异常,以下特别列出在开发时容易疏忽的地方:
1. 广播时的 Appearance,主机扫描到时就会将装置类型显示出来,比如说键盘或是鼠标,在代码
中位于 user_config.h里面的宏定义 APP_HID_ADV_DATA_APPEARANCE, 0x03C2代表鼠标 , 0x03C1代表键盘,
更详细的 内容可以参考 SIG的 Spec., 这里我们使用通用 HID,其值为0x03C0
图1. Appearance Part of ADV Data


2. 联机建立后,主机会来读取装置的 GAP, 这个时候就会得到这个装置是属于哪一种类型,如果
没有正确填写,在主机端的驱动安装完成后,显示的装置类型会与预期的不同。 这个部份的代
码位于 app_task.c中的 gapc_get_dev_info_req_ind_handler函式 , 代码中 已经定义了通用
HID, Mouce及 Keyboard, 使用者可以依据需求扩充。
图2. GAP Client Gets Device Apperance


3. 在新增 HID Profile时,填入当前的应用类型,这位于 app_hid.c中的 app_hid_add_hids函式,
在本应用指南中,因为是开发的一个自定义的 HID装置,因此填入 Protocol Mode即可 。
图3. HID device type


2.3 资源准备
1) 硬件环境:
对应产品型号的AT-START BOARD
2) 软件环境
wb415_hogp_bt_demo\projects\ble_app_remote
wb415_hogp_mcu_demo\utilities\wb415_hogp_mcu_demo\mdk_v5

2.4 软件设计
1) 配置流程
a) MCU端
 配置USER KEY作为击键
 编写USART3通讯函数
 轮询USER KEY是否按下
 根据需求去配置USER KEY按下后发出的AT command
b) BT端
 将HOGP的Profile加入database
 编写应用层与GATT之间的界面
 在应用层中轮询AT command
 透过HOGP将不同的key function发给host端
2) 代码介绍
 MCU端
 at_cmd_handler函数代码描述
static void at_cmd_handler(void)
{
uint8_t msg_id = SIZEOFMSG-1, i;
if(recv_cmp_flag == SET)
{
// parse at command
for(i = 0; i <= SIZEOFMSG; i++)
{
if(memcmp(recv_data, at_cmd_list[i].at_cmd_string, strlen(recv_data)) == 0)
{
msg_id = i;
break;
}
}
// according to message id to select cases
switch(at_cmd_list[msg_id].msg_id)
{
case AT_CMD_MSG_LED2_ON:
{
at32_led_on(LED2);
break;
}
case AT_CMD_MSG_LED2_OFF:
{
at32_led_off(LED2);
break;
}
case AT_CMD_MSG_LED3_ON:
{
at32_led_on(LED3);
break;
}

 BT端
原则上不需要去修改Profile层的内容,由APP层去设定HID装置的内容即可
 初始化HOGP装置变量
void app_hid_init(void)
{
// Reset the environment
memset(&app_hid_env, 0, sizeof(app_hid_env));
app_hid_env.state = APP_HID_IDLE;
app_hid_set_send_flag(true);
}
这边要注意到,代码将真实的HID report ID依序指派给db_cfg结构体中的report_id, 这在report
output时回用来作为接收数据的参考索引,会与真实的report ID不同,举例来说,我们要写入HID_REPORT_ID_6, 它在descriptor中是被定义为0xF0, 但对应到的report_id索引值为1, 使用者在开发时需要谨慎。
 将HOGP加入database

void app_hid_add_hids(void)
{
struct hogpd_db_cfg *db_cfg;
// Prepare the HOGPD_CREATE_DB_REQ message
struct gapm_profile_task_add_cmd *req = KE_MSG_ALLOC_DYN(GAPM_PROFILE_TASK_ADD_CMD,
TASK_GAPM, TASK_APP,
gapm_profile_task_add_cmd, sizeof(struct hogpd_db_cfg));
// Fill message
req->operation = GAPM_PROFILE_TASK_ADD;
req->sec_lvl = 0;
req->prf_task_id = TASK_ID_HOGPD;
req->app_task = TASK_APP;
req->start_hdl = 0;
// Set parameters
db_cfg = (struct hogpd_db_cfg *)req->param;
// Only one HIDS instance is useful
db_cfg->hids_nb = 1;
...
在main函数之中的while loop不断轮询app_user_entry()来确认有无收到AT command,如果收到有收到AT command则执行该命令的内容。
 解析AT command并执行对应的程序

void app_user_entry(void)
{
struct mouse_msg report = {0};
// GPIO_int_enable();
if (ke_state_get(TASK_APP) == APPM_READY)
{
UART_PRINTF("start advertising\r\n");
appm_start_advertising();
}
if (uart_rx_done == 1)
{
// uint8_t baud_change = 0;
uint8_t len;
uint8_t rsp_code;
// uint8_t idx;
extern uint8_t rxdata_buffer_len;
at_prefix_t *prefix_cmd;
// len = strlen((char*)rxdata_buffer);
len = rxdata_buffer_len;
rxdata_buffer_len = 0;
if (rxdata_buffer[len - 1] == '\n')
{
// AT command finish
// UART_PRINTF("finish\r\n");
memcpy(&AT_cmd_buf[recv_AT_cmd_idx], rxdata_buffer, len);
// UART_PRINTF("%s\r\n",AT_cmd_buf);
AT_cmd_len += len;
recv_AT_cmd_idx = 0;
}
...
Report output的部份,是实现在app_hid.c中的hogpd_report_req_ind_handler()函式,代码中是透过report的索引值判断当前接收到的数据是属于那一个report, 并根据报告内容对数据进行处理。
 根据report映像到的索引值进行数据处理

static int hogpd_report_req_ind_handler(ke_msg_id_t const msgid,
struct hogpd_report_req_ind const *param,
ke_task_id_t const dest_id,
ke_task_id_t const src_id)
{
if ((param->operation == HOGPD_OP_REPORT_READ) && (param->report.type == HOGPD_REPORT_MAP))
{
struct hogpd_report_cfm *req = KE_MSG_ALLOC_DYN(HOGPD_REPORT_CFM, prf_get_task_from_id(TASK_ID_HOGPD),
TASK_APP,
hogpd_report_cfm,
APP_HID_BK_REPORT_MAP_LEN);
req->conidx = app_hid_env.conidx;
...

2.5 实验效果
 按下AT-START板上的USER KEY发送按键状态,上位机以灯号反应按键状态
 在上位机上始能或失能LED2, LED3, LED4的选取方块可以控制开发板LED的明灭
 在上位机的Output Report byte length填写数据长度(在本应用笔记中以63 bytes为限), 在output的字段填写数据后按下Write, input字段会显示出output写入的数据
图 4. 上位机 的 控制界面


更多详细内容请参考附件:
AN0174_AT32WB415_Custom_HID_over_BLE_Development_Guide_ZH_V2.0.0.zip (12.93 MB)

使用特权

评论回复
沙发
yangxiaor520| | 2023-8-9 08:36 | 只看该作者
现在蓝牙都升到5点几版本了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

179

主题

276

帖子

11

粉丝