static void ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm, int sched_new) { uint32_t max_usecs; struct ble_ll_sched_item *sch; sch = &advsm->adv_sch; sch->cb_arg = advsm; sch->sched_cb = ble_ll_adv_tx_start_cb; sch->sched_type = BLE_LL_SCHED_TYPE_ADV; /* Set end time to maximum time this schedule item may take */ max_usecs = BLE_TX_DUR_USECS_M(advsm->adv_pdu_len); switch (advsm->adv_type) { case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD: case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD: max_usecs += BLE_LL_ADV_DIRECT_SCHED_MAX_USECS; break; case BLE_HCI_ADV_TYPE_ADV_IND: case BLE_HCI_ADV_TYPE_ADV_SCAN_IND: max_usecs += BLE_LL_ADV_SCHED_MAX_USECS; break; default: break; } /* * XXX: For now, just schedule some additional time so we insure we have * enough time to do everything we want. */ max_usecs += XCVR_PROC_DELAY_USECS; if (sched_new) { /* * We have to add the scheduling delay and tx start delay to the max * time of the event since the pdu does not start at the scheduled start. */ max_usecs += XCVR_TX_SCHED_DELAY_USECS; sch->start_time = os_cputime_get32(); sch->end_time = sch->start_time + os_cputime_usecs_to_ticks(max_usecs); } else { sch->start_time = advsm->adv_pdu_start_time - os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS); sch->end_time = advsm->adv_pdu_start_time + os_cputime_usecs_to_ticks(max_usecs); } }
/** * Called to set the start time of a transmission. * * This function is called to set the start time when we are not going from * rx to tx automatically. * * NOTE: care must be taken when calling this function. The channel should * already be set. * * @param cputime * * @return int */ int ble_phy_tx_set_start_time(uint32_t cputime) { int rc; NRF_TIMER0->CC[0] = cputime; NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk; NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; if ((int32_t)(os_cputime_get32() - cputime) >= 0) { STATS_INC(ble_phy_stats, tx_late); ble_phy_disable(); rc = BLE_PHY_ERR_TX_LATE; } else { rc = 0; } return rc; }
void ble_ll_log(uint8_t id, uint8_t arg8, uint16_t arg16, uint32_t arg32) { os_sr_t sr; struct ble_ll_log *le; OS_ENTER_CRITICAL(sr); le = &g_ble_ll_log[g_ble_ll_log_index]; le->cputime = os_cputime_get32(); le->log_id = id; le->log_a8 = arg8; le->log_a16 = arg16; le->log_a32 = arg32; ++g_ble_ll_log_index; if (g_ble_ll_log_index == BLE_LL_LOG_LEN) { g_ble_ll_log_index = 0; } OS_EXIT_CRITICAL(sr); }
/** * Called when an advertising event is over. * * Context: Link Layer task. * * @param arg Pointer to advertising state machine. */ static void ble_ll_adv_done(struct ble_ll_adv_sm *advsm) { uint8_t mask; uint8_t final_adv_chan; int32_t delta_t; uint32_t itvl; uint32_t start_time; assert(advsm->enabled); /* Remove the element from the schedule if it is still there. */ ble_ll_sched_rmv_elem(&advsm->adv_sch); os_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); /* * Check if we have ended our advertising event. If our last advertising * packet was sent on the last channel, it means we are done with this * event. */ if (advsm->adv_chanmask & 0x04) { final_adv_chan = BLE_PHY_ADV_CHAN_START + 2; } else if (advsm->adv_chanmask & 0x02) { final_adv_chan = BLE_PHY_ADV_CHAN_START + 1; } else { final_adv_chan = BLE_PHY_ADV_CHAN_START; } if (advsm->adv_chan == final_adv_chan) { /* Check if we need to resume scanning */ ble_ll_scan_chk_resume(); /* This event is over. Set adv channel to first one */ advsm->adv_chan = ble_ll_adv_first_chan(advsm); /* Calculate start time of next advertising event */ itvl = advsm->adv_itvl_usecs; if (advsm->adv_type != BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) { itvl += rand() % (BLE_LL_ADV_DELAY_MS_MAX * 1000); } advsm->adv_event_start_time += os_cputime_usecs_to_ticks(itvl); advsm->adv_pdu_start_time = advsm->adv_event_start_time; /* * The scheduled time better be in the future! If it is not, we will * just keep advancing until we the time is in the future */ start_time = advsm->adv_pdu_start_time - os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS); delta_t = (int32_t)(start_time - os_cputime_get32()); if (delta_t < 0) { /* Calculate start time of next advertising event */ while (delta_t < 0) { itvl = advsm->adv_itvl_usecs; if (advsm->adv_type != BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) { itvl += rand() % (BLE_LL_ADV_DELAY_MS_MAX * 1000); } itvl = os_cputime_usecs_to_ticks(itvl); advsm->adv_event_start_time += itvl; advsm->adv_pdu_start_time = advsm->adv_event_start_time; delta_t += (int32_t)itvl; } } } else { /* * Move to next advertising channel. If not in the mask, just * increment by 1. We can do this because we already checked if we * just transmitted on the last advertising channel */ ++advsm->adv_chan; mask = 1 << (advsm->adv_chan - BLE_PHY_ADV_CHAN_START); if ((mask & advsm->adv_chanmask) == 0) { ++advsm->adv_chan; } /* * We will transmit right away. Set next pdu start time to now * plus a xcvr start delay just so we dont count late adv starts */ advsm->adv_pdu_start_time = os_cputime_get32() + os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS); } /* * Stop high duty cycle directed advertising if we have been doing * it for more than 1.28 seconds */ if (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) { if (advsm->adv_pdu_start_time >= advsm->adv_dir_hd_end_time) { /* Disable advertising */ advsm->enabled = 0; ble_ll_conn_comp_event_send(NULL, BLE_ERR_DIR_ADV_TMO, advsm->conn_comp_ev); advsm->conn_comp_ev = NULL; ble_ll_scan_chk_resume(); return; } } /* We need to regenerate our RPA's if we have passed timeout */ #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1) ble_ll_adv_chk_rpa_timeout(advsm); #endif /* Schedule advertising transmit */ ble_ll_adv_set_sched(advsm, 0); /* * In the unlikely event we cant reschedule this, just post a done * event and we will reschedule the next advertising event */ if (ble_ll_sched_adv_reschedule(&advsm->adv_sch)) { os_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); } }