1 /**
2 ****************************************************************************************
3 *
4 * @file ans.c
5 *
6 * @brief Alert Notification Service implementation.
7 *
8 ****************************************************************************************
9 * @attention
10 #####Copyright (c) 2019 GOODIX
11 All rights reserved.
12
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions are met:
15 * Redistributions of source code must retain the above copyright
16 notice, this list of conditions and the following disclaimer.
17 * Redistributions in binary form must reproduce the above copyright
18 notice, this list of conditions and the following disclaimer in the
19 documentation and/or other materials provided with the distribution.
20 * Neither the name of GOODIX nor the names of its contributors may be used
21 to endorse or promote products derived from this software without
22 specific prior written permission.
23
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
28 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 POSSIBILITY OF SUCH DAMAGE.
35 *****************************************************************************************
36 */
37
38 /*
39 * INCLUDE FILES
40 ****************************************************************************************
41 */
42 #include "ans.h"
43 #include "ble_prf_types.h"
44 #include "ble_prf_utils.h"
45 #include "gr55xx_sys.h"
46 #include "utility.h"
47
48 /*
49 * ENUMERATIONS
50 ****************************************************************************************
51 */
52 /**@brief Alert Notification Service Attributes Indexes. */
53 enum {
54 // Alert Notification Service
55 ANS_IDX_SVC,
56
57 // Supported New Alert Category
58 ANS_IDX_SUP_NEW_ALET_CAT_CHAR,
59 ANS_IDX_SUP_NEW_ALET_CAT_VAL,
60
61 // New Alert
62 ANS_IDX_NEWS_ALERT_CHAR,
63 ANS_IDX_NEWS_ALERT_VAL,
64 ANS_IDX_NEWS_ALERT_NTF_CFG,
65
66 // Supported Unread Alert Category
67 ANS_IDX_SUP_UNREAD_ALERT_CAT_CHAR,
68 ANS_IDX_SUP_UNREAD_ALERT_CAT_VAL,
69
70 // Unread Alert Status
71 ANS_IDX_UNREAD_ALERT_STA_CHAR,
72 ANS_IDX_UNREAD_ALERT_STA_VAL,
73 ANS_IDX_UNREAD_ALERT_STA_NTF_CFG,
74
75 // Alert Notification Control Point
76 ANS_IDX_ALERT_NTF_CTRL_PT_CHAR,
77 ANS_IDX_ALERT_NTF_CTRL_PT_VAL,
78
79 ANS_IDX_NB
80 };
81
82 /*
83 * STRUCTURES
84 *****************************************************************************************
85 */
86 /**@brief Alert Notification Service environment variable. */
87 struct ans_env_t {
88 ans_init_t ans_init; /**< Alert Notification Service initialization variables. */
89 uint16_t start_hdl; /**< Alert Notification Service start handle. */
90 uint16_t
91 new_alert_ntf_cfg[ANS_CONNECTION_MAX]; /**< The configuration of New Alert Notification \
92 which is configured by the peer devices. */
93 uint16_t
94 unread_alert_sta_ntf_cfg[ANS_CONNECTION_MAX]; /**< The configuration of Unread Alert Status Notification \
95 which is configured by the peer devices. */
96 uint16_t ntf_new_alert_cfg; /**< New Alert category notification configuration. */
97 uint16_t
98 ntf_unread_alert_cfg; /**< Unread Alert Status category notification configuration. */
99 };
100
101 /*
102 * LOCAL FUNCTION DECLARATION
103 *****************************************************************************************
104 */
105 static sdk_err_t ans_init(void);
106 static void ans_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param);
107 static void ans_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
108 static void ans_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value);
109 static void ans_connected_cb(uint8_t conn_idx);
110 static bool ans_ctrl_pt_sup_check(ans_ctrl_pt_t *p_ctrl_pt);
111 static void ans_ctrl_pt_handler(uint8_t conn_idx, ans_ctrl_pt_t *p_ctrl_pt);
112
113 /*
114 * LOCAL VARIABLE DEFINITIONS
115 *****************************************************************************************
116 */
117 static struct ans_env_t s_ans_env;
118 static uint16_t s_ans_char_mask = 0x1fff;
119
120 /**@brief Full ANS Database Description - Used to add attributes into the database. */
121 static const attm_desc_t pass_attr_tab[ANS_IDX_NB] = {
122 // Alert Notification Service
123 [ANS_IDX_SVC] = {BLE_ATT_DECL_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
124
125 // Alert Status Characteristic - Declaration
126 [ANS_IDX_SUP_NEW_ALET_CAT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
127 // Alert Status Characteristic - Value
128 [ANS_IDX_SUP_NEW_ALET_CAT_VAL] = {
129 BLE_ATT_CHAR_SUP_NEW_ALERT_CAT,
130 READ_PERM_UNSEC,
131 ATT_VAL_LOC_USER,
132 ANS_SUP_NEW_ALERT_CAT_VAL_LEN
133 },
134
135 // New Alert Characteristic - Declaration
136 [ANS_IDX_NEWS_ALERT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
137 // New Alert Characteristic - Value
138 [ANS_IDX_NEWS_ALERT_VAL] = {
139 BLE_ATT_CHAR_NEW_ALERT,
140 NOTIFY_PERM_UNSEC,
141 ATT_VAL_LOC_USER,
142 ANS_NEWS_ALERT_VAL_LEN
143 },
144 // New Alert Characteristic - Client Characteristic Configuration Descriptor
145 [ANS_IDX_NEWS_ALERT_NTF_CFG] = {BLE_ATT_DESC_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0},
146
147 // Supported Unread AlertCategory Characteristic - Declaration
148 [ANS_IDX_SUP_UNREAD_ALERT_CAT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
149 // Supported Unread Alert Category Characteristic - Value
150 [ANS_IDX_SUP_UNREAD_ALERT_CAT_VAL] = {
151 BLE_ATT_CHAR_SUP_UNREAD_ALERT_CAT,
152 READ_PERM_UNSEC,
153 ATT_VAL_LOC_USER,
154 ANS_SUP_UNREAD_ALERT_CAT_VAL_LEN
155 },
156
157 // Unread Alert Status Characteristic - Declaration
158 [ANS_IDX_UNREAD_ALERT_STA_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
159 // Unread Alert Status Characteristic - Value
160 [ANS_IDX_UNREAD_ALERT_STA_VAL] = {
161 BLE_ATT_CHAR_UNREAD_ALERT_STATUS,
162 NOTIFY_PERM_UNSEC,
163 ATT_VAL_LOC_USER,
164 ANS_UNREAD_ALERT_STA_VAL_LEN
165 },
166 // Unread Alert Status Characteristic - Client Characteristic Configuration Descriptor
167 [ANS_IDX_UNREAD_ALERT_STA_NTF_CFG] = {
168 BLE_ATT_DESC_CLIENT_CHAR_CFG,
169 READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
170 0,
171 0
172 },
173
174 // Alert Notification Control Point Characteristic - Declaration
175 [ANS_IDX_ALERT_NTF_CTRL_PT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
176 // Alert Notification Control Point Characteristic - Value
177 [ANS_IDX_ALERT_NTF_CTRL_PT_VAL] = {
178 BLE_ATT_CHAR_ALERT_NTF_CTNL_PT,
179 #if defined(PTS_AUTO_TEST)
180 WRITE_REQ_PERM_UNSEC,
181 #else
182 WRITE_CMD_PERM_UNSEC,
183 #endif
184 ATT_VAL_LOC_USER,
185 ANS_ALERT_NTF_CTRL_PT_VAL_LEN
186 },
187 };
188
189 /**@brief ANS Task interface required by profile manager. */
190 static ble_prf_manager_cbs_t ans_task_cbs = {
191 (prf_init_func_t) ans_init,
192 ans_connected_cb,
193 NULL,
194 };
195
196 /**@brief ANS Task Callbacks. */
197 static gatts_prf_cbs_t ans_cb_func = {
198 ans_read_att_cb,
199 ans_write_att_cb,
200 NULL,
201 NULL,
202 ans_cccd_set_cb
203 };
204
205 /**@brief ANS Information. */
206 static const prf_server_info_t ans_prf_info = {
207 .max_connection_nb = ANS_CONNECTION_MAX,
208 .manager_cbs = &ans_task_cbs,
209 .gatts_prf_cbs = &ans_cb_func,
210 };
211
212 /*
213 * LOCAL FUNCTION DEFINITIONS
214 *****************************************************************************************
215 */
216 /**
217 *****************************************************************************************
218 * @brief Initialize Alert Notify Service and create db in att
219 *
220 * @return Error code to know if profile initialization succeed or not.
221 *****************************************************************************************
222 */
ans_init(void)223 static sdk_err_t ans_init(void)
224 {
225 // The start hanlde must be set with PRF_INVALID_HANDLE to be allocated automatically by BLE Stack.
226 uint16_t start_hdl = PRF_INVALID_HANDLE;
227 const uint8_t pass_svc_uuid[] = BLE_ATT_16_TO_16_ARRAY(BLE_ATT_SVC_ALERT_NTF);
228 sdk_err_t error_code;
229 gatts_create_db_t gatts_db;
230
231 error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
232 if (error_code < 0) {
233 return error_code;
234 }
235
236 gatts_db.shdl = &start_hdl;
237 gatts_db.uuid = pass_svc_uuid;
238 gatts_db.attr_tab_cfg = (uint8_t *)&s_ans_char_mask;
239 gatts_db.max_nb_attr = ANS_IDX_NB;
240 gatts_db.srvc_perm = 0;
241 gatts_db.attr_tab_type = SERVICE_TABLE_TYPE_16;
242 gatts_db.attr_tab.attr_tab_16 = pass_attr_tab;
243
244 error_code = ble_gatts_srvc_db_create(&gatts_db);
245 if (SDK_SUCCESS == error_code) {
246 s_ans_env.start_hdl = *gatts_db.shdl;
247 }
248
249 return error_code;
250 }
251
252 /**
253 *****************************************************************************************
254 * @brief Handles reception of the attribute info request message.
255 *
256 * @param[in] conn_idx: Connection index
257 * @param[in] p_param: The parameters of the read request.
258 *****************************************************************************************
259 */
ans_read_att_cb(uint8_t conn_idx,const gatts_read_req_cb_t * p_param)260 static void ans_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
261 {
262 gatts_read_cfm_t cfm;
263 uint8_t handle = p_param->handle;
264 uint8_t tab_index = prf_find_idx_by_handle(handle,
265 s_ans_env.start_hdl,
266 ANS_IDX_NB,
267 (uint8_t *)&s_ans_char_mask);
268 cfm.handle = handle;
269 cfm.status = BLE_SUCCESS;
270
271 switch (tab_index) {
272 case ANS_IDX_SUP_NEW_ALET_CAT_VAL:
273 cfm.length = ANS_SUP_NEW_ALERT_CAT_VAL_LEN;
274 cfm.value = (uint8_t *)&s_ans_env.ans_init.sup_new_alert_cat;
275 break;
276
277 case ANS_IDX_NEWS_ALERT_NTF_CFG:
278 cfm.length = sizeof(uint16_t);
279 cfm.value = (uint8_t *)&s_ans_env.new_alert_ntf_cfg[conn_idx];
280 break;
281
282 case ANS_IDX_SUP_UNREAD_ALERT_CAT_VAL:
283 cfm.length = ANS_SUP_UNREAD_ALERT_CAT_VAL_LEN;
284 cfm.value = (uint8_t *)&s_ans_env.ans_init.sup_unread_alert_sta;
285 break;
286
287 case ANS_IDX_UNREAD_ALERT_STA_NTF_CFG:
288 cfm.length = sizeof(uint16_t);
289 cfm.value = (uint8_t *)&s_ans_env.unread_alert_sta_ntf_cfg[conn_idx];
290 break;
291
292 default:
293 cfm.length = 0;
294 cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
295 break;
296 }
297
298 ble_gatts_read_cfm(conn_idx, &cfm);
299 }
300
301 /**
302 *****************************************************************************************
303 * @brief Handles reception of the write request.
304 *
305 * @param[in]: conn_idx: Connection index
306 * @param[in]: p_param: The parameters of the write request.
307 *****************************************************************************************
308 */
ans_write_att_cb(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)309 static void ans_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
310 {
311 uint16_t handle = p_param->handle;
312 uint16_t tab_index = 0;
313 uint16_t cccd_value = 0;
314 bool is_ctrl_pt_rec = false;
315 ans_ctrl_pt_t ctrl_pt;
316 ans_evt_t event;
317 gatts_write_cfm_t cfm;
318
319 tab_index = prf_find_idx_by_handle(handle,
320 s_ans_env.start_hdl,
321 ANS_IDX_NB,
322 (uint8_t *)&s_ans_char_mask);
323 cfm.handle = handle;
324 cfm.status = BLE_SUCCESS;
325 event.evt_type = ANS_EVT_INVALID;
326 event.conn_idx = conn_idx;
327
328 switch (tab_index) {
329 case ANS_IDX_NEWS_ALERT_NTF_CFG:
330 cccd_value = le16toh(&p_param->value[0]);
331 event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
332 ANS_EVT_NEW_ALERT_NTF_ENABLE : \
333 ANS_EVT_NEW_ALERT_NTF_DISABLE);
334 s_ans_env.new_alert_ntf_cfg[conn_idx] = cccd_value;
335 break;
336
337 case ANS_IDX_UNREAD_ALERT_STA_NTF_CFG:
338 cccd_value = le16toh(&p_param->value[0]);
339 event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
340 ANS_EVT_UNREAD_ALERT_STA_NTF_ENABLE : \
341 ANS_EVT_UNREAD_ALERT_STA_NTF_DISABLE);
342 s_ans_env.unread_alert_sta_ntf_cfg[conn_idx] = cccd_value;
343 break;
344
345 case ANS_IDX_ALERT_NTF_CTRL_PT_VAL:
346 ctrl_pt.cmd_id = (ans_ctrl_pt_id_t)p_param->value[0];
347 ctrl_pt.cat_id = (ans_alert_cat_id_t)p_param->value[1];
348
349 if (ans_ctrl_pt_sup_check(&ctrl_pt)) {
350 is_ctrl_pt_rec = true;
351 } else {
352 cfm.status = ANS_ERROR_CMD_NOT_SUP;
353 }
354
355 break;
356
357 default:
358 cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
359 break;
360 }
361
362 ble_gatts_write_cfm(conn_idx, &cfm);
363
364 if (is_ctrl_pt_rec) {
365 is_ctrl_pt_rec = false;
366 ans_ctrl_pt_handler(conn_idx, &ctrl_pt);
367 }
368
369 if (BLE_ATT_ERR_INVALID_HANDLE != cfm.status && \
370 ANS_EVT_INVALID != event.evt_type && \
371 s_ans_env.ans_init.evt_handler) {
372 s_ans_env.ans_init.evt_handler(&event);
373 }
374 }
375
376 /**
377 *****************************************************************************************
378 * @brief Handles reception of the cccd recover request.
379 *
380 * @param[in]: conn_idx: Connection index
381 * @param[in]: handle: The handle of cccd attribute.
382 * @param[in]: cccd_value: The value of cccd attribute.
383 *****************************************************************************************
384 */
ans_cccd_set_cb(uint8_t conn_idx,uint16_t handle,uint16_t cccd_value)385 static void ans_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value)
386 {
387 uint16_t tab_index = 0;
388 ans_evt_t event;
389
390 if (!prf_is_cccd_value_valid(cccd_value)) {
391 return;
392 }
393
394 tab_index = prf_find_idx_by_handle(handle,
395 s_ans_env.start_hdl,
396 ANS_IDX_NB,
397 (uint8_t *)&s_ans_char_mask);
398
399 event.evt_type = ANS_EVT_INVALID;
400 event.conn_idx = conn_idx;
401
402 switch (tab_index) {
403 case ANS_IDX_NEWS_ALERT_NTF_CFG:
404 event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
405 ANS_EVT_NEW_ALERT_NTF_ENABLE : \
406 ANS_EVT_NEW_ALERT_NTF_DISABLE);
407 s_ans_env.new_alert_ntf_cfg[conn_idx] = cccd_value;
408 break;
409
410 case ANS_IDX_UNREAD_ALERT_STA_NTF_CFG:
411 event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
412 ANS_EVT_UNREAD_ALERT_STA_NTF_ENABLE : \
413 ANS_EVT_UNREAD_ALERT_STA_NTF_DISABLE);
414 s_ans_env.unread_alert_sta_ntf_cfg[conn_idx] = cccd_value;
415 break;
416
417 default:
418 break;
419 }
420
421 if (ANS_EVT_INVALID != event.evt_type && \
422 s_ans_env.ans_init.evt_handler) {
423 s_ans_env.ans_init.evt_handler(&event);
424 }
425 }
426
427 /**
428 *****************************************************************************************
429 * @brief Connected callback.
430 *
431 * @param[in]: conn_idx: Connection index
432 *****************************************************************************************
433 */
ans_connected_cb(uint8_t conn_idx)434 static void ans_connected_cb(uint8_t conn_idx)
435 {
436 s_ans_env.ntf_new_alert_cfg = 0;
437 s_ans_env.ntf_unread_alert_cfg = 0;
438 }
439
440 /**
441 *****************************************************************************************
442 * @brief Check ANS Control Point is supported or not.
443 *
444 * @param[in] p_ctrl_pt: Pointer to control pointer.
445 *
446 * @return True or False
447 *****************************************************************************************
448 */
ans_ctrl_pt_sup_check(ans_ctrl_pt_t * p_ctrl_pt)449 static bool ans_ctrl_pt_sup_check(ans_ctrl_pt_t *p_ctrl_pt)
450 {
451 if (ANS_CTRL_PT_NTF_UNREAD_CAT_STA_IMME < p_ctrl_pt->cmd_id) {
452 return false;
453 }
454
455 if (ANS_CAT_ID_INSTANT_MES < p_ctrl_pt->cat_id && ANS_CAT_ID_ALL != p_ctrl_pt->cat_id) {
456 return false;
457 }
458
459 if ((ANS_CTRL_PT_EN_NEW_INC_ALERT_NTF == p_ctrl_pt->cmd_id) && \
460 (ANS_CTRL_PT_DIS_NEW_INC_ALERT_NTF == p_ctrl_pt->cmd_id) && \
461 (ANS_CTRL_PT_NTF_NEW_INC_ALERT_IMME == p_ctrl_pt->cmd_id)) {
462 if (ANS_CAT_ID_ALL == p_ctrl_pt->cat_id) {
463 if (s_ans_env.ans_init.sup_new_alert_cat == 0) {
464 return false;
465 }
466 } else if (!(s_ans_env.ans_init.sup_new_alert_cat & (1 << p_ctrl_pt->cat_id))) {
467 return false;
468 }
469 } else {
470 if (p_ctrl_pt->cat_id == ANS_CAT_ID_ALL) {
471 if (s_ans_env.ans_init.sup_new_alert_cat == 0) {
472 return false;
473 }
474 } else if (!(s_ans_env.ans_init.sup_unread_alert_sta & (1 << p_ctrl_pt->cat_id))) {
475 return false;
476 }
477 }
478
479 return true;
480 }
481
482 /**
483 *****************************************************************************************
484 * @brief ANS Control Point handler.
485 *
486 * @param[in] conn_idx: Connection index.
487 * @param[in] p_ctrl_pt: Pointer to control pointer.
488 *****************************************************************************************
489 */
ans_ctrl_pt_handler(uint8_t conn_idx,ans_ctrl_pt_t * p_ctrl_pt)490 static void ans_ctrl_pt_handler(uint8_t conn_idx, ans_ctrl_pt_t *p_ctrl_pt)
491 {
492 ans_evt_t event;
493 event.evt_type = ANS_EVT_INVALID;
494 event.conn_idx = conn_idx;
495
496 switch (p_ctrl_pt->cmd_id) {
497 case ANS_CTRL_PT_EN_NEW_INC_ALERT_NTF:
498 if (ANS_CAT_ID_ALL == p_ctrl_pt->cat_id) {
499 s_ans_env.ntf_new_alert_cfg |= s_ans_env.ans_init.sup_new_alert_cat;
500 } else {
501 s_ans_env.ntf_new_alert_cfg |= 1 << p_ctrl_pt->cat_id;
502 }
503
504 break;
505
506 case ANS_CTRL_PT_EN_UNREAD_CAT_STA_NTF:
507 if (ANS_CAT_ID_ALL == p_ctrl_pt->cat_id) {
508 s_ans_env.ntf_unread_alert_cfg |= s_ans_env.ans_init.sup_new_alert_cat;
509 } else {
510 s_ans_env.ntf_unread_alert_cfg |= 1 << p_ctrl_pt->cat_id;
511 }
512
513 break;
514
515 case ANS_CTRL_PT_DIS_NEW_INC_ALERT_NTF:
516 if (ANS_CAT_ID_ALL == p_ctrl_pt->cat_id) {
517 s_ans_env.ntf_new_alert_cfg &= ~s_ans_env.ans_init.sup_new_alert_cat;
518 } else {
519 s_ans_env.ntf_new_alert_cfg &= ~(1 << p_ctrl_pt->cat_id);
520 }
521
522 break;
523
524 case ANS_CTRL_PT_DIS_UNREAD_CAT_STA_NTF:
525 if (ANS_CAT_ID_ALL == p_ctrl_pt->cat_id) {
526 s_ans_env.ntf_unread_alert_cfg &= ~s_ans_env.ans_init.sup_unread_alert_sta;
527 } else {
528 s_ans_env.ntf_unread_alert_cfg &= ~(1 << p_ctrl_pt->cat_id);
529 }
530
531 break;
532
533 case ANS_CTRL_PT_NTF_NEW_INC_ALERT_IMME:
534 if (ANS_CAT_ID_ALL == p_ctrl_pt->cat_id) {
535 event.cat_ids = s_ans_env.ntf_new_alert_cfg;
536 } else {
537 event.cat_ids = 1 << p_ctrl_pt->cat_id;
538 }
539
540 event.evt_type = ANS_EVT_NEW_ALERT_IMME_NTF_REQ;
541 break;
542
543 case ANS_CTRL_PT_NTF_UNREAD_CAT_STA_IMME:
544 if (ANS_CAT_ID_ALL == p_ctrl_pt->cat_id) {
545 event.cat_ids = s_ans_env.ntf_unread_alert_cfg;
546 } else {
547 event.cat_ids = 1 << p_ctrl_pt->cat_id;
548 }
549
550 event.evt_type = ANS_EVT_Unread_ALERT_IMME_NTF_REQ;
551 break;
552
553 default:
554 break;
555 }
556
557 if (ANS_EVT_INVALID != event.evt_type && s_ans_env.ans_init.evt_handler) {
558 s_ans_env.ans_init.evt_handler(&event);
559 }
560 }
561
562 /**
563 *****************************************************************************************
564 * @brief Encode a New Alert.
565 *
566 * @param[in] p_new_alert: Pointer to New Alert value to be encoded.
567 * @param[out] p_encoded_data: Pointer to encoded buffer will be written.
568 *
569 * @return Length of encoded.
570 *****************************************************************************************
571 */
ans_new_alert_encode(ans_new_alert_t * p_new_alert,uint8_t * p_buff)572 static uint16_t ans_new_alert_encode(ans_new_alert_t *p_new_alert, uint8_t *p_buff)
573 {
574 uint16_t length = 0;
575 uint16_t ret;
576
577 p_buff[length++] = p_new_alert->cat_id;
578 p_buff[length++] = p_new_alert->alert_num;
579
580 if (0 < p_new_alert->length) {
581 ret = memcpy_s(&p_buff[length], p_new_alert->length, p_new_alert->str_info, p_new_alert->length);
582 if (ret < 0) {
583 return ret;
584 }
585 }
586
587 return (length + p_new_alert->length);
588 }
589
590 /*
591 * GLOBAL FUNCTION DEFINITIONS
592 *****************************************************************************************
593 */
ans_new_alert_send(uint8_t conn_idx,ans_new_alert_t * p_new_alert)594 sdk_err_t ans_new_alert_send(uint8_t conn_idx, ans_new_alert_t *p_new_alert)
595 {
596 uint8_t encoded_new_alert[ANS_NEWS_ALERT_VAL_LEN];
597 gatts_noti_ind_t new_alert_ntf;
598 uint16_t length;
599
600 length = ans_new_alert_encode(p_new_alert, encoded_new_alert);
601 if (ANS_UTF_8_STR_LEN_MAX < p_new_alert->length) {
602 return SDK_ERR_INVALID_PARAM;
603 }
604
605 if (ANS_CAT_ID_INSTANT_MES < p_new_alert->cat_id) {
606 return SDK_ERR_INVALID_PARAM;
607 }
608
609 if (!(s_ans_env.ans_init.sup_new_alert_cat & (1 << p_new_alert->cat_id))) {
610 return SDK_ERR_INVALID_PARAM;
611 }
612
613 if (PRF_CLI_START_NTF != s_ans_env.new_alert_ntf_cfg[conn_idx]) {
614 return SDK_ERR_NTF_DISABLED;
615 }
616
617 if (!(s_ans_env.ntf_new_alert_cfg & (1 << p_new_alert->cat_id))) {
618 return SDK_ERR_NTF_DISABLED;
619 }
620
621 new_alert_ntf.type = BLE_GATT_NOTIFICATION;
622 new_alert_ntf.handle = prf_find_handle_by_idx(ANS_IDX_NEWS_ALERT_VAL,
623 s_ans_env.start_hdl,
624 (uint8_t *)&s_ans_char_mask);
625 new_alert_ntf.length = length;
626 new_alert_ntf.value = encoded_new_alert;
627
628 return ble_gatts_noti_ind(conn_idx, &new_alert_ntf);
629 }
630
ans_unread_alert_send(uint8_t conn_idx,ans_unread_alert_t * p_unread_alert)631 sdk_err_t ans_unread_alert_send(uint8_t conn_idx, ans_unread_alert_t *p_unread_alert)
632 {
633 uint8_t encoded_unread_alert[ANS_UNREAD_ALERT_STA_VAL_LEN];
634 gatts_noti_ind_t unread_alert_ntf;
635
636 encoded_unread_alert[0] = p_unread_alert->cat_id;
637 encoded_unread_alert[1] = p_unread_alert->unread_num;
638
639 if (ANS_CAT_ID_INSTANT_MES < p_unread_alert->cat_id) {
640 return SDK_ERR_INVALID_PARAM;
641 }
642
643 if (!(s_ans_env.ans_init.sup_unread_alert_sta & (1 << p_unread_alert->cat_id))) {
644 return SDK_ERR_INVALID_PARAM;
645 }
646
647 if (PRF_CLI_START_NTF != s_ans_env.unread_alert_sta_ntf_cfg[conn_idx]) {
648 return SDK_ERR_NTF_DISABLED;
649 }
650
651 if (!(s_ans_env.ntf_unread_alert_cfg & (1 << p_unread_alert->cat_id))) {
652 return SDK_ERR_NTF_DISABLED;
653 }
654
655 unread_alert_ntf.type = BLE_GATT_NOTIFICATION;
656 unread_alert_ntf.handle = prf_find_handle_by_idx(ANS_IDX_UNREAD_ALERT_STA_VAL,
657 s_ans_env.start_hdl,
658 (uint8_t *)&s_ans_char_mask);
659 unread_alert_ntf.length = ANS_UNREAD_ALERT_STA_VAL_LEN;
660 unread_alert_ntf.value = encoded_unread_alert;
661
662 return ble_gatts_noti_ind(conn_idx, &unread_alert_ntf);
663 }
664
ans_service_init(ans_init_t * p_ans_init)665 sdk_err_t ans_service_init(ans_init_t *p_ans_init)
666 {
667 sdk_err_t ret;
668 if (p_ans_init == NULL) {
669 return SDK_ERR_POINTER_NULL;
670 }
671
672 ret = memcpy_s(&s_ans_env.ans_init, sizeof(ans_init_t), p_ans_init, sizeof(ans_init_t));
673 if (ret < 0) {
674 return ret;
675 }
676
677 return ble_server_prf_add(&ans_prf_info);
678 }
679
680