ancs_attr.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  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 "osal.h"
  31. #include "gatt.h"
  32. #include "gapgattserver.h"
  33. #include "gattservapp.h"
  34. #include "peripheral.h"
  35. #include "gapbondmgr.h"
  36. #include "gatt_profile_uuid.h"
  37. #include "ble_ancs.h"
  38. #include "ancs_attr.h"
  39. #include "log.h"
  40. static bool all_req_attrs_parsed(ancs_ctx_t * p_ancs)
  41. {
  42. if (p_ancs->parse_info.expected_number_of_attrs == 0)
  43. {
  44. return TRUE;
  45. }
  46. return FALSE;
  47. }
  48. static bool attr_is_requested(ancs_ctx_t * p_ancs, ancs_attr_evt_t* pattr)
  49. {
  50. if(p_ancs->parse_info.p_attr_list[pattr->attr_id].en == TRUE)
  51. {
  52. return TRUE;
  53. }
  54. return FALSE;
  55. }
  56. static ancs_parse_state_t command_id_parse(ancs_ctx_t* p_ancs, const uint8_t * p_data_src, uint32_t * index)
  57. {
  58. ancs_parse_state_t parse_state;
  59. p_ancs->parse_info.command_id = (ancs_cmd_id_val_t) p_data_src[(*index)++];
  60. p_ancs->attr_rsp_evt.msg = (void*)(&(p_ancs->attr_evt_msg));
  61. switch (p_ancs->parse_info.command_id)
  62. {
  63. case ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES:
  64. p_ancs->attr_rsp_evt.type = BLE_ANCS_EVT_NOTIF_ATTRIBUTE;
  65. p_ancs->parse_info.p_attr_list = p_ancs->notif_attr_list;
  66. p_ancs->parse_info.nb_of_attr = ANCS_NB_OF_NOTIF_ATTR;
  67. parse_state = NOTIF_UID;
  68. break;
  69. case ANCS_COMMAND_ID_GET_APP_ATTRIBUTES:
  70. p_ancs->attr_rsp_evt.type = BLE_ANCS_EVT_APP_ATTRIBUTE;
  71. p_ancs->parse_info.p_attr_list = p_ancs->app_attr_list;
  72. p_ancs->parse_info.nb_of_attr = ANCS_NB_OF_APP_ATTR;
  73. parse_state = APP_ID;
  74. break;
  75. default:
  76. //no valid command_id, abort the rest of the parsing procedure.
  77. LOG("Invalid Command ID");
  78. parse_state = DONE;
  79. break;
  80. }
  81. return parse_state;
  82. }
  83. static ancs_parse_state_t notif_uid_parse(ancs_ctx_t * p_ancs,
  84. const uint8_t * p_data_src,
  85. uint32_t * index)
  86. {
  87. p_ancs->attr_evt_msg.notif_uid = BUILD_UINT32(p_data_src[*index],p_data_src[*index+1],p_data_src[*index+2],p_data_src[*index+3]);
  88. *index += sizeof(uint32_t);
  89. return ATTR_ID;
  90. }
  91. static ancs_parse_state_t app_id_parse(ancs_ctx_t * p_ancs,
  92. const uint8_t * p_data_src,
  93. uint32_t * index)
  94. {
  95. p_ancs->attr_evt_msg.app_id[p_ancs->parse_info.current_app_id_index] = p_data_src[(*index)++];
  96. if(p_ancs->attr_evt_msg.app_id[p_ancs->parse_info.current_app_id_index] != '\0')
  97. {
  98. p_ancs->parse_info.current_app_id_index++;
  99. return APP_ID;
  100. }
  101. else
  102. {
  103. return ATTR_ID;
  104. }
  105. }
  106. static ancs_parse_state_t attr_id_parse(ancs_ctx_t * p_ancs,
  107. const uint8_t * p_data_src,
  108. uint32_t * index)
  109. {
  110. p_ancs->attr_evt_msg.attr_id = p_data_src[(*index)++];
  111. if (p_ancs->attr_evt_msg.attr_id >= p_ancs->parse_info.nb_of_attr)
  112. {
  113. LOG("Attribute ID Invalid.\r\n");
  114. return DONE;
  115. }
  116. p_ancs->attr_evt_msg.p_attr_data = p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].p_attr_data;
  117. if (all_req_attrs_parsed(p_ancs))
  118. {
  119. LOG("All requested attributes received. \r\n");
  120. return DONE;
  121. }
  122. else
  123. {
  124. if (attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg)))
  125. {
  126. p_ancs->parse_info.expected_number_of_attrs--;
  127. }
  128. LOG("Attribute ID %i \r\n", p_ancs->attr_evt_msg.attr_id);
  129. return ATTR_LEN1;
  130. }
  131. }
  132. static ancs_parse_state_t attr_len1_parse(ancs_ctx_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
  133. {
  134. p_ancs->attr_evt_msg.attr_len = p_data_src[(*index)++];
  135. return ATTR_LEN2;
  136. }
  137. static ancs_parse_state_t attr_len2_parse(ancs_ctx_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
  138. {
  139. p_ancs->attr_evt_msg.attr_len |= (p_data_src[(*index)++] << 8);
  140. p_ancs->parse_info.current_attr_index = 0;
  141. if (p_ancs->attr_evt_msg.attr_len != 0)
  142. {
  143. //If the attribute has a length but there is no allocated space for this attribute
  144. if((p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].attr_len == 0) ||
  145. (p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].p_attr_data == NULL))
  146. {
  147. return ATTR_SKIP;
  148. }
  149. else
  150. {
  151. return ATTR_DATA;
  152. }
  153. }
  154. else
  155. {
  156. LOG("Attribute LEN %i \r\n", p_ancs->attr_evt_msg.attr_len);
  157. if(attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg)))
  158. {
  159. p_ancs->callback(&p_ancs->attr_rsp_evt);
  160. }
  161. if(all_req_attrs_parsed(p_ancs))
  162. {
  163. return DONE;
  164. }
  165. else
  166. {
  167. return ATTR_ID;
  168. }
  169. }
  170. }
  171. static ancs_parse_state_t attr_data_parse(ancs_ctx_t * p_ancs,
  172. const uint8_t * p_data_src,
  173. uint32_t * index)
  174. {
  175. // We have not reached the end of the attribute, nor our max allocated internal size.
  176. // Proceed with copying data over to our buffer.
  177. if ( (p_ancs->parse_info.current_attr_index < p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].attr_len)
  178. && (p_ancs->parse_info.current_attr_index < p_ancs->attr_evt_msg.attr_len))
  179. {
  180. //LOG("Byte copied to buffer: %c\r\n", p_data_src[(*index)]); // Un-comment this line to see every byte of an attribute as it is parsed. Commented out by default since it can overflow the uart buffer.
  181. p_ancs->attr_evt_msg.p_attr_data[p_ancs->parse_info.current_attr_index++] = p_data_src[(*index)++];
  182. }
  183. // We have reached the end of the attribute, or our max allocated internal size.
  184. // Stop copying data over to our buffer. NUL-terminate at the current index.
  185. if ( (p_ancs->parse_info.current_attr_index == p_ancs->attr_evt_msg.attr_len) ||
  186. (p_ancs->parse_info.current_attr_index == p_ancs->parse_info.p_attr_list[p_ancs->attr_evt_msg.attr_id].attr_len - 1))
  187. {
  188. if (attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg)))
  189. {
  190. p_ancs->attr_evt_msg.p_attr_data[p_ancs->parse_info.current_attr_index] = '\0';
  191. }
  192. // If our max buffer size is smaller than the remaining attribute data, we must
  193. // increase index to skip the data until the start of the next attribute.
  194. if (p_ancs->parse_info.current_attr_index < p_ancs->attr_evt_msg.attr_len)
  195. {
  196. return ATTR_SKIP;
  197. }
  198. LOG("Attribute finished!\r\n");
  199. if(attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg)))
  200. {
  201. p_ancs->callback(&p_ancs->attr_rsp_evt);
  202. }
  203. if(all_req_attrs_parsed(p_ancs))
  204. {
  205. return DONE;
  206. }
  207. else
  208. {
  209. return ATTR_ID;
  210. }
  211. }
  212. return ATTR_DATA;
  213. }
  214. static ancs_parse_state_t attr_skip(ancs_ctx_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
  215. {
  216. // We have not reached the end of the attribute, nor our max allocated internal size.
  217. // Proceed with copying data over to our buffer.
  218. if (p_ancs->parse_info.current_attr_index < p_ancs->attr_evt_msg.attr_len)
  219. {
  220. p_ancs->parse_info.current_attr_index++;
  221. (*index)++;
  222. }
  223. // At the end of the attribute, determine if it should be passed to event handler and
  224. // continue parsing the next attribute ID if we are not done with all the attributes.
  225. if (p_ancs->parse_info.current_attr_index == p_ancs->attr_evt_msg.attr_len)
  226. {
  227. if(attr_is_requested(p_ancs, &(p_ancs->attr_evt_msg)))
  228. {
  229. p_ancs->callback(&p_ancs->attr_rsp_evt);
  230. }
  231. if(all_req_attrs_parsed(p_ancs))
  232. {
  233. return DONE;
  234. }
  235. else
  236. {
  237. return ATTR_ID;
  238. }
  239. }
  240. return ATTR_SKIP;
  241. }
  242. static void print_hex (const uint8 *data, uint16 len)
  243. {
  244. uint16 i;
  245. for (i = 0; i < len - 1; i++)
  246. {
  247. LOG("%x,",data[i]);
  248. LOG(" ");
  249. }
  250. LOG("%d\n",data[i]);
  251. }
  252. void ancs_parse_get_attrs_response(ancs_ctx_t * p_ancs, const uint8_t * p_data_src, uint8_t hvx_data_len)
  253. {
  254. uint32_t index;
  255. LOG("ancs_parse_get_attrs_response:\n");
  256. print_hex(p_data_src, hvx_data_len);
  257. for (index = 0; index < hvx_data_len;)
  258. {
  259. switch (p_ancs->parse_info.parse_state)
  260. {
  261. case COMMAND_ID:
  262. p_ancs->parse_info.parse_state = command_id_parse(p_ancs, p_data_src, &index);
  263. break;
  264. case NOTIF_UID:
  265. p_ancs->parse_info.parse_state = notif_uid_parse(p_ancs, p_data_src, &index);
  266. break;
  267. case APP_ID:
  268. p_ancs->parse_info.parse_state = app_id_parse(p_ancs, p_data_src, &index);
  269. break;
  270. case ATTR_ID:
  271. p_ancs->parse_info.parse_state = attr_id_parse(p_ancs, p_data_src, &index);
  272. break;
  273. case ATTR_LEN1:
  274. p_ancs->parse_info.parse_state = attr_len1_parse(p_ancs, p_data_src, &index);
  275. break;
  276. case ATTR_LEN2:
  277. p_ancs->parse_info.parse_state = attr_len2_parse(p_ancs, p_data_src, &index);
  278. break;
  279. case ATTR_DATA:
  280. p_ancs->parse_info.parse_state = attr_data_parse(p_ancs, p_data_src, &index);
  281. break;
  282. case ATTR_SKIP:
  283. p_ancs->parse_info.parse_state = attr_skip(p_ancs, p_data_src, &index);
  284. break;
  285. case DONE:
  286. LOG("Parse state: Done %s\r\n", p_ancs->attr_evt_msg.p_attr_data);
  287. index = hvx_data_len;
  288. break;
  289. default:
  290. // Default case will never trigger intentionally. Go to the DONE state to minimize the consequences.
  291. p_ancs->parse_info.parse_state = DONE;
  292. break;
  293. }
  294. }
  295. }
  296. static bool app_attr_is_requested(ancs_ctx_t * p_ancs, uint32_t attr_id)
  297. {
  298. if(p_ancs->app_attr_list[attr_id].en == TRUE)
  299. {
  300. return TRUE;
  301. }
  302. return false;
  303. }
  304. static uint32_t app_attr_nb_to_get(ancs_ctx_t * p_ancs)
  305. {
  306. uint32_t attr_nb_to_get = 0;
  307. for(uint32_t i = 0; i < (sizeof(p_ancs->app_attr_list)/sizeof(ancs_attr_list_t)); i++)
  308. {
  309. if(app_attr_is_requested(p_ancs,i))
  310. {
  311. attr_nb_to_get++;
  312. }
  313. }
  314. return attr_nb_to_get;
  315. }
  316. static encode_app_attr_t app_attr_encode_cmd_id(ancs_ctx_t * p_ancs,
  317. uint32_t * index,
  318. uint8_t * tx_buf)
  319. {
  320. LOG("Encoding Command ID\r\n");
  321. // Encode Command ID.
  322. tx_buf[(*index)++] = ANCS_COMMAND_ID_GET_APP_ATTRIBUTES;
  323. return APP_ATTR_APP_ID;
  324. }
  325. static encode_app_attr_t app_attr_encode_app_id(ancs_ctx_t * p_ancs,
  326. uint32_t * p_index,
  327. uint16_t * p_offset,
  328. uint8_t * tx_buf,
  329. const uint8_t * p_app_id,
  330. const uint32_t app_id_len,
  331. uint32_t * p_app_id_bytes_encoded_count)
  332. {
  333. LOG("Encoding APP ID\r\n");
  334. //Encode App Identifier.
  335. if(*p_app_id_bytes_encoded_count == app_id_len)
  336. {
  337. tx_buf[(*p_index)++] = '\0';
  338. (*p_app_id_bytes_encoded_count)++;
  339. }
  340. LOG("%c\r\n", p_app_id[(*p_app_id_bytes_encoded_count)]);
  341. if(*p_app_id_bytes_encoded_count < app_id_len)
  342. {
  343. tx_buf[(*p_index)++] = p_app_id[(*p_app_id_bytes_encoded_count)++];
  344. }
  345. if(*p_app_id_bytes_encoded_count > app_id_len)
  346. {
  347. return APP_ATTR_ATTR_ID;
  348. }
  349. return APP_ATTR_APP_ID;
  350. }
  351. static encode_app_attr_t app_attr_encode_attr_id(ancs_ctx_t * p_ancs,
  352. uint32_t * p_index,
  353. uint16_t * p_offset,
  354. uint8_t * tx_buf,
  355. uint32_t * p_attr_count,
  356. uint32_t * attr_get_total_nb)
  357. {
  358. LOG("Encoding Attribute ID\r\n");
  359. //Encode Attribute ID.
  360. if (*p_attr_count < ANCS_NB_OF_APP_ATTR)
  361. {
  362. if (app_attr_is_requested(p_ancs, *p_attr_count))
  363. {
  364. tx_buf[(*p_index)] = *p_attr_count;
  365. (*p_index)++;
  366. LOG("offset %i\r\n", *p_offset);
  367. }
  368. (*p_attr_count)++;
  369. }
  370. if (*p_attr_count == ANCS_NB_OF_APP_ATTR)
  371. {
  372. return APP_ATTR_DONE;
  373. }
  374. return APP_ATTR_APP_ID;
  375. }
  376. bStatus_t app_attrs_get(ancs_ctx_t * p_ancs, const uint8_t * p_app_id, uint8_t app_id_len)
  377. {
  378. ancs_service_t* pservice = &(p_ancs->ancs_service);
  379. uint32_t index = 0;
  380. uint32_t attr_bytes_encoded_count = 0;
  381. uint16_t offset = 0;
  382. uint32_t app_id_bytes_encoded_count = 0;
  383. encode_app_attr_t state = APP_ATTR_COMMAND_ID;
  384. bStatus_t status;
  385. p_ancs->parse_info.parse_state = COMMAND_ID;
  386. uint32_t attr_get_total_nb = app_attr_nb_to_get(p_ancs);
  387. uint8_t* tx_buf = p_ancs->app_attr_tx_buf;
  388. if(app_id_len == 0)
  389. {
  390. return INVALIDPARAMETER;
  391. }
  392. if(p_app_id[app_id_len] != '\0') // App id to be requestes must be NULL terminated
  393. {
  394. return INVALIDPARAMETER;
  395. }
  396. osal_memset(tx_buf, 0, sizeof(ANCS_APP_ATTR_TX_SIZE));
  397. while(state != APP_ATTR_DONE)
  398. {
  399. switch(state)
  400. {
  401. case APP_ATTR_COMMAND_ID:
  402. state = app_attr_encode_cmd_id(p_ancs,
  403. &index,
  404. tx_buf);
  405. break;
  406. case APP_ATTR_APP_ID:
  407. state = app_attr_encode_app_id(p_ancs,
  408. &index,
  409. &offset,
  410. tx_buf,
  411. p_app_id,
  412. app_id_len,
  413. &app_id_bytes_encoded_count);
  414. break;
  415. case APP_ATTR_ATTR_ID:
  416. state = app_attr_encode_attr_id(p_ancs,
  417. &index,
  418. &offset,
  419. tx_buf,
  420. &attr_bytes_encoded_count,
  421. &attr_get_total_nb);
  422. break;
  423. case APP_ATTR_DONE:
  424. break;
  425. default:
  426. break;
  427. }
  428. }
  429. p_ancs->parse_info.expected_number_of_attrs = ANCS_NB_OF_APP_ATTR;
  430. if(index > 20){
  431. gattPrepareWriteReq_t lreq = {0,0};
  432. lreq.pValue = osal_mem_alloc(index);
  433. osal_memcpy(lreq.pValue, tx_buf, index);
  434. lreq.handle = pservice->chars_hdl[ANCS_CTRL_POINT_HDL_START];
  435. lreq.len = index;
  436. status = GATT_WriteLongCharValue(pservice->conn_hdl, &lreq, p_ancs->app_task_ID);
  437. if (status != SUCCESS)
  438. {
  439. // If it fails free the message.
  440. LOG("CP WRITE ERROR:\t%d\n",status);
  441. osal_mem_free(lreq.pValue);
  442. }
  443. }
  444. else
  445. {
  446. attWriteReq_t req;
  447. osal_memcpy(req.value, tx_buf, index);
  448. req.sig = 0;
  449. req.cmd = 0;
  450. req.handle = pservice->chars_hdl[ANCS_CTRL_POINT_HDL_START];
  451. req.len = index;
  452. status = GATT_WriteCharValue(pservice->conn_hdl, &req, p_ancs->app_task_ID);
  453. if (status != SUCCESS)
  454. {
  455. // If it fails free the message.
  456. LOG("CP WRITE ERROR:\t%d\n",status);
  457. }
  458. }
  459. return SUCCESS;
  460. }
  461. bStatus_t notif_attrs_get(ancs_ctx_t * p_ancs,const uint8_t * pNotificationUID)
  462. {
  463. ancs_service_t* pservice = &(p_ancs->ancs_service);
  464. ancs_attr_list_t* pattrlist = p_ancs->notif_attr_list;
  465. bStatus_t status;
  466. uint8_t* tx_buf = p_ancs->app_attr_tx_buf;
  467. uint8_t number_of_requested_attr = 0;
  468. p_ancs->parse_info.parse_state = COMMAND_ID;
  469. osal_memset(tx_buf, 0, sizeof(ANCS_APP_ATTR_TX_SIZE));
  470. uint32_t index = 0;
  471. //Encode Command ID.
  472. tx_buf[index++] = ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES;
  473. //Encode Notification UID.
  474. tx_buf[index++] = pNotificationUID[0];
  475. tx_buf[index++] = pNotificationUID[1];
  476. tx_buf[index++] = pNotificationUID[2];
  477. tx_buf[index++] = pNotificationUID[3];
  478. //Encode Attribute ID.
  479. for (uint32_t attr = 0; attr < ANCS_NB_OF_NOTIF_ATTR; attr++)
  480. {
  481. if (pattrlist[attr].en == TRUE)
  482. {
  483. tx_buf[index++] = attr;
  484. if ((attr == BLE_ANCS_NOTIF_ATTR_ID_TITLE) ||
  485. (attr == BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE) ||
  486. (attr == BLE_ANCS_NOTIF_ATTR_ID_MESSAGE))
  487. {
  488. //Encode Length field, only applicable for Title, Subtitle and Message
  489. tx_buf[index++] = (uint8_t)(pattrlist[attr].attr_len & 0xff);
  490. tx_buf[index++] = (uint8_t)((pattrlist[attr].attr_len >> 8)&0xff);
  491. }
  492. number_of_requested_attr++;
  493. }
  494. }
  495. LOG("notif_attrs_get:\n");
  496. print_hex(tx_buf, index);
  497. p_ancs->parse_info.expected_number_of_attrs = number_of_requested_attr;
  498. if(index > 20){
  499. gattPrepareWriteReq_t lreq = {0,0};
  500. lreq.pValue = osal_mem_alloc(index);
  501. osal_memcpy(lreq.pValue, tx_buf, index);
  502. lreq.handle = pservice->chars_hdl[ANCS_CTRL_POINT_HDL_START];
  503. lreq.len = index;
  504. status = GATT_WriteLongCharValue(pservice->conn_hdl, &lreq, p_ancs->app_task_ID);
  505. if (status != SUCCESS)
  506. {
  507. // If it fails free the message.
  508. LOG("CP WRITE ERROR:\t%d\n",status);
  509. osal_mem_free(lreq.pValue);
  510. }
  511. }
  512. else
  513. {
  514. attWriteReq_t req;
  515. osal_memcpy(req.value, tx_buf, index);
  516. req.sig = 0;
  517. req.cmd = 0;
  518. req.handle = pservice->chars_hdl[ANCS_CTRL_POINT_HDL_START];
  519. req.len = index;
  520. status = GATT_WriteCharValue(pservice->conn_hdl, &req, p_ancs->app_task_ID);
  521. if (status != SUCCESS)
  522. {
  523. // If it fails free the message.
  524. LOG("CP WRITE ERROR:\t%d\n",status);
  525. }
  526. }
  527. return SUCCESS;
  528. }