[应用相关] AN0174—AT32WB415 Custom HID over BLE开发指南

[复制链接]
1297|1
 楼主| ArterySW 发表于 2023-8-8 19:23 | 显示全部楼层 |阅读模式
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
  1. 0x06, 0xFF, 0x00, /* USAGE_PAGE(Vendor Page:0xFF00) */
  2. 0x09, 0x01, /* USAGE (Demo Kit) */
  3. 0xa1, 0x01, /* COLLECTION (Application) */
  4. /* Led 2 */
  5. 0x85, HID_REPORT_ID_2, /* REPORT_ID 2 */
  6. 0x09, 0x02, /* USAGE (LED 2) */
  7. 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
  8. 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
  9. 0x75, 0x08, /* REPORT_SIZE (8) */
  10. 0x95, 0x3F, /* REPORT_COUNT (1) */
  11. 0xB1, 0x82, /* FEATURE (Data,Var,Abs,Vol) */
  12. 0x85, 0x02, /* REPORT_ID (2) */
  13. 0x09, 0x02, /* USAGE (LED 2) */
  14. 0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vol) */
  15. /* Led 3 */
  16. 0x85, HID_REPORT_ID_3, /* REPORT_ID (3) */
  17. 0x09, 0x03, /* USAGE (LED 3) */
  18. 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
  19. 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
  20. 0x75, 0x08, /* REPORT_SIZE (8) */
  21. 0x95, 0x3F, /* REPORT_COUNT (1) */
  22. 0xB1, 0x82, /* FEATURE (Data,Var,Abs,Vol) */
  23. 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
263164d224e1ec7e6.png

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

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

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函数代码描述
  1. static void at_cmd_handler(void)
  2. {
  3. uint8_t msg_id = SIZEOFMSG-1, i;
  4. if(recv_cmp_flag == SET)
  5. {
  6. // parse at command
  7. for(i = 0; i <= SIZEOFMSG; i++)
  8. {
  9. if(memcmp(recv_data, at_cmd_list[i].at_cmd_string, strlen(recv_data)) == 0)
  10. {
  11. msg_id = i;
  12. break;
  13. }
  14. }
  15. // according to message id to select cases
  16. switch(at_cmd_list[msg_id].msg_id)
  17. {
  18. case AT_CMD_MSG_LED2_ON:
  19. {
  20. at32_led_on(LED2);
  21. break;
  22. }
  23. case AT_CMD_MSG_LED2_OFF:
  24. {
  25. at32_led_off(LED2);
  26. break;
  27. }
  28. case AT_CMD_MSG_LED3_ON:
  29. {
  30. at32_led_on(LED3);
  31. break;
  32. }

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

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

  1. void app_user_entry(void)
  2. {
  3. struct mouse_msg report = {0};
  4. // GPIO_int_enable();
  5. if (ke_state_get(TASK_APP) == APPM_READY)
  6. {
  7. UART_PRINTF("start advertising\r\n");
  8. appm_start_advertising();
  9. }
  10. if (uart_rx_done == 1)
  11. {
  12. // uint8_t baud_change = 0;
  13. uint8_t len;
  14. uint8_t rsp_code;
  15. // uint8_t idx;
  16. extern uint8_t rxdata_buffer_len;
  17. at_prefix_t *prefix_cmd;
  18. // len = strlen((char*)rxdata_buffer);
  19. len = rxdata_buffer_len;
  20. rxdata_buffer_len = 0;
  21. if (rxdata_buffer[len - 1] == '\n')
  22. {
  23. // AT command finish
  24. // UART_PRINTF("finish\r\n");
  25. memcpy(&AT_cmd_buf[recv_AT_cmd_idx], rxdata_buffer, len);
  26. // UART_PRINTF("%s\r\n",AT_cmd_buf);
  27. AT_cmd_len += len;
  28. recv_AT_cmd_idx = 0;
  29. }
  30. ...
Report output的部份,是实现在app_hid.c中的hogpd_report_req_ind_handler()函式,代码中是透过report的索引值判断当前接收到的数据是属于那一个report, 并根据报告内容对数据进行处理。
 根据report映像到的索引值进行数据处理

  1. static int hogpd_report_req_ind_handler(ke_msg_id_t const msgid,
  2. struct hogpd_report_req_ind const *param,
  3. ke_task_id_t const dest_id,
  4. ke_task_id_t const src_id)
  5. {
  6. if ((param->operation == HOGPD_OP_REPORT_READ) && (param->report.type == HOGPD_REPORT_MAP))
  7. {
  8. struct hogpd_report_cfm *req = KE_MSG_ALLOC_DYN(HOGPD_REPORT_CFM, prf_get_task_from_id(TASK_ID_HOGPD),
  9. TASK_APP,
  10. hogpd_report_cfm,
  11. APP_HID_BK_REPORT_MAP_LEN);
  12. req->conidx = app_hid_env.conidx;
  13. ...

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

更多详细内容请参考附件:
AN0174_AT32WB415_Custom_HID_over_BLE_Development_Guide_ZH_V2.0.0.zip (12.93 MB, 下载次数: 7)

yangxiaor520 发表于 2023-8-9 08:36 来自手机 | 显示全部楼层
现在蓝牙都升到5点几版本了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

198

主题

305

帖子

17

粉丝
快速回复 在线客服 返回列表 返回顶部