ble_ancs.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. /**************************************************************************************************
  2. Phyplus Microelectronics Limited confidential and proprietary.
  3. All rights reserved.
  4. IMPORTANT: All rights of this software belong to Phyplus Microelectronics
  5. Limited ("Phyplus"). Your use of this Software is limited to those
  6. specific rights granted under the terms of the business contract, the
  7. confidential agreement, the non-disclosure agreement and any other forms
  8. of agreements as a customer or a partner of Phyplus. You may not use this
  9. Software unless you agree to abide by the terms of these agreements.
  10. You acknowledge that the Software may not be modified, copied,
  11. distributed or disclosed unless embedded on a Phyplus Bluetooth Low Energy
  12. (BLE) integrated circuit, either as a product or is integrated into your
  13. products. Other than for the aforementioned purposes, you may not use,
  14. reproduce, copy, prepare derivative works of, modify, distribute, perform,
  15. display or sell this Software and/or its documentation for any purposes.
  16. YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  17. PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  18. INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  19. NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  20. PHYPLUS OR ITS SUBSIDIARIES BE LIABLE OR OBLIGATED UNDER CONTRACT,
  21. NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  22. LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  23. INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  24. OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  25. OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  26. (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
  27. **************************************************************************************************/
  28. #include "bcomdef.h"
  29. #include "linkdb.h"
  30. #include "hal_defs.h"
  31. #include "gatt.h"
  32. #include "gapgattserver.h"
  33. #include "gattservapp.h"
  34. #include "gatt_uuid.h"
  35. #include "peripheral.h"
  36. #include "gapbondmgr.h"
  37. #include "gatt_profile_uuid.h"
  38. #include "ble_ancs.h"
  39. #include "ancs_attr.h"
  40. #include "log.h"
  41. static uint8_t Ancs_CCCDConfig(uint16_t attrHdl, uint8_t isEnable);
  42. static ancs_ctx_t s_ancs_ctx;
  43. bStatus_t ble_ancs_attr_add(const ancs_notif_attr_id id, uint8_t * p_data, const uint16_t len)
  44. {
  45. ancs_attr_list_t* p_ancs_notif_attr_list = s_ancs_ctx.notif_attr_list;
  46. if(!p_data)
  47. return INVALIDPARAMETER;
  48. if((len == 0) || (len > ANCS_ATTR_DATA_MAX))
  49. {
  50. return INVALID_MEM_SIZE;
  51. }
  52. p_ancs_notif_attr_list[id].en = true;
  53. p_ancs_notif_attr_list[id].attr_len = len;
  54. p_ancs_notif_attr_list[id].p_attr_data = p_data;
  55. return SUCCESS;
  56. }
  57. static uint8_t figure_out_chars_end_hdl(void)
  58. {
  59. uint8_t errorcode = 0;
  60. ancs_ctx_t* pctx = &s_ancs_ctx;
  61. ancs_service_t* pservie = &(s_ancs_ctx.ancs_service);
  62. uint16_t* p_chars_hdl = pservie->chars_hdl;
  63. uint16_t ntf, cp, dt;
  64. ntf = p_chars_hdl[ANCS_NOTIF_SCR_HDL_START];
  65. cp = p_chars_hdl[ANCS_CTRL_POINT_HDL_START];
  66. dt = p_chars_hdl[ANCS_DATA_SRC_HDL_START];
  67. if(ntf < ((cp < dt) ? cp :dt))
  68. p_chars_hdl[ANCS_NOTIF_SCR_HDL_END] = cp > dt ? dt : cp;
  69. else if(ntf < ((cp < dt) ? dt :cp))
  70. p_chars_hdl[ANCS_NOTIF_SCR_HDL_END] = cp > dt ? cp : dt;
  71. else
  72. p_chars_hdl[ANCS_NOTIF_SCR_HDL_END] = pservie->service_hdl[1];
  73. if(cp < ((ntf < dt) ? ntf:dt))
  74. p_chars_hdl[ANCS_CTRL_POINT_HDL_END] = ntf > dt ? dt : ntf;
  75. else if(cp < ((ntf < dt) ? dt :ntf))
  76. p_chars_hdl[ANCS_CTRL_POINT_HDL_END] = ntf > dt ? ntf : dt;
  77. else
  78. p_chars_hdl[ANCS_CTRL_POINT_HDL_END] = pservie->service_hdl[1];
  79. if(dt < ((ntf < cp) ? ntf :cp))
  80. p_chars_hdl[ANCS_DATA_SRC_HDL_END] = ntf > cp ? cp : ntf;
  81. else if(dt < ((ntf < cp) ? cp :ntf))
  82. p_chars_hdl[ANCS_DATA_SRC_HDL_END] = ntf > cp ? ntf : cp;
  83. else
  84. p_chars_hdl[ANCS_DATA_SRC_HDL_END] = pservie->service_hdl[1];
  85. // Sanity check to ensure that each start handle is valid and
  86. // less than each respective end handle.
  87. if(p_chars_hdl[ANCS_NOTIF_SCR_HDL_START] != 0 &&
  88. p_chars_hdl[ANCS_CTRL_POINT_HDL_START] != 0 &&
  89. p_chars_hdl[ANCS_DATA_SRC_HDL_START] != 0)
  90. {
  91. if(p_chars_hdl[ANCS_NOTIF_SCR_HDL_START] < p_chars_hdl[ANCS_NOTIF_SCR_HDL_END] &&
  92. p_chars_hdl[ANCS_CTRL_POINT_HDL_START] < p_chars_hdl[ANCS_CTRL_POINT_HDL_END] &&
  93. p_chars_hdl[ANCS_DATA_SRC_HDL_START] < p_chars_hdl[ANCS_DATA_SRC_HDL_END])
  94. {
  95. LOG("All chars discoveried\n");
  96. }
  97. else
  98. {
  99. LOG("ANCS_STORE_CHARS_HANDLES FAILURE\n");
  100. pctx->disc_state = ANCS_DISC_FAILED;
  101. errorcode = 4;
  102. }
  103. }
  104. // Throw an error if the handles are invalid.
  105. else
  106. {
  107. LOG("ANCS_STORE_CHARS_HANDLES FAILURE\n");
  108. pctx->disc_state = ANCS_DISC_FAILED;
  109. errorcode = 5;
  110. }
  111. return errorcode;
  112. }
  113. static bStatus_t ble_disc_service(gattMsgEvent_t *pMsg)
  114. {
  115. ancs_ctx_t* pctx = &s_ancs_ctx;
  116. ancs_service_t* pservie = &(pctx->ancs_service);
  117. // Stores the error code, should the discovery process fail at any state.
  118. uint8_t errorcode = 0;
  119. //if(pMsg){
  120. // LOG("ble_disc_service->pMsg->method: 0x%x\n",pMsg->method);
  121. //}
  122. // Enter the state machine.
  123. switch (pctx->disc_state)
  124. {
  125. case ANCS_UNINIT:
  126. LOG("Discovery Progress:\t1\n");
  127. return FAILURE;
  128. // Perform a GATT Discover Primary Service By Service UUID to located the ANCS
  129. // handles.
  130. case ANCS_DISC_SERVICE:
  131. {
  132. LOG("Discovery Progress:\t2\n");
  133. LOG("Discovery State:\tDiscover the ANCS\n");
  134. // Initialize the ANCS handles to zero.
  135. pservie->service_hdl[0] = 0;
  136. pservie->service_hdl[1] = 0;
  137. // Store the ANCS UUID for GATT request.
  138. uint8_t uuid[ATT_UUID_SIZE] = {ANCSAPP_ANCS_SVC_UUID};
  139. // Discover the ANCS by UUID.
  140. bStatus_t ret = GATT_DiscPrimaryServiceByUUID(pservie->conn_hdl , uuid, ATT_UUID_SIZE, pctx->app_task_ID);
  141. // If successfully discovered proceed, throw error if not.
  142. if(ret == SUCCESS){
  143. pctx->disc_state = ANCS_STORE_SERVICE_HANDLES;
  144. pservie->expect_type_value_num = 0;
  145. //ancsAppState = ANCS_STATE_READY;
  146. }
  147. else
  148. {
  149. LOG("ANCS_DISC_SERVICE FAILURE, Error code:\t%d\n", ret);
  150. pctx->disc_state = ANCS_DISC_FAILED;
  151. errorcode = 1;
  152. }
  153. }
  154. break;
  155. // Store the ANCS handles requested in the previous state.
  156. case ANCS_STORE_SERVICE_HANDLES:
  157. {
  158. LOG("Discovery Progress:\t3\n");
  159. LOG("Discovery State:\tStore the ANCS handles %d\n",pMsg->method);
  160. // Did the application receive a response from the GATT Disc Primary Service?
  161. if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP )
  162. {
  163. LOG("found :%d\n",pMsg->msg.findByTypeValueRsp.numInfo);
  164. // Check if the ANCS was found.
  165. if (pMsg->msg.findByTypeValueRsp.numInfo > 0)
  166. {
  167. // Found the ANCS, so store the handles and proceed.
  168. pservie->service_hdl[0] = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle;
  169. pservie->service_hdl[1] = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;
  170. pctx->disc_state = ANCS_DISC_CHARS;
  171. //for(i = 0; i< pMsg->msg.findByTypeValueRsp.numInfo; i++){
  172. // pservie->service_hdl[pservie->expect_type_value_num] = pMsg->msg.findByTypeValueRsp.handlesInfo[i].handle;
  173. // pservie->expect_type_value_num ++;
  174. // if(pservie->expect_type_value_num == 2){
  175. // pctx->disc_state = ANCS_DISC_CHARS;
  176. // break;
  177. // }
  178. //}
  179. }
  180. else
  181. {
  182. // The ANCS was not found.
  183. LOG("ANCS_STORE_SERVICE_HANDLES FAILURE\n");
  184. pctx->disc_state = ANCS_DISC_FAILED;
  185. errorcode = 2;
  186. }
  187. }
  188. else
  189. {
  190. LOG("ble_disc_service->pMsg->method: 0x%x\n",pMsg->method);
  191. LOG("ANCS_STORE_SERVICE_HANDLES FAILURE\n");
  192. pctx->disc_state = ANCS_DISC_FAILED;
  193. errorcode = 2;
  194. }
  195. }
  196. break;
  197. // Use the ANCS handles to discovery the ANCS's characteristics' handles.
  198. case ANCS_DISC_CHARS:
  199. {
  200. LOG("Discovery Progress:\t4\n");
  201. LOG("Discovery State:\tDiscover the ANCS characteristics\n");
  202. // Check if service handle discovery event has completed.
  203. if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP )
  204. {
  205. LOG("ble_disc_service->pMsg->method: 0x%x\n",pMsg->method);
  206. if(pMsg->hdr.status == bleProcedureComplete)
  207. {
  208. // Sanity check to make sure the handle is valid before proceeding.
  209. if (pservie->service_hdl[0] != 0 && pservie->service_hdl[1] != 0 )
  210. {
  211. // Discover all characteristics of the ANCS.
  212. bStatus_t ret = GATT_DiscAllChars(
  213. pservie->conn_hdl,
  214. pservie->service_hdl[0],
  215. pservie->service_hdl[1],
  216. pctx->app_task_ID);
  217. pservie->chars_disc_num = 0;
  218. // If the request was successfully sent, proceed with the discovery process.
  219. if (ret == SUCCESS)
  220. {
  221. pctx->disc_state = ANCS_STORE_CHARS_HANDLES;
  222. }
  223. // If not, throw an error.
  224. else
  225. {
  226. LOG("ANCS_DISC_CHARS FAILURE, Error code:\t%d\n",ret);
  227. pctx->disc_state = ANCS_DISC_FAILED;
  228. errorcode = 3;
  229. }
  230. }
  231. }
  232. }
  233. else
  234. {
  235. LOG("ble_disc_service->pMsg->method: 0x%x\n",pMsg->method);
  236. }
  237. }
  238. break;
  239. // Store the retrieved ANCS characteristic handles.
  240. case ANCS_STORE_CHARS_HANDLES:
  241. {
  242. LOG("Discovery Progress:\t5\n");
  243. LOG("Discovery State:\tStore the ANCS characteristics' handles\n");
  244. // Wait until GATT "Read by type response" is received, then confirm that the correct number of
  245. // pairs are present, and that their length is correct
  246. if (pMsg->method == ATT_READ_BY_TYPE_RSP )
  247. {
  248. //if ( (pMsg->msg.readByTypeRsp.numPairs == NUMBER_OF_ANCS_CHARS) && (pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID128_LEN) )
  249. if ((pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID128_LEN) )
  250. {
  251. // Pointer to the pair list data in the GATT response.
  252. uint8_t *pCharPairList;
  253. // Will store the start and end handles of the current pair.
  254. uint16_t charStartHandle;
  255. // Stores to the UUID of the current pair.
  256. uint16_t charUuid;
  257. // Stores what pair the loop is currently processing.
  258. uint8_t currentCharIndex;
  259. // Set the pair pointer to the first pair.
  260. pCharPairList = pMsg->msg.readByTypeRsp.dataList;
  261. // Iterate through all three pairs found.
  262. for(currentCharIndex = 0; currentCharIndex < pMsg->msg.readByTypeRsp.numPairs ; currentCharIndex++)
  263. {
  264. uint16_t* p_chars_hdl = pservie->chars_hdl;
  265. // Extract the starting handle, ending handle, and UUID of the current characteristic.
  266. charStartHandle = BUILD_UINT16(pCharPairList[3], pCharPairList[4]);
  267. charUuid = BUILD_UINT16(pCharPairList[5], pCharPairList[6]);
  268. LOG("Chars found handle is is %d, uuid is %x\n", charStartHandle, charUuid);
  269. // Store the start and end handles in the handle cache corresponding to
  270. // their UUID.
  271. switch (charUuid)
  272. {
  273. // If it's the Notification Source.
  274. case ANCSAPP_NOTIF_SRC_CHAR_UUID:
  275. p_chars_hdl[ANCS_NOTIF_SCR_HDL_START] = charStartHandle;
  276. p_chars_hdl[ANCS_NOTIF_SCR_HDL_END] = 0;
  277. break;
  278. // If it's the Control Point.
  279. case ANCSAPP_CTRL_PT_CHAR_UUID:
  280. p_chars_hdl[ANCS_CTRL_POINT_HDL_START] = charStartHandle;
  281. p_chars_hdl[ANCS_CTRL_POINT_HDL_END] = 0;
  282. break;
  283. // If it's the Data Source.
  284. case ANCSAPP_DATA_SRC_CHAR_UUID:
  285. p_chars_hdl[ANCS_DATA_SRC_HDL_START] = charStartHandle;
  286. p_chars_hdl[ANCS_DATA_SRC_HDL_END] = 0;
  287. break;
  288. default:
  289. break;
  290. }
  291. pservie->chars_disc_num ++;
  292. // If this is the final characteristic found in the response,
  293. // reset its end handle to the ANCS's end handle. This is because
  294. // there is no next staring handle to use as a reference and subtract one
  295. // from, so instead the ending handle of the ANCS must be used.
  296. if(pservie->chars_disc_num == NUMBER_OF_ANCS_CHARS){
  297. errorcode = figure_out_chars_end_hdl();
  298. pctx->disc_state = (errorcode == 0) ? ANCS_DISC_NS_DESCS : ANCS_DISC_FAILED;
  299. }
  300. // Increment the pair pointer to the next pair.
  301. pCharPairList += CHAR_DESC_HDL_UUID128_LEN;
  302. }
  303. }
  304. // Throw an error if the length or number of pairs is incorrect.
  305. else
  306. {
  307. LOG("ANCS_STORE_CHARS_HANDLES FAILURE\n");
  308. pctx->disc_state = ANCS_DISC_FAILED;
  309. errorcode = 6;
  310. }
  311. }
  312. else
  313. {
  314. LOG("ble_disc_service->pMsg->method: 0x%x\n",pMsg->method);
  315. if(pMsg->method == ATT_ERROR_RSP){
  316. attErrorRsp_t* perr = &(pMsg->msg.errorRsp);
  317. LOG("ATT_ERROR_RSP 0x%x, 0x%x, 0x%x\n", perr->errCode, perr->handle, perr->reqOpcode);
  318. }
  319. }
  320. }
  321. break;
  322. // Discover the Notification Source's descriptors (namely, the CCCD) using the start
  323. // and end handle stored in the handle cache.
  324. case ANCS_DISC_NS_DESCS:
  325. {
  326. LOG("Discovery Progress:\t6\n");
  327. LOG("Discovery State:\tDiscover the Notification Source's CCCD\n");
  328. // Wait until the characteristic handle discovery has finished.
  329. if ( (pMsg->method == ATT_READ_BY_TYPE_RSP) && (pMsg->hdr.status == bleProcedureComplete) )
  330. {
  331. // Discover the ANCS Notification Source descriptors.
  332. bStatus_t ret = GATT_DiscAllCharDescs(pservie->conn_hdl,
  333. pservie->chars_hdl[ANCS_NOTIF_SCR_HDL_START],
  334. pservie->chars_hdl[ANCS_NOTIF_SCR_HDL_END]-1,
  335. pctx->app_task_ID);
  336. // If the discovery was successful, proceed.
  337. if ( ret == SUCCESS )
  338. pctx->disc_state = ANCS_STORE_NS_DESCS_HANDLES;
  339. // If not, throw an error and invalidate the CCCD handle in the handle cache.
  340. else
  341. {
  342. LOG("ANCS_DISC_NS_DESCS FAILURE\n");
  343. pservie->chars_hdl[ANCS_NOTIF_SCR_HDL_START] = 0;
  344. pctx->disc_state = ANCS_DISC_FAILED;
  345. errorcode = 7;
  346. }
  347. }
  348. }
  349. break;
  350. // Store the retrieved Notification Source descriptors (namely, the CCCD).
  351. case ANCS_STORE_NS_DESCS_HANDLES:
  352. {
  353. LOG("Discovery Progress:\t7\n");
  354. LOG("Discovery State:\tStore the Notification Source's CCCD handle\n");
  355. // Wait for the discovery response.
  356. if (pMsg->method == ATT_FIND_INFO_RSP )
  357. {
  358. // Sanity check to validate that at least one descriptors pair was found,
  359. // and that the pair length is correct.
  360. if ( (pMsg->msg.findInfoRsp.numInfo > 0) &&
  361. (pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE) )
  362. {
  363. // This will keep track of the current pair being processed.
  364. uint8_t currentPair;
  365. // Iterate through the pair list.
  366. for(currentPair = 0; currentPair < pMsg->msg.findInfoRsp.numInfo; currentPair++)
  367. {
  368. // Check if the pair is a CCCD.
  369. uint16_t uuid = BUILD_UINT16(pMsg->msg.findInfoRsp.info.btPair[currentPair].uuid[0], pMsg->msg.findInfoRsp.info.btPair[currentPair].uuid[1]);
  370. if (uuid == GATT_CLIENT_CHAR_CFG_UUID)
  371. {
  372. // If so, store the handle in the handle cache, and proceed.
  373. pservie->chars_hdl[ANCS_NOTIF_SCR_HDL_CCCD] = pMsg->msg.findInfoRsp.info.btPair[currentPair].handle;
  374. pctx->disc_state = ANCS_DISC_DS_DESCS;
  375. }
  376. }
  377. }
  378. }
  379. }
  380. break;
  381. // Discover the Data Source's descriptors (namely, the CCCD) using the start
  382. // and end handle stored in the handle cache.
  383. case ANCS_DISC_DS_DESCS:
  384. {
  385. LOG("Discovery Progress:\t8\n");
  386. LOG("Discovery State:\tDiscover the Data Source's CCCD\n");
  387. // Wait until the Notification Source descriptors discovery has finished.
  388. if ( (pMsg->method == ATT_FIND_INFO_RSP) && (pMsg->hdr.status == bleProcedureComplete) )
  389. {
  390. // Discover ANCS Notification Source CCCD
  391. uint8_t discCheck = GATT_DiscAllCharDescs(pservie->conn_hdl,
  392. pservie->chars_hdl[ANCS_DATA_SRC_HDL_START] + 1,
  393. pservie->chars_hdl[ANCS_DATA_SRC_HDL_END],
  394. pctx->app_task_ID);
  395. // If the discovery was successful, proceed.
  396. if (discCheck == SUCCESS )
  397. pctx->disc_state = ANCS_STORE_DS_DESCS_HANDLES;
  398. // If not, throw an error and invalidate the CCCD handle in the handle cache.
  399. else
  400. {
  401. LOG("ANCS_DISC_DS_DESCS FAILURE\n");
  402. pservie->chars_hdl[ANCS_DATA_SRC_HDL_CCCD] = 0;
  403. pctx->disc_state = ANCS_DISC_FAILED;
  404. errorcode = 8;
  405. }
  406. }
  407. }
  408. break;
  409. // Discover the Data Source's descriptors (namely, the CCCD) using the start
  410. // and end handle stored in the handle cache.
  411. case ANCS_STORE_DS_DESCS_HANDLES:
  412. {
  413. LOG("Discovery Progress:\t9\n");
  414. LOG("Discovery State:\tStore the Data Source's CCCD handle\n");
  415. // Wait for the discovery response.
  416. if (pMsg->method == ATT_FIND_INFO_RSP )
  417. {
  418. bool flg = FALSE;
  419. // Sanity check to validate that at least one descriptors pair was found,
  420. // and that the pair length is correct.
  421. if ( (pMsg->msg.findInfoRsp.numInfo > 0) && (pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE) )
  422. {
  423. // This will keep track of the current pair being processed.
  424. uint8_t currentPair;
  425. // Iterate through the pair list.
  426. for(currentPair = 0; currentPair < pMsg->msg.findInfoRsp.numInfo; currentPair++)
  427. {
  428. // Check if the pair is a CCCD.
  429. uint16_t uuid = BUILD_UINT16(pMsg->msg.findInfoRsp.info.btPair[currentPair].uuid[0], pMsg->msg.findInfoRsp.info.btPair[currentPair].uuid[1]);
  430. if (uuid == GATT_CLIENT_CHAR_CFG_UUID)
  431. {
  432. // If so, store the handle in the handle cache, and proceed to the subscription process.
  433. pservie->chars_hdl[ANCS_DATA_SRC_HDL_CCCD] = pMsg->msg.findInfoRsp.info.btPair[currentPair].handle;
  434. flg = TRUE;
  435. }
  436. }
  437. if(flg == FALSE){
  438. LOG("ANCS_STORE_DS_DESCS_HANDLES FAILURE\n");
  439. pservie->chars_hdl[ANCS_DATA_SRC_HDL_CCCD] = 0;
  440. pctx->disc_state = ANCS_DISC_FAILED;
  441. errorcode = 9;
  442. }
  443. else{
  444. pctx->disc_state = ANCS_ENABLE_NS_CCCD;
  445. }
  446. }
  447. }
  448. }
  449. break;
  450. case ANCS_ENABLE_NS_CCCD:
  451. {
  452. bStatus_t ret;
  453. if (pMsg->method == ATT_FIND_INFO_RSP && (pMsg->hdr.status == bleProcedureComplete)){
  454. ret = Ancs_CCCDConfig(pservie->chars_hdl[ANCS_NOTIF_SCR_HDL_CCCD], TRUE);
  455. if(ret != SUCCESS){
  456. LOG("ANCS_DATA_SRC_HDL_CCCD FAILURE\n");
  457. pservie->chars_hdl[ANCS_DATA_SRC_HDL_CCCD] = 0;
  458. pctx->disc_state = ANCS_DISC_FAILED;
  459. errorcode = 10;
  460. break;
  461. }
  462. pctx->disc_state = ANCS_ENABLE_DS_CCCD;
  463. }
  464. }
  465. case ANCS_ENABLE_DS_CCCD:
  466. {
  467. bStatus_t ret;
  468. if (pMsg->method == ATT_WRITE_RSP ){
  469. ret = Ancs_CCCDConfig(pservie->chars_hdl[ANCS_DATA_SRC_HDL_CCCD], TRUE);
  470. if(ret != SUCCESS){
  471. LOG("ANCS_DATA_SRC_HDL_CCCD FAILURE\n");
  472. pservie->chars_hdl[ANCS_DATA_SRC_HDL_CCCD] = 0;
  473. pctx->disc_state = ANCS_DISC_FAILED;
  474. errorcode = 10;
  475. break;
  476. }
  477. pctx->disc_state = ANCS_DISC_FINISH;
  478. pctx->app_state = ANCS_STATE_READY;
  479. //pctx->disc_state = ANCS_WAIT_CCCD_READY;
  480. }
  481. }
  482. break;
  483. case ANCS_WAIT_CCCD_READY:
  484. if (pMsg->method == ATT_WRITE_RSP ){
  485. pctx->disc_state = ANCS_DISC_FINISH;
  486. pctx->app_state = ANCS_STATE_READY;
  487. LOG("Discovery Progress:\t12\n");
  488. LOG("Discovery State:\tProcessing notification data\n");
  489. break;
  490. }
  491. default:
  492. {
  493. pctx->disc_state = ANCS_DISC_FAILED;
  494. errorcode = 11;
  495. }
  496. break;
  497. }
  498. if(errorcode != 0)
  499. {
  500. LOG("Discovery State:\tDiscovery Error: %d\n",errorcode);
  501. }
  502. return errorcode;
  503. }
  504. static uint8_t Ancs_CCCDConfig(uint16_t attrHdl, uint8_t isEnable)
  505. {
  506. ancs_ctx_t* pctx = &s_ancs_ctx;
  507. // Declare return variable status.
  508. uint8_t status;
  509. // Stores the GATT write request parameters.
  510. attWriteReq_t req;
  511. LOG("Ancs_CCCDConfig handle %d\n", attrHdl);
  512. // Else, prepare the request.
  513. // Set the data length to 2 ("01" = 2 bytes).
  514. req.len = 2;
  515. // If we are enabling notifications, set the write data to "01".
  516. if (isEnable == TRUE)
  517. {
  518. req.value[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY);
  519. req.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);
  520. }
  521. // Else, disable notifications, thus set the write data to "00".
  522. else
  523. {
  524. req.value[0] = 0x00;
  525. req.value[1] = 0x00;
  526. }
  527. // Signature and command must be set to zero.
  528. req.sig = 0;
  529. req.cmd = 0;
  530. // Set the handle to the passed value (either the Notification Source's CCCD handle
  531. // or the Data Source's CCCD handle).
  532. req.handle = attrHdl;
  533. // Send write request. If it fails, free the memory allocated and
  534. // return a failure.
  535. status = GATT_WriteCharValue(pctx->ancs_service.conn_hdl, &req, pctx->app_task_ID);
  536. if ( status != SUCCESS){
  537. LOG("Ancs_CCCDConfig %d\n", status);
  538. }
  539. return status;
  540. }
  541. bStatus_t ble_ancs_start_descovery(uint16_t conn_handle)
  542. {
  543. ancs_ctx_t* pctx = &s_ancs_ctx;
  544. ancs_service_t* pservie = &(pctx->ancs_service);
  545. pservie->conn_hdl = conn_handle;
  546. pctx->disc_state = ANCS_DISC_SERVICE;
  547. pctx->app_state = ANCS_STATE_DISCOVERY;
  548. ble_disc_service(NULL);
  549. return SUCCESS;
  550. }
  551. static void ble_ancs_process_ds_notify(gattMsgEvent_t *pMsg)
  552. {
  553. ancs_ctx_t* pctx = &s_ancs_ctx;
  554. ancs_parse_get_attrs_response(pctx, (const uint8_t*)pMsg->msg.handleValueNoti.value, pMsg->msg.handleValueNoti.len);
  555. return;
  556. }
  557. void ble_ancs_process_ns_notify(gattMsgEvent_t *pMsg)
  558. {
  559. ancs_ctx_t* pctx = &s_ancs_ctx;
  560. ancs_evt_t evt;
  561. ancs_notify_evt_t notify_msg;
  562. uint8_t len = pMsg->msg.handleValueNoti.len;
  563. if (len != 8)
  564. {
  565. LOG("\n");
  566. LOG("Error evt len\n");
  567. return;
  568. }
  569. // Create pointer to GATT notification data.
  570. uint8_t *packetData = pMsg->msg.handleValueNoti.value;
  571. // Store the ANCS notification's eventID
  572. notify_msg.eventID = packetData[0];
  573. // Store the ANCS notification's eventFlag
  574. notify_msg.eventFlag = packetData[1];
  575. // Store the ANCS notification's categoryID
  576. notify_msg.categoryID = packetData[2];
  577. notify_msg.categoryCount = packetData[3];
  578. // Notification UID from packetData[4] to packetData[7]
  579. notify_msg.notifUID[0] = packetData[ANCS_NOTIF_UID_LENGTH];
  580. notify_msg.notifUID[1] = packetData[ANCS_NOTIF_UID_LENGTH+1];
  581. notify_msg.notifUID[2] = packetData[ANCS_NOTIF_UID_LENGTH+2];
  582. notify_msg.notifUID[3] = packetData[ANCS_NOTIF_UID_LENGTH+3];
  583. evt.msg = (void*)(&notify_msg);
  584. evt.len = sizeof(notify_msg);
  585. evt.type = BLE_ANCS_EVT_NOTIF;
  586. if(pctx->callback){
  587. pctx->callback(&evt);
  588. }
  589. }
  590. bStatus_t ble_ancs_get_notif_attrs(const uint8_t * pNotificationUID)
  591. {
  592. return notif_attrs_get(&s_ancs_ctx, pNotificationUID);
  593. }
  594. bStatus_t ble_ancs_get_app_attrs(const uint8_t * p_app_id, uint8_t app_id_len)
  595. {
  596. return app_attrs_get(&s_ancs_ctx, p_app_id, app_id_len);
  597. }
  598. bStatus_t ble_ancs_handle_gatt_event(gattMsgEvent_t* pMsg)
  599. {
  600. ancs_ctx_t* pctx = &s_ancs_ctx;
  601. ancs_service_t* pservie = &(pctx->ancs_service);
  602. if(pctx->app_state == ANCS_STATE_DISCOVERY)
  603. {
  604. ble_disc_service(pMsg);
  605. }
  606. else if (pMsg->method == ATT_HANDLE_VALUE_NOTI || pMsg->method == ATT_HANDLE_VALUE_IND)
  607. {
  608. // If we receive a GATT notification, we can assume it pertains to ANCS
  609. // because we only subscribe to notifications from the Notification Source
  610. // ancs Data Source.
  611. uint8_t notifHandle = pMsg->msg.handleValueNoti.handle;
  612. if ( notifHandle == pservie->chars_hdl[ANCS_NOTIF_SCR_HDL_START])
  613. {
  614. ble_ancs_process_ns_notify(pMsg);
  615. }
  616. else if ( notifHandle == pservie->chars_hdl[ANCS_DATA_SRC_HDL_START])
  617. {
  618. ble_ancs_process_ds_notify(pMsg);
  619. }
  620. }
  621. //If we have received a read or write response, assume that it is related to
  622. //CCCD configuration
  623. else if (pMsg->method == ATT_WRITE_RSP)
  624. {
  625. }
  626. // It's safe to free the incoming message
  627. return (TRUE);
  628. }
  629. bStatus_t ble_ancs_disconnect(void)
  630. {
  631. ancs_ctx_t* pctx = &s_ancs_ctx;
  632. uint8_t app_task_ID = pctx->app_task_ID;
  633. ancs_evt_hdl_t callback = pctx->callback;
  634. osal_memset(&s_ancs_ctx, 0, sizeof(s_ancs_ctx));
  635. pctx->app_task_ID = app_task_ID;
  636. pctx->callback = callback;
  637. return SUCCESS;
  638. }
  639. bStatus_t ble_ancs_init(ancs_evt_hdl_t evt_hdl, uint8_t task_ID)
  640. {
  641. ancs_ctx_t* pctx = &s_ancs_ctx;
  642. osal_memset(&s_ancs_ctx, 0, sizeof(s_ancs_ctx));
  643. pctx->app_task_ID = task_ID;
  644. pctx->callback = evt_hdl;
  645. return SUCCESS;
  646. }