static void intervals_calculate(void) { bool etlm_required = false; uint8_t no_of_eid_slots = eddystone_adv_slot_num_of_current_eids(NULL, &etlm_required); /*Buffers to hardcode a small shortening of the intervals just in case of any delays between all the running timer interrupts (scheduled to main context) + variance in encyrption time of eTLMs so that all slots have enough time to advertise before the next advertising interval comes around*/ const uint8_t etlm_dist_buffer_ms = 25; const uint8_t slot_dist_buffer_ms = 25; /**@note From internal testing we can see that eTLM encryption takes about ~170 ms on the NRF52. Which means that the delay after the timer interrupt fires to advertise and the actual eTLM advertisement is ~170 ms, this is a significant limiting factor for the minimum advertising interval. Please read the comments above @ref timers_init to see what is the current scheme of advertising timing before continuing. Thus if there N EIDs configured (N > 0) in the beacon and at least 1 TLM configured, then the TLM frame auto switches to eTLM and cycles through the set of EIKs of the EIDs frames and advertises N eTLM frames, all within one slot interval, each encrypted with the EIK of one of the EID slots. Hence there must be enough time alotted in 1 slot interval for N*(~170 ms + buffer). */ /*Minimum interval between two eTLM advertisements (2+ EIDs) in one eTLM slot in ms*/ const uint16_t ETLM_INTERVAL_LIMIT = 225; /*MUST be > ~170 ms + etlm_dist_buffer_ms */ /*Minimum interval between two slots in ms. If eTLM is required then SLOT_INTERVAL_LIMIT becomes just the first half of the sum, else the second half (MIN_NON_CONN_ADV_INTERVAL) since there is no significant real-time encrytion delays*/ const uint16_t SLOT_INTERVAL_LIMIT = (no_of_eid_slots*ETLM_INTERVAL_LIMIT)*(uint8_t)(etlm_required) + MIN_NON_CONN_ADV_INTERVAL*((uint8_t)(!etlm_required)); DEBUG_PRINTF(0,"SLOT_INTERVAL_LIMIT: %d \r\n", SLOT_INTERVAL_LIMIT); //See if any slot is configured at all uint8_t no_of_currently_configed_slots = eddystone_adv_slot_num_of_configured_slots(m_currently_configured_slots); DEBUG_PRINTF(0,"Number of Configured Slots: %d \r\n", no_of_currently_configed_slots); //Gets slot 0's advertising interval since only global advertising interval is supported currently eddystone_adv_slot_params_t adv_slot_0_params; eddystone_adv_slot_params_get(0, &adv_slot_0_params); m_intervals.adv_intrvl = adv_slot_0_params.adv_intrvl; //Can happen when flash R/W for storing/loading slot configs did not behave as expected //which can crash the app_timer_start //TODO: might need a better error handling strategy for this... if (m_intervals.adv_intrvl == 0) { m_intervals.adv_intrvl = 1000; } if (no_of_currently_configed_slots == 0) { m_intervals.slot_slot_interval = 0; m_intervals.etlm_etlm_interval = 0; } else { //Slot-Slot Interval m_intervals.slot_slot_interval = (m_intervals.adv_intrvl/(no_of_currently_configed_slots)) - slot_dist_buffer_ms; if (m_intervals.slot_slot_interval < SLOT_INTERVAL_LIMIT) { ble_ecs_adv_intrvl_t adjusted_interval = (SLOT_INTERVAL_LIMIT + slot_dist_buffer_ms)*no_of_currently_configed_slots; m_intervals.adv_intrvl = adjusted_interval; DEBUG_PRINTF(0,"1 - ADV INTERVAL ADJUSTED BY ADV MGR: %d \r\n", adjusted_interval); adjusted_interval = BYTES_SWAP_16BIT(adjusted_interval); eddystone_adv_slot_adv_intrvl_set(0, &adjusted_interval, true); m_intervals.slot_slot_interval = m_intervals.adv_intrvl/no_of_currently_configed_slots - slot_dist_buffer_ms; DEBUG_PRINTF(0,"Slot-Slot Interval: %d \r\n", m_intervals.slot_slot_interval ); } //eTLM-eTLM interval if (no_of_eid_slots != 0 && etlm_required == true) { m_intervals.etlm_etlm_interval = (m_intervals.slot_slot_interval/no_of_eid_slots) - etlm_dist_buffer_ms; if (m_intervals.etlm_etlm_interval < ETLM_INTERVAL_LIMIT) { m_intervals.etlm_etlm_interval = ETLM_INTERVAL_LIMIT; m_intervals.slot_slot_interval = (m_intervals.etlm_etlm_interval + etlm_dist_buffer_ms)*no_of_eid_slots - slot_dist_buffer_ms; ble_ecs_adv_intrvl_t adjusted_interval = (m_intervals.slot_slot_interval + slot_dist_buffer_ms)*no_of_currently_configed_slots; m_intervals.adv_intrvl = adjusted_interval; DEBUG_PRINTF(0,"2 - ADV INTERVAL ADJUSTED BY ADV MGR: %d \r\n", adjusted_interval); adjusted_interval = BYTES_SWAP_16BIT(adjusted_interval); eddystone_adv_slot_adv_intrvl_set(0, &adjusted_interval, true); DEBUG_PRINTF(0,"eTLM-eTLM Interval: %d \r\n", m_intervals.etlm_etlm_interval ); DEBUG_PRINTF(0,"Slot-Slot Interval: %d \r\n", m_intervals.slot_slot_interval ); } } else { m_intervals.etlm_etlm_interval = 0; } } }
ret_code_t nrf_ble_escs_init(nrf_ble_escs_t * p_escs, const nrf_ble_escs_init_t * p_escs_init) { uint32_t err_code; ble_uuid_t ble_uuid; ble_uuid128_t ecs_base_uuid = ESCS_BASE_UUID; uint8_t zero_val = 0; VERIFY_PARAM_NOT_NULL(p_escs); VERIFY_PARAM_NOT_NULL(p_escs_init); // Initialize the service structure. p_escs->conn_handle = BLE_CONN_HANDLE_INVALID; p_escs->write_evt_handler = p_escs_init->write_evt_handler; p_escs->read_evt_handler = p_escs_init->read_evt_handler; // Add a custom base UUID. err_code = sd_ble_uuid_vs_add(&ecs_base_uuid, &p_escs->uuid_type); VERIFY_SUCCESS(err_code); ble_uuid.type = p_escs->uuid_type; ble_uuid.uuid = BLE_UUID_ESCS_SERVICE; // Add the service. err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_escs->service_handle); VERIFY_SUCCESS(err_code); m_handle_to_uuid_map_idx = 0; // Set up initial values for characteristics // Eddystone spec requires big endian nrf_ble_escs_broadcast_cap_t temp = p_escs_init->p_init_vals->broadcast_cap; temp.supp_frame_types = BYTES_SWAP_16BIT(temp.supp_frame_types); nrf_ble_escs_adv_interval_t temp_interval = p_escs_init->p_init_vals->adv_interval; temp_interval = BYTES_SWAP_16BIT(temp_interval); // Adding chracteristics err_code = char_add(&BROADCAST_CAP_CHAR_INIT, p_escs, &temp, &p_escs->broadcast_cap_handles); VERIFY_SUCCESS(err_code); err_code = char_add(&ACTIVE_SLOT_CHAR_INIT, p_escs, p_escs->p_active_slot, &p_escs->active_slot_handles); VERIFY_SUCCESS(err_code); err_code = char_add(&ADV_INTERVAL_CHAR_INIT, p_escs, &temp_interval, &p_escs->adv_interval_handles); VERIFY_SUCCESS(err_code); err_code = char_add(&RADIO_TX_PWR_CHAR_INIT, p_escs, &(p_escs_init->p_init_vals->radio_tx_pwr), &p_escs->radio_tx_pwr_handles); VERIFY_SUCCESS(err_code); err_code = char_add(&ADV_TX_PWR_CHAR_INIT, p_escs, &(p_escs_init->p_init_vals->adv_tx_pwr), &p_escs->adv_tx_pwr_handles); VERIFY_SUCCESS(err_code); err_code = char_add(&LOCK_STATE_CHAR_INIT, p_escs, p_escs->p_lock_state, &p_escs->lock_state_handles); VERIFY_SUCCESS(err_code); err_code = char_add(&UNLOCK_CHAR_INIT, p_escs, &zero_val, &p_escs->unlock_handles); VERIFY_SUCCESS(err_code); err_code = char_add(&PUBLIC_ECDH_KEY_CHAR_INIT, p_escs, &zero_val, &p_escs->pub_ecdh_key_handles); VERIFY_SUCCESS(err_code); err_code = char_add(&EID_ID_KEY_CHAR_INIT, p_escs, &zero_val, &p_escs->eid_id_key_handles); VERIFY_SUCCESS(err_code); err_code = char_add(&RW_ADV_SLOT_CHAR_INIT, p_escs, &zero_val, &p_escs->rw_adv_slot_handles); VERIFY_SUCCESS(err_code); err_code = char_add(&FACTORY_RESET_CHAR_INIT, p_escs, &(p_escs_init->p_init_vals->factory_reset), &p_escs->factory_reset_handles); VERIFY_SUCCESS(err_code); err_code = char_add(&REMAIN_CONNECTABLE_CHAR_INIT, p_escs, &(p_escs_init->p_init_vals->remain_connectable.r_is_non_connectable_supported), &p_escs->remain_connectable_handles); VERIFY_SUCCESS(err_code); return NRF_SUCCESS; }