1 /******************************************************************************
2 * Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
3 * All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *****************************************************************************/
18 #include "drivers.h"
19 #include "stack/ble/ble.h"
20 #include "tl_common.h"
21
22 #include "blt_common.h"
23 #include "device_manage.h"
24 #include "simple_sdp.h"
25
26 #if (BLE_MASTER_SIMPLE_SDP_ENABLE)
27
28 typedef struct {
29 u8 type;
30 u8 rf_len;
31 u16 l2capLen;
32 u16 chanId;
33 u8 opcode;
34 u8 format;
35 u8 data[1]; // character_handle / property / value_handle / value
36 } ble_att_findInfoRsp_t;
37
38 int master_sdp_pending = 0; // SDP: service discovery
39
40 dev_char_info_t cur_sdp_device; // current connected device which is in SDP flow
41
42 main_service_t main_service = 0;
43
44 static const u8 my_OtaUUID[16] = WRAPPING_BRACES(TELINK_SPP_DATA_OTA);
45
46 ble_sts_t host_att_discoveryService(u16 handle, att_db_uuid16_t *p16, int n16, att_db_uuid128_t *p128, int n128);
47
simple_sdp_loop(void)48 void simple_sdp_loop(void)
49 {
50 if (main_service) {
51 main_service();
52 main_service = 0;
53 }
54 }
55
56 /**
57 * @brief SDP handler.
58 * !!! Note: This is a simple SDP processing implemented by telink.
59 * @param none.
60 * @return none.
61 */
app_service_discovery(void)62 void app_service_discovery(void)
63 {
64 att_db_uuid16_t db16[ATT_DB_UUID16_NUM];
65 att_db_uuid128_t db128[ATT_DB_UUID128_NUM];
66 memset(db16, 0, ATT_DB_UUID16_NUM * sizeof(att_db_uuid16_t));
67 memset(db128, 0, ATT_DB_UUID128_NUM * sizeof(att_db_uuid128_t));
68
69 if (master_sdp_pending && host_att_discoveryService(master_sdp_pending, db16, ATT_DB_UUID16_NUM, db128,
70 ATT_DB_UUID128_NUM) == BLE_SUCCESS) {
71 // service discovery OK
72 cur_sdp_device.char_handle[2] = blm_att_findHandleOfUuid128(db128, my_OtaUUID); // OTA
73 cur_sdp_device.char_handle[3] = blm_att_findHandleOfUuid16(
74 db16, CHARACTERISTIC_UUID_HID_REPORT,
75 HID_REPORT_ID_CONSUME_CONTROL_INPUT | (HID_REPORT_TYPE_INPUT << 8)); // consume report(media key report)
76 cur_sdp_device.char_handle[4] = blm_att_findHandleOfUuid16(
77 db16, CHARACTERISTIC_UUID_HID_REPORT,
78 HID_REPORT_ID_KEYBOARD_INPUT | (HID_REPORT_TYPE_INPUT << 8)); // normal key report
79 /* add the peer device att_handle value to conn_dev_list after service discovery is correctly finished */
80 dev_char_info_add_peer_att_handle(&cur_sdp_device);
81
82 /* peer device att_handle value store in flash */
83 dev_char_info_store_peer_att_handle(&cur_sdp_device);
84 }
85
86 master_sdp_pending = 0; // service discovery finish
87 }
88
89 /**
90 * @brief This function is used to register SDP handler.
91 * @param[in] p - Pointer point to SDP handler.
92 * @return none.
93 */
app_register_service(void * p)94 void app_register_service(void *p)
95 {
96 main_service = p;
97 }
98
99 u8 *p_att_response = 0;
100
101 volatile u32 host_att_req_busy = 0;
102
103 /**
104 * @brief This function is used to process ATT packets related to SDP
105 * @param[in] connHandle - connection handle
106 * @param[in] p - Pointer point to ATT data buffer.
107 * @return
108 */
host_att_client_handler(u16 connHandle,u8 * p)109 int host_att_client_handler(u16 connHandle, u8 *p)
110 {
111 ble_att_readByTypeRsp_t *p_rsp = (ble_att_readByTypeRsp_t *)p;
112 if (p_att_response) {
113 if ((connHandle & 7) == (host_att_req_busy & 7) && p_rsp->chanId == 0x04 &&
114 (p_rsp->opcode == 0x01 || p_rsp->opcode == ((host_att_req_busy >> 16) | 1))) {
115 memcpy(p_att_response, p, 32);
116 host_att_req_busy = 0;
117 }
118 }
119 return 0;
120 }
121
122 typedef int (*host_att_idle_func_t)(void);
123 host_att_idle_func_t host_att_idle_func = 0;
124
125 /**
126 * @brief This function is used to register ble stack mainloop function.
127 * @param[in] p - Pointer point to ble stack mainloop function.
128 * @return
129 */
host_att_register_idle_func(void * p)130 int host_att_register_idle_func(void *p)
131 {
132 if (host_att_idle_func)
133 return 1;
134
135 host_att_idle_func = p;
136 return 0;
137 }
138
host_att_response()139 int host_att_response()
140 {
141 return host_att_req_busy == 0;
142 }
143
host_att_service_wait_event(u16 handle,u8 * p,u32 timeout)144 int host_att_service_wait_event(u16 handle, u8 *p, u32 timeout)
145 {
146 host_att_req_busy = handle | (p[6] << 16);
147 p_att_response = p;
148
149 u32 t = clock_time();
150 while (!clock_time_exceed(t, timeout)) {
151 if (host_att_response()) {
152 return 0;
153 }
154 if (host_att_idle_func) {
155 if (host_att_idle_func()) {
156 break;
157 }
158 }
159 }
160 return 1;
161 }
162
163 // Gaoqiu add ------------------------------------------------------------------
app_char_discovery(u8 * reslut,u16 connHandle,u16 startAttHandle,u16 endAttHandle,u8 * uuid,u8 uuidLen)164 int app_char_discovery(u8 *reslut, u16 connHandle, u16 startAttHandle, u16 endAttHandle, u8 *uuid, u8 uuidLen)
165 {
166 blc_gatt_pushReadByTypeRequest(connHandle, startAttHandle, endAttHandle, uuid, uuidLen);
167
168 return host_att_service_wait_event(connHandle, reslut, 1000000);
169 }
170
app_read_char_value(u8 * reslut,u16 connHandle,u16 attHandle)171 int app_read_char_value(u8 *reslut, u16 connHandle, u16 attHandle)
172 {
173 blc_gatt_pushReadRequest(connHandle, attHandle);
174
175 return host_att_service_wait_event(connHandle, reslut, 1000000);
176 }
177
app_find_char_info(u8 * reslut,u16 connHandle,u16 startAttHandle,u16 endAttHandle)178 int app_find_char_info(u8 *reslut, u16 connHandle, u16 startAttHandle, u16 endAttHandle)
179 {
180 blc_gatt_pushFindInformationRequest(connHandle, startAttHandle, endAttHandle);
181
182 return host_att_service_wait_event(connHandle, reslut, 1000000);
183 }
184
blm_att_findHandleOfUuid16(att_db_uuid16_t * p,u16 uuid,u16 ref)185 u16 blm_att_findHandleOfUuid16(att_db_uuid16_t *p, u16 uuid, u16 ref)
186 {
187 for (int i = 0; i < p->num; i++) {
188 if (p[i].uuid == uuid && p[i].ref == ref) {
189 return p[i].handle;
190 }
191 }
192 return 0;
193 }
194
blm_att_findHandleOfUuid128(att_db_uuid128_t * p,const u8 * uuid)195 u16 blm_att_findHandleOfUuid128(att_db_uuid128_t *p, const u8 *uuid)
196 {
197 for (int i = 0; i < p->num; i++) {
198 if (memcmp(p[i].uuid, uuid, 16) == 0) {
199 return p[i].handle;
200 }
201 }
202 return 0;
203 }
204
host_att_discoveryService(u16 handle,att_db_uuid16_t * p16,int n16,att_db_uuid128_t * p128,int n128)205 ble_sts_t host_att_discoveryService(u16 handle, att_db_uuid16_t *p16, int n16, att_db_uuid128_t *p128, int n128)
206 {
207 att_db_uuid16_t *ps16 = p16;
208 att_db_uuid128_t *ps128 = p128;
209 int i16 = 0;
210 int i128 = 0;
211
212 ps16->num = 0;
213 ps128->num = 0;
214
215 // char discovery: att_read_by_type
216 // hid discovery: att_find_info
217 u8 dat[32];
218 u16 s = 1;
219 u16 uuid = GATT_UUID_CHARACTER;
220 do {
221 dat[6] = ATT_OP_READ_BY_TYPE_REQ;
222 if (app_char_discovery(dat, handle, s, 0xffff, (u8 *)&uuid, 2)) {
223 // 1s
224 return GATT_ERR_SERVICE_DISCOVERY_TIEMOUT; // timeout
225 }
226
227 // process response data
228 ble_att_readByTypeRsp_t *p_rsp = (ble_att_readByTypeRsp_t *)dat;
229 if (p_rsp->opcode != ATT_OP_READ_BY_TYPE_RSP) {
230 break;
231 }
232
233 if (p_rsp->datalen == 21) {
234 // uuid128
235 s = p_rsp->data[3] + p_rsp->data[4] * 256;
236 if (i128 < n128) {
237 p128->property = p_rsp->data[2];
238 p128->handle = s;
239 memcpy(p128->uuid, p_rsp->data + 5, 16);
240 i128++;
241 p128++;
242 }
243 } else if (p_rsp->datalen == 7) {
244 // uuid16
245 u8 *pd = p_rsp->data;
246 while (p_rsp->l2capLen > 7) {
247 s = pd[3] + pd[4] * 256;
248 if (i16 < n16) {
249 p16->property = pd[2];
250 p16->handle = s;
251 p16->uuid = pd[5] | (pd[6] << 8);
252 p16->ref = 0;
253 i16++;
254 p16++;
255 }
256 p_rsp->l2capLen -= 7;
257 pd += 7;
258 }
259 }
260 } while (1);
261
262 ps16->num = i16;
263 ps128->num = i128;
264
265 // --------- use att_find_info to find the reference property for hid ----------
266 p16 = ps16;
267 for (int i = 0; i < i16; i++) {
268 if (p16->uuid == CHARACTERISTIC_UUID_HID_REPORT) {
269 // find reference
270 dat[6] = ATT_OP_FIND_INFORMATION_REQ;
271 if (app_find_char_info(dat, handle, p16->handle, 0xffff)) {
272 // 1s
273 return GATT_ERR_SERVICE_DISCOVERY_TIEMOUT; // timeout
274 }
275
276 ble_att_findInfoRsp_t *p_rsp = (ble_att_findInfoRsp_t *)dat;
277 if (p_rsp->opcode == ATT_OP_FIND_INFO_RSP && p_rsp->format == 1) {
278 int n = p_rsp->l2capLen - 2;
279 u8 *pd = p_rsp->data;
280 while (n > 0) {
281 if ((pd[2] == U16_LO(GATT_UUID_CHARACTER) && pd[3] == U16_HI(GATT_UUID_CHARACTER)) ||
282 (pd[2] == U16_LO(GATT_UUID_PRIMARY_SERVICE) && pd[3] == U16_HI(GATT_UUID_PRIMARY_SERVICE))) {
283 break;
284 }
285
286 if (pd[2] == U16_LO(GATT_UUID_REPORT_REF) && pd[3] == U16_HI(GATT_UUID_REPORT_REF)) {
287 // ----------- read attribute ----------------
288 dat[6] = ATT_OP_READ_REQ;
289 if (app_read_char_value(dat, handle, pd[0])) {
290 return GATT_ERR_SERVICE_DISCOVERY_TIEMOUT; // timeout
291 }
292
293 ble_att_readRsp_t *pr = (ble_att_readRsp_t *)dat;
294 if (pr->opcode == ATT_OP_READ_RSP) {
295 p16->ref = pr->value[0] | (pr->value[1] << 8);
296 }
297
298 break;
299 }
300 n -= 4;
301 pd += 4;
302 }
303 }
304 } // ----- end for if CHARACTERISTIC_UUID_HID_REPORT
305
306 p16++;
307 }
308
309 return BLE_SUCCESS;
310 }
311
312 /**
313 * @brief Used for add peer device service ATThandle.
314 * @param[in] dev_char_info - Pointer point to data buffer.
315 * @return 0: success
316 * 1: failed
317 */
dev_char_info_add_peer_att_handle(dev_char_info_t * dev_char_info)318 int dev_char_info_add_peer_att_handle(dev_char_info_t *dev_char_info)
319 {
320 int i;
321 for (i = 0; i < conn_master_num; i++) {
322 if (conn_dev_list[i].conn_handle == dev_char_info->conn_handle) {
323 break;
324 }
325 }
326
327 if (i < conn_master_num) {
328 for (int j = 0; j < CHAR_HANDLE_MAX; j++) {
329 conn_dev_list[i].char_handle[j] = dev_char_info->char_handle[j];
330 }
331
332 conn_dev_list[i].char_handle_valid = 1;
333
334 return 0; // success
335 } else {
336 return 1; // fail
337 }
338 }
339
340 /**
341 * @brief Use for store peer device att handle to flash.
342 * @param[in] dev_char_info Pointer point to peer device ATT handle info.
343 * @return 0: failed
344 * !0: return falsh address
345 */
dev_char_info_store_peer_att_handle(dev_char_info_t * pdev_char)346 int dev_char_info_store_peer_att_handle(dev_char_info_t *pdev_char)
347 {
348 u8 mark;
349 u32 current_flash_adr;
350 for (current_flash_adr = FLASH_SDP_ATT_ADRRESS;
351 current_flash_adr < (FLASH_SDP_ATT_ADRRESS + FLASH_SDP_ATT_MAX_SIZE);
352 current_flash_adr += sizeof(dev_att_t)) {
353 flash_read_page(current_flash_adr, 1, &mark);
354
355 if (mark == U8_MAX) {
356 flash_write_page(current_flash_adr + OFFSETOF(dev_att_t, adr_type), 7,
357 (u8 *)&pdev_char->peer_adrType); // peer_adrType(1)+peer_addr(6)
358
359 #if (PEER_SLAVE_USE_RPA_EN)
360 if (IS_RESOLVABLE_PRIVATE_ADDR(pdev_char->peer_adrType, pdev_char->peer_addr)) {
361 }
362 #endif
363
364 // char_handle[0] : MIC
365 // char_handle[1] : Speaker
366 // char_handle[2] : OTA
367 // char_handle[3] : Consume Report
368 // char_handle[4] : Key Report
369 // char_handle[5] :
370 // char_handle[6] : BLE Module, SPP Server to Client
371 // char_handle[7] : BLE Module, SPP Client to Server
372 flash_write_page(current_flash_adr + OFFSETOF(dev_att_t, char_handle) + 2 * 2, 2,
373 (u8 *)&pdev_char->char_handle[2]); // save OTA att_handle
374 flash_write_page(current_flash_adr + OFFSETOF(dev_att_t, char_handle) + 3 * 2, 2,
375 (u8 *)&pdev_char->char_handle[3]); // save Consume Report att_handle
376 flash_write_page(current_flash_adr + OFFSETOF(dev_att_t, char_handle) + 4 * 2, 2,
377 (u8 *)&pdev_char->char_handle[4]); // save Key Report att_handle
378
379 mark = ATT_BOND_MARK;
380 flash_write_page(current_flash_adr, 1, (u8 *)&mark);
381
382 return current_flash_adr; // Store Success
383 }
384 }
385
386 return 0; // Store Fail
387 }
388
389 /**
390 * @brief Get peer device att handle info by peer address
391 * @param[in] adr_type address type
392 * @param[in] addr Pointer point to peer address buffer
393 * @param[out] dev_att Pointer point to dev_att_t
394 * @return 0: failed
395 * !0: return falsh address
396 */
dev_char_info_search_peer_att_handle_by_peer_mac(u8 adr_type,u8 * addr,dev_att_t * pdev_att)397 int dev_char_info_search_peer_att_handle_by_peer_mac(u8 adr_type, u8 *addr, dev_att_t *pdev_att)
398 {
399 u8 mark;
400 u32 current_flash_adr;
401 for (current_flash_adr = FLASH_SDP_ATT_ADRRESS;
402 current_flash_adr < (FLASH_SDP_ATT_ADRRESS + FLASH_SDP_ATT_MAX_SIZE);
403 current_flash_adr += sizeof(dev_att_t)) {
404 flash_read_page(current_flash_adr, 1, &mark);
405
406 if (mark == U8_MAX) {
407 return 0; // Search Fail
408 } else if (mark == ATT_ERASE_MARK) {
409 continue; // Search for next unit
410 } else if (mark == ATT_BOND_MARK) {
411 flash_read_page(current_flash_adr, sizeof(dev_att_t), (u8 *)pdev_att);
412
413 int addr_match = 0;
414 #if (PEER_SLAVE_USE_RPA_EN)
415 if (IS_RESOLVABLE_PRIVATE_ADDR(pdev_att->adr_type, pdev_att->addr)) {
416 if (0) {
417 addr_match = 1;
418 }
419 } else
420 #endif
421 {
422 if (adr_type == pdev_att->adr_type && !memcmp(addr, pdev_att->addr, 6)) { // match
423 addr_match = 1;
424 }
425 }
426
427 if (addr_match) {
428 return current_flash_adr;
429 }
430 }
431 }
432
433 return 0; // Search Fail
434 }
435
436 /**
437 * @brief Delete peer device att handle info by peer address
438 * @param[in] adr_type address type
439 * @param[in] addr Pointer point to peer address buffer
440 * @return 0: success
441 * 1: not find
442 */
dev_char_info_delete_peer_att_handle_by_peer_mac(u8 addrType,u8 * addr)443 int dev_char_info_delete_peer_att_handle_by_peer_mac(u8 addrType, u8 *addr)
444 {
445 dev_att_t dev_info;
446
447 for (u32 cur_flash_addr = FLASH_SDP_ATT_ADRRESS; cur_flash_addr < FLASH_SDP_ATT_ADRRESS + FLASH_SDP_ATT_MAX_SIZE;
448 cur_flash_addr += sizeof(dev_att_t)) {
449 u8 flag;
450 flash_read_page(cur_flash_addr, 1, &flag);
451
452 // have no device information
453 if (flag == 0xff)
454 return 1; // not find
455
456 if (flag == ATT_BOND_MARK) {
457 // only read per device MAC address type and MAC address
458 flash_read_page(cur_flash_addr, 8, (u8 *)&dev_info);
459 #if (PEER_SLAVE_USE_RPA_EN)
460 if (IS_RESOLVABLE_PRIVATE_ADDR(addrType, addr)) {
461 // todo: resolve private address using IRK
462 } else
463 #endif
464 {
465 if (dev_info.adr_type == addrType && !memcmp(dev_info.addr, addr, 6)) {
466 u8 temp = ATT_ERASE_MARK;
467 flash_write_page(cur_flash_addr, 1, (u8 *)&temp);
468 return 0; // find
469 }
470 }
471 }
472 }
473 return 1; // not find
474 }
475
476 #endif // end of BLE_MASTER_SIMPLE_SDP_ENABLE
477