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