/**
 * 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);
    }
}
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;
}