• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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