Esempio n. 1
0
static void
ble_phy_rx_start_isr(void)
{
    int rc;
    uint32_t state;
    struct ble_mbuf_hdr *ble_hdr;

    /* Clear events and clear interrupt */
    NRF_RADIO->EVENTS_ADDRESS = 0;
    NRF_RADIO->INTENCLR = RADIO_INTENCLR_ADDRESS_Msk;

    /* Wait to get 1st byte of frame */
    while (1) {
        state = NRF_RADIO->STATE;
        if (NRF_RADIO->EVENTS_BCMATCH != 0) {
            break;
        }

        /*
         * If state is disabled, we should have the BCMATCH. If not,
         * something is wrong!
         */
        if (state == RADIO_STATE_STATE_Disabled) {
            NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
            NRF_RADIO->SHORTS = 0;
            return;
        }
    }

    /* Initialize flags, channel and state in ble header at rx start */
    ble_hdr = &g_ble_phy_data.rxhdr;
    ble_hdr->rxinfo.flags = ble_ll_state_get();
    ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
    ble_hdr->rxinfo.handle = 0;
    ble_hdr->beg_cputime = NRF_TIMER0->CC[1] -
        os_cputime_usecs_to_ticks(BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET));

    /* Call Link Layer receive start function */
    rc = ble_ll_rx_start((uint8_t *)&g_ble_phy_rx_buf[0] + 3,
                         g_ble_phy_data.phy_chan,
                         &g_ble_phy_data.rxhdr);
    if (rc >= 0) {
        /* Set rx started flag and enable rx end ISR */
        g_ble_phy_data.phy_rx_started = 1;
        NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk;

#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
        /* Must start aar if we need to  */
        if (g_ble_phy_data.phy_privacy) {
            NRF_RADIO->EVENTS_BCMATCH = 0;
            NRF_PPI->CHENSET = PPI_CHEN_CH23_Msk;
            NRF_RADIO->BCC = (BLE_DEV_ADDR_LEN + BLE_LL_PDU_HDR_LEN) * 8;
        }
#endif
    } else {
        /* Disable PHY */
        ble_phy_disable();
        STATS_INC(ble_phy_stats, rx_aborts);
    }

    /* Count rx starts */
    STATS_INC(ble_phy_stats, rx_starts);
}
static void
ble_phy_isr(void)
{
    int rc;
    uint8_t transition;
    uint8_t crcok;
    uint32_t irq_en;
    uint32_t state;
    uint32_t wfr_time;
    struct os_mbuf *rxpdu;
    struct ble_mbuf_hdr *ble_hdr;

    /* Read irq register to determine which interrupts are enabled */
    irq_en = NRF_RADIO->INTENCLR;

    /* Check for disabled event. This only happens for transmits now */
    if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) {
        /* Better be in TX state! */
        assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX);

        ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, g_ble_phy_txrx_buf[1], 0, 
                   NRF_TIMER0->CC[2]);

        /* 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;
        state = NRF_RADIO->SHORTS;

        transition = g_ble_phy_data.phy_transition;
        if (transition == BLE_PHY_TRANSITION_TX_RX) {
            /* Clear the rx started flag */
            g_ble_phy_data.phy_rx_started = 0;

            /* Packet pointer needs to be reset. */
            if (g_ble_phy_data.rxpdu != NULL) {
                NRF_RADIO->PACKETPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data;

                /* I want to know when 1st byte received (after address) */
                NRF_RADIO->BCC = 8; /* in bits */
                NRF_RADIO->EVENTS_ADDRESS = 0;
                NRF_RADIO->EVENTS_DEVMATCH = 0;
                NRF_RADIO->EVENTS_BCMATCH = 0;
                NRF_RADIO->EVENTS_RSSIEND = 0;
                NRF_RADIO->SHORTS = RADIO_SHORTS_END_DISABLE_Msk | 
                                    RADIO_SHORTS_READY_START_Msk |
                                    RADIO_SHORTS_ADDRESS_BCSTART_Msk |
                                    RADIO_SHORTS_ADDRESS_RSSISTART_Msk |
                                    RADIO_SHORTS_DISABLED_RSSISTOP_Msk;

                NRF_RADIO->INTENSET = RADIO_INTENSET_ADDRESS_Msk;
                g_ble_phy_data.phy_state = BLE_PHY_STATE_RX;
            } else {
                /* Disable the phy */
                ++g_ble_phy_stats.no_bufs;
                ble_phy_disable();
            }

            /* 
             * Enable the wait for response timer. Note that cc #2 on
             * timer 0 contains the transmit end time
             */ 
            wfr_time = NRF_TIMER0->CC[2];
            wfr_time += cputime_usecs_to_ticks(BLE_LL_WFR_USECS);
            ble_ll_wfr_enable(wfr_time);
        } else {
            /* Better not be going from rx to tx! */
            assert(transition == BLE_PHY_TRANSITION_NONE);
        }

        /* Call transmit end callback */
        if (g_ble_phy_data.txend_cb) {
            g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg);
        }
    }

    /* We get this if we have started to receive a frame */
    if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO->EVENTS_ADDRESS) {
        /* Clear events and clear interrupt */
        NRF_RADIO->EVENTS_ADDRESS = 0;
        NRF_RADIO->INTENCLR = RADIO_INTENCLR_ADDRESS_Msk;

        assert(g_ble_phy_data.rxpdu != NULL);

        /* Wait to get 1st byte of frame */
        while (1) {
            state = NRF_RADIO->STATE;
            if (NRF_RADIO->EVENTS_BCMATCH != 0) {
                break;
            }

            /* 
             * If state is disabled, we should have the BCMATCH. If not,
             * something is wrong!
             */ 
            if (state == RADIO_STATE_STATE_Disabled) {
                NRF_RADIO->INTENCLR = NRF52_RADIO_IRQ_MASK_ALL;
                NRF_RADIO->SHORTS = 0;
                goto phy_isr_exit;
            }
        }

        /* Initialize flags, channel and state in ble header at rx start */
        ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu);
        ble_hdr->rxinfo.flags = ble_ll_state_get();
        ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
        ble_hdr->rxinfo.handle = 0;

        /* Call Link Layer receive start function */
        rc = ble_ll_rx_start(g_ble_phy_data.rxpdu, g_ble_phy_data.phy_chan);
        if (rc >= 0) {
            g_ble_phy_data.phy_rx_started = 1;
            if (rc > 0) {
                /* We need to go from disabled to TXEN */
                NRF_RADIO->SHORTS = RADIO_SHORTS_END_DISABLE_Msk | 
                                    RADIO_SHORTS_READY_START_Msk |
                                    RADIO_SHORTS_DISABLED_TXEN_Msk;
            } else {
                NRF_RADIO->SHORTS = RADIO_SHORTS_END_DISABLE_Msk | 
                                    RADIO_SHORTS_READY_START_Msk;
            }

            /* Set rx end ISR enable */
            NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk;
        } else {
            /* Disable PHY */
            ble_phy_disable();
            irq_en = 0;
            ++g_ble_phy_stats.rx_aborts;
        }

        /* Count rx starts */
        ++g_ble_phy_stats.rx_starts;
    }

    /* Receive packet end (we dont enable this for transmit) */
    if ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO->EVENTS_END) {
        /* Clear events and clear interrupt */
        NRF_RADIO->EVENTS_END = 0;
        NRF_RADIO->INTENCLR = RADIO_INTENCLR_END_Msk;

        /* Set RSSI and CRC status flag in header */
        ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu);
        assert(NRF_RADIO->EVENTS_RSSIEND != 0);
        ble_hdr->rxinfo.rssi = -1 * NRF_RADIO->RSSISAMPLE;
        ble_hdr->end_cputime = NRF_TIMER0->CC[2];

        /* Count PHY crc errors and valid packets */
        crcok = (uint8_t)NRF_RADIO->CRCSTATUS;
        if (!crcok) {
            ++g_ble_phy_stats.rx_crc_err;
        } else {
            ++g_ble_phy_stats.rx_valid;
            ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK;
        }

        /* Call Link Layer receive payload function */
        rxpdu = g_ble_phy_data.rxpdu;
        g_ble_phy_data.rxpdu = NULL;
        rc = ble_ll_rx_end(rxpdu, ble_hdr);
        if (rc < 0) {
            /* Disable the PHY. */
            ble_phy_disable();
        }
    }

phy_isr_exit:
    /* Ensures IRQ is cleared */
    state = NRF_RADIO->SHORTS;

    /* Count # of interrupts */
    ++g_ble_phy_stats.phy_isrs;
}