static void ble_phy_rx_end_isr(void) { int rc; uint8_t *dptr; uint8_t crcok; struct ble_mbuf_hdr *ble_hdr; /* Clear events and clear interrupt */ NRF_RADIO->EVENTS_END = 0; NRF_RADIO->INTENCLR = RADIO_INTENCLR_END_Msk; /* Disable automatic RXEN */ NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; /* Set RSSI and CRC status flag in header */ ble_hdr = &g_ble_phy_data.rxhdr; assert(NRF_RADIO->EVENTS_RSSIEND != 0); ble_hdr->rxinfo.rssi = -1 * NRF_RADIO->RSSISAMPLE; dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; dptr += 3; /* Count PHY crc errors and valid packets */ crcok = (uint8_t)NRF_RADIO->CRCSTATUS; if (!crcok) { STATS_INC(ble_phy_stats, rx_crc_err); } else { STATS_INC(ble_phy_stats, rx_valid); ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK; #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1) if (g_ble_phy_data.phy_encrypted) { /* Only set MIC failure flag if frame is not zero length */ if ((dptr[1] != 0) && (NRF_CCM->MICSTATUS == 0)) { ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE; } /* * XXX: not sure how to deal with this. This should not * be a MIC failure but we should not hand it up. I guess * this is just some form of rx error and that is how we * handle it? For now, just set CRC error flags */ if (NRF_CCM->EVENTS_ERROR) { STATS_INC(ble_phy_stats, rx_hw_err); ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK; } /* * XXX: This is a total hack work-around for now but I dont * know what else to do. If ENDCRYPT is not set and we are * encrypted we need to not trust this frame and drop it. */ if (NRF_CCM->EVENTS_ENDCRYPT == 0) { STATS_INC(ble_phy_stats, rx_hw_err); ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK; } } #endif } /* * XXX: This is a horrible ugly hack to deal with the RAM S1 byte * that is not sent over the air but is present here. Simply move the * data pointer to deal with it. Fix this later. */ dptr[2] = dptr[1]; dptr[1] = dptr[0]; rc = ble_ll_rx_end(dptr + 1, ble_hdr); if (rc < 0) { ble_phy_disable(); } }
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; }