一、简介
本篇在《CC2541的SimpleBLECentral发现服务与特征值过程》的基础上,进一步讲述主机端如何发现从机的多个特征值句柄。
二、实验平台
协议栈版本:BLE-CC254x-1.3.2
编译软件:IAR 8.20.2
三、思路
主机通过“从机服务的UUID”发现从机相对应的服务,再通过分别发送“特征值的UUID”依次获取到特征值句柄。
由于有些特征值句柄是获取不到的,所以本篇只获取char1、char2、char4(需要修改从机)和char6(从机要有char6)的特征值句柄。
四、实现过程
1、增加多个特征值状态的宏(sImpleBLECentral.c中)
1. // Discovery states
2. enum
3. {
4. // Idle
5. // Service discovery
6. // Characteristic discovery 1
7. // Characteristic discovery 2
8. // Characteristic discovery 3
9. // Characteristic discovery 4
10. // Characteristic discovery 5
11. // Characteristic discovery 6
12. };
默认的特征值状态的宏只有BLE_DISC_STATE_CHAR,因此在这里修改为6个。(具体要看从机有几个可读特征值)
2、定义一个自己存放特征句柄的数组(sImpleBLECentral.c中)
1. // Discovered characteristic handle
2. static uint16 simpleBLECharHdl = 0;
3. static uint16 GUA_charHdl[6] = {0}; //6个特征值句柄保存位置
当然也可以直接修改为simpleBLECharHdl[6],但这样需要修改代码中其他用到simpleBLECharHdl的地方。
为了省事,很懒的我自己定义一个GUA_charHdl[6]。
3、修改发现事件的处理函数simpleBLEGATTDiscoveryEvent(sImpleBLECentral.c中)
1. /*********************************************************************
2. * @fn simpleBLEGATTDiscoveryEvent
3. *
4. * @brief Process GATT discovery event
5. *
6. * @return none
7. */
8. static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )
9. {
10. attReadByTypeReq_t req;
11.
12. if ( simpleBLEDiscState == BLE_DISC_STATE_SVC )
13. {
14. // Service found, store handles
15. if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
16. pMsg->msg.findByTypeValueRsp.numInfo > 0 )
17. {
18. simpleBLESvcStartHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle;
19. simpleBLESvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;
20. }
21.
22. // If procedure complete
23. if ( ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
24. pMsg->hdr.status == bleProcedureComplete ) ||
25. ( pMsg->method == ATT_ERROR_RSP ) )
26. {
27. if ( simpleBLESvcStartHdl != 0 )
28. {
29. // Discover characteristic
30. simpleBLEDiscState = BLE_DISC_STATE_CHAR1;
31.
32. req.startHandle = simpleBLESvcStartHdl;
33. req.endHandle = simpleBLESvcEndHdl;
34. req.type.len = ATT_BT_UUID_SIZE;
35. uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);
36. uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);
37.
38.
39. GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
40. }
41. }
42. }
43.
44. else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR1 ) //发现char1
45. {
46. //读出char1的handle并保存到GUA_charHdl
47. if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
48. pMsg->msg.readByTypeRsp.numPairs > 0 )
49. {
50. GUA_charHdl[0] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
51. pMsg->msg.readByTypeRsp.dataList[1] );
52.
53.
54. //此时仍在进程中
55. }
56.
57.
58. //发送命令读取下一个特征值的句柄
59. else{ //注意这里一定要else,当numPairs=0时才能再读下一个,下同
60. simpleBLEDiscState = BLE_DISC_STATE_CHAR2;
61.
62. req.startHandle = simpleBLESvcStartHdl;
63. req.endHandle = simpleBLESvcEndHdl;
64. req.type.len = ATT_BT_UUID_SIZE;
65. uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR2_UUID);
66. uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR2_UUID);
67.
68.
69. GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
70. }
71. }
72.
73. else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR2 ) //发现char2
74. {
75. //读出char2的handle并保存到GUA_charHdl
76. if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
77. pMsg->msg.readByTypeRsp.numPairs > 0 )
78. {
79. GUA_charHdl[1] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
80. pMsg->msg.readByTypeRsp.dataList[1] );
81.
82.
83. //此时仍在进程中
84. }
85.
86.
87. //发送命令读取下一个特征值的句柄
88. else{
89. simpleBLEDiscState = BLE_DISC_STATE_CHAR4;
90.
91. req.startHandle = simpleBLESvcStartHdl;
92. req.endHandle = simpleBLESvcEndHdl;
93. req.type.len = ATT_BT_UUID_SIZE;
94. uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR4_UUID);
95. uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR4_UUID);
96.
97.
98. GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
99. }
100. }
101. /*
102. else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR3 ) //发现char3
103. {
104. //读出char3的handle并保存到GUA_charHdl
105. if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
106. pMsg->msg.readByTypeRsp.numPairs > 0 )
107. {
108. GUA_charHdl[2] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
109. pMsg->msg.readByTypeRsp.dataList[1] );
110.
111.
112. simpleBLEProcedureInProgress = TRUE; //此时仍在进程中
113. }
114.
115.
116. //发送命令读取下一个特征值的句柄
117. else{
118. simpleBLEDiscState = BLE_DISC_STATE_CHAR4;
119.
120. req.startHandle = simpleBLESvcStartHdl;
121. req.endHandle = simpleBLESvcEndHdl;
122. req.type.len = ATT_BT_UUID_SIZE;
123. req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR4_UUID);
124. req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR4_UUID);
125.
126.
127. GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
128. }
129. }
130. */
131. else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR4 ) //发现char4
132. {
133. //读出char3的handle并保存到GUA_charHdl
134. if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
135. pMsg->msg.readByTypeRsp.numPairs > 0 )
136. {
137. GUA_charHdl[3] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
138. pMsg->msg.readByTypeRsp.dataList[1] );
139.
140.
141. //此时仍在进程中
142. }
143.
144. //发送命令读取下一个特征值的句柄
145. else{
146. simpleBLEDiscState = BLE_DISC_STATE_CHAR6;
147.
148. req.startHandle = simpleBLESvcStartHdl;
149. req.endHandle = simpleBLESvcEndHdl;
150. req.type.len = ATT_BT_UUID_SIZE;
151. uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR6_UUID);
152. uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR6_UUID);
153.
154.
155. GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
156. }
157. }
158. /*
159. else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR5 ) //发现char5
160. {
161. //读出char3的handle并保存到GUA_charHdl
162. if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
163. pMsg->msg.readByTypeRsp.numPairs > 0 )
164. {
165. GUA_charHdl[4] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
166. pMsg->msg.readByTypeRsp.dataList[1] );
167.
168.
169. simpleBLEProcedureInProgress = TRUE; //此时仍在进程中
170. }
171.
172.
173. //发送命令读取下一个特征值的句柄
174. else{
175. simpleBLEDiscState = BLE_DISC_STATE_CHAR6;
176.
177. req.startHandle = simpleBLESvcStartHdl;
178. req.endHandle = simpleBLESvcEndHdl;
179. req.type.len = ATT_BT_UUID_SIZE;
180. req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR6_UUID);
181. req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR6_UUID);
182.
183.
184. GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
185. }
186. }
187. */
188. else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR6 ) //发现char6
189. {
190. // Characteristic found, store handle
191. if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
192. pMsg->msg.readByTypeRsp.numPairs > 0 )
193. {
194. GUA_charHdl[5] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
195. pMsg->msg.readByTypeRsp.dataList[1] );
196.
197. "Char5 Found", HAL_LCD_LINE_6 );
198. //注意最后一个特征值时需要赋值
199. }
200.
201. //读完最后的char6,就可以返回闲置模式了
202.
203.
204.
205. }
206. }
注意:
1)主机端只能获得“特征值属性为读、通知,并且属性表中为可读”的特征值句柄。
说的通俗一点,就是特征值的属性要为GATT_PROP_READ或GATT_PROP_NOTIFY,且属性表中对应的值的属性要为GATT_PERMIT_READ,主机端才能获取到它的特征值句柄。
例子一:
SimpleBLEPeripheral工程的char1的属性是可读可写(满足条件)
1. // Simple Profile Characteristic 1 Properties
2. static uint8 simpleProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE;
属性表中的属性是GATT_PERMIT_READ(满足条件)
1. // Characteristic Value 1
2. {
3. { ATT_BT_UUID_SIZE, simpleProfilechar1UUID },
4. GATT_PERMIT_READ | GATT_PERMIT_WRITE,
5. 0,
6. &simpleProfileChar1
7. },
因此,主机端可获取到同时满足两个条件的char1的特征值句柄。
例子二:
SimpleBLEPeripheral工程的char3的属性是可写,不可读(不满足条件)
并且属性表中的属性也是GATT_PERMIT_WRITE(不满足条件)
1. // Simple Profile Characteristic 3 Properties
2. static uint8 simpleProfileChar3Props = GATT_PROP_WRITE;
1. // Characteristic Value 3
2. {
3. { ATT_BT_UUID_SIZE, simpleProfilechar3UUID },
4. GATT_PERMIT_WRITE,
5. 0,
6. &simpleProfileChar3
7. },
因此,主机端不能获取char3的特征值句柄。(如果想获取,需要char3修改为GATT_PROP_READ和GATT_PERMIT_READ)
例子三:
SimpleBLEPeripheral工程的char4的属性是通知(满足条件)
1. // Simple Profile Characteristic 4 Properties
2. static uint8 simpleProfileChar4Props = GATT_PROP_NOTIFY;
但是属性表中的属性是0,即不可读不可写(不满足条件)
1. // Characteristic Value 4
2. {
3. { ATT_BT_UUID_SIZE, simpleProfilechar4UUID },
4. 0,
5. 0,
6. &simpleProfileChar4
7. },
因此,主机端不能获取char4的特征值句柄。(如果想获取,需要char4的属性表修改为GATT_PERMIT_READ)
2)连续读取特征值句柄时,如果中间某个特征值句柄读取失败,则会导致后续的特征值也读取不到。
3)char5的属性表的值的属性是GATT_PERMIT_AUTHEN_READ,似乎是加密的,我不熟,就暂时不考虑啦。会用的朋友可以告诉我。
五、实验结果
注:char3和char5的特征值我没有去读,而char4则是修改了从机的属性表为GATT_PERMIT_READ才可读到。
六、此方法存在的问题
实验中发现:从char1一直读到char6时,由于char3不能读,导致后面几个也读不到了。而屏蔽了char3,后面的就可以读了。
目前的解决办法:屏蔽不能读的char3和char5,跳过问题。
待验证的解决方案:用GATT_DiscCharsByUUID函数获取特征值句柄。