/** * Called when a connect request has been received. * * Context: Link Layer * * @param rxbuf * @param flags * * @return 0: no connection started. 1: connection started */ int ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr) { int valid; uint8_t pyld_len; uint8_t *inita; uint32_t endtime; struct ble_ll_adv_sm *advsm; /* Check filter policy. */ valid = 0; advsm = &g_ble_ll_adv_sm; if (advsm->adv_filter_policy & 2) { if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_DEVMATCH) { /* valid connection request received */ valid = 1; } } else { /* If this is for us? */ if (!ble_ll_adv_addr_cmp(rxbuf)) { /* * Only accept connect requests from the desired address if we * are doing directed advertising */ if ((advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) || (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD)) { /* XXX: not sure if this works if address is random */ /* Compare addresses */ inita = rxbuf + BLE_LL_PDU_HDR_LEN; if (!memcmp(advsm->initiator_addr, inita, BLE_DEV_ADDR_LEN)) { valid = 1; } } else { valid = 1; } } } if (valid) { /* Try to start slave connection. If successful, stop advertising */ pyld_len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK; endtime = hdr->beg_cputime + BLE_TX_DUR_USECS_M(pyld_len); valid = ble_ll_conn_slave_start(rxbuf, endtime); if (valid) { ble_ll_adv_sm_stop(advsm); } } return valid; }
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 when a connect request has been received. * * Context: Link Layer * * @param rxbuf * @param flags * * @return 0: no connection started. 1: connection started */ int ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr) { int valid; uint8_t pyld_len; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) uint8_t resolved; #endif uint8_t addr_type; uint8_t *inita; uint8_t *ident_addr; uint32_t endtime; struct ble_ll_adv_sm *advsm; /* Check filter policy. */ valid = 0; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) resolved = BLE_MBUF_HDR_RESOLVED(hdr); #endif advsm = &g_ble_ll_adv_sm; inita = rxbuf + BLE_LL_PDU_HDR_LEN; if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_DEVMATCH) { valid = 1; if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) { addr_type = BLE_ADDR_TYPE_RANDOM; } else { addr_type = BLE_ADDR_TYPE_PUBLIC; } /* * Only accept connect requests from the desired address if we * are doing directed advertising */ if ((advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) || (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD)) { ident_addr = inita; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) if (resolved) { ident_addr = g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_identity_addr; addr_type = g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_addr_type; } #endif if ((addr_type != advsm->peer_addr_type) || memcmp(advsm->peer_addr, ident_addr, BLE_DEV_ADDR_LEN)) { valid = 0; } } } if (valid) { #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) if (resolved) { /* Retain the resolvable private address that we received. */ memcpy(advsm->adv_rpa, inita, BLE_DEV_ADDR_LEN); /* * Overwrite received inita with identity address since that * is used from now on. */ memcpy(inita, g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_identity_addr, BLE_DEV_ADDR_LEN); /* Peer address type is an identity address */ addr_type = g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_addr_type; addr_type += 2; } #endif /* Try to start slave connection. If successful, stop advertising */ pyld_len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK; endtime = hdr->beg_cputime + BLE_TX_DUR_USECS_M(pyld_len); valid = ble_ll_conn_slave_start(rxbuf, endtime, addr_type); if (valid) { ble_ll_adv_sm_stop(advsm); } } return valid; }
/** * Called from interrupt context when the transmit ends * */ static void ble_phy_tx_end_isr(void) { uint8_t was_encrypted; uint8_t transition; uint8_t txlen; uint32_t wfr_time; uint32_t txstart; /* * Read captured tx start time. This is not the actual transmit start * time but it is the time at which the address event occurred * (after transmission of access address) */ txstart = NRF_TIMER0->CC[1]; /* If this transmission was encrypted we need to remember it */ was_encrypted = g_ble_phy_data.phy_encrypted; /* Better be in TX state! */ assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX); /* Log the event */ ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, g_ble_phy_data.phy_tx_pyld_len, was_encrypted, txstart); /* Clear events and clear interrupt on disabled event */ NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk; NRF_RADIO->EVENTS_END = 0; wfr_time = NRF_RADIO->SHORTS; #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1) /* * XXX: not sure what to do. We had a HW error during transmission. * For now I just count a stat but continue on like all is good. */ if (was_encrypted) { if (NRF_CCM->EVENTS_ERROR) { STATS_INC(ble_phy_stats, tx_hw_err); NRF_CCM->EVENTS_ERROR = 0; } } #endif /* Call transmit end callback */ if (g_ble_phy_data.txend_cb) { g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg); } transition = g_ble_phy_data.phy_transition; if (transition == BLE_PHY_TRANSITION_TX_RX) { /* Packet pointer needs to be reset. */ ble_phy_rx_xcvr_setup(); /* * Enable the wait for response timer. Note that cc #1 on * timer 0 contains the transmit start time */ txlen = g_ble_phy_data.phy_tx_pyld_len; if (txlen && was_encrypted) { txlen += BLE_LL_DATA_MIC_LEN; } wfr_time = BLE_LL_WFR_USECS - BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET); wfr_time += BLE_TX_DUR_USECS_M(txlen); wfr_time = os_cputime_usecs_to_ticks(wfr_time); ble_ll_wfr_enable(txstart + wfr_time); } else { /* Disable automatic TXEN */ NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk; assert(transition == BLE_PHY_TRANSITION_NONE); } }