/**
 * 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;
}
Example #4
0
/**
 * 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);
    }
}