• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  ****************************************************************************************
3  *
4  * @file pass.c
5  *
6  * @brief Phone Alert Status 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 "pass.h"
43 #include "ble_prf_types.h"
44 #include "ble_prf_utils.h"
45 #include "utility.h"
46 
47 /*
48  * ENUMERATIONS
49  ****************************************************************************************
50  */
51 /**@brief Phone Alert Status Service Attributes Indexes. */
52 enum {
53     // Phone Alert Status Service
54     PASS_IDX_SVC,
55 
56     // Alert Status
57     PASS_IDX_ALERT_STATUS_CHAR,
58     PASS_IDX_ALERT_STATUS_VAL,
59     PASS_IDX_ALERT_STATUS_NTF_CFG,
60 
61     // Ringer Setting
62     PASS_IDX_RINGER_SET_CHAR,
63     PASS_IDX_RINGER_SET_VAL,
64     PASS_IDX_RINGER_SET_NTF_CFG,
65 
66     // Ringer Control Point
67     PASS_IDX_RINGER_CTRL_PT_CHAR,
68     PASS_IDX_RINGER_CTRL_PT_VAL,
69 
70     PASS_IDX_NB
71 };
72 
73 /*
74  * STRUCTURES
75  *****************************************************************************************
76  */
77 /**@brief Phone Alert Status Service environment variable. */
78 struct pass_env_t {
79     pass_init_t  pass_init;    /**< Phone Alert Status Service initialization variables. */
80     uint16_t     start_hdl;    /**< Phone Alert Status Service start handle. */
81     uint16_t
82     alert_status_ntf_cfg[PASS_CONNECTION_MAX];     /**< The configuration of Alert Status Notification
83                                                         which is configured by the peer devices. */
84     uint16_t
85     ringer_setting_ntf_cfg[PASS_CONNECTION_MAX];   /**< The configuration of Ringer Setting Notification
86                                                         which is configured by the peer devices. */
87 };
88 
89 /*
90  * LOCAL FUNCTION DECLARATION
91  *****************************************************************************************
92  */
93 static sdk_err_t   pass_init(void);
94 static void        pass_read_att_cb(uint8_t  conn_idx, const gatts_read_req_cb_t  *p_param);
95 static void        pass_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
96 static void        pass_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value);
97 
98 
99 /*
100  * LOCAL VARIABLE DEFINITIONS
101  *****************************************************************************************
102  */
103 static struct pass_env_t s_pass_env;
104 
105 /**@brief Full PASS Database Description - Used to add attributes into the database. */
106 static const attm_desc_t pass_attr_tab[PASS_IDX_NB] = {
107     // Phone Alert Status Service Declaration
108     [PASS_IDX_SVC]              = {BLE_ATT_DECL_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
109 
110     // Alert Status Characteristic - Declaration
111     [PASS_IDX_ALERT_STATUS_CHAR]    = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
112     // Alert Status Characteristic - Value
113     [PASS_IDX_ALERT_STATUS_VAL]     = {
114         BLE_ATT_CHAR_ALERT_STATUS,
115         NOTIFY_PERM_UNSEC | READ_PERM_UNSEC,
116         ATT_VAL_LOC_USER,
117         PASS_ALERT_STATUS_VAL_LEN
118     },
119     // Alert Status Characteristic - Client Characteristic Configuration Descriptor
120     [PASS_IDX_ALERT_STATUS_NTF_CFG] = {BLE_ATT_DESC_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0},
121 
122     // Ringer Setting Characteristic - Declaration
123     [PASS_IDX_RINGER_SET_CHAR]    = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
124     // Ringer Setting Characteristic - Value
125     [PASS_IDX_RINGER_SET_VAL]     = {
126         BLE_ATT_CHAR_RINGER_SETTING,
127         NOTIFY_PERM_UNSEC | READ_PERM_UNSEC,
128         ATT_VAL_LOC_USER,
129         PASS_RINGER_SET_VAL_LEN
130     },
131     // Ringer Setting Characteristic - Client Characteristic Configuration Descriptor
132     [PASS_IDX_RINGER_SET_NTF_CFG] = {BLE_ATT_DESC_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0},
133 
134     // Ringer Setting Characteristic - Declaration
135     [PASS_IDX_RINGER_CTRL_PT_CHAR]  = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
136     // Ringer Setting Characteristic - Value
137     [PASS_IDX_RINGER_CTRL_PT_VAL]   = {
138         BLE_ATT_CHAR_RINGER_CNTL_POINT,
139         WRITE_CMD_PERM_UNSEC,
140         ATT_VAL_LOC_USER,
141         PASS_RINGER_CTRL_PT_VAL_LEN
142     },
143 };
144 
145 /**@brief PASS Task interface required by profile manager. */
146 static ble_prf_manager_cbs_t pass_task_cbs = {
147     (prf_init_func_t) pass_init,
148     NULL,
149     NULL,
150 };
151 
152 /**@brief PASS Task Callbacks. */
153 static gatts_prf_cbs_t pass_cb_func = {
154     pass_read_att_cb,
155     pass_write_att_cb,
156     NULL,
157     NULL,
158     pass_cccd_set_cb
159 };
160 
161 /**@brief PASS Information. */
162 static const prf_server_info_t pass_prf_info = {
163     .max_connection_nb = PASS_CONNECTION_MAX,
164     .manager_cbs       = &pass_task_cbs,
165     .gatts_prf_cbs     = &pass_cb_func,
166 };
167 
168 /*
169  * LOCAL FUNCTION DEFINITIONS
170  *****************************************************************************************
171  */
172 /**
173  *****************************************************************************************
174  * @brief Initialize Phone Alert Status Service and create db in att
175  *
176  * @return Error code to know if profile initialization succeed or not.
177  *****************************************************************************************
178  */
pass_init(void)179 static sdk_err_t pass_init(void)
180 {
181     // The start hanlde must be set with PRF_INVALID_HANDLE to be allocated automatically by BLE Stack.
182     uint16_t          start_hdl       = PRF_INVALID_HANDLE;
183     const uint8_t     pass_svc_uuid[] = BLE_ATT_16_TO_16_ARRAY(BLE_ATT_SVC_PHONE_ALERT_STATUS);
184     sdk_err_t         error_code;
185     gatts_create_db_t gatts_db;
186 
187     error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
188     if (error_code < 0) {
189         return error_code;
190     }
191 
192     gatts_db.shdl                 = &start_hdl;
193     gatts_db.uuid                 = pass_svc_uuid;
194     gatts_db.attr_tab_cfg         = (uint8_t *) & (s_pass_env.pass_init.char_mask);
195     gatts_db.max_nb_attr          = PASS_IDX_NB;
196     gatts_db.srvc_perm            = 0;
197     gatts_db.attr_tab_type        = SERVICE_TABLE_TYPE_16;
198     gatts_db.attr_tab.attr_tab_16 = pass_attr_tab;
199 
200     error_code = ble_gatts_srvc_db_create(&gatts_db);
201     if (SDK_SUCCESS == error_code) {
202         s_pass_env.start_hdl = *gatts_db.shdl;
203     }
204 
205     return error_code;
206 }
207 
208 /**
209  *****************************************************************************************
210  * @brief Handles reception of the attribute info request message.
211  *
212  * @param[in] conn_idx: Connection index
213  * @param[in] p_param:  The parameters of the read request.
214  *****************************************************************************************
215  */
pass_read_att_cb(uint8_t conn_idx,const gatts_read_req_cb_t * p_param)216 static void   pass_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
217 {
218     gatts_read_cfm_t  cfm;
219     uint8_t           handle    = p_param->handle;
220     uint8_t           tab_index = prf_find_idx_by_handle(handle,
221                                                          s_pass_env.start_hdl,
222                                                          PASS_IDX_NB,
223                                                          (uint8_t *)&s_pass_env.pass_init.char_mask);
224     cfm.handle = handle;
225     cfm.status = BLE_SUCCESS;
226 
227     switch (tab_index) {
228         case PASS_IDX_ALERT_STATUS_VAL:
229             cfm.length = PASS_ALERT_STATUS_VAL_LEN;
230             cfm.value  = &s_pass_env.pass_init.alert_status;
231             break;
232 
233         case PASS_IDX_ALERT_STATUS_NTF_CFG:
234             cfm.length = sizeof(uint16_t);
235             cfm.value  = (uint8_t *)&s_pass_env.alert_status_ntf_cfg[conn_idx];
236             break;
237 
238         case PASS_IDX_RINGER_SET_VAL:
239             cfm.length = PASS_RINGER_SET_VAL_LEN;
240             cfm.value  = &s_pass_env.pass_init.ringer_setting;
241             break;
242 
243         case PASS_IDX_RINGER_SET_NTF_CFG:
244             cfm.length = sizeof(uint16_t);
245             cfm.value  = (uint8_t *)&s_pass_env.ringer_setting_ntf_cfg[conn_idx];
246             break;
247 
248         default:
249             cfm.length = 0;
250             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
251             break;
252     }
253 
254     ble_gatts_read_cfm(conn_idx, &cfm);
255 }
256 
257 /**
258  *****************************************************************************************
259  * @brief Handles reception of the write request.
260  *
261  * @param[in]: conn_idx: Connection index
262  * @param[in]: p_param:  The parameters of the write request.
263  *****************************************************************************************
264  */
pass_write_att_cb(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)265 static void   pass_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
266 {
267     uint16_t          handle      = p_param->handle;
268     uint16_t          tab_index   = 0;
269     uint16_t          cccd_value  = 0;
270     pass_evt_t        event;
271     gatts_write_cfm_t cfm;
272 
273     tab_index  = prf_find_idx_by_handle(handle,
274                                         s_pass_env.start_hdl,
275                                         PASS_IDX_NB,
276                                         (uint8_t *)&s_pass_env.pass_init.char_mask);
277     cfm.handle     = handle;
278     cfm.status     = BLE_SUCCESS;
279     event.evt_type = PASS_EVT_INVALID;
280     event.conn_idx = conn_idx;
281 
282     switch (tab_index) {
283         case PASS_IDX_ALERT_STATUS_NTF_CFG:
284             cccd_value     = le16toh(&p_param->value[0]);
285             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
286                               PASS_EVT_ALERT_STATUS_NTF_ENABLE : \
287                               PASS_EVT_ALERT_STATUS_NTF_DISABLE);
288             s_pass_env.alert_status_ntf_cfg[conn_idx] = cccd_value;
289             break;
290 
291         case PASS_IDX_RINGER_SET_NTF_CFG:
292             cccd_value     = le16toh(&p_param->value[0]);
293             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
294                               PASS_EVT_RINGER_SET_NTF_ENABLE : \
295                               PASS_EVT_RINGER_SET_NTF_DISABLE);
296             s_pass_env.ringer_setting_ntf_cfg[conn_idx] = cccd_value;
297             break;
298 
299         case PASS_IDX_RINGER_CTRL_PT_VAL: {
300             switch (p_param->value[0]) {
301                 case PASS_CTRL_PT_SILENT_MODE:
302                     if ((PASS_RINGER_SET_NORMAL == s_pass_env.pass_init.ringer_setting) && \
303                             (PASS_RINGER_ACTIVE & s_pass_env.pass_init.alert_status)) {
304                         event.evt_type = PASS_EVT_SILENT_MODE_SET;
305                     }
306                     break;
307 
308                 case PASS_CTRL_PT_MUTE_ONCE:
309                     event.evt_type = PASS_EVT_MUTE_ONCE_SET;
310                     break;
311 
312                 case PASS_CTRL_PT_CANCEL_SLIENT_MODE:
313                     if ((PASS_RINGER_SET_SILENT == s_pass_env.pass_init.ringer_setting) && \
314                             (PASS_RINGER_ACTIVE & s_pass_env.pass_init.alert_status)) {
315                         event.evt_type = PASS_EVT_SILENT_MODE_CANCEL;
316                     }
317                     break;
318 
319                 default:
320                     break;
321             }
322         }
323             break;
324 
325         default:
326             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
327             break;
328     }
329 
330     ble_gatts_write_cfm(conn_idx, &cfm);
331 
332     if (BLE_ATT_ERR_INVALID_HANDLE != cfm.status && PASS_EVT_INVALID != event.evt_type
333             && s_pass_env.pass_init.evt_handler) {
334         s_pass_env.pass_init.evt_handler(&event);
335     }
336 }
337 
338 /**
339  *****************************************************************************************
340  * @brief Handles reception of the cccd recover request.
341  *
342  * @param[in]: conn_idx:   Connection index
343  * @param[in]: handle:     The handle of cccd attribute.
344  * @param[in]: cccd_value: The value of cccd attribute.
345  *****************************************************************************************
346  */
pass_cccd_set_cb(uint8_t conn_idx,uint16_t handle,uint16_t cccd_value)347 static void pass_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value)
348 {
349     uint16_t          tab_index   = 0;
350     pass_evt_t        event;
351 
352     if (!prf_is_cccd_value_valid(cccd_value)) {
353         return;
354     }
355 
356     tab_index  = prf_find_idx_by_handle(handle,
357                                         s_pass_env.start_hdl,
358                                         PASS_IDX_NB,
359                                         (uint8_t *)&s_pass_env.pass_init.char_mask);
360 
361     event.evt_type = PASS_EVT_INVALID;
362     event.conn_idx = conn_idx;
363 
364     switch (tab_index) {
365         case PASS_IDX_ALERT_STATUS_NTF_CFG:
366             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
367                               PASS_EVT_ALERT_STATUS_NTF_ENABLE : \
368                               PASS_EVT_ALERT_STATUS_NTF_DISABLE);
369             s_pass_env.alert_status_ntf_cfg[conn_idx] = cccd_value;
370             break;
371 
372         case PASS_IDX_RINGER_SET_NTF_CFG:
373             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
374                               PASS_EVT_RINGER_SET_NTF_ENABLE : \
375                               PASS_EVT_RINGER_SET_NTF_DISABLE);
376             s_pass_env.ringer_setting_ntf_cfg[conn_idx] = cccd_value;
377             break;
378 
379         default:
380             break;
381     }
382 
383     if (PASS_EVT_INVALID != event.evt_type && s_pass_env.pass_init.evt_handler) {
384         s_pass_env.pass_init.evt_handler(&event);
385     }
386 }
387 
388 /**
389  *****************************************************************************************
390  * @brief Notify Alert Status.
391 
392  * @param[in] conn_idx: Connnection index.
393  *****************************************************************************************
394  */
pass_alert_status_send(uint8_t conn_idx)395 static sdk_err_t pass_alert_status_send(uint8_t conn_idx)
396 {
397     sdk_err_t        error_code = SDK_ERR_NTF_DISABLED;
398     gatts_noti_ind_t alert_status_ntf;
399 
400     if (PRF_CLI_START_NTF == s_pass_env.alert_status_ntf_cfg[conn_idx]) {
401         alert_status_ntf.type   = BLE_GATT_NOTIFICATION;
402         alert_status_ntf.handle = prf_find_handle_by_idx(PASS_IDX_ALERT_STATUS_VAL,
403                                                          s_pass_env.start_hdl,
404                                                          (uint8_t *)&s_pass_env.pass_init.char_mask);
405         alert_status_ntf.length = PASS_ALERT_STATUS_VAL_LEN;
406         alert_status_ntf.value  = &s_pass_env.pass_init.alert_status;
407         error_code              = ble_gatts_noti_ind(conn_idx, &alert_status_ntf);
408     }
409 
410     return error_code;
411 }
412 
413 /**
414  *****************************************************************************************
415  * @brief Notify Ringer Setting.
416  *
417  * @param[in] conn_idx: Connnection index.
418  *****************************************************************************************
419  */
pass_ringer_set_send(uint8_t conn_idx)420 sdk_err_t pass_ringer_set_send(uint8_t conn_idx)
421 {
422     sdk_err_t        error_code = SDK_ERR_NTF_DISABLED;
423     gatts_noti_ind_t ringer_set_ntf;
424 
425     if (PRF_CLI_START_NTF == s_pass_env.ringer_setting_ntf_cfg[conn_idx]) {
426         ringer_set_ntf.type   = BLE_GATT_NOTIFICATION;
427         ringer_set_ntf.handle = prf_find_handle_by_idx(PASS_IDX_RINGER_SET_VAL,
428                                                        s_pass_env.start_hdl,
429                                                        (uint8_t *)&s_pass_env.pass_init.char_mask);
430         ringer_set_ntf.length = PASS_ALERT_STATUS_VAL_LEN;
431         ringer_set_ntf.value  = &s_pass_env.pass_init.ringer_setting;
432         error_code            = ble_gatts_noti_ind(conn_idx, &ringer_set_ntf);
433     }
434 
435     return error_code;
436 }
437 
438 /*
439  * GLOBAL FUNCTION DEFINITIONS
440  *****************************************************************************************
441  */
pass_ringer_setting_get(void)442 uint8_t pass_ringer_setting_get(void)
443 {
444     return s_pass_env.pass_init.ringer_setting;
445 }
446 
pass_alert_status_set(uint8_t conn_idx,uint8_t new_status)447 void pass_alert_status_set(uint8_t conn_idx, uint8_t new_status)
448 {
449     if (new_status != s_pass_env.pass_init.alert_status) {
450         s_pass_env.pass_init.alert_status = new_status;
451         pass_alert_status_send(conn_idx);
452     }
453 }
454 
pass_ringer_setting_set(uint8_t conn_idx,uint8_t new_setting)455 void pass_ringer_setting_set(uint8_t conn_idx, uint8_t new_setting)
456 {
457     if (new_setting != s_pass_env.pass_init.ringer_setting) {
458         s_pass_env.pass_init.ringer_setting = new_setting;
459         pass_ringer_set_send(conn_idx);
460     }
461 }
462 
pass_service_init(pass_init_t * p_pass_init)463 sdk_err_t pass_service_init(pass_init_t *p_pass_init)
464 {
465     sdk_err_t ret;
466     if (p_pass_init == NULL) {
467         return SDK_ERR_POINTER_NULL;
468     }
469 
470     ret = memcpy_s(&s_pass_env.pass_init, sizeof(pass_init_t), p_pass_init, sizeof(pass_init_t));
471     if (ret < 0) {
472         return ret;
473     }
474 
475     return ble_server_prf_add(&pass_prf_info);
476 }
477 
478