基于富芮坤fr8016 蓝牙5.0 芯片设计的BLE HID Joystick 游戏摇杆设备

news/2024/11/24 13:41:29/

文章目录

  • ble hid 学习笔记
    • HID报告描述符与BLE HID profile之间关系
      • 1、HID报告描述符
    • 富芮坤fr8016 设计Joystick例子
      • 1、描述X轴Y轴Z轴
      • 2、描述按钮
      • 3、Joystick 报告描述符
      • 4、程序修改
      • 5、win10测试
      • 6、android 测试
  • 总结

ble hid 学习笔记

HID报告描述符与BLE HID profile之间关系

​ 说起BLE HID(Human Interface Device)设备,就不得不提USB HID。我的理解HID 读写报告属于传输层,所以BLE和USB在关于HID协议的规定都是一样的,运输层的通信不关心底层是通过蓝牙传还是USB传输。能研究BLE HID的朋友一定明白BLE通信是通过读写GATT属性表中的特征值实现的,同样HID是基于BLE实现的,所以HID协议中的读写报告,是基于BLE属性表中特征值实现的。蓝牙联盟已经替大家想好了,推出了HID profile规范,这个规范规定了BLE HID 模型是啥样的,大家都执行这个标准就可以互通往来了。

1、HID报告描述符

​ HID类设备定义连接https://usb.org/sites/default/files/hid1_11.pdf

​ 一个报告以说USAGE_PAGE和USAGE开头 COLLECTION Application 和END_COLLECTION相当于一个大括号里面的内容是对 USAGE进行解释。 一个集合分配是一个报告ID,一个报告描述符内可以有多个集合。也就是可以有多个报告ID。每个集合内最多有3种报告。3种报告对应着input、 output、 feature三种报告。比如下图例子。最先出现的是input 其次是 output 所以这个集合有2个报告,报告顺序是input ,output 。依此类推,整理出整个报告描述符中的3种报告的顺序和数量与GATT HID profile 的report 特征值的一一对应关系。

    0x05, 0x01,     // Usage Pg (Generic Desktop)0x09, 0x06,     // Usage (Keyboard)0xA1, 0x01,     // Collection: (Application)
//    0x85, 0x03,     // Report Id (3 for keyboard)//0x05, 0x07,     // Usage Pg (Key Codes)0x19, 0xE0,     // Usage Min (224)0x29, 0xE7,     // Usage Max (231)0x15, 0x00,     // Log Min (0)0x25, 0x01,     // Log Max (1)//// Modifier byte0x75, 0x01,     // Report Size (1)   1 bit * 80x95, 0x08,     // Report Count (8)0x81, 0x02,     // Input: (Data, Variable, Absolute)// Reserved byte0x95, 0x01, // Report Count (1)0x75, 0x08, // Report Size (8)0x81, 0x01, // Input: (Constant)//LED repor0x95, 0x05,    //Report Count (5)0x75, 0x01,    //Report Size (1)0x05, 0x08,    //Usage Pg (LEDs )0x19, 0x01,    //Usage Min0x29, 0x05,    //Usage Max0x91, 0x02,    //Output (Data, Variable, Absolute)//3 bit reserved0x95, 0x01,    //Report Count (1)0x75, 0x03,    //Report Size (3)0x91, 0x01,    //Output (Constant)// Key arrays (6 bytes)// this is key array,support simultaneously pressing 6keys report,// from report_buf[3]~report_buf[3]0x95, 0x06,     // Report Count (6)0x75, 0x08,     // Report Size (8)0x15, 0x00,     // Log Min (0)0x25, 0xE7,     // Log Max (237)0x05, 0x07,     // Usage Pg (Key Codes) , here is the key page,look usb hid key define0x19, 0x00,     // Usage Min (0)0x29, 0xE7,     // Usage Max (237)0x81, 0x00,     // Input: (Data, Array)0xC0,            // End Collection

富芮坤fr8016 设计Joystick例子

​ 使用富芮坤FR8016H 蓝牙5,0芯片,做一个蓝牙Joystick,Joystick有3个轴分别是X、Y、Z3个轴,加上8个按钮。每个轴对应一个字节,一个按钮对应一个比特所以8个按钮对应1个字节。所以输入报告需要4个字节。

数据结构如下所示:

在这里插入图片描述

1、描述X轴Y轴Z轴

​ 在报告描述符中,一个项目必须包含三个字段, 定义3轴:

//(Generic Desktop)  详细解释上摇杆上的3个轴属于桌面设备0x09, 0x30,                    //     USAGE (X)  定义一个X轴0x09, 0x31,                    //     USAGE (Y)  定义一个Y轴0x09, 0x32,                    //     USAGE (Z)  定义一个Z轴

​ 每个轴的逻辑范围 最小-127 最大12

  0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)  对3个轴进行规范 逻辑最小值为-1270x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)   对3个轴进行规范 逻辑最大值为127

用3个字节表示3个轴

	//报告大小为8bit 有符号 对应-127 到1270x75, 0x08,                    //     REPORT_SIZE (8)0x95, 0x03,                    //     REPORT_COUNT (3)  3个轴总共有3个字节

发送这3个轴数据到电脑:

3个轴总共有3个字节0x81, 0x02,                    //     INPUT (Data,Var,Abs) 报告为输入,变量,值,绝对值。

3个轴最终描述

    0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)  详细解释上摇杆上的3个轴属于桌面设备0x09, 0x30,                    //     USAGE (X)  定义一个X轴0x09, 0x31,                    //     USAGE (Y)  定义一个Y轴0x09, 0x32,                    //     USAGE (Z)  定义一个Z轴0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)  对3个轴进行规范 逻辑最小值为-1270x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)   对3个轴进行规范 逻辑最大值为127//报告大小为8bit 有符号 对应-127 到1270x75, 0x08,                    //     REPORT_SIZE (8)0x95, 0x03,                    //     REPORT_COUNT (3)  3个轴总共有3个字节0x81, 0x02,                    //     INPUT (Data,Var,Abs) 报告为输入,变量,值,绝对值。

2、描述按钮

​ 定义8个按钮

	  0x05, 0x09,                    //     USAGE_PAGE (Button)  详细解释 摇杆上有按钮 0x19, 0x01,                    // 		USAGE_MINIMUM (Button 1) 定义最小按钮 0x29, 0x08,                    // 		USAGE_MAXIMUM (Button 8) 定义最大按钮 	

每个按钮的状态有2种 0 和1

// 对8个按钮进行规范 逻辑最小值为00x25, 0x01,                    //     LOGICAL_MAXIMUM (1) 对8个按钮进行规范 逻辑最大值为10x95, 0x08,                    //     REPORT_COUNT (8)  8个按钮总共有1个字节  最小按钮到最大按钮对应低到高bit位

用1个字节表示8个按钮

    0x75, 0x01,                    //     REPORT_SIZE (1)  8个按钮总共1个字节0x81, 0x02,                    //     INPUT 

最为输入报告发送到电脑上

    0x81, 0x02,                    //     INPUT (Data,Var,Abs)  报告为输入,变量,值,绝对值。

​ 最终的按钮表示方式

	  0x05, 0x09,                    //     USAGE_PAGE (Button)  详细解释 摇杆上有按钮 0x19, 0x01,                    // 		USAGE_MINIMUM (Button 1) 定义最小按钮 0x29, 0x08,                    // 		USAGE_MAXIMUM (Button 8) 定义最大按钮 	0x15, 0x00,                    //     LOGICAL_MINIMUM (0) 对8个按钮进行规范 逻辑最小值为00x25, 0x01,                    //     LOGICAL_MAXIMUM (1) 对8个按钮进行规范 逻辑最大值为10x95, 0x08,                    //     REPORT_COUNT (8)  8个按钮总共有1个字节  最小按钮到最大按钮对应低到高bit位0x75, 0x01,                    //     REPORT_SIZE (1)  8个按钮总共1个字节0x81, 0x02,                    //     INPUT (Data,Var,Abs)  报告为输入,变量,值,绝对值。

3个轴和8个按钮合并一起

  0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)  详细解释上摇杆上的3个轴属于桌面设备0x09, 0x30,                    //     USAGE (X)  定义一个X轴0x09, 0x31,                    //     USAGE (Y)  定义一个Y轴0x09, 0x32,                    //     USAGE (Z)  定义一个Z轴0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)  对3个轴进行规范 逻辑最小值为-1270x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)   对3个轴进行规范 逻辑最大值为127//报告大小为8bit 有符号 对应-127 到1270x75, 0x08,                    //     REPORT_SIZE (8)0x95, 0x03,                    //     REPORT_COUNT (3)  3个轴总共有3个字节0x81, 0x02,                    //     INPUT (Data,Var,Abs) 报告为输入,变量,值,绝对值。0x05, 0x09,                    //     USAGE_PAGE (Button)  详细解释 摇杆上有按钮 0x19, 0x01,                    // 		USAGE_MINIMUM (Button 1) 定义最小按钮 0x29, 0x08,                    // 		USAGE_MAXIMUM (Button 8) 定义最大按钮 	0x15, 0x00,                    //     LOGICAL_MINIMUM (0) 对8个按钮进行规范 逻辑最小值为00x25, 0x01,                    //     LOGICAL_MAXIMUM (1) 对8个按钮进行规范 逻辑最大值为10x95, 0x08,                    //     REPORT_COUNT (8)  8个按钮总共有1个字节  最小按钮到最大按钮对应低到高bit位0x75, 0x01,                    //     REPORT_SIZE (1)  8个按钮总共1个字节0x81, 0x02,                    //     INPUT (Data,Var,Abs)  报告为输入,变量,值,绝对值。

要注意的是即使按照上面的写法电脑还是解析不出来,还要给报告描述符加上个壳用了标记自己是桌面摇杆设备。(TI 可以不写报告ID也能识别到,富芮坤 的SDK 不写报告ID 电脑识别不到)

USAGE_PAGE (Generic Desktop)
USAGE (Joystick)
COLLECTION (Application)``Report Id (1)  ``COLLECTION (Physical)//上面的报告描述写到这里    ``END COLLECTION
END COLLECTION

3、Joystick 报告描述符

按照上诉要求整理,最后的报告描述符如下所示:

/******************************* HID Report Map characteristic defination */
static const uint8_t hid_report_map[] =
{0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)  开始声明当前设备为 桌面设备0x09, 0x04,                    // USAGE (Joystick)						  指明作为一个摇杆设备//集合相当于括号,必须要以COLLECTION开始 END_COLLECTION结束0xa1, 0x01,                    // COLLECTION (Application)0x85, 0x01,  									 // Report Id (1)   报告ID为1  规范上不写也可以但是实测富芮坤的SDK 不加电脑识别不到0xa1, 0x00,                    //   COLLECTION (Physical)0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)  详细解释上摇杆上的3个轴属于桌面设备0x09, 0x30,                    //     USAGE (X)  定义一个X轴0x09, 0x31,                    //     USAGE (Y)  定义一个Y轴0x09, 0x32,                    //     USAGE (Z)  定义一个Z轴0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)  对3个轴进行规范 逻辑最小值为-1270x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)   对3个轴进行规范 逻辑最大值为127//报告大小为8bit 有符号 对应-127 到1270x75, 0x08,                    //     REPORT_SIZE (8)0x95, 0x03,                    //     REPORT_COUNT (3)  3个轴总共有3个字节0x81, 0x02,                    //     INPUT (Data,Var,Abs) 报告为输入,变量,值,绝对值。0x05, 0x09,                    //     USAGE_PAGE (Button)  详细解释 摇杆上有按钮 0x19, 0x01,                    // 		USAGE_MINIMUM (Button 1) 定义最小按钮 0x29, 0x08,                    // 		USAGE_MAXIMUM (Button 8) 定义最大按钮 	0x15, 0x00,                    //     LOGICAL_MINIMUM (0) 对8个按钮进行规范 逻辑最小值为00x25, 0x01,                    //     LOGICAL_MAXIMUM (1) 对8个按钮进行规范 逻辑最大值为10x95, 0x08,                    //     REPORT_COUNT (8)  8个按钮总共有1个字节  最小按钮到最大按钮对应低到高bit位0x75, 0x01,                    //     REPORT_SIZE (1)  8个按钮总共1个字节0x81, 0x02,                    //     INPUT (Data,Var,Abs)  报告为输入,变量,值,绝对值。0xc0,                          //         END_COLLECTION  //关集合,跟上面Physical的对应0xc0                           //     END_COLLECTION      //关集合,跟上面Application的对应};

4、程序修改

​ 富芮坤提供了 ble_hid_kbd_mice demo 在此基础上修改蓝牙的报告描述符,报告特征值数量,即可完整通信。

按照开头的分析方法,分析Joystick报告描述符可知,Joystick需要一个input 报告 这个报告向主机发送4个字节的数据。

所以先报告的数量改成 1

// Number of HID reports defined in the service
#define HID_NUM_REPORTS          1

因为只有一个报告 所以BLE HID profile中多余的报告屏蔽掉,保留一个报告特征值,用于传输HID input 报告。

// HID Feature Report No 0[HID_FEATURE_DECL_IDX]          =   { { UUID_SIZE_2, UUID16_ARR(GATT_CHARACTER_UUID) },GATT_PROP_READ, 0,NULL,},[HID_FEATURE_IDX]               =   { { UUID_SIZE_2, UUID16_ARR(REPORT_UUID) },GATT_PROP_READ | GATT_PROP_NOTI,60,NULL,},[HID_REPORT_REF_FEATURE_IDX]    =   { { UUID_SIZE_2, UUID16_ARR(GATT_REPORT_REF_UUID) },GATT_PROP_READ,sizeof(hid_report_ref_t), NULL,},[HID_FEATURE_CCCD_IDX]          =   { { UUID_SIZE_2, UUID16_ARR(GATT_CLIENT_CHAR_CFG_UUID) },GATT_PROP_READ | GATT_PROP_WRITE, 0, NULL,},

再修改hid_gatt_add_service中的hid 报告信息数组,因为只有一个输入报告,所以只写一个报告即可。

/********************************************************************** @fn      hid_gatt_add_service** @brief   Simple Profile add GATT service function.*          添加GATT service到ATT的数据库里面。** @param   None.*** @return  None.*/
void hid_gatt_add_service(void)
{gatt_service_t hid_profie_svc;hid_profie_svc.p_att_tb = hid_profile_att_table;hid_profie_svc.att_nb = HID_ATT_NB;hid_profie_svc.gatt_msg_handler = hid_gatt_msg_handler;hid_rpt_info[0].report_id = 1;      //refer to report map, this is Joystick input.hid_rpt_info[0].report_type = HID_REPORT_TYPE_INPUT;     //att_table, perm must be GATT_PROP_READ | GATT_PROP_NOTIhid_svc_id = gatt_add_service(&hid_profie_svc);
}

最后是发送报告,这里测试发现如果发送报告的数据特别频繁容易导致发送出错,所以这里 程序修改成,当3个轴数据 按钮 和之前不一样则更新数据。

    adc_enable(NULL, NULL, 0);adc_get_result(ADC_TRANS_SOURCE_PAD, 0x01, &result);myJoystick.axis_x = 255.00*result/1023;adc_get_result(ADC_TRANS_SOURCE_PAD, 0x02, &result);myJoystick.axis_y = 255.00*result/1023;adc_get_result(ADC_TRANS_SOURCE_PAD, 0x04, &result);myJoystick.axis_z = 255.00*result/1023;key[0] = myJoystick.axis_x ;         //  key[1] = myJoystick.axis_y ;         //  key[2] = myJoystick.axis_z ;   			 //   1if(oldMyJoystick.axis_x != myJoystick.axis_x||oldMyJoystick.axis_y != myJoystick.axis_y||oldMyJoystick.axis_z != myJoystick.axis_z){hid_gatt_report_notify(slave_link_conidx,HID_KEYBOARD_RPT_ID,key,HID_KEYBOARD_IN_RPT_LEN);}oldMyJoystick.axis_x = myJoystick.axis_x ;oldMyJoystick.axis_y = myJoystick.axis_y ;oldMyJoystick.axis_z = myJoystick.axis_z ;

5、win10测试

按照上述修改将程序下载到芯片中,电脑连接蓝牙,如下图所示。

只有当摇杆出现在鼠标,键盘和笔这一栏时,说明设备连接成功可以发送数据。

在这里插入图片描述

在这里插入图片描述

电脑端可以用win10 自带的驱动对摇杆进行测试,打开控制面板下的设备和打印机,如果写的没有问题,就会在设备栏出现个手柄。

在这里插入图片描述
在手柄上右键游戏控制器设置点击属性

在这里插入图片描述

当出现下面界面时,就可以按手柄上的按钮和3个轴,界面就会显示对于的值。

在这里插入图片描述

如果觉得自带的软件麻烦可以用 joystick tester软件也可以测试。

在这里插入图片描述

6、android 测试

手机上安装 Game Pad Test 手机上只能识别到2个轴不知道啥原因

在这里插入图片描述
在这里插入图片描述

总结

​ 设计 BLE HID 设备的前提一定要搞懂 BLE特征值和HID报告描述符之间的关系,以及报告描述符中有多少个报告每个报告有多少个字节,如果这些关系弄明白了 做BLE HID 设备将轻车熟路了。


http://www.ppmy.cn/news/562615.html

相关文章

2023-06-25 LeetCode每日一题(圆和矩形是否有重叠)

2023-06-25每日一题 一、题目编号 1401. 圆和矩形是否有重叠二、题目链接 点击跳转到题目位置 三、题目描述 给你一个以 (radius, xCenter, yCenter) 表示的圆和一个与坐标轴平行的矩形 (x1, y1, x2, y2) ,其中 (x1, y1) 是矩形左下角的坐标,而 (x2…

【PCB专题】Allegro中设置泪滴

PCB绘制完成后有时按需要对PCB进行添加泪滴的操作是非常必要的。 添加泪滴的作用主要是: 信号传输时平滑阻抗,减少阻抗的急剧跳变,避免高频信号传输时由于线宽突然变小而造成反射。 焊接时可以保护焊盘,避免多次焊接时焊盘的脱落,生产时可以避免蚀刻不均,以及过孔偏位出…

ViewModel进阶 | 使用SavedState实现数据复用的另一种方式

前言:金风玉露一相逢,便胜人间无数。 前言 本文需要有上一篇文章基础,如果不了解的可以先看看《由浅入深,ViewModel配置变更的复用详解》 前面我们了解到,ViewModel 它只能做到因为配置变更页面被销毁而导致重建数据…

人工智能技术与GIS结合的发展

个人本是GIS专业出身,不知名985高校本硕。工作几年后先后积累了国土空间规划、cesium开发、地理信息数据采集、地理大数据处理,遥感影像处理、人工智能识别,做过十多个500万以上的相关项目,有一些浅薄的经验,想和大家分…

伪娘之男扮女装

>>伪娘 伪娘,是一个ACG界名词(动画、漫画、游戏),通常指的是男扮女装且有女性美貌的男性角色,变装后常常带有很强的萌属性,有的可能更胜过一般女性角色,在日本年轻男性中正在兴起一种女装男子的“伪娘”热。聘用…

女装搭配的方法,搭配需要注意的地方

女装搭配的方法,搭配需要注意的地方 一、上下装的搭配 一般上浅下深的色彩搭配方式会在视觉上产生稳定与稳重的感觉服装搭配技巧,而上深下浅的色彩搭配方式会相对给人以活跃于轻松的感受。 1、上下装颜色相同时,可以选择面料质地不同的服装…

趣题:怎么从一帮女装大佬中分辨出谁是真妹子?(大雾)

尝试一篇仿m67风格的博客。 你受邀参加一场女装聚会,除了你和聚会组织者之外还有n个人参加,这些人你都不认识。 组织者告诉你:这场聚会上所有人都会穿女装,但其中有一部分是真妹子,另外一些则是女装大佬。 作为直男…

女装大佬

F. 女装大佬 什么样才能算的上牛逼的程序员?当然是女装大佬了.这一天在操场上,有很多男人很多女人和很多的女装大佬.张队长想要把他们排成m列,每列一个人.要求女装大佬必须要在男人和女人中间&…