• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  *****************************************************************************************
3  *
4  * @file bas.c
5  *
6  * @brief Link Loss Server 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 "lls.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 LLS Attributes database index list. */
52 enum lls_attr_idx_t {
53     LLS_IDX_SVC,
54 
55     LLS_IDX_ALERT_LVL_CHAR,
56     LLS_IDX_ALERT_LVL_VAL,
57 
58     LLS_IDX_NB,
59 };
60 
61 /*
62  * STRUCTURES
63  *****************************************************************************************
64  */
65 /**@brief Link Loss Service environment variable. */
66 struct lls_env_t {
67     lls_init_t lls_init;         /**< Link Loss Service initialization variables. */
68     uint16_t   start_hdl;        /**< Link Loss Service start handle. */
69 };
70 
71 /*
72  * LOCAL VARIABLE DEFINITIONS
73  *****************************************************************************************
74  */
75 /** Pointer to Link Loss Service environment variable. */
76 static struct lls_env_t s_lls_env;            /**< Link Loss Service instance. */
77 static uint8_t          s_char_mask = 0x07;   /**< Features added into ATT database.
78                                                * bit0 - Link Loss Service Declaration
79                                                * bit1 - Alert Level Characteristic Declaration
80                                                * bit2 - Alert Level Characteristic Value
81                                                */
82 
83 /**@brief Full LLS Database Description - Used to add attributes into the
84  *        database.
85  */
86 static const attm_desc_t lls_attr_tab[LLS_IDX_NB] = {
87     // Link Loss Service Declaration
88     [LLS_IDX_SVC]            = {BLE_ATT_DECL_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
89     // Alert Level Characteristic Declaration
90     [LLS_IDX_ALERT_LVL_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC,  READ_PERM_UNSEC, 0, 0},
91     // Alert Level Characteristic Value
92     [LLS_IDX_ALERT_LVL_VAL]  = {BLE_ATT_CHAR_ALERT_LEVEL,
93                                 READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, sizeof(uint8_t)},
94 };
95 
96 /*
97  * LOCAL FUNCTION DECLARATIONS
98  *******************************************************************************
99  */
100 static sdk_err_t   lls_init(void);
101 static void        lls_on_connect(uint8_t conn_idx);
102 static void        lls_on_disconnect(uint8_t conn_idx, uint8_t reason);
103 static void        lls_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
104 
105 /**@brief LLS interface required by profile manager. */
106 static ble_prf_manager_cbs_t lls_mgr_cbs = {
107     (prf_init_func_t)lls_init,
108     lls_on_connect,
109     lls_on_disconnect
110 };
111 
112 /**@brief LLS GATT server callbacks. */
113 static gatts_prf_cbs_t lls_gatts_cbs = {
114     NULL,
115     lls_write_att_cb,
116     NULL,
117     NULL
118 };
119 
120 /**@brief LLS Information. */
121 static const prf_server_info_t lls_prf_info = {
122     /* There shall be only one connection on a device. */
123     .max_connection_nb = 1,
124     .manager_cbs       = &lls_mgr_cbs,
125     .gatts_prf_cbs     = &lls_gatts_cbs
126 };
127 
128 /**
129  *****************************************************************************************
130  * @brief Initialize Link Loss service and create database in BLE Stack.
131  *
132  * @return BLE_ATT_ERR_NO_ERROR on success, otherwise error code.
133  *****************************************************************************************
134  */
lls_init(void)135 static sdk_err_t lls_init(void)
136 {
137     const uint8_t lls_svc_uuid[] = BLE_ATT_16_TO_16_ARRAY(BLE_ATT_SVC_LINK_LOSS);
138     gatts_create_db_t gatts_db;
139     sdk_err_t ret;
140     uint16_t start_hdl = PRF_INVALID_HANDLE; /* The start hanlde is an in/out
141                                               * parameter of ble_gatts_srvc_db_create().
142                                               * It must be set with PRF_INVALID_HANDLE
143                                               * to be allocated automatically by BLE Stack. */
144 
145     ret = memset_S(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
146     if (ret < 0) {
147         return ret;
148     }
149 
150     gatts_db.shdl                 = &start_hdl;
151     gatts_db.uuid                 = (uint8_t *)lls_svc_uuid;
152     gatts_db.attr_tab_cfg         = &s_char_mask;
153     gatts_db.max_nb_attr          = LLS_IDX_NB;
154     gatts_db.srvc_perm            = 0;
155     gatts_db.attr_tab_type        = SERVICE_TABLE_TYPE_16;
156     gatts_db.attr_tab.attr_tab_16 = lls_attr_tab;
157 
158     sdk_err_t   error_code = ble_gatts_srvc_db_create(&gatts_db);
159     if (SDK_SUCCESS == error_code) {
160         s_lls_env.start_hdl = *gatts_db.shdl;
161 
162         uint16_t handle = prf_find_handle_by_idx(LLS_IDX_ALERT_LVL_VAL,  s_lls_env.start_hdl, &s_char_mask);
163         ble_gatts_value_set(handle, sizeof(uint8_t), 0, (unsigned char *)(&s_lls_env.lls_init.initial_alert_level));
164     }
165 
166     return error_code;
167 }
168 
169 /**
170  *****************************************************************************************
171  * @brief Handle the connect event.
172  *
173  * @param[in] conn_idx: Connection index.
174  *****************************************************************************************
175  */
lls_on_connect(uint8_t conn_idx)176 static void lls_on_connect(uint8_t conn_idx)
177 {
178     lls_evt_t   evt;
179     sdk_err_t   ret;
180 
181     if (s_lls_env.lls_init.evt_handler) {
182         evt.evt_type = LLS_EVT_LINK_LOSS_ALERT;
183 
184         ret = lls_alert_level_get((unsigned char *)(&evt.alert_level));
185         if (SDK_SUCCESS == ret && s_lls_env.lls_init.evt_handler) {
186             /* Inform Application the link is (re)connected */
187             s_lls_env.lls_init.evt_handler(&evt);
188         }
189     }
190 }
191 
192 /**
193  *****************************************************************************************
194  * @brief Handle the disconnect event.
195  *
196  * @param[in] conn_idx:Connect index.
197  * @param[in] reason:  The reason of disconnect.
198  *****************************************************************************************
199  */
lls_on_disconnect(uint8_t conn_idx,uint8_t reason)200 static void lls_on_disconnect(uint8_t conn_idx, uint8_t reason)
201 {
202     /* The reason is HCI Connection Timeout */
203     if (BLE_LL_ERR_CON_TIMEOUT == reason || BLE_LL_ERR_INSTANT_PASSED == reason) {
204         /* Link loss detected, inform application */
205         lls_evt_t evt;
206         sdk_err_t ret;
207 
208         evt.evt_type = LLS_EVT_LINK_LOSS_ALERT;
209 
210         ret = lls_alert_level_get((unsigned char *)(&evt.alert_level));
211         if (SDK_SUCCESS == ret) {
212             if (s_lls_env.lls_init.evt_handler) {
213                 s_lls_env.lls_init.evt_handler(&evt);
214             }
215         }
216     }
217 
218     return;
219 }
220 
221 /**
222  *****************************************************************************************
223  * @brief Handles reception of the write request.
224  *
225  * @param[in] conn_idx: Connection index
226  * @param[in] p_param:  Pointer to the parameters of the write request.
227  *****************************************************************************************
228  */
lls_write_att_cb(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)229 static void   lls_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
230 {
231     uint16_t handle = prf_find_handle_by_idx(LLS_IDX_ALERT_LVL_VAL, s_lls_env.start_hdl, &s_char_mask);
232     gatts_write_cfm_t cfm;
233 
234     cfm.handle = p_param->handle;
235 
236     if (handle != p_param->handle) {
237         cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
238     } else {
239         if (p_param->length != sizeof(uint8_t)) {
240             cfm.status = SDK_ERR_INVALID_ATT_VAL_LEN;
241         } else {
242             // Send write response
243             uint8_t value = p_param->value[0];
244 
245             cfm.status = (uint8_t)ble_gatts_value_set(cfm.handle, sizeof(uint8_t), 0, &value);
246         }
247     }
248 
249     ble_gatts_write_cfm(conn_idx, &cfm);
250 }
251 
252 /*
253  * GLOBAL FUNCTION DEFINITIONS
254  *****************************************************************************************
255  */
lls_service_init(lls_init_t * p_lls_init)256 sdk_err_t lls_service_init(lls_init_t *p_lls_init)
257 {
258     if (p_lls_init == NULL) {
259         return SDK_ERR_POINTER_NULL;
260     }
261 
262     s_lls_env.lls_init.evt_handler = p_lls_init->evt_handler;
263 
264     return ble_server_prf_add(&lls_prf_info);
265 }
266 
lls_alert_level_get(uint8_t * p_alert_level)267 sdk_err_t   lls_alert_level_get(uint8_t *p_alert_level)
268 {
269     uint16_t handle = prf_find_handle_by_idx(LLS_IDX_ALERT_LVL_VAL, s_lls_env.start_hdl, (uint8_t *)&s_char_mask);
270     uint16_t length = sizeof(uint8_t);
271 
272     return ble_gatts_value_get(handle, &length, p_alert_level);
273 }
274 
275