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