1 /**
2 *******************************************************************************
3 *
4 * @file hrs.c
5 *
6 * @brief Heart Rate Profile Sensor 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 * INCLUDE FILES
39 *****************************************************************************************
40 */
41 #include "escs.h"
42 #include "ble_prf_types.h"
43 #include "ble_prf_utils.h"
44 #include "utility.h"
45
46 /*
47 * STRUCT DEFINE
48 *******************************************************************************
49 */
50 /**@brief EddyStone Configuration Service environment variable. */
51 typedef struct {
52 ble_escs_init_params_t escs_init; /**< EddyStone Configuration Service initialization variables. */
53 uint16_t start_hdl; /**< EddyStone Configuration Service start handle. */
54 } escs_env_t;
55
56 /*
57 * LOCAL FUNCTION DECLARATION
58 *****************************************************************************************
59 */
60 static sdk_err_t escs_init (void);
61 static sdk_err_t escs_write_att_cb (uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
62 static sdk_err_t escs_read_att_cb (uint8_t conn_idx, const gatts_read_req_cb_t *p_param);
63 static void escs_gatts_cmp_cb (uint8_t conn_idx, const gatt_op_cmp_evt_t *p_param);
64
65 /*
66 * LOCAL VARIABLE DEFINITIONS
67 *******************************************************************************
68 */
69 uint16_t my_escs_service_start_handle;
70
71 /**@brief ESCS Information. */
72 static escs_env_t s_escs_env;
73
74 static const attm_desc_128_t escs_att_db[ESCSS_IDX_NB] = {
75 [ESEC_IDX_SVC] = {ATT_128_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
76 [ESCS_BROADCAST_CAP_RD_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
77 [ESCS_BROADCAST_CAP_RD_VALUE] = {BLE_UUID_ESCS_BROADCAST_CAP_CHAR, READ_PERM_UNSEC,
78 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET (UUID_TYPE_128),
79 ESEC_CAP_DEFAULT_LEN + ESCS_NUM_OF_SUPPORTED_TX_POWER},
80 [ESCS_ACTIVE_SLOT_RW_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
81 [ESCS_ACTIVE_SLOT_RW_VALUE] = {BLE_UUID_ESCS_ACTIVE_SLOT_CHAR, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
82 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET (UUID_TYPE_128), 1},
83 [ESCS_ADV_INTERVAL_RW_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
84 [ESCS_ADV_INTERVAL_RW_VALUE] = {BLE_UUID_ESCS_ADV_INTERVAL_CHAR, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
85 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET (UUID_TYPE_128), 2},
86 [ESCS_RADIO_TX_PWR_RW_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
87 [ESCS_RADIO_TX_PWR_RW_VALUE] = {BLE_UUID_ESCS_RADIO_TX_PWR_CHAR, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
88 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET (UUID_TYPE_128), 1},
89 [ESCS_ADV_TX_PWR_RW_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
90 [ESCS_ADV_TX_PWR_RW_VALUE] = {BLE_UUID_ESCS_ADV_TX_PWR_CHAR, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
91 TT_VAL_LOC_USER | ATT_UUID_TYPE_SET (UUID_TYPE_128), 1},
92 [ESCS_LOCK_STATE_RW_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
93 [ESCS_LOCK_STATE_RW_VALUE] = {BLE_UUID_ESCS_LOCK_STATE_CHAR, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
94 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET (UUID_TYPE_128), ESCS_LOCK_CODE_WRITE_LENGTH},
95 [ESCS_UNLOCK_RW_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
96 [ESCS_UNLOCK_RW_VALUE] = {BLE_UUID_ESCS_UNLOCK_CHAR, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
97 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET (UUID_TYPE_128), ESCS_AES_KEY_SIZE},
98 [ESCS_PUBLIC_ECDH_KEY_RD_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
99 [ESCS_PUBLIC_ECDH_KEY_RD_VALUE] = {BLE_UUID_ESCS_PUBLIC_ECDH_KEY_CHAR, READ_PERM_UNSEC,
100 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET (UUID_TYPE_128), ESCS_ECDH_KEY_SIZE},
101 [ESCS_EID_ID_KEY_RD_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
102 [ESCS_EID_ID_KEY_RD_VALUE] = {BLE_UUID_ESCS_EID_ID_KEY_CHAR, READ_PERM_UNSEC,
103 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET (UUID_TYPE_128), ESCS_AES_KEY_SIZE},
104 [ESCS_RW_ADV_SLOT_RW_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
105 [ESCS_RW_ADV_SLOT_RW_VALUE] = {BLE_UUID_ESCS_RW_ADV_SLOT_CHAR, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
106 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET (UUID_TYPE_128),
107 ESCS_ADV_SLOT_CHAR_LENGTH_MAX},
108 [ESCS_FACTORY_RESET_SET_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
109 [ESCS_FACTORY_RESET_SET_VALUE] = {BLE_UUID_ESCS_FACTORY_RESET_CHAR, WRITE_REQ_PERM_UNSEC,
110 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET (UUID_TYPE_128), 1},
111 [ESCS_REMAIN_CONNECTABLE_RW_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
112 [ESCS_REMAIN_CONNECTABLE_RW_VALUE] = {BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR,
113 READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
114 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET (UUID_TYPE_128), 1},
115 };
116
117 /**@brief ESCS interface required by profile manager. */
118 static ble_prf_manager_cbs_t escs_tack_cbs = {
119 (prf_init_func_t) escs_init,
120 NULL,
121 NULL
122 };
123
124 /**@brief ESCS GATT server Callbacks. */
125 static gatts_prf_cbs_t escs_cb_func = {
126 escs_read_att_cb,
127 escs_write_att_cb,
128 NULL,
129 escs_gatts_cmp_cb,
130 };
131
132 /**@brief ESCS Information. */
133 static const prf_server_info_t escs_prf_info = {
134 .max_connection_nb = ESCS_CONNECTION_MAX,
135 .manager_cbs = &escs_tack_cbs,
136 .gatts_prf_cbs = &escs_cb_func
137 };
138
139 /*
140 * LOCAL FUNCTION DEFINITIONS
141 *****************************************************************************************
142 */
143 /**
144 *****************************************************************************************
145 * @brief Initialize Immediate Alert Service and create DB in ATT.
146 *
147 * @return Error code to know if service initialization succeed or not.
148 *****************************************************************************************
149 */
escs_init(void)150 static sdk_err_t escs_init (void)
151 {
152 const uint8_t escs_svc_uuid[] = {EDDYSTONE_CONFIGURATION_SERVICE_UUID};
153 sdk_err_t error_code = SDK_SUCCESS;
154 uint16_t start_hdl = 0;
155 gatts_create_db_t gatts_db;
156
157 uint32_t escs_char_mask = ESCS_DEFAULT_CHAR_MASK;
158
159 error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
160 if (error_code < 0) {
161 return error_code;
162 }
163 gatts_db.shdl = &start_hdl;
164 gatts_db.uuid = escs_svc_uuid;
165 gatts_db.attr_tab_cfg = (uint8_t *) (&escs_char_mask);
166 gatts_db.max_nb_attr = ESCSS_IDX_NB;
167 gatts_db.srvc_perm = SRVC_UUID_TYPE_SET (UUID_TYPE_128);
168 gatts_db.attr_tab_type = SERVICE_TABLE_TYPE_128;
169 gatts_db.attr_tab.attr_tab_128 = escs_att_db;
170
171 error_code = ble_gatts_srvc_db_create (&gatts_db);
172 ERROR_CODE_PRINT (error_code, BLE_SUCCESS);
173
174 if (SDK_SUCCESS == error_code) {
175 my_escs_service_start_handle = * (gatts_db.shdl);
176 }
177
178 return error_code;
179 }
180
181 /**
182 *****************************************************************************************
183 * @brief Handles reception of the attribute info request message.
184 *
185 * @param[in] conn_idx: Connection index
186 * @param[in] p_param: Pointer to the parameters of the read request.
187 *
188 * @retval ::BLE_SDK_SUCCESS Send write confirm status to stack successfully.
189 * @retval ::BLE_SDK_ERR_BAD_PARAM Conidx is invalid or param is NULL.
190 *
191 *****************************************************************************************
192 */
escs_read_att_cb(uint8_t conn_idx,const gatts_read_req_cb_t * p_param)193 static sdk_err_t escs_read_att_cb (uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
194 {
195 sdk_err_t error_code;
196 uint8_t handle = p_param->handle;
197 uint8_t tab_index = 0;
198 gatts_read_cfm_t cfm;
199 uint8_t att_data_array[ESEC_MAX_READ_LEN];
200 uint32_t escs_char_mask = ESCS_DEFAULT_CHAR_MASK;
201 tab_index = prf_find_idx_by_handle (handle,
202 my_escs_service_start_handle,
203 ESCSS_IDX_NB,
204 (uint8_t *) (&escs_char_mask));
205 cfm.handle = handle;
206 cfm.status = BLE_SUCCESS;
207 cfm.value = att_data_array;
208
209 escs_attribute_value_set (tab_index, &cfm, s_escs_env.escs_init.lock_state);
210
211 error_code = ble_gatts_read_cfm (conn_idx, &cfm);
212 RETURN_IF_ERROR (error_code, BLE_SUCCESS);
213
214 return error_code;
215 }
216
217 /**
218 *****************************************************************************************
219 * @brief Handles reception of the write request.
220 *
221 * @param[in] conn_idx: Connection index
222 * @param[in] p_param: Pointer to the parameters of the write request.
223 *
224 * @retval ::BLE_SDK_SUCCESS Send write confirm status to stack successfully.
225 * @retval ::BLE_SDK_ERR_BAD_PARAM Conidx is invalid or param is NULL.
226 *
227 *****************************************************************************************
228 */
escs_write_att_cb(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)229 static sdk_err_t escs_write_att_cb (uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
230 {
231 uint8_t handle = p_param->handle;
232 uint8_t tab_index = 0;
233 gatts_write_cfm_t cfm;
234 cfm.handle = handle;
235 cfm.status = BLE_SUCCESS;
236 uint32_t escs_char_mask = ESCS_DEFAULT_CHAR_MASK;
237
238 tab_index = prf_find_idx_by_handle (handle,
239 my_escs_service_start_handle,
240 ESCSS_IDX_NB,
241 (uint8_t *) (&escs_char_mask));
242
243 cfm.status = escs_attribute_value_get (tab_index, (gatts_write_req_cb_t*) p_param, s_escs_env.escs_init.lock_state);
244 return ble_gatts_write_cfm (conn_idx, &cfm);
245 }
246
247 /**
248 *****************************************************************************************
249 * @brief Handles reception of the complete event.
250 *
251 * @param[in] conn_idx: Connection index
252 * @param[in] p_param: Pointer to the parameters of the complete event.
253 *
254 *****************************************************************************************
255 */
escs_gatts_cmp_cb(uint8_t conn_idx,const gatt_op_cmp_evt_t * p_param)256 static void escs_gatts_cmp_cb (uint8_t conn_idx, const gatt_op_cmp_evt_t *p_param)
257 {
258 }
259
260 /*
261 * GLOBAL FUNCTION DEFINITIONS
262 *****************************************************************************************
263 */
esec_service_init(ble_escs_init_params_t * p_escs_init)264 void esec_service_init (ble_escs_init_params_t *p_escs_init)
265 {
266 sdk_err_t error_code;
267
268 error_code = memcpy_s(&s_escs_env.escs_init, sizeof(ble_escs_init_params_t),
269 p_escs_init, sizeof(ble_escs_init_params_t));
270 if (error_code < 0) {
271 return;
272 }
273
274 error_code = ble_server_prf_add (&escs_prf_info);
275 ERROR_CODE_PRINT (error_code, BLE_SUCCESS);
276 }
277
set_beacon_locked(void)278 void set_beacon_locked (void)
279 {
280 s_escs_env.escs_init.lock_state = ESCS_LOCK_STATE_LOCKED;
281 }
282
set_beacon_unlocked(void)283 void set_beacon_unlocked (void)
284 {
285 s_escs_env.escs_init.lock_state = ESCS_LOCK_STATE_UNLOCKED;
286 }
287
es_active_slot_number_get(void)288 uint8_t es_active_slot_number_get (void)
289 {
290 return s_escs_env.escs_init.active_slot_no;
291 }
292
es_active_slot_number_set(uint8_t slot_no)293 void es_active_slot_number_set (uint8_t slot_no)
294 {
295 s_escs_env.escs_init.active_slot_no = slot_no;
296 }
297
es_adv_interval_get(void)298 uint16_t es_adv_interval_get (void)
299 {
300 if (s_escs_env.escs_init.adv_interval > APP_CONFIG_ADV_INTERVAL_MS_MAX) {
301 s_escs_env.escs_init.adv_interval = APP_CONFIG_ADV_INTERVAL_MS_MAX;
302 } else if (s_escs_env.escs_init.adv_interval < APP_CONFIG_ADV_FRAME_SPACING_MS_MIN) {
303 s_escs_env.escs_init.adv_interval = APP_CONFIG_ADV_FRAME_SPACING_MS_MIN;
304 }
305
306 return s_escs_env.escs_init.adv_interval;
307 }
308
es_adv_interval_set(uint16_t adv_interval)309 void es_adv_interval_set (uint16_t adv_interval)
310 {
311 if (adv_interval > APP_CONFIG_ADV_INTERVAL_MS_MAX) {
312 s_escs_env.escs_init.adv_interval = APP_CONFIG_ADV_INTERVAL_MS_MAX;
313 } else if (adv_interval < APP_CONFIG_ADV_FRAME_SPACING_MS_MIN) {
314 s_escs_env.escs_init.adv_interval = APP_CONFIG_ADV_FRAME_SPACING_MS_MIN;
315 } else {
316 s_escs_env.escs_init.adv_interval = adv_interval;
317 }
318 }
319
es_slot_tx_power_get(void)320 int8_t es_slot_tx_power_get (void)
321 {
322 uint8_t slot_no;
323 slot_no = es_active_slot_number_get();
324 return s_escs_env.escs_init.slot_tx_power[slot_no];
325 }
326
es_slot_tx_power_set(int8_t tx_power)327 void es_slot_tx_power_set (int8_t tx_power)
328 {
329 uint8_t slot_no;
330 int8_t supported_tx[ESCS_NUM_OF_SUPPORTED_TX_POWER] = ESCS_SUPPORTED_TX_POWER;
331 int8_t tx_power_suitable_setting;
332 int8_t i;
333 uint32_t a, b;
334
335 slot_no = es_active_slot_number_get();
336 tx_power_suitable_setting = supported_tx[0];
337
338 if (strstr((const char*)supported_tx, (const char*)(&tx_power))) {
339 tx_power_suitable_setting = tx_power;
340 } else if (tx_power < supported_tx[0]) {
341 tx_power_suitable_setting = supported_tx[0];
342 } else if (tx_power > supported_tx[ESCS_NUM_OF_SUPPORTED_TX_POWER - 1]) {
343 tx_power_suitable_setting = supported_tx[ESCS_NUM_OF_SUPPORTED_TX_POWER - 1];
344 } else {
345 for (i = 0; i < (ESCS_NUM_OF_SUPPORTED_TX_POWER - 1); i++) {
346 if ((tx_power >= supported_tx[i]) && (tx_power <= supported_tx[i + 1])) {
347 a = ABS (tx_power - supported_tx[i]);
348 b = ABS (tx_power - supported_tx[i + 1]);
349 if (a > b) {
350 tx_power_suitable_setting = supported_tx[i + 1];
351 } else {
352 tx_power_suitable_setting = supported_tx[i];
353 }
354 break;
355 }
356 }
357 }
358
359 s_escs_env.escs_init.slot_tx_power[slot_no] = tx_power_suitable_setting;
360 }
361
es_adv_tx_power_get(void)362 int8_t es_adv_tx_power_get (void)
363 {
364 return s_escs_env.escs_init.adv_tx_power;
365 }
366
es_adv_tx_power_set(int8_t adv_tx_power)367 void es_adv_tx_power_set (int8_t adv_tx_power)
368 {
369 s_escs_env.escs_init.adv_tx_power = adv_tx_power;
370 }
371
es_security_key_set(uint8_t * p_security_key,bool is_eid_write)372 void es_security_key_set (uint8_t* p_security_key, bool is_eid_write)
373 {
374 uint8_t ret;
375 #if(APP_IS_EID_SUPPORTED)
376 if (is_eid_write) {
377 s_escs_env.escs_init.beacon_lock_code.k_scaler = p_security_key[ESCS_AES_KEY_SIZE];
378 }
379 #endif // APP_IS_EID_SUPPORTED
380 ret = memcpy_s(s_escs_env.escs_init.beacon_lock_code.security_key, ESCS_AES_KEY_SIZE,
381 p_security_key, ESCS_AES_KEY_SIZE);
382 if (ret < 0) {
383 return;
384 }
385 es_nvds_lock_key_set (p_security_key);
386 }
387
is_active_slot_eid(void)388 bool is_active_slot_eid (void)
389 {
390 #if(APP_IS_EID_SUPPORTED)
391 return true;
392 #else // APP_IS_EID_SUPPORTED
393 return false;
394 #endif // APP_IS_EID_SUPPORTED
395 }
396
es_adv_remain_connectable_set(bool remain_connectable)397 void es_adv_remain_connectable_set (bool remain_connectable)
398 {
399 s_escs_env.escs_init.remain_connectable = remain_connectable;
400 }
401
es_adv_remain_connectable_get(void)402 bool es_adv_remain_connectable_get (void)
403 {
404 return s_escs_env.escs_init.remain_connectable;
405 }
406
es_public_ecdh_key_get(uint8_t * p_ecdh_key_buf)407 void es_public_ecdh_key_get (uint8_t* p_ecdh_key_buf)
408 {
409 uint8_t ret;
410 #if(APP_IS_EID_SUPPORTED)
411 ret = memcpy_s(p_ecdh_key_buf, ESCS_ECDH_KEY_SIZE,
412 s_escs_env.escs_init.eid_slot_data[s_escs_env.escs_init.active_slot_no].pub_ecdh_key,
413 ESCS_ECDH_KEY_SIZE);
414 if (ret < 0) {
415 return;
416 }
417 #endif // APP_IS_EID_SUPPORTED
418 }
419
es_public_ecdh_key_set(uint8_t * p_ecdh_key_buf)420 void es_public_ecdh_key_set (uint8_t* p_ecdh_key_buf)
421 {
422 uint8_t ret;
423 #if(APP_IS_EID_SUPPORTED)
424 ret = memcpy_s(s_escs_env.escs_init.eid_slot_data[s_escs_env.escs_init.active_slot_no].pub_ecdh_key,
425 ESCS_ECDH_KEY_SIZE, p_ecdh_key_buf + 1, ESCS_ECDH_KEY_SIZE);
426 if (ret < 0) {
427 return;
428 }
429 s_escs_env.escs_init.eid_slot_data[s_escs_env.escs_init.active_slot_no].k_scaler = \
430 p_ecdh_key_buf[ESCS_ECDH_KEY_SIZE + 1];
431 #endif // APP_IS_EID_SUPPORTED
432 }
433
es_beacon_has_eid_adv(void)434 bool es_beacon_has_eid_adv (void)
435 {
436 #if(APP_IS_EID_SUPPORTED)
437 return true;
438 #endif // APP_IS_EID_SUPPORTED
439 return false;
440 }
441
442