1 /** 2 ***************************************************************************************** 3 * 4 * @file dss.c 5 * 6 * @brief Device Synchronize 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 "dss.h" 43 #include "ble_prf_types.h" 44 #include "ble_prf_utils.h" 45 #include "utility.h" 46 #include "app_error.h" 47 #include "app_log.h" 48 49 /* 50 * DEFINES 51 ***************************************************************************************** 52 */ 53 /**@brief The UUIDs of DSS service and characteristics. */ 54 #define DSS_SERVICE_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, 0x0A, 0x46, 0x44, 0xD3, 55 0x01, 0x0A, 0xED, 0xA6} 56 #define DSS_ROLE_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, 0x0A, 0x46, 0x44, 0xD3, 57 0x02, 0x0A, 0xED, 0xA6} 58 #define DSS_EVT_CNT_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, 0x0A, 0x46, 0x44, 0xD3, 59 0x03, 0x0A, 0xED, 0xA6} 60 #define DSS_EVT_PERIOD_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, 0x0A, 0x46, 0x44, 0xD3, 61 0x04, 0x0A, 0xED, 0xA6} 62 #define DSS_STATUS_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, 0x0A, 0x46, 0x44, 0xD3, 63 0x05, 0x0A, 0xED, 0xA6} 64 #define DSS_CTRL_PT_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, 0x0A, 0x46, 0x44, 0xD3, 65 0x06, 0x0A, 0xED, 0xA6} 66 67 /**@brief Macros for conversion of 128bit to 16bit UUID. */ 68 #define ATT_128_PRIMARY_SERVICE BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_PRIMARY_SERVICE) 69 #define ATT_128_CHARACTERISTIC BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_CHARACTERISTIC) 70 #define ATT_128_CLIENT_CHAR_CFG BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DESC_CLIENT_CHAR_CFG) 71 72 /* 73 * ENUMERATIONS 74 ***************************************************************************************** 75 */ 76 /**@brief Device Synchronize Service Attributes database index list. */ 77 enum dss_attr_idx_t { 78 DSS_IDX_SVC, 79 80 DSS_IDX_ROLE_CHAR, 81 DSS_IDX_ROLE_VAL, 82 83 DSS_IDX_SYNC_CNT_CHAR, 84 DSS_IDX_SYNC_CNT_VAL, 85 DSS_IDX_SYNC_CNT_CFG, 86 87 DSS_IDX_SYNC_PERIOD_CHAR, 88 DSS_IDX_SYNC_PERIOD_VAL, 89 90 DSS_IDX_SYNC_STATUS_CHAR, 91 DSS_IDX_SYNC_STATUS_VAL, 92 93 DSS_IDX_CTRL_PT_CHAR, 94 DSS_IDX_CTRL_PT_VAL, 95 DSS_IDX_CTRL_PT_CFG, 96 97 DSS_IDX_NB, 98 }; 99 100 /* 101 * STRUCTURES 102 ***************************************************************************************** 103 */ 104 /**@brief Device Synchronize Service environment variable. */ 105 struct dss_env_t { 106 dss_evt_handler_t evt_handler; 107 uint16_t start_hdl; 108 uint16_t char_mask; 109 dss_role_t dss_role; 110 dss_staus_t sync_status; 111 uint16_t event_period; 112 uint32_t sync_cnt; 113 uint8_t sync_cfg_conn_idx; 114 bool is_busy_send; 115 bool is_auto_calib_drift; 116 bool is_auto_enter_lp; 117 bool is_in_lp; 118 uint32_t auto_calib_timing; 119 uint8_t sync_device_num; 120 uint16_t evt_cnt_ntf[DSS_CONNECTION_MAX]; 121 uint16_t ctrl_pt_ind[DSS_CONNECTION_MAX]; 122 }; 123 124 /* 125 * LOCAL FUNCTION DECLARATION 126 ***************************************************************************************** 127 */ 128 static sdk_err_t dss_init(void); 129 static void dss_disconnect_cb(uint8_t conn_idx, uint8_t reason); 130 static void dss_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param); 131 static void dss_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param); 132 static void dss_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value); 133 static void dss_ntf_ind_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind); 134 static void dss_ctrl_pt_handler(uint8_t conn_idx, const uint8_t *p_data, uint16_t length); 135 static sdk_err_t dss_ctrl_pt_rsp_send(uint8_t conn_idx, dss_op_id_t op_id, dss_rsp_id_t rsp_id); 136 /* 137 * LOCAL VARIABLE DEFINITIONS 138 ***************************************************************************************** 139 */ 140 static struct dss_env_t s_dss_env; 141 142 /**@brief Full DSS Database Description which is used to add attributes into the ATT database. */ 143 static const attm_desc_128_t dss_attr_tab[DSS_IDX_NB] = { 144 [DSS_IDX_SVC] = {ATT_128_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0}, 145 146 [DSS_IDX_ROLE_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0}, 147 [DSS_IDX_ROLE_VAL] = { 148 DSS_ROLE_UUID, 149 READ_PERM_UNSEC, 150 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128), 151 DSS_ROLE_VALUE_LEN 152 }, 153 154 [DSS_IDX_SYNC_CNT_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0}, 155 [DSS_IDX_SYNC_CNT_VAL] = { 156 DSS_EVT_CNT_UUID, 157 READ_PERM_UNSEC | NOTIFY_PERM_UNSEC, 158 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128), 159 DSS_EVT_CNT_VALUE_LEN 160 }, 161 [DSS_IDX_SYNC_CNT_CFG] = {ATT_128_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0}, 162 163 [DSS_IDX_SYNC_PERIOD_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0}, 164 [DSS_IDX_SYNC_PERIOD_VAL] = { 165 DSS_EVT_PERIOD_UUID, 166 READ_PERM_UNSEC, 167 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128), 168 DSS_EVT_PERIOD_VALUE_LEN 169 }, 170 171 [DSS_IDX_SYNC_STATUS_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0}, 172 [DSS_IDX_SYNC_STATUS_VAL] = { 173 DSS_STATUS_UUID, 174 READ_PERM_UNSEC, 175 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128), 176 DSS_STATUS_VALUE_LEN 177 }, 178 179 [DSS_IDX_CTRL_PT_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0}, 180 [DSS_IDX_CTRL_PT_VAL] = { 181 DSS_CTRL_PT_UUID, 182 WRITE_REQ_PERM_UNSEC | INDICATE_PERM_UNSEC, 183 ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128), 184 DSS_CTRL_PT_VALUE_LEN 185 }, 186 [DSS_IDX_CTRL_PT_CFG] = {ATT_128_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0}, 187 }; 188 189 /**@brief Device Synchronize Service interface required by profile manager. */ 190 static ble_prf_manager_cbs_t dss_mgr_cbs = { 191 (prf_init_func_t)dss_init, 192 NULL, 193 dss_disconnect_cb 194 }; 195 196 /**@brief Device Synchronize GATT Server Callbacks. */ 197 static gatts_prf_cbs_t dss_gatts_cbs = { 198 dss_read_att_cb, 199 dss_write_att_cb, 200 NULL, 201 dss_ntf_ind_cb, 202 dss_cccd_set_cb 203 }; 204 205 /**@brief Device Synchronize Service Information. */ 206 static const prf_server_info_t dss_prf_info = { 207 .max_connection_nb = DSS_CONNECTION_MAX, 208 .manager_cbs = &dss_mgr_cbs, 209 .gatts_prf_cbs = &dss_gatts_cbs 210 }; 211 212 /* 213 * LOCAL FUNCTION DEFINITIONS 214 ***************************************************************************************** 215 */ 216 /** 217 ***************************************************************************************** 218 * @brief Initialize Device Synchronize Service and create DB in ATT. 219 * 220 * @return Error code to know if service initialization succeed or not. 221 ***************************************************************************************** 222 */ 223 static sdk_err_t dss_init(void) 224 { 225 // The start hanlde must be set with PRF_INVALID_HANDLE to be allocated automatically by BLE Stack. 226 uint16_t start_hdl = PRF_INVALID_HANDLE; 227 const uint8_t dss_svc_uuid[] = DSS_SERVICE_UUID; 228 sdk_err_t error_code = SDK_SUCCESS; 229 gatts_create_db_t gatts_db; 230 231 error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db)); 232 if (error_code < 0) { 233 return error_code; 234 } 235 236 gatts_db.shdl = &start_hdl; 237 gatts_db.uuid = dss_svc_uuid; 238 gatts_db.attr_tab_cfg = (uint8_t *)&s_dss_env.char_mask; 239 gatts_db.max_nb_attr = DSS_IDX_NB; 240 gatts_db.srvc_perm = SRVC_UUID_TYPE_SET(UUID_TYPE_128); 241 gatts_db.attr_tab_type = SERVICE_TABLE_TYPE_128; 242 gatts_db.attr_tab.attr_tab_128 = dss_attr_tab; 243 244 error_code = ble_gatts_srvc_db_create(&gatts_db); 245 if (SDK_SUCCESS == error_code) { 246 s_dss_env.start_hdl = *gatts_db.shdl; 247 } 248 249 return error_code; 250 } 251 252 /** 253 ***************************************************************************************** 254 * @brief Device Synchronize Service disconnect callback. 255 ***************************************************************************************** 256 */ 257 static void dss_disconnect_cb(uint8_t conn_idx, uint8_t reason) 258 { 259 s_dss_env.evt_cnt_ntf[conn_idx] = 0x0000; 260 s_dss_env.ctrl_pt_ind[conn_idx] = 0x0000; 261 262 if (conn_idx == s_dss_env.sync_cfg_conn_idx) { 263 s_dss_env.sync_cfg_conn_idx = GAP_INVALID_CONN_INDEX; 264 } 265 } 266 267 /** 268 ***************************************************************************************** 269 * @brief Handles reception of the attribute info request message. 270 * 271 * @param[in] conn_idx: Connection index 272 * @param[in] p_param: Pointer to the parameters of the read request. 273 ***************************************************************************************** 274 */ 275 static void dss_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param) 276 { 277 gatts_read_cfm_t cfm; 278 uint16_t handle = p_param->handle; 279 uint8_t tab_index = prf_find_idx_by_handle(handle, 280 s_dss_env.start_hdl, 281 DSS_IDX_NB, 282 (uint8_t *)&s_dss_env.char_mask); 283 cfm.handle = handle; 284 cfm.status = BLE_SUCCESS; 285 286 switch (tab_index) { 287 case DSS_IDX_ROLE_VAL: 288 cfm.length = DSS_ROLE_VALUE_LEN; 289 cfm.value = (uint8_t *)&s_dss_env.dss_role; 290 break; 291 292 case DSS_IDX_SYNC_CNT_VAL: 293 cfm.length = DSS_EVT_CNT_VALUE_LEN; 294 cfm.value = (uint8_t *)&s_dss_env.sync_cnt; 295 break; 296 297 case DSS_IDX_SYNC_CNT_CFG: 298 cfm.length = sizeof(uint16_t); 299 cfm.value = (uint8_t *)&s_dss_env.evt_cnt_ntf[conn_idx]; 300 break; 301 302 case DSS_IDX_SYNC_PERIOD_VAL: 303 cfm.length = DSS_EVT_PERIOD_VALUE_LEN; 304 cfm.value = (uint8_t *)&s_dss_env.event_period; 305 break; 306 307 case DSS_IDX_SYNC_STATUS_VAL: 308 cfm.length = DSS_STATUS_VALUE_LEN; 309 cfm.value = (uint8_t *)&s_dss_env.sync_status; 310 break; 311 312 case DSS_IDX_CTRL_PT_CFG: 313 cfm.length = sizeof(uint16_t); 314 cfm.value = (uint8_t *)&s_dss_env.ctrl_pt_ind[conn_idx]; 315 break; 316 317 default: 318 cfm.length = 0; 319 cfm.status = BLE_ATT_ERR_INVALID_HANDLE; 320 break; 321 } 322 323 ble_gatts_read_cfm(conn_idx, &cfm); 324 } 325 326 327 /** 328 ***************************************************************************************** 329 * @brief Handles reception of the write request. 330 * 331 * @param[in] conn_idx: Index of the connection. 332 * @param[in] p_param: Point to the parameters of the write request. 333 ***************************************************************************************** 334 */ 335 static void dss_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param) 336 { 337 uint8_t handle = p_param->handle; 338 uint8_t tab_index = 0; 339 gatts_write_cfm_t cfm; 340 bool ctrl_pt_evt = false; 341 342 s_dss_env.sync_cfg_conn_idx = conn_idx; 343 tab_index = prf_find_idx_by_handle(handle, 344 s_dss_env.start_hdl, 345 DSS_IDX_NB, 346 (uint8_t *)&s_dss_env.char_mask); 347 cfm.handle = handle; 348 cfm.status = BLE_SUCCESS; 349 350 switch (tab_index) { 351 case DSS_IDX_SYNC_CNT_CFG: 352 s_dss_env.evt_cnt_ntf[conn_idx] = le16toh(&p_param->value[0]); 353 break; 354 355 case DSS_IDX_CTRL_PT_VAL: 356 ctrl_pt_evt = true; 357 break; 358 359 case DSS_IDX_CTRL_PT_CFG: 360 s_dss_env.ctrl_pt_ind[conn_idx] = le16toh(&p_param->value[0]); 361 break; 362 363 default: 364 cfm.status = BLE_ATT_ERR_INVALID_HANDLE; 365 break; 366 } 367 368 ble_gatts_write_cfm(conn_idx, &cfm); 369 370 if (ctrl_pt_evt) { 371 dss_ctrl_pt_handler(conn_idx, p_param->value, p_param->length); 372 } 373 } 374 375 /** 376 ***************************************************************************************** 377 * @brief Handles reception of the cccd recover request. 378 * 379 * @param[in]: conn_idx: Connection index 380 * @param[in]: handle: The handle of cccd attribute. 381 * @param[in]: cccd_value: The value of cccd attribute. 382 ***************************************************************************************** 383 */ 384 static void dss_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value) 385 { 386 uint8_t tab_index = 0; 387 388 if (!prf_is_cccd_value_valid(cccd_value)) { 389 return; 390 } 391 392 tab_index = prf_find_idx_by_handle(handle, 393 s_dss_env.start_hdl, 394 DSS_IDX_NB, 395 (uint8_t *)&s_dss_env.char_mask); 396 397 switch (tab_index) { 398 case DSS_IDX_SYNC_CNT_CFG: 399 s_dss_env.evt_cnt_ntf[conn_idx] = cccd_value; 400 break; 401 402 case DSS_IDX_CTRL_PT_CFG: 403 s_dss_env.ctrl_pt_ind[conn_idx] = cccd_value; 404 break; 405 406 default: 407 break; 408 } 409 } 410 411 /** 412 ***************************************************************************************** 413 * @brief Handles reception of the complete event. 414 * 415 * @param[in] conn_idx: Connection index. 416 * @param[in] status: The status of GATTC operation. 417 * @param[in] p_ntf_ind: Pointer to the parameters of the complete event. 418 ***************************************************************************************** 419 */ 420 static void dss_ntf_ind_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind) 421 { 422 if (BLE_SUCCESS == status && BLE_GATT_NOTIFICATION == p_ntf_ind->type) { 423 s_dss_env.is_busy_send = false; 424 } else if (status && BLE_GATT_NOTIFICATION == p_ntf_ind->type) { 425 s_dss_env.is_busy_send = true; 426 } 427 } 428 429 430 /** 431 ***************************************************************************************** 432 * @brief Set role OP handler. 433 * 434 * @param[in] conn_idx: Connection index. 435 * @param[in] p_data: Pointer to data. 436 * @param[in] length: Length of data. 437 ***************************************************************************************** 438 */ 439 static void dss_op_role_set_handler(uint8_t conn_idx, const uint8_t *p_data, uint16_t length) 440 { 441 dss_rsp_id_t rsp_id = DSS_RSP_ID_SUCCESS; 442 dss_evt_t evt; 443 444 if (length != 2 || (p_data[1] != DSS_ROLE_SYNC_SOURCE && p_data[1] != DSS_ROLE_SYNC_DEVICE)) { 445 rsp_id = DSS_RSP_ID_PARAM_ERR; 446 } else if (s_dss_env.sync_status != DSS_STATUS_CFG_READY) { 447 rsp_id = DSS_RSP_ID_STATUS_ERR; 448 } else { 449 s_dss_env.dss_role = (dss_role_t)p_data[1]; 450 451 evt.evt_type = s_dss_env.dss_role == DSS_ROLE_SYNC_SOURCE ? DSS_EVT_SOURCE_ROLE_SET : DSS_EVT_DEVICE_ROLE_SET; 452 s_dss_env.evt_handler(&evt); 453 } 454 455 dss_ctrl_pt_rsp_send(conn_idx, DSS_OP_ID_ROLE_SET, rsp_id); 456 } 457 458 /** 459 ***************************************************************************************** 460 * @brief Create sync source OP handler. 461 * 462 * @param[in] conn_idx: Connection index. 463 * @param[in] p_data: Pointer to data. 464 * @param[in] length: Length of data. 465 ***************************************************************************************** 466 */ 467 static void dss_op_sync_src_create_handler(uint8_t conn_idx, const uint8_t *p_data, uint16_t length) 468 { 469 dss_rsp_id_t rsp_id = DSS_RSP_ID_SUCCESS; 470 uint16_t event_period = le16toh(&p_data[1]); 471 dss_evt_t evt; 472 473 if (length != 3 || (le16toh(&p_data[1]) < 32) || (le16toh(&p_data[1]) > 3200)) { 474 rsp_id = DSS_RSP_ID_PARAM_ERR; 475 } else if (s_dss_env.sync_status != DSS_STATUS_CFG_READY) { 476 rsp_id = DSS_RSP_ID_STATUS_ERR; 477 } else if (s_dss_env.dss_role != DSS_ROLE_SYNC_SOURCE) { 478 rsp_id = DSS_RSP_ID_ROLE_ERR; 479 } else { 480 if (ble_sync_source_create(event_period)) { 481 rsp_id = DSS_RSP_ID_CREATE_SRC_FAIL; 482 } else { 483 s_dss_env.sync_status = DSS_STATUS_CFG_READY; 484 s_dss_env.event_period = event_period; 485 486 evt.evt_type = DSS_EVT_SYNC_SRC_CREATE; 487 s_dss_env.evt_handler(&evt); 488 } 489 } 490 491 dss_ctrl_pt_rsp_send(conn_idx, DSS_OP_ID_SYNC_SRC_CREATE, rsp_id); 492 } 493 494 495 /** 496 ***************************************************************************************** 497 * @brief Synchronize handler. 498 * 499 * @param[in] conn_idx: Connection index. 500 * @param[in] p_data: Pointer to data. 501 * @param[in] length: Length of data. 502 ***************************************************************************************** 503 */ 504 static void dss_op_sync_handler(uint8_t conn_idx, const uint8_t *p_data, uint16_t length, dss_op_id_t op_id) 505 { 506 dss_rsp_id_t rsp_id = DSS_RSP_ID_SUCCESS; 507 dss_evt_t evt; 508 509 if ((op_id != DSS_OP_ID_SYNC) || length != 7 || p_data[6] == 0) { 510 rsp_id = DSS_RSP_ID_PARAM_ERR; 511 } else if (s_dss_env.sync_status != DSS_STATUS_CFG_READY) { 512 rsp_id = DSS_RSP_ID_STATUS_ERR; 513 } else if (!s_dss_env.event_period && s_dss_env.dss_role == DSS_ROLE_SYNC_SOURCE) { 514 rsp_id = DSS_RSP_ID_DISALLOWED; 515 } else if (s_dss_env.dss_role == DSS_ROLE_SYNC_INVALID) { 516 rsp_id = DSS_RSP_ID_ROLE_ERR; 517 } else if (!s_dss_env.evt_handler) { 518 rsp_id = DSS_RSP_ID_NO_HANDLER; 519 } else { 520 s_dss_env.is_auto_calib_drift = (p_data[1] & 0x01) ? true : false; 521 s_dss_env.is_auto_enter_lp = (p_data[1] & 0x02) ? true : false; 522 523 s_dss_env.auto_calib_timing = BUILD_U32(p_data[2], p_data[3], p_data[4], p_data[5]); 524 s_dss_env.sync_device_num = p_data[6]; 525 526 if (s_dss_env.is_auto_calib_drift && !s_dss_env.auto_calib_timing) { 527 s_dss_env.is_auto_calib_drift = false; 528 s_dss_env.is_auto_enter_lp = false; 529 rsp_id = DSS_RSP_ID_PARAM_ERR; 530 } else { 531 s_dss_env.is_in_lp = false; 532 s_dss_env.sync_status = s_dss_env.dss_role == DSS_ROLE_SYNC_SOURCE ? DSS_STATUS_IN_SCAN : DSS_STATUS_IN_ADV; 533 534 evt.conn_idx = conn_idx; 535 evt.evt_type = DSS_EVT_SYNC_SELF_OR_PEER; 536 evt.is_enter_lp_mode = s_dss_env.is_auto_enter_lp; 537 evt.sync_dev_num = s_dss_env.sync_device_num; 538 s_dss_env.evt_handler(&evt); 539 } 540 } 541 542 if (rsp_id) { 543 dss_ctrl_pt_rsp_send(conn_idx, op_id, rsp_id); 544 } 545 } 546 547 /** 548 ***************************************************************************************** 549 * @brief Cancel Synchronization handler. 550 * 551 * @param[in] conn_idx: Connection index. 552 ***************************************************************************************** 553 */ 554 static void dss_op_cancel_sync_handler(uint8_t conn_idx) 555 { 556 dss_rsp_id_t rsp_id = DSS_RSP_ID_SUCCESS; 557 dss_evt_t evt; 558 559 if (((s_dss_env.sync_status != DSS_STATUS_IN_SCAN) && (DSS_ROLE_SYNC_SOURCE == s_dss_env.dss_role)) || 560 ((s_dss_env.sync_status != DSS_STATUS_IN_ADV) && (DSS_ROLE_SYNC_DEVICE == s_dss_env.dss_role))) { 561 rsp_id = DSS_RSP_ID_STATUS_ERR; 562 } else if (s_dss_env.evt_handler == NULL) { 563 rsp_id = DSS_RSP_ID_NO_HANDLER; 564 } else { 565 evt.conn_idx = conn_idx; 566 evt.evt_type = DSS_EVT_SYNC_CANCEL; 567 s_dss_env.evt_handler(&evt); 568 } 569 570 if (rsp_id) { 571 dss_ctrl_pt_rsp_send(conn_idx, DSS_OP_ID_CANCEL_SYNC, rsp_id); 572 } 573 } 574 575 /** 576 ***************************************************************************************** 577 * @brief Enter low power handler. 578 * 579 * @param[in] conn_idx: Connection index. 580 ***************************************************************************************** 581 */ 582 static void dss_op_lp_enter_handler(uint8_t conn_idx) 583 { 584 dss_rsp_id_t rsp_id = DSS_RSP_ID_SUCCESS; 585 dss_evt_t evt; 586 587 if (s_dss_env.sync_status != DSS_STATUS_CFG_READY) { 588 rsp_id = DSS_RSP_ID_STATUS_ERR; 589 } else if (s_dss_env.evt_handler == NULL) { 590 rsp_id = DSS_RSP_ID_NO_HANDLER; 591 } else { 592 s_dss_env.is_auto_enter_lp = true; 593 s_dss_env.sync_status = DSS_STATUS_CFG_READY; 594 595 evt.conn_idx = conn_idx; 596 evt.evt_type = DSS_EVT_LP_ENTER; 597 evt.is_enter_lp_mode = s_dss_env.is_auto_enter_lp; 598 599 dss_ctrl_pt_rsp_send(conn_idx, DSS_OP_ID_LP_ENTER, rsp_id); 600 s_dss_env.evt_handler(&evt); 601 } 602 603 if (rsp_id) { 604 dss_ctrl_pt_rsp_send(conn_idx, DSS_OP_ID_LP_ENTER, rsp_id); 605 } 606 } 607 608 /** 609 ***************************************************************************************** 610 * @brief Destroy sync. 611 * 612 * @param[in] conn_idx: Connection index. 613 ***************************************************************************************** 614 */ 615 static void dss_op_sync_destroy_handler(uint8_t conn_idx) 616 { 617 dss_rsp_id_t rsp_id = DSS_RSP_ID_SUCCESS; 618 dss_evt_t evt; 619 620 if (s_dss_env.dss_role == DSS_ROLE_SYNC_INVALID) { 621 rsp_id = DSS_RSP_ID_ROLE_ERR; 622 } else if (ble_sync_source_destroy()) { 623 rsp_id = DSS_RSP_ID_DESTROY_SRC_FAIL; 624 } else { 625 s_dss_env.sync_status = DSS_STATUS_CFG_READY; 626 s_dss_env.is_in_lp = false; 627 s_dss_env.is_auto_enter_lp = false; 628 s_dss_env.is_auto_calib_drift = false; 629 s_dss_env.event_period = 0; 630 s_dss_env.sync_cnt = 0; 631 s_dss_env.sync_device_num = 0; 632 633 evt.conn_idx = conn_idx; 634 evt.evt_type = DSS_EVT_SYNC_DESTROY; 635 s_dss_env.evt_handler(&evt); 636 } 637 638 if (rsp_id) { 639 dss_ctrl_pt_rsp_send(conn_idx, DSS_OP_ID_SYNC_DESTROY, rsp_id); 640 } 641 } 642 643 /** 644 ***************************************************************************************** 645 * @brief Send Control Point Response. 646 * 647 * @param[in] conn_idx: Connection index. 648 * @param[in] op_id: OP ID. 649 * @param[in] rsp_id: Response id. 650 ***************************************************************************************** 651 */ 652 static sdk_err_t dss_ctrl_pt_rsp_send(uint8_t conn_idx, dss_op_id_t op_id, dss_rsp_id_t rsp_id) 653 { 654 sdk_err_t error_code = SDK_ERR_IND_DISABLED; 655 uint8_t rsp[DSS_CTRL_PT_RSP_VAL_LEN] = {0}; 656 gatts_noti_ind_t rsp_ind; 657 658 rsp[0] = DSS_OP_ID_RSP; 659 rsp[1] = op_id; 660 rsp[2] = rsp_id; 661 662 if (s_dss_env.ctrl_pt_ind[conn_idx] == PRF_CLI_START_IND) { 663 rsp_ind.type = BLE_GATT_INDICATION; 664 rsp_ind.handle = prf_find_handle_by_idx(DSS_IDX_CTRL_PT_VAL, s_dss_env.start_hdl, 665 (uint8_t *)&s_dss_env.char_mask); 666 rsp_ind.length = DSS_CTRL_PT_RSP_VAL_LEN; 667 rsp_ind.value = rsp; 668 669 error_code = ble_gatts_noti_ind(conn_idx, &rsp_ind); 670 } 671 672 return error_code; 673 } 674 675 /** 676 ***************************************************************************************** 677 * @brief Control Point handler. 678 * 679 * @param[in] conn_idx: Connection index. 680 * @param[in] p_data: Pointer to data. 681 * @param[in] length: Length of data. 682 ***************************************************************************************** 683 */ 684 static void dss_ctrl_pt_handler(uint8_t conn_idx, const uint8_t *p_data, uint16_t length) 685 { 686 switch (p_data[0]) { 687 case DSS_OP_ID_ROLE_SET: 688 dss_op_role_set_handler(conn_idx, p_data, length); 689 break; 690 691 case DSS_OP_ID_SYNC_SRC_CREATE: 692 dss_op_sync_src_create_handler(conn_idx, p_data, length); 693 break; 694 695 case DSS_OP_ID_SYNC: 696 dss_op_sync_handler(conn_idx, p_data, length, (dss_op_id_t)p_data[0]); 697 break; 698 699 case DSS_OP_ID_LP_ENTER: 700 dss_op_lp_enter_handler(conn_idx); 701 break; 702 703 case DSS_OP_ID_SYNC_DESTROY: 704 dss_op_sync_destroy_handler(conn_idx); 705 break; 706 707 case DSS_OP_ID_CANCEL_SYNC: 708 dss_op_cancel_sync_handler(conn_idx); 709 break; 710 711 default: 712 dss_ctrl_pt_rsp_send(conn_idx, (dss_op_id_t)p_data[0], DSS_RSP_ID_UNSUPPORT); 713 break; 714 } 715 } 716 717 718 static void dss_sync_evt_cb(uint32_t sync_cnt, uint16_t event_period) 719 { 720 gatts_noti_ind_t send_ntf; 721 sdk_err_t error_code = SDK_ERR_NTF_DISABLED; 722 dss_evt_t evt; 723 724 if (s_dss_env.evt_handler == NULL) { 725 return; 726 } 727 728 evt.evt_type = DSS_EVT_INVALID; 729 730 evt.conn_idx = GAP_INVALID_CONN_INDEX; 731 evt.evt_type = DSS_EVT_SYNC_OCCUR; 732 evt.sync_cnt = sync_cnt; 733 734 s_dss_env.evt_handler(&evt); 735 736 if (!s_dss_env.is_in_lp && s_dss_env.is_auto_enter_lp && s_dss_env.evt_handler) { 737 evt.evt_type = DSS_EVT_LP_ENTER; 738 evt.is_enter_lp_mode = true; 739 740 s_dss_env.evt_handler(&evt); 741 } 742 743 if (s_dss_env.is_auto_calib_drift && !(sync_cnt % s_dss_env.auto_calib_timing)) { 744 evt.sync_dev_num = s_dss_env.sync_device_num; 745 evt.evt_type = DSS_EVT_SYNC_SELF_OR_PEER; 746 evt.is_enter_lp_mode = s_dss_env.is_auto_enter_lp; 747 748 s_dss_env.sync_status = s_dss_env.dss_role == DSS_ROLE_SYNC_DEVICE ? DSS_STATUS_IN_ADV : DSS_STATUS_IN_SCAN; 749 s_dss_env.evt_handler(&evt); 750 s_dss_env.is_in_lp = false; 751 } else { 752 s_dss_env.sync_cnt = sync_cnt; 753 s_dss_env.event_period = event_period; 754 755 if (!s_dss_env.is_busy_send) { 756 if (s_dss_env.evt_cnt_ntf[s_dss_env.sync_cfg_conn_idx] == PRF_CLI_START_NTF) { 757 send_ntf.type = BLE_GATT_NOTIFICATION; 758 send_ntf.handle = prf_find_handle_by_idx(DSS_IDX_SYNC_CNT_VAL, s_dss_env.start_hdl, 759 (uint8_t *)&s_dss_env.char_mask); 760 send_ntf.length = DSS_EVT_CNT_VALUE_LEN; 761 send_ntf.value = (uint8_t *)&s_dss_env.sync_cnt; 762 763 error_code = ble_gatts_noti_ind(s_dss_env.sync_cfg_conn_idx, &send_ntf); 764 APP_ERROR_CHECK(error_code); 765 } 766 } 767 } 768 } 769 770 /* 771 * GLOBAL FUNCTION DEFINITIONS 772 ***************************************************************************************** 773 */ 774 sdk_err_t dss_service_init(dss_evt_handler_t evt_handler) 775 { 776 if (evt_handler == NULL) { 777 return SDK_ERR_POINTER_NULL; 778 } 779 780 ble_sync_evt_cb_register(dss_sync_evt_cb); 781 782 s_dss_env.evt_handler = evt_handler; 783 s_dss_env.dss_role = DSS_ROLE_SYNC_INVALID; 784 s_dss_env.sync_status = DSS_STATUS_CFG_READY; 785 s_dss_env.char_mask = 0x1fff; 786 s_dss_env.is_busy_send = false; 787 s_dss_env.is_auto_calib_drift = false; 788 s_dss_env.is_auto_enter_lp = false; 789 s_dss_env.is_in_lp = false; 790 s_dss_env.event_period = 0; 791 s_dss_env.auto_calib_timing = 0; 792 s_dss_env.sync_device_num = 0; 793 s_dss_env.sync_cnt = 0; 794 795 return ble_server_prf_add(&dss_prf_info); 796 } 797 798 sdk_err_t dss_sync_op_result_send(uint8_t conn_idx, dss_evt_type_t evt_type, dss_rsp_id_t rsp_id) 799 { 800 if (evt_type == DSS_EVT_SYNC_SELF_OR_PEER) { 801 return dss_ctrl_pt_rsp_send(conn_idx, DSS_OP_ID_SYNC, rsp_id); 802 } else if (evt_type == DSS_EVT_SYNC_CANCEL) { 803 return dss_ctrl_pt_rsp_send(conn_idx, DSS_OP_ID_CANCEL_SYNC, rsp_id); 804 } else if (evt_type == DSS_EVT_LP_ENTER) { 805 return dss_ctrl_pt_rsp_send(conn_idx, DSS_OP_ID_LP_ENTER, rsp_id); 806 } else if (evt_type == DSS_EVT_SYNC_DESTROY) { 807 return dss_ctrl_pt_rsp_send(conn_idx, DSS_OP_ID_SYNC_DESTROY, rsp_id); 808 } else { 809 return SDK_ERR_INVALID_PARAM; 810 } 811 } 812 813 814 void dss_set_status(uint8_t conn_idx, dss_staus_t status) 815 { 816 s_dss_env.sync_status = status; 817 } 818 819 void dss_set_sync_params(uint8_t conn_idx, bool is_auto_enter_lp, bool is_auto_calib_drift) 820 { 821 s_dss_env.is_auto_enter_lp = is_auto_enter_lp; 822 s_dss_env.is_auto_calib_drift = is_auto_calib_drift; 823 } 824 825 void dss_set_lp_mode(uint8_t conn_idx, bool is_in_lp_mode) 826 { 827 s_dss_env.is_in_lp = is_in_lp_mode; 828 } 829 830 void dss_sync_src_distribute(uint8_t conn_idx) 831 { 832 dss_op_id_t op_id; 833 dss_rsp_id_t rsp_id = DSS_RSP_ID_SUCCESS; 834 835 if (DSS_ROLE_SYNC_SOURCE == s_dss_env.dss_role && ble_sync_source_distribute(conn_idx)) { 836 rsp_id = DSS_RSP_ID_DISTR_SRC_FAIL; 837 } 838 839 op_id = DSS_OP_ID_SYNC; 840 841 s_dss_env.sync_status = DSS_STATUS_CFG_READY; 842 843 dss_ctrl_pt_rsp_send(s_dss_env.sync_cfg_conn_idx, op_id, rsp_id); 844 } 845