You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by we...@apache.org on 2016/04/28 01:47:04 UTC

[1/2] incubator-mynewt-core git commit: MYNEWT-85: Fix BLE timing for start of connection events. MYNEWT-283: Slave anchor point now set correctly on CRC error.

Repository: incubator-mynewt-core
Updated Branches:
  refs/heads/develop f04731b06 -> 8ddc20eed


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/drivers/nrf52/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/nrf52/src/ble_phy.c b/net/nimble/drivers/nrf52/src/ble_phy.c
index cecbe60..609242c 100644
--- a/net/nimble/drivers/nrf52/src/ble_phy.c
+++ b/net/nimble/drivers/nrf52/src/ble_phy.c
@@ -21,6 +21,7 @@
 #include <string.h>
 #include <assert.h>
 #include "os/os.h"
+#include "ble/xcvr.h"
 #include "bsp/cmsis_nvic.h"
 #include "nimble/ble.h"
 #include "nimble/nimble_opt.h"
@@ -48,6 +49,7 @@
 /* Maximum length of frames */
 #define NRF_MAXLEN              (255)
 #define NRF_BALEN               (3)     /* For base address of 3 bytes */
+#define NRF_RX_START_OFFSET     (5)
 
 /* Maximum tx power */
 #define NRF_TX_PWR_MAX_DBM      (4)
@@ -63,6 +65,7 @@ struct ble_phy_obj
     uint8_t phy_transition;
     uint8_t phy_rx_started;
     uint8_t phy_encrypted;
+    uint8_t phy_tx_pyld_len;
     uint32_t phy_access_address;
     struct os_mbuf *rxpdu;
     void *txend_arg;
@@ -89,6 +92,7 @@ STATS_SECT_START(ble_phy_stats)
     STATS_SECT_ENTRY(rx_aborts)
     STATS_SECT_ENTRY(rx_valid)
     STATS_SECT_ENTRY(rx_crc_err)
+    STATS_SECT_ENTRY(rx_late)
     STATS_SECT_ENTRY(no_bufs)
     STATS_SECT_ENTRY(radio_state_errs)
     STATS_SECT_ENTRY(rx_hw_err)
@@ -106,6 +110,7 @@ STATS_NAME_START(ble_phy_stats)
     STATS_NAME(ble_phy_stats, rx_aborts)
     STATS_NAME(ble_phy_stats, rx_valid)
     STATS_NAME(ble_phy_stats, rx_crc_err)
+    STATS_NAME(ble_phy_stats, rx_late)
     STATS_NAME(ble_phy_stats, no_bufs)
     STATS_NAME(ble_phy_stats, radio_state_errs)
     STATS_NAME(ble_phy_stats, rx_hw_err)
@@ -220,8 +225,7 @@ nrf_wait_disabled(void)
 }
 
 /**
- * Setup transceiver for receive
- *
+ * Setup transceiver for receive.
  */
 static void
 ble_phy_rx_xcvr_setup(void)
@@ -245,6 +249,9 @@ ble_phy_rx_xcvr_setup(void)
     NRF_RADIO->PACKETPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data;
 #endif
 
+    /* We dont want to trigger TXEN on output compare match */
+    NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
+
     /* Reset the rx started flag. Used for the wait for response */
     g_ble_phy_data.phy_rx_started = 0;
     g_ble_phy_data.phy_state = BLE_PHY_STATE_RX;
@@ -280,7 +287,7 @@ ble_phy_tx_end_isr(void)
 
     /* Log the event */
     ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, (g_ble_phy_txrx_buf[0] >> 8) & 0xFF,
-               g_ble_phy_data.phy_encrypted, NRF_TIMER0->CC[2]);
+               g_ble_phy_data.phy_encrypted, NRF_TIMER0->CC[1]);
 
     /* Clear events and clear interrupt on disabled event */
     NRF_RADIO->EVENTS_DISABLED = 0;
@@ -313,14 +320,16 @@ ble_phy_tx_end_isr(void)
         }
 
         /*
-         * Enable the wait for response timer. Note that cc #2 on
-         * timer 0 contains the transmit end time
+         * Enable the wait for response timer. Note that cc #1 on
+         * timer 0 contains the transmit start time
          */
-        wfr_time = NRF_TIMER0->CC[2];
+        wfr_time = NRF_TIMER0->CC[1] - BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET);
+        wfr_time += BLE_TX_DUR_USECS_M(g_ble_phy_data.phy_tx_pyld_len);
         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! */
+        /* Disable automatic TXEN */
+        NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
         assert(transition == BLE_PHY_TRANSITION_NONE);
     }
 
@@ -331,147 +340,165 @@ ble_phy_tx_end_isr(void)
 }
 
 static void
-ble_phy_isr(void)
+ble_phy_rx_end_isr(void)
 {
     int rc;
-    uint8_t crcok;
-    uint32_t irq_en;
-    uint32_t state;
     uint8_t *dptr;
+    uint8_t crcok;
     struct os_mbuf *rxpdu;
     struct ble_mbuf_hdr *ble_hdr;
 
-    /* Read irq register to determine which interrupts are enabled */
-    irq_en = NRF_RADIO->INTENCLR;
+    /* Clear events and clear interrupt */
+    NRF_RADIO->EVENTS_END = 0;
+    NRF_RADIO->INTENCLR = RADIO_INTENCLR_END_Msk;
 
-    /* Check for disabled event. This only happens for transmits now */
-    if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) {
-        ble_phy_tx_end_isr();
-    }
+    /* Disable automatic RXEN */
+    NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
 
-    /* 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;
+    /* 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;
 
-        assert(g_ble_phy_data.rxpdu != NULL);
+    dptr = g_ble_phy_data.rxpdu->om_data;
+
+    /* 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;
+#ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
+        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;
+            }
 
-        /* Wait to get 1st byte of frame */
-        while (1) {
-            state = NRF_RADIO->STATE;
-            if (NRF_RADIO->EVENTS_BCMATCH != 0) {
-                break;
+            /*
+             * 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;
             }
 
             /*
-             * If state is disabled, we should have the BCMATCH. If not,
-             * something is wrong!
+             * 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 (state == RADIO_STATE_STATE_Disabled) {
-                NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
-                NRF_RADIO->SHORTS = 0;
-                goto phy_isr_exit;
+            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
+    }
 
-        /* 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) {
-            /* Set rx started flag and enable rx end ISR */
-            g_ble_phy_data.phy_rx_started = 1;
-            NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk;
-        } else {
-            /* Disable PHY */
-            ble_phy_disable();
-            irq_en = 0;
-            STATS_INC(ble_phy_stats, rx_aborts);
-        }
+    /* Call Link Layer receive payload function */
+    rxpdu = g_ble_phy_data.rxpdu;
+    g_ble_phy_data.rxpdu = NULL;
 
-        /* Count rx starts */
-        STATS_INC(ble_phy_stats, rx_starts);
+    /*
+     * 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. Do this in the nrf52
+     */
+    dptr[2] = dptr[1];
+    dptr[1] = dptr[0];
+    rxpdu->om_data += 1;
+
+    rc = ble_ll_rx_end(rxpdu, ble_hdr);
+    if (rc < 0) {
+        ble_phy_disable();
     }
+}
 
-    /* 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];
-        dptr = g_ble_phy_data.rxpdu->om_data;
-
-        /* 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;
-#ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
-            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
-        }
+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;
+
+    assert(g_ble_phy_data.rxpdu != NULL);
 
-        /* Call Link Layer receive payload function */
-        rxpdu = g_ble_phy_data.rxpdu;
-        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;
+        }
 
         /*
-         * 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. Do this in the nrf52
+         * If state is disabled, we should have the BCMATCH. If not,
+         * something is wrong!
          */
-        dptr[2] = dptr[1];
-        dptr[1] = dptr[0];
-        rxpdu->om_data += 1;
-
-        rc = ble_ll_rx_end(rxpdu, ble_hdr);
-        if (rc < 0) {
-            /* Disable the PHY. */
-            ble_phy_disable();
+        if (state == RADIO_STATE_STATE_Disabled) {
+            NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
+            NRF_RADIO->SHORTS = 0;
+            return;
         }
     }
 
-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;
+    ble_hdr->beg_cputime = NRF_TIMER0->CC[1] -
+        BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET);
+
+    /* 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) {
+        /* Set rx started flag and enable rx end ISR */
+        g_ble_phy_data.phy_rx_started = 1;
+        NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk;
+    } 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)
+{
+    uint32_t irq_en;
+
+    /* 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) {
+        ble_phy_tx_end_isr();
+    }
+
+    /* We get this if we have started to receive a frame */
+    if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO->EVENTS_ADDRESS) {
+        ble_phy_rx_start_isr();
+    }
+
+    /* Receive packet end (we dont enable this for transmit) */
+    if ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO->EVENTS_END) {
+        ble_phy_rx_end_isr();
+    }
+
     /* Ensures IRQ is cleared */
-    state = NRF_RADIO->SHORTS;
+    irq_en = NRF_RADIO->SHORTS;
 
     /* Count # of interrupts */
     STATS_INC(ble_phy_stats, phy_isrs);
@@ -538,11 +565,8 @@ ble_phy_init(void)
     /* Configure IFS */
     NRF_RADIO->TIFS = BLE_LL_IFS;
 
-    /*
-     * Enable the pre-programmed PPI to capture the time when a receive
-     * or transmit ends
-     */
-    NRF_PPI->CHENSET = PPI_CHEN_CH27_Msk;
+    /* Captures tx/rx start in timer0 capture 1 */
+    NRF_PPI->CHENSET = PPI_CHEN_CH26_Msk;
 
 #ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
     NRF_CCM->INTENCLR = 0xffffffff;
@@ -603,8 +627,12 @@ ble_phy_rx(void)
     /* Setup for rx */
     ble_phy_rx_xcvr_setup();
 
-    /* Start the receive task in the radio */
-    NRF_RADIO->TASKS_RXEN = 1;
+    /* Start the receive task in the radio if not automatically going to rx */
+    if ((NRF_PPI->CHEN & PPI_CHEN_CH21_Msk) == 0) {
+        NRF_RADIO->TASKS_RXEN = 1;
+    }
+
+    ble_ll_log(BLE_LL_LOG_ID_PHY_RX, g_ble_phy_data.phy_encrypted, 0, 0);
 
     return 0;
 }
@@ -656,11 +684,76 @@ ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg)
     g_ble_phy_data.txend_arg = arg;
 }
 
+/**
+ * Called to set the start time of a transmission.
+ *
+ * This function is called to set the start time when we are not going from
+ * rx to tx automatically.
+ *
+ * NOTE: care must be taken when calling this function. The channel should
+ * already be set.
+ *
+ * @param cputime
+ *
+ * @return int
+ */
+int
+ble_phy_tx_set_start_time(uint32_t cputime)
+{
+    int rc;
+
+    NRF_TIMER0->CC[0] = cputime;
+    NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk;
+    NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
+    if ((int32_t)(cputime_get32() - cputime) >= 0) {
+        STATS_INC(ble_phy_stats, tx_late);
+        ble_phy_disable();
+        rc =  BLE_PHY_ERR_TX_LATE;
+    } else {
+        rc = 0;
+    }
+    return rc;
+}
+
+/**
+ * Called to set the start time of a reception
+ *
+ * This function acts a bit differently than transmit. If we are late getting
+ * here we will still attempt to receive.
+ *
+ * NOTE: care must be taken when calling this function. The channel should
+ * already be set.
+ *
+ * @param cputime
+ *
+ * @return int
+ */
+int
+ble_phy_rx_set_start_time(uint32_t cputime)
+{
+    int rc;
+
+    NRF_TIMER0->CC[0] = cputime;
+    NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
+    NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk;
+    if ((int32_t)(cputime_get32() - cputime) >= 0) {
+        STATS_INC(ble_phy_stats, rx_late);
+        NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
+        NRF_RADIO->TASKS_RXEN = 1;
+        rc =  BLE_PHY_ERR_TX_LATE;
+    } else {
+        rc = 0;
+    }
+    return rc;
+}
+
+
 int
-ble_phy_tx(struct os_mbuf *txpdu, uint8_t beg_trans, uint8_t end_trans)
+ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
 {
     int rc;
     uint8_t *dptr;
+    uint8_t payload_len;
     uint32_t state;
     uint32_t shortcuts;
     struct ble_mbuf_hdr *ble_hdr;
@@ -668,37 +761,18 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t beg_trans, uint8_t end_trans)
     /* Better have a pdu! */
     assert(txpdu != NULL);
 
-    /* If radio is not disabled, */
+    /*
+     * This check is to make sure that the radio is not in a state where
+     * it is moving to disabled state. If so, let it get there.
+     */
     nrf_wait_disabled();
 
-    if (beg_trans == BLE_PHY_TRANSITION_RX_TX) {
-        if ((NRF_RADIO->SHORTS & RADIO_SHORTS_DISABLED_TXEN_Msk) == 0) {
-            assert(0);
-        }
-        /* Radio better be in TXRU state or we are in bad shape */
-        state = RADIO_STATE_STATE_TxRu;
-    } else {
-        /* Radio should be in disabled state */
-        state = RADIO_STATE_STATE_Disabled;
-    }
-
-    if (NRF_RADIO->STATE != state) {
-        ble_phy_disable();
-        STATS_INC(ble_phy_stats, radio_state_errs);
-        return BLE_PHY_ERR_RADIO_STATE;
-    }
+    ble_hdr = BLE_MBUF_HDR_PTR(txpdu);
+    payload_len = ble_hdr->txinfo.pyld_len;
 
 #ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
     if (g_ble_phy_data.phy_encrypted) {
-        /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */
-        ble_hdr = BLE_MBUF_HDR_PTR(txpdu);
         dptr = (uint8_t *)&g_ble_phy_enc_buf[0];
-        dptr[0] = ble_hdr->txinfo.hdr_byte;
-        dptr[1] = ble_hdr->txinfo.pyld_len;
-        dptr[2] = 0;
-        dptr += 3;
-
-        NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_txrx_buf[0];
         NRF_CCM->SHORTS = 1;
         NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0];
         NRF_CCM->OUTPTR = (uint32_t)&g_ble_phy_txrx_buf[0];
@@ -709,27 +783,18 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t beg_trans, uint8_t end_trans)
         NRF_PPI->CHENCLR = PPI_CHEN_CH25_Msk;
         NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk;
     } else {
-        /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */
-        ble_hdr = BLE_MBUF_HDR_PTR(txpdu);
         dptr = (uint8_t *)&g_ble_phy_txrx_buf[0];
-        dptr[0] = ble_hdr->txinfo.hdr_byte;
-        dptr[1] = ble_hdr->txinfo.pyld_len;
-        dptr[2] = 0;
-        dptr += 3;
-
-        NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_txrx_buf[0];
     }
 #else
-    /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */
-    ble_hdr = BLE_MBUF_HDR_PTR(txpdu);
     dptr = (uint8_t *)&g_ble_phy_txrx_buf[0];
+#endif
+
+    /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */
     dptr[0] = ble_hdr->txinfo.hdr_byte;
-    dptr[1] = ble_hdr->txinfo.pyld_len;
+    dptr[1] = payload_len;
     dptr[2] = 0;
     dptr += 3;
-
     NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_txrx_buf[0];
-#endif
 
     /* Clear the ready, end and disabled events */
     NRF_RADIO->EVENTS_READY = 0;
@@ -747,36 +812,26 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t beg_trans, uint8_t end_trans)
     NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
     NRF_RADIO->SHORTS = shortcuts;
 
-    /* Trigger transmit if our state was disabled */
-    if (state == RADIO_STATE_STATE_Disabled) {
-        NRF_RADIO->TASKS_TXEN = 1;
-    }
+    /* Set transmitted payload length */
+    g_ble_phy_data.phy_tx_pyld_len = payload_len;
 
     /* Set the PHY transition */
     g_ble_phy_data.phy_transition = end_trans;
 
-    /* Read back radio state. If in TXRU, we are fine */
+    /* If we already started transmitting, abort it! */
     state = NRF_RADIO->STATE;
-    if (state == RADIO_STATE_STATE_TxRu) {
+    if (state != RADIO_STATE_STATE_Tx) {
         /* Copy data from mbuf into transmit buffer */
-        os_mbuf_copydata(txpdu, ble_hdr->txinfo.offset,
-                         ble_hdr->txinfo.pyld_len, dptr);
+        os_mbuf_copydata(txpdu, ble_hdr->txinfo.offset, payload_len, dptr);
 
         /* Set phy state to transmitting and count packet statistics */
         g_ble_phy_data.phy_state = BLE_PHY_STATE_TX;
         STATS_INC(ble_phy_stats, tx_good);
-        STATS_INCN(ble_phy_stats, tx_bytes,
-                   ble_hdr->txinfo.pyld_len + BLE_LL_PDU_HDR_LEN);
+        STATS_INCN(ble_phy_stats, tx_bytes, payload_len + BLE_LL_PDU_HDR_LEN);
         rc = BLE_ERR_SUCCESS;
     } else {
-        if (state == RADIO_STATE_STATE_Tx) {
-            STATS_INC(ble_phy_stats, tx_late);
-        } else {
-            STATS_INC(ble_phy_stats, tx_fail);
-        }
-
-        /* Frame failed to transmit */
         ble_phy_disable();
+        STATS_INC(ble_phy_stats, tx_late);
         rc = BLE_PHY_ERR_RADIO_STATE;
     }
 
@@ -916,6 +971,7 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit)
  *  -> Turn off all phy interrupts.
  *  -> Disable internal shortcuts.
  *  -> Disable the radio.
+ *  -> Make sure we wont automatically go to rx/tx on output compare
  *  -> Sets phy state to idle.
  *  -> Clears any pending irqs in the NVIC. Might not be necessary but we do
  *  it as a precaution.
@@ -928,6 +984,7 @@ ble_phy_disable(void)
     NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
     NRF_RADIO->SHORTS = 0;
     NRF_RADIO->TASKS_DISABLE = 1;
+    NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk | PPI_CHEN_CH20_Msk;
     NVIC_ClearPendingIRQ(RADIO_IRQn);
     g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/include/nimble/ble.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/ble.h b/net/nimble/include/nimble/ble.h
index 894dff4..c0b5b74 100644
--- a/net/nimble/include/nimble/ble.h
+++ b/net/nimble/include/nimble/ble.h
@@ -88,7 +88,7 @@ struct ble_mbuf_hdr
         struct ble_mbuf_hdr_rxinfo rxinfo;
         struct ble_mbuf_hdr_txinfo txinfo;
     };
-    uint32_t end_cputime;
+    uint32_t beg_cputime;
 };
 
 /*


[2/2] incubator-mynewt-core git commit: MYNEWT-85: Fix BLE timing for start of connection events. MYNEWT-283: Slave anchor point now set correctly on CRC error.

Posted by we...@apache.org.
MYNEWT-85: Fix BLE timing for start of connection events.
MYNEWT-283: Slave anchor point now set correctly on CRC error.

Please read the respective tickets for a discussion of
the changes.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/8ddc20ee
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/8ddc20ee
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/8ddc20ee

Branch: refs/heads/develop
Commit: 8ddc20eed045e5d9d0abe6b0bd5d6af83f872dcf
Parents: f04731b
Author: William San Filippo <wi...@runtime.io>
Authored: Wed Apr 27 16:45:17 2016 -0700
Committer: William San Filippo <wi...@runtime.io>
Committed: Wed Apr 27 16:46:54 2016 -0700

----------------------------------------------------------------------
 apps/bletest/src/main.c                         |  39 +-
 hw/mcu/nordic/nrf51xxx/src/hal_cputime.c        | 225 +++++-----
 hw/mcu/nordic/nrf52xxx/src/hal_cputime.c        | 224 +++++-----
 .../controller/include/controller/ble_ll.h      |   5 +
 .../controller/include/controller/ble_phy.h     |  21 +-
 net/nimble/controller/pkg.yml                   |   1 +
 net/nimble/controller/src/ble_ll.c              |   2 +-
 net/nimble/controller/src/ble_ll_adv.c          |  34 +-
 net/nimble/controller/src/ble_ll_conn.c         |  86 ++--
 net/nimble/controller/src/ble_ll_scan.c         |   3 +-
 net/nimble/controller/src/ble_ll_sched.c        |   1 +
 net/nimble/drivers/native/src/ble_phy.c         |   2 +-
 net/nimble/drivers/nrf51/include/ble/xcvr.h     |  32 ++
 net/nimble/drivers/nrf51/src/ble_phy.c          | 419 ++++++++++--------
 net/nimble/drivers/nrf52/include/ble/xcvr.h     |  32 ++
 net/nimble/drivers/nrf52/src/ble_phy.c          | 423 +++++++++++--------
 net/nimble/include/nimble/ble.h                 |   2 +-
 17 files changed, 882 insertions(+), 669 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/apps/bletest/src/main.c
----------------------------------------------------------------------
diff --git a/apps/bletest/src/main.c b/apps/bletest/src/main.c
index 9510641..7218fd1 100755
--- a/apps/bletest/src/main.c
+++ b/apps/bletest/src/main.c
@@ -356,27 +356,30 @@ bletest_init_scanner(void)
 {
     int rc;
     uint8_t dev_addr[BLE_DEV_ADDR_LEN];
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_PARAM_LEN];
     uint8_t filter_policy;
 
-    /* Set scanning parameters */
-    rc = bletest_hci_le_set_scan_params(BLETEST_CFG_SCAN_TYPE,
-                                        BLETEST_CFG_SCAN_ITVL,
-                                        BLETEST_CFG_SCAN_WINDOW,
-                                        BLE_HCI_ADV_OWN_ADDR_PUBLIC,
-                                        BLETEST_CFG_SCAN_FILT_POLICY);
+    rc = host_hci_cmd_build_le_set_scan_params(BLETEST_CFG_SCAN_TYPE,
+                                               BLETEST_CFG_SCAN_ITVL,
+                                               BLETEST_CFG_SCAN_WINDOW,
+                                               BLE_HCI_ADV_OWN_ADDR_PUBLIC,
+                                               BLETEST_CFG_SCAN_FILT_POLICY,
+                                               buf, sizeof buf);
     assert(rc == 0);
-
-    filter_policy = BLETEST_CFG_SCAN_FILT_POLICY;
-    if (filter_policy & 1) {
-        /* Add some whitelist addresses */
-        dev_addr[0] = 0x00;
-        dev_addr[1] = 0x00;
-        dev_addr[2] = 0x00;
-        dev_addr[3] = 0x88;
-        dev_addr[4] = 0x88;
-        dev_addr[5] = 0x08;
-        rc = bletest_hci_le_add_to_whitelist(dev_addr, BLE_ADDR_TYPE_PUBLIC);
-        assert(rc == 0);
+    rc = ble_hci_cmd_tx_empty_ack(buf);
+    if (rc == 0) {
+        filter_policy = BLETEST_CFG_SCAN_FILT_POLICY;
+        if (filter_policy & 1) {
+            /* Add some whitelist addresses */
+            dev_addr[0] = 0x00;
+            dev_addr[1] = 0x00;
+            dev_addr[2] = 0x00;
+            dev_addr[3] = 0x88;
+            dev_addr[4] = 0x88;
+            dev_addr[5] = 0x08;
+            rc = bletest_hci_le_add_to_whitelist(dev_addr, BLE_ADDR_TYPE_PUBLIC);
+            assert(rc == 0);
+        }
     }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/hw/mcu/nordic/nrf51xxx/src/hal_cputime.c
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/nrf51xxx/src/hal_cputime.c b/hw/mcu/nordic/nrf51xxx/src/hal_cputime.c
index 2f1c4fa..eb12237 100644
--- a/hw/mcu/nordic/nrf51xxx/src/hal_cputime.c
+++ b/hw/mcu/nordic/nrf51xxx/src/hal_cputime.c
@@ -6,7 +6,7 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- * 
+ *
  *  http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
 #include <string.h>
 #include <stdint.h>
 #include <assert.h>
@@ -28,18 +29,15 @@
 /* Maximum timer frequency */
 #define NRF51_MAX_TIMER_FREQ    (16000000)
 
-/* 
- * Use these defines to select a timer and the compare channels. The reason
- * channel 2 is left open for TIMER0 is that there are pre-programmed PPI
- * channels that use timer 0 channel 2 for certain events. For example, the
- * radio has RADIO->EVENTS_END tied to capture channel 2. This can be
- * used to capture rx/tx end times.
- */
+#undef HAL_CPUTIME_USE_OVERFLOW
 
+/* The RF peripheral uses CC registers 0 and 1 for RF events. */
 #define CPUTIMER                NRF_TIMER0
 #define CPUTIMER_IRQ            (TIMER0_IRQn)
-#define CPUTIMER_CC_CNTR        (0)
-#define CPUTIMER_CC_OVERFLOW    (1)
+#define CPUTIMER_CC_CNTR        (2)
+#ifdef HAL_CPUTIME_USE_OVERFLOW
+#define CPUTIMER_CC_OVERFLOW    (2)
+#endif
 #define CPUTIMER_CC_INT         (3)
 
 /* Interrupt mask for interrupt enable/clear */
@@ -73,12 +71,12 @@ cputime_disable_ocmp(void)
 }
 
 /**
- * cputime set ocmp 
- *  
- * Set the OCMP used by the cputime module to the desired cputime. 
- *  
- * NOTE: Must be called with interrupts disabled. 
- * 
+ * cputime set ocmp
+ *
+ * Set the OCMP used by the cputime module to the desired cputime.
+ *
+ * NOTE: Must be called with interrupts disabled.
+ *
  * @param timer Pointer to timer.
  */
 static void
@@ -103,12 +101,12 @@ cputime_set_ocmp(struct cpu_timer *timer)
 }
 
 /**
- * cputime chk expiration 
- *  
- * Iterates through the cputimer queue to determine if any timers have expired. 
- * If the timer has expired the timer is removed from the queue and the timer 
- * callback function is executed. 
- * 
+ * cputime chk expiration
+ *
+ * Iterates through the cputimer queue to determine if any timers have expired.
+ * If the timer has expired the timer is removed from the queue and the timer
+ * callback function is executed.
+ *
  */
 static void
 cputime_chk_expiration(void)
@@ -138,37 +136,38 @@ cputime_chk_expiration(void)
 }
 
 /**
- * cputime isr 
- *  
- * This is the global timer interrupt routine. 
- * 
+ * cputime isr
+ *
+ * This is the global timer interrupt routine.
+ *
  */
 static void
 cputime_isr(void)
 {
     uint32_t compare;
+#ifdef HAL_CPUTIME_USE_OVERFLOW
     uint32_t overflow;
+#endif
 
     /* Check interrupt source. If set, clear them */
     compare = CPUTIMER->EVENTS_COMPARE[CPUTIMER_CC_INT];
     if (compare) {
         CPUTIMER->EVENTS_COMPARE[CPUTIMER_CC_INT] = 0;
     }
+
+#ifdef HAL_CPUTIME_USE_OVERFLOW
     overflow = CPUTIMER->EVENTS_COMPARE[CPUTIMER_CC_OVERFLOW];
     if (overflow) {
         CPUTIMER->EVENTS_COMPARE[CPUTIMER_CC_OVERFLOW] = 0;
+        ++g_cputime.uif_ints;
+        ++g_cputime.cputime_high;
     }
+#endif
 
     /* Count # of interrupts */
     ++g_cputime.timer_isrs;
 
-    /* If overflow, increment high word of cpu time */
-    if (overflow) {
-        ++g_cputime.uif_ints;
-        ++g_cputime.cputime_high;
-    }
-
-    /* 
+    /*
      * NOTE: we dont check the 'compare' variable here due to how the timer
      * is implemented on this chip. There is no way to force an output
      * compare, so if we are late setting the output compare (i.e. the timer
@@ -187,14 +186,14 @@ cputime_isr(void)
 }
 
 /**
- * cputime init 
- *  
- * Initialize the cputime module. This must be called after os_init is called 
- * and before any other timer API are used. This should be called only once 
- * and should be called before the hardware timer is used. 
- * 
+ * cputime init
+ *
+ * Initialize the cputime module. This must be called after os_init is called
+ * and before any other timer API are used. This should be called only once
+ * and should be called before the hardware timer is used.
+ *
  * @param clock_freq The desired cputime frequency, in hertz (Hz).
- * 
+ *
  * @return int 0 on success; -1 on error.
  */
 int
@@ -221,7 +220,7 @@ cputime_init(uint32_t clock_freq)
         return -1;
     }
 
-    /* 
+    /*
      * Pre-scaler is 4 bits and is a 2^n, so the only possible values that
      * work are 1, 2, 4, 8 and 16, which gives a valid pre-scaler of 0, 1, 2,
      * 3 or 4.
@@ -276,9 +275,11 @@ cputime_init(uint32_t clock_freq)
     CPUTIMER->TASKS_START = 1;
 
     /*  Use an output compare to generate an overflow */
+#ifdef HAL_CPUTIME_USE_OVERFLOW
     CPUTIMER->CC[CPUTIMER_CC_OVERFLOW] = 0;
     CPUTIMER->EVENTS_COMPARE[CPUTIMER_CC_OVERFLOW] = 0;
     CPUTIMER->INTENSET = CPUTIMER_INT_MASK(CPUTIMER_CC_OVERFLOW);
+#endif
 
     /* Set isr in vector table and enable interrupt */
     NVIC_SetVector(CPUTIMER_IRQ, (uint32_t)cputime_isr);
@@ -291,12 +292,13 @@ cputime_init(uint32_t clock_freq)
 
 /**
  * cputime get64
- *  
- * Returns cputime as a 64-bit number. 
- * 
+ *
+ * Returns cputime as a 64-bit number.
+ *
  * @return uint64_t The 64-bit representation of cputime.
  */
-uint64_t 
+#ifdef HAL_CPUTIME_USE_OVERFLOW
+uint64_t
 cputime_get64(void)
 {
     uint32_t ctx;
@@ -317,12 +319,13 @@ cputime_get64(void)
 
     return cpu_time;
 }
+#endif
 
 /**
- * cputime get32 
- *  
- * Returns the low 32 bits of cputime. 
- * 
+ * cputime get32
+ *
+ * Returns the low 32 bits of cputime.
+ *
  * @return uint32_t The lower 32 bits of cputime
  */
 uint32_t
@@ -338,15 +341,15 @@ cputime_get32(void)
 }
 
 /**
- * cputime nsecs to ticks 
- *  
- * Converts the given number of nanoseconds into cputime ticks. 
- * 
+ * cputime nsecs to ticks
+ *
+ * Converts the given number of nanoseconds into cputime ticks.
+ *
  * @param usecs The number of nanoseconds to convert to ticks
- * 
+ *
  * @return uint32_t The number of ticks corresponding to 'nsecs'
  */
-uint32_t 
+uint32_t
 cputime_nsecs_to_ticks(uint32_t nsecs)
 {
     uint32_t ticks;
@@ -357,34 +360,34 @@ cputime_nsecs_to_ticks(uint32_t nsecs)
 
 /**
  * cputime ticks to nsecs
- *  
- * Convert the given number of ticks into nanoseconds. 
- * 
+ *
+ * Convert the given number of ticks into nanoseconds.
+ *
  * @param ticks The number of ticks to convert to nanoseconds.
- * 
+ *
  * @return uint32_t The number of nanoseconds corresponding to 'ticks'
  */
-uint32_t 
+uint32_t
 cputime_ticks_to_nsecs(uint32_t ticks)
 {
     uint32_t nsecs;
 
-    nsecs = ((ticks * 1000) + (g_cputime.ticks_per_usec - 1)) / 
+    nsecs = ((ticks * 1000) + (g_cputime.ticks_per_usec - 1)) /
             g_cputime.ticks_per_usec;
 
     return nsecs;
 }
 
 /**
- * cputime usecs to ticks 
- *  
- * Converts the given number of microseconds into cputime ticks. 
- * 
+ * cputime usecs to ticks
+ *
+ * Converts the given number of microseconds into cputime ticks.
+ *
  * @param usecs The number of microseconds to convert to ticks
- * 
+ *
  * @return uint32_t The number of ticks corresponding to 'usecs'
  */
-uint32_t 
+uint32_t
 cputime_usecs_to_ticks(uint32_t usecs)
 {
     uint32_t ticks;
@@ -395,14 +398,14 @@ cputime_usecs_to_ticks(uint32_t usecs)
 
 /**
  * cputime ticks to usecs
- *  
- * Convert the given number of ticks into microseconds. 
- * 
+ *
+ * Convert the given number of ticks into microseconds.
+ *
  * @param ticks The number of ticks to convert to microseconds.
- * 
+ *
  * @return uint32_t The number of microseconds corresponding to 'ticks'
  */
-uint32_t 
+uint32_t
 cputime_ticks_to_usecs(uint32_t ticks)
 {
     uint32_t us;
@@ -413,12 +416,12 @@ cputime_ticks_to_usecs(uint32_t ticks)
 
 /**
  * cputime delay ticks
- *  
- * Wait until the number of ticks has elapsed. This is a blocking delay. 
- * 
+ *
+ * Wait until the number of ticks has elapsed. This is a blocking delay.
+ *
  * @param ticks The number of ticks to wait.
  */
-void 
+void
 cputime_delay_ticks(uint32_t ticks)
 {
     uint32_t until;
@@ -430,13 +433,13 @@ cputime_delay_ticks(uint32_t ticks)
 }
 
 /**
- * cputime delay nsecs 
- *  
- * Wait until 'nsecs' nanoseconds has elapsed. This is a blocking delay. 
- *  
+ * cputime delay nsecs
+ *
+ * Wait until 'nsecs' nanoseconds has elapsed. This is a blocking delay.
+ *
  * @param nsecs The number of nanoseconds to wait.
  */
-void 
+void
 cputime_delay_nsecs(uint32_t nsecs)
 {
     uint32_t ticks;
@@ -446,13 +449,13 @@ cputime_delay_nsecs(uint32_t nsecs)
 }
 
 /**
- * cputime delay usecs 
- *  
- * Wait until 'usecs' microseconds has elapsed. This is a blocking delay. 
- *  
+ * cputime delay usecs
+ *
+ * Wait until 'usecs' microseconds has elapsed. This is a blocking delay.
+ *
  * @param usecs The number of usecs to wait.
  */
-void 
+void
 cputime_delay_usecs(uint32_t usecs)
 {
     uint32_t ticks;
@@ -463,13 +466,13 @@ cputime_delay_usecs(uint32_t usecs)
 
 /**
  * cputime timer init
- * 
- * 
+ *
+ *
  * @param timer The timer to initialize. Cannot be NULL.
  * @param fp    The timer callback function. Cannot be NULL.
- * @param arg   Pointer to data object to pass to timer. 
+ * @param arg   Pointer to data object to pass to timer.
  */
-void 
+void
 cputime_timer_init(struct cpu_timer *timer, cputimer_func fp, void *arg)
 {
     assert(timer != NULL);
@@ -481,16 +484,16 @@ cputime_timer_init(struct cpu_timer *timer, cputimer_func fp, void *arg)
 }
 
 /**
- * cputime timer start 
- *  
- * Start a cputimer that will expire at 'cputime'. If cputime has already 
- * passed, the timer callback will still be called (at interrupt context). 
- * Cannot be called when the timer has already started. 
- * 
+ * cputime timer start
+ *
+ * Start a cputimer that will expire at 'cputime'. If cputime has already
+ * passed, the timer callback will still be called (at interrupt context).
+ * Cannot be called when the timer has already started.
+ *
  * @param timer     Pointer to timer to start. Cannot be NULL.
  * @param cputime   The cputime at which the timer should expire.
  */
-void 
+void
 cputime_timer_start(struct cpu_timer *timer, uint32_t cputime)
 {
     struct cpu_timer *entry;
@@ -508,7 +511,7 @@ cputime_timer_start(struct cpu_timer *timer, uint32_t cputime)
     } else {
         TAILQ_FOREACH(entry, &g_cputimer_q, link) {
             if ((int32_t)(timer->cputime - entry->cputime) < 0) {
-                TAILQ_INSERT_BEFORE(entry, timer, link);   
+                TAILQ_INSERT_BEFORE(entry, timer, link);
                 break;
             }
         }
@@ -526,15 +529,15 @@ cputime_timer_start(struct cpu_timer *timer, uint32_t cputime)
 }
 
 /**
- * cputimer timer relative 
- *  
- * Sets a cpu timer that will expire 'usecs' microseconds from the current 
- * cputime. 
- * 
+ * cputimer timer relative
+ *
+ * Sets a cpu timer that will expire 'usecs' microseconds from the current
+ * cputime.
+ *
  * @param timer Pointer to timer. Cannot be NULL.
  * @param usecs The number of usecs from now at which the timer will expire.
  */
-void 
+void
 cputime_timer_relative(struct cpu_timer *timer, uint32_t usecs)
 {
     uint32_t cputime;
@@ -546,15 +549,15 @@ cputime_timer_relative(struct cpu_timer *timer, uint32_t usecs)
 }
 
 /**
- * cputime timer stop 
- *  
- * Stops a cputimer from running. The timer is removed from the timer queue 
- * and interrupts are disabled if no timers are left on the queue. Can be 
- * called even if timer is not running. 
- * 
+ * cputime timer stop
+ *
+ * Stops a cputimer from running. The timer is removed from the timer queue
+ * and interrupts are disabled if no timers are left on the queue. Can be
+ * called even if timer is not running.
+ *
  * @param timer Pointer to cputimer to stop. Cannot be NULL.
  */
-void 
+void
 cputime_timer_stop(struct cpu_timer *timer)
 {
     int reset_ocmp;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/hw/mcu/nordic/nrf52xxx/src/hal_cputime.c
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/nrf52xxx/src/hal_cputime.c b/hw/mcu/nordic/nrf52xxx/src/hal_cputime.c
index 134a601..fbcc96d 100644
--- a/hw/mcu/nordic/nrf52xxx/src/hal_cputime.c
+++ b/hw/mcu/nordic/nrf52xxx/src/hal_cputime.c
@@ -6,7 +6,7 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- * 
+ *
  *  http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
@@ -29,18 +29,15 @@
 /* Maximum timer frequency */
 #define NRF52_MAX_TIMER_FREQ    (16000000)
 
-/* 
- * Use these defines to select a timer and the compare channels. The reason
- * channel 2 is left open for TIMER0 is that there are pre-programmed PPI
- * channels that use timer 0 channel 2 for certain events. For example, the
- * radio has RADIO->EVENTS_END tied to capture channel 2. This can be
- * used to capture rx/tx end times.
- */
+#undef HAL_CPUTIME_USE_OVERFLOW
 
+/* The RF peripheral uses CC registers 0 and 1 for RF events. */
 #define CPUTIMER                NRF_TIMER0
 #define CPUTIMER_IRQ            (TIMER0_IRQn)
-#define CPUTIMER_CC_CNTR        (0)
-#define CPUTIMER_CC_OVERFLOW    (1)
+#define CPUTIMER_CC_CNTR        (2)
+#ifdef HAL_CPUTIME_USE_OVERFLOW
+#define CPUTIMER_CC_OVERFLOW    (2)
+#endif
 #define CPUTIMER_CC_INT         (3)
 
 /* Interrupt mask for interrupt enable/clear */
@@ -74,12 +71,12 @@ cputime_disable_ocmp(void)
 }
 
 /**
- * cputime set ocmp 
- *  
- * Set the OCMP used by the cputime module to the desired cputime. 
- *  
- * NOTE: Must be called with interrupts disabled. 
- * 
+ * cputime set ocmp
+ *
+ * Set the OCMP used by the cputime module to the desired cputime.
+ *
+ * NOTE: Must be called with interrupts disabled.
+ *
  * @param timer Pointer to timer.
  */
 static void
@@ -104,12 +101,12 @@ cputime_set_ocmp(struct cpu_timer *timer)
 }
 
 /**
- * cputime chk expiration 
- *  
- * Iterates through the cputimer queue to determine if any timers have expired. 
- * If the timer has expired the timer is removed from the queue and the timer 
- * callback function is executed. 
- * 
+ * cputime chk expiration
+ *
+ * Iterates through the cputimer queue to determine if any timers have expired.
+ * If the timer has expired the timer is removed from the queue and the timer
+ * callback function is executed.
+ *
  */
 static void
 cputime_chk_expiration(void)
@@ -139,37 +136,38 @@ cputime_chk_expiration(void)
 }
 
 /**
- * cputime isr 
- *  
- * This is the global timer interrupt routine. 
- * 
+ * cputime isr
+ *
+ * This is the global timer interrupt routine.
+ *
  */
 static void
 cputime_isr(void)
 {
     uint32_t compare;
+#ifdef HAL_CPUTIME_USE_OVERFLOW
     uint32_t overflow;
+#endif
 
     /* Check interrupt source. If set, clear them */
     compare = CPUTIMER->EVENTS_COMPARE[CPUTIMER_CC_INT];
     if (compare) {
         CPUTIMER->EVENTS_COMPARE[CPUTIMER_CC_INT] = 0;
     }
+
+#ifdef HAL_CPUTIME_USE_OVERFLOW
     overflow = CPUTIMER->EVENTS_COMPARE[CPUTIMER_CC_OVERFLOW];
     if (overflow) {
         CPUTIMER->EVENTS_COMPARE[CPUTIMER_CC_OVERFLOW] = 0;
+        ++g_cputime.uif_ints;
+        ++g_cputime.cputime_high;
     }
+#endif
 
     /* Count # of interrupts */
     ++g_cputime.timer_isrs;
 
-    /* If overflow, increment high word of cpu time */
-    if (overflow) {
-        ++g_cputime.uif_ints;
-        ++g_cputime.cputime_high;
-    }
-
-    /* 
+    /*
      * NOTE: we dont check the 'compare' variable here due to how the timer
      * is implemented on this chip. There is no way to force an output
      * compare, so if we are late setting the output compare (i.e. the timer
@@ -188,14 +186,14 @@ cputime_isr(void)
 }
 
 /**
- * cputime init 
- *  
- * Initialize the cputime module. This must be called after os_init is called 
- * and before any other timer API are used. This should be called only once 
- * and should be called before the hardware timer is used. 
- * 
+ * cputime init
+ *
+ * Initialize the cputime module. This must be called after os_init is called
+ * and before any other timer API are used. This should be called only once
+ * and should be called before the hardware timer is used.
+ *
  * @param clock_freq The desired cputime frequency, in hertz (Hz).
- * 
+ *
  * @return int 0 on success; -1 on error.
  */
 int
@@ -222,7 +220,7 @@ cputime_init(uint32_t clock_freq)
         return -1;
     }
 
-    /* 
+    /*
      * Pre-scaler is 4 bits and is a 2^n, so the only possible values that
      * work are 1, 2, 4, 8 and 16, which gives a valid pre-scaler of 0, 1, 2,
      * 3 or 4.
@@ -277,9 +275,11 @@ cputime_init(uint32_t clock_freq)
     CPUTIMER->TASKS_START = 1;
 
     /*  Use an output compare to generate an overflow */
+#ifdef HAL_CPUTIME_USE_OVERFLOW
     CPUTIMER->CC[CPUTIMER_CC_OVERFLOW] = 0;
     CPUTIMER->EVENTS_COMPARE[CPUTIMER_CC_OVERFLOW] = 0;
     CPUTIMER->INTENSET = CPUTIMER_INT_MASK(CPUTIMER_CC_OVERFLOW);
+#endif
 
     /* Set isr in vector table and enable interrupt */
     NVIC_SetVector(CPUTIMER_IRQ, (uint32_t)cputime_isr);
@@ -292,12 +292,13 @@ cputime_init(uint32_t clock_freq)
 
 /**
  * cputime get64
- *  
- * Returns cputime as a 64-bit number. 
- * 
+ *
+ * Returns cputime as a 64-bit number.
+ *
  * @return uint64_t The 64-bit representation of cputime.
  */
-uint64_t 
+#ifdef HAL_CPUTIME_USE_OVERFLOW
+uint64_t
 cputime_get64(void)
 {
     uint32_t ctx;
@@ -318,12 +319,13 @@ cputime_get64(void)
 
     return cpu_time;
 }
+#endif
 
 /**
- * cputime get32 
- *  
- * Returns the low 32 bits of cputime. 
- * 
+ * cputime get32
+ *
+ * Returns the low 32 bits of cputime.
+ *
  * @return uint32_t The lower 32 bits of cputime
  */
 uint32_t
@@ -339,15 +341,15 @@ cputime_get32(void)
 }
 
 /**
- * cputime nsecs to ticks 
- *  
- * Converts the given number of nanoseconds into cputime ticks. 
- * 
+ * cputime nsecs to ticks
+ *
+ * Converts the given number of nanoseconds into cputime ticks.
+ *
  * @param usecs The number of nanoseconds to convert to ticks
- * 
+ *
  * @return uint32_t The number of ticks corresponding to 'nsecs'
  */
-uint32_t 
+uint32_t
 cputime_nsecs_to_ticks(uint32_t nsecs)
 {
     uint32_t ticks;
@@ -358,34 +360,34 @@ cputime_nsecs_to_ticks(uint32_t nsecs)
 
 /**
  * cputime ticks to nsecs
- *  
- * Convert the given number of ticks into nanoseconds. 
- * 
+ *
+ * Convert the given number of ticks into nanoseconds.
+ *
  * @param ticks The number of ticks to convert to nanoseconds.
- * 
+ *
  * @return uint32_t The number of nanoseconds corresponding to 'ticks'
  */
-uint32_t 
+uint32_t
 cputime_ticks_to_nsecs(uint32_t ticks)
 {
     uint32_t nsecs;
 
-    nsecs = ((ticks * 1000) + (g_cputime.ticks_per_usec - 1)) / 
+    nsecs = ((ticks * 1000) + (g_cputime.ticks_per_usec - 1)) /
             g_cputime.ticks_per_usec;
 
     return nsecs;
 }
 
 /**
- * cputime usecs to ticks 
- *  
- * Converts the given number of microseconds into cputime ticks. 
- * 
+ * cputime usecs to ticks
+ *
+ * Converts the given number of microseconds into cputime ticks.
+ *
  * @param usecs The number of microseconds to convert to ticks
- * 
+ *
  * @return uint32_t The number of ticks corresponding to 'usecs'
  */
-uint32_t 
+uint32_t
 cputime_usecs_to_ticks(uint32_t usecs)
 {
     uint32_t ticks;
@@ -396,14 +398,14 @@ cputime_usecs_to_ticks(uint32_t usecs)
 
 /**
  * cputime ticks to usecs
- *  
- * Convert the given number of ticks into microseconds. 
- * 
+ *
+ * Convert the given number of ticks into microseconds.
+ *
  * @param ticks The number of ticks to convert to microseconds.
- * 
+ *
  * @return uint32_t The number of microseconds corresponding to 'ticks'
  */
-uint32_t 
+uint32_t
 cputime_ticks_to_usecs(uint32_t ticks)
 {
     uint32_t us;
@@ -414,12 +416,12 @@ cputime_ticks_to_usecs(uint32_t ticks)
 
 /**
  * cputime delay ticks
- *  
- * Wait until the number of ticks has elapsed. This is a blocking delay. 
- * 
+ *
+ * Wait until the number of ticks has elapsed. This is a blocking delay.
+ *
  * @param ticks The number of ticks to wait.
  */
-void 
+void
 cputime_delay_ticks(uint32_t ticks)
 {
     uint32_t until;
@@ -431,13 +433,13 @@ cputime_delay_ticks(uint32_t ticks)
 }
 
 /**
- * cputime delay nsecs 
- *  
- * Wait until 'nsecs' nanoseconds has elapsed. This is a blocking delay. 
- *  
+ * cputime delay nsecs
+ *
+ * Wait until 'nsecs' nanoseconds has elapsed. This is a blocking delay.
+ *
  * @param nsecs The number of nanoseconds to wait.
  */
-void 
+void
 cputime_delay_nsecs(uint32_t nsecs)
 {
     uint32_t ticks;
@@ -447,13 +449,13 @@ cputime_delay_nsecs(uint32_t nsecs)
 }
 
 /**
- * cputime delay usecs 
- *  
- * Wait until 'usecs' microseconds has elapsed. This is a blocking delay. 
- *  
+ * cputime delay usecs
+ *
+ * Wait until 'usecs' microseconds has elapsed. This is a blocking delay.
+ *
  * @param usecs The number of usecs to wait.
  */
-void 
+void
 cputime_delay_usecs(uint32_t usecs)
 {
     uint32_t ticks;
@@ -464,13 +466,13 @@ cputime_delay_usecs(uint32_t usecs)
 
 /**
  * cputime timer init
- * 
- * 
+ *
+ *
  * @param timer The timer to initialize. Cannot be NULL.
  * @param fp    The timer callback function. Cannot be NULL.
- * @param arg   Pointer to data object to pass to timer. 
+ * @param arg   Pointer to data object to pass to timer.
  */
-void 
+void
 cputime_timer_init(struct cpu_timer *timer, cputimer_func fp, void *arg)
 {
     assert(timer != NULL);
@@ -482,16 +484,16 @@ cputime_timer_init(struct cpu_timer *timer, cputimer_func fp, void *arg)
 }
 
 /**
- * cputime timer start 
- *  
- * Start a cputimer that will expire at 'cputime'. If cputime has already 
- * passed, the timer callback will still be called (at interrupt context). 
- * Cannot be called when the timer has already started. 
- * 
+ * cputime timer start
+ *
+ * Start a cputimer that will expire at 'cputime'. If cputime has already
+ * passed, the timer callback will still be called (at interrupt context).
+ * Cannot be called when the timer has already started.
+ *
  * @param timer     Pointer to timer to start. Cannot be NULL.
  * @param cputime   The cputime at which the timer should expire.
  */
-void 
+void
 cputime_timer_start(struct cpu_timer *timer, uint32_t cputime)
 {
     struct cpu_timer *entry;
@@ -509,7 +511,7 @@ cputime_timer_start(struct cpu_timer *timer, uint32_t cputime)
     } else {
         TAILQ_FOREACH(entry, &g_cputimer_q, link) {
             if ((int32_t)(timer->cputime - entry->cputime) < 0) {
-                TAILQ_INSERT_BEFORE(entry, timer, link);   
+                TAILQ_INSERT_BEFORE(entry, timer, link);
                 break;
             }
         }
@@ -527,15 +529,15 @@ cputime_timer_start(struct cpu_timer *timer, uint32_t cputime)
 }
 
 /**
- * cputimer timer relative 
- *  
- * Sets a cpu timer that will expire 'usecs' microseconds from the current 
- * cputime. 
- * 
+ * cputimer timer relative
+ *
+ * Sets a cpu timer that will expire 'usecs' microseconds from the current
+ * cputime.
+ *
  * @param timer Pointer to timer. Cannot be NULL.
  * @param usecs The number of usecs from now at which the timer will expire.
  */
-void 
+void
 cputime_timer_relative(struct cpu_timer *timer, uint32_t usecs)
 {
     uint32_t cputime;
@@ -547,15 +549,15 @@ cputime_timer_relative(struct cpu_timer *timer, uint32_t usecs)
 }
 
 /**
- * cputime timer stop 
- *  
- * Stops a cputimer from running. The timer is removed from the timer queue 
- * and interrupts are disabled if no timers are left on the queue. Can be 
- * called even if timer is not running. 
- * 
+ * cputime timer stop
+ *
+ * Stops a cputimer from running. The timer is removed from the timer queue
+ * and interrupts are disabled if no timers are left on the queue. Can be
+ * called even if timer is not running.
+ *
  * @param timer Pointer to cputimer to stop. Cannot be NULL.
  */
-void 
+void
 cputime_timer_stop(struct cpu_timer *timer)
 {
     int reset_ocmp;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/controller/include/controller/ble_ll.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll.h b/net/nimble/controller/include/controller/ble_ll.h
index 60a8408..e579a26 100644
--- a/net/nimble/controller/include/controller/ble_ll.h
+++ b/net/nimble/controller/include/controller/ble_ll.h
@@ -201,6 +201,9 @@ struct ble_dev_addr
  */
 #define BLE_TX_DUR_USECS_M(len)     (((len) + BLE_LL_PDU_OVERHEAD) << 3)
 
+/* Calculates the time it takes to transmit 'len' bytes */
+#define BLE_TX_LEN_USECS_M(len)     ((len) << 3)
+
 /* Access address for advertising channels */
 #define BLE_ACCESS_ADDR_ADV             (0x8E89BED6)
 
@@ -373,6 +376,8 @@ int ble_ll_rand_start(void);
 #define BLE_LL_LOG_ID_RX_END            (3)
 #define BLE_LL_LOG_ID_WFR_EXP           (4)
 #define BLE_LL_LOG_ID_PHY_TXEND         (5)
+#define BLE_LL_LOG_ID_PHY_TX            (6)
+#define BLE_LL_LOG_ID_PHY_RX            (7)
 #define BLE_LL_LOG_ID_PHY_DISABLE       (9)
 #define BLE_LL_LOG_ID_CONN_EV_START     (10)
 #define BLE_LL_LOG_ID_CONN_TX           (15)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/controller/include/controller/ble_phy.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_phy.h b/net/nimble/controller/include/controller/ble_phy.h
index 88373c2..af31dbd 100644
--- a/net/nimble/controller/include/controller/ble_phy.h
+++ b/net/nimble/controller/include/controller/ble_phy.h
@@ -23,18 +23,6 @@
 /* Forward declarations */
 struct os_mbuf;
 
-/*
- * XXX: Transceiver definitions. These dont belong here and will be moved
- * once we finalize transceiver specific support.
- */
-#define XCVR_RX_START_DELAY_USECS     (140)
-#define XCVR_TX_START_DELAY_USECS     (140)
-#define XCVR_PROC_DELAY_USECS         (50)
-#define XCVR_TX_SCHED_DELAY_USECS     \
-    (XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
-#define XCVR_RX_SCHED_DELAY_USECS     \
-    (XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
-
 /* Channel/Frequency defintions */
 #define BLE_PHY_NUM_CHANS           (40)
 #define BLE_PHY_NUM_DATA_CHANS      (37)
@@ -77,6 +65,7 @@ struct os_mbuf;
 #define BLE_PHY_ERR_INIT            (2)
 #define BLE_PHY_ERR_INV_PARAM       (3)
 #define BLE_PHY_ERR_NO_BUFS         (4)
+#define BLE_PHY_ERR_TX_LATE         (5)
 
 /* Maximun PDU length. Includes LL header of 2 bytes and 255 bytes payload. */
 #define BLE_PHY_MAX_PDU_LEN         (257)
@@ -93,11 +82,17 @@ int ble_phy_reset(void);
 /* Set the PHY channel */
 int ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit);
 
+/* Set transmit start time */
+int ble_phy_tx_set_start_time(uint32_t cputime);
+
+/* Set receive start time */
+int ble_phy_rx_set_start_time(uint32_t cputime);
+
 /* Set the transmit end callback and argument */
 void ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg);
 
 /* Place the PHY into transmit mode */
-int ble_phy_tx(struct os_mbuf *txpdu, uint8_t beg_trans, uint8_t end_trans);
+int ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans);
 
 /* Place the PHY into receive mode */
 int ble_phy_rx(void);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/controller/pkg.yml
----------------------------------------------------------------------
diff --git a/net/nimble/controller/pkg.yml b/net/nimble/controller/pkg.yml
index f9c3eae..07a9d56 100644
--- a/net/nimble/controller/pkg.yml
+++ b/net/nimble/controller/pkg.yml
@@ -25,6 +25,7 @@ pkg.keywords:
     - ble
     - bluetooth
 
+pkg.req_apis: ble_driver
 pkg.deps:
     - libs/os
     - sys/stats

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/controller/src/ble_ll.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll.c b/net/nimble/controller/src/ble_ll.c
index 003d594..a5ba967 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -737,7 +737,7 @@ ble_ll_rx_end(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *ble_hdr)
 
     ble_ll_log(BLE_LL_LOG_ID_RX_END, rxbuf[0],
                ((uint16_t)ble_hdr->rxinfo.flags << 8) | rxbuf[1],
-               (BLE_MBUF_HDR_PTR(rxpdu))->end_cputime);
+               (BLE_MBUF_HDR_PTR(rxpdu))->beg_cputime);
 
     /* Check channel type */
     if (chan < BLE_PHY_NUM_DATA_CHANS) {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/controller/src/ble_ll_adv.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_adv.c b/net/nimble/controller/src/ble_ll_adv.c
index d6a208a..4d45f16 100644
--- a/net/nimble/controller/src/ble_ll_adv.c
+++ b/net/nimble/controller/src/ble_ll_adv.c
@@ -21,6 +21,7 @@
 #include <assert.h>
 #include "os/os.h"
 #include "bsp/bsp.h"
+#include "ble/xcvr.h"
 #include "nimble/ble.h"
 #include "nimble/nimble_opt.h"
 #include "nimble/hci_common.h"
@@ -343,7 +344,7 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch)
 {
     int rc;
     uint8_t end_trans;
-    uint32_t start_time;
+    uint32_t txstart;
     struct ble_ll_adv_sm *advsm;
 
     /* Get the state machine for the event */
@@ -353,6 +354,15 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch)
     rc = ble_phy_setchan(advsm->adv_chan, 0, 0);
     assert(rc == 0);
 
+    /* Set transmit start time. */
+    txstart = sch->start_time + XCVR_PROC_DELAY_USECS;
+    rc = ble_phy_tx_set_start_time(txstart);
+    if (rc) {
+        STATS_INC(ble_ll_stats, adv_late_starts);
+        ble_ll_adv_tx_done(advsm);
+        return BLE_LL_SCHED_STATE_DONE;
+    }
+
 #ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
     ble_phy_encrypt_disable();
 #endif
@@ -366,23 +376,12 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch)
         ble_phy_set_txend_cb(NULL, NULL);
     }
 
-    /* This is for debug */
-    start_time = cputime_get32();
-
-    /* XXX: transmit using an output compare */
     /* Transmit advertisement */
-    rc = ble_phy_tx(advsm->adv_pdu, BLE_PHY_TRANSITION_NONE, end_trans);
+    rc = ble_phy_tx(advsm->adv_pdu, end_trans);
     if (rc) {
-        /* Transmit failed. */
         ble_ll_adv_tx_done(advsm);
         rc =  BLE_LL_SCHED_STATE_DONE;
     } else {
-        /* Check if we were late getting here */
-        if ((int32_t)(start_time - (advsm->adv_pdu_start_time -
-               cputime_usecs_to_ticks(XCVR_TX_START_DELAY_USECS))) > 0) {
-            STATS_INC(ble_ll_stats, adv_late_starts);
-        }
-
         /* Enable/disable whitelisting based on filter policy */
         if (advsm->adv_filter_policy != BLE_HCI_ADV_FILT_NONE) {
             ble_ll_whitelist_enable();
@@ -878,8 +877,7 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu)
     rc = -1;
     if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) {
         ble_phy_set_txend_cb(ble_ll_adv_tx_done, &g_ble_ll_adv_sm);
-        rc = ble_phy_tx(advsm->scan_rsp_pdu, BLE_PHY_TRANSITION_RX_TX,
-                        BLE_PHY_TRANSITION_NONE);
+        rc = ble_phy_tx(advsm->scan_rsp_pdu, BLE_PHY_TRANSITION_NONE);
         if (!rc) {
             ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_SCAN_RSP_TXD;
             STATS_INC(ble_ll_stats, scan_rsp_txg);
@@ -903,7 +901,9 @@ 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. */
@@ -937,7 +937,9 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
 
     if (valid) {
         /* Try to start slave connection. If successful, stop advertising */
-        valid = ble_ll_conn_slave_start(rxbuf, hdr->end_cputime);
+        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);
         }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/controller/src/ble_ll_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn.c b/net/nimble/controller/src/ble_ll_conn.c
index 05b2c6c..07e7fad 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -25,6 +25,7 @@
 #include "nimble/ble.h"
 #include "nimble/nimble_opt.h"
 #include "nimble/hci_common.h"
+#include "ble/xcvr.h"
 #include "controller/ble_ll.h"
 #include "controller/ble_ll_hci.h"
 #include "controller/ble_ll_scan.h"
@@ -740,7 +741,7 @@ ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm)
  * @return int 0: success; otherwise failure to transmit
  */
 static int
-ble_ll_conn_tx_data_pdu(struct ble_ll_conn_sm *connsm, int beg_transition)
+ble_ll_conn_tx_data_pdu(struct ble_ll_conn_sm *connsm)
 {
     int rc;
     uint8_t md;
@@ -1049,7 +1050,7 @@ conn_tx_pdu:
 
     /* Set transmit end callback */
     ble_phy_set_txend_cb(txend_func, connsm);
-    rc = ble_phy_tx(m, beg_transition, end_transition);
+    rc = ble_phy_tx(m, end_transition);
     if (!rc) {
         /* Log transmit on connection state */
         cur_txlen = ble_hdr->txinfo.pyld_len;
@@ -1115,21 +1116,28 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
                     connsm->crcinit);
 
     if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+        /* Set start time of transmission */
+        rc = ble_phy_tx_set_start_time(sch->start_time + XCVR_PROC_DELAY_USECS);
+        if (!rc) {
 #ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
-        if (CONN_F_ENCRYPTED(connsm)) {
-            ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr,
-                                   connsm->enc_data.iv,
-                                   connsm->enc_data.enc_block.cipher_text,
-                                   1);
-        } else {
-            ble_phy_encrypt_disable();
-        }
+            if (CONN_F_ENCRYPTED(connsm)) {
+                ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr,
+                                       connsm->enc_data.iv,
+                                       connsm->enc_data.enc_block.cipher_text,
+                                       1);
+            } else {
+                ble_phy_encrypt_disable();
+            }
 #endif
-        rc = ble_ll_conn_tx_data_pdu(connsm, BLE_PHY_TRANSITION_NONE);
-        if (!rc) {
-            rc = BLE_LL_SCHED_STATE_RUNNING;
+            rc = ble_ll_conn_tx_data_pdu(connsm);
+            if (!rc) {
+                rc = BLE_LL_SCHED_STATE_RUNNING;
+            } else {
+                /* Inform LL task of connection event end */
+                rc = BLE_LL_SCHED_STATE_DONE;
+            }
         } else {
-            /* Inform LL task of connection event end */
+            STATS_INC(ble_ll_conn_stats, conn_ev_late);
             rc = BLE_LL_SCHED_STATE_DONE;
         }
     } else {
@@ -1143,6 +1151,10 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
                 ble_phy_encrypt_disable();
             }
 #endif
+        /*
+         * XXX: make sure I dont care that I get here early to start receiving.
+         * I could use events compare and all that shit to start rx.
+         */
         rc = ble_phy_rx();
         if (rc) {
             /* End the connection event as we have no more buffers */
@@ -1938,7 +1950,7 @@ ble_ll_conn_request_send(uint8_t addr_type, uint8_t *adva, uint16_t txoffset)
     m = ble_ll_scan_get_pdu();
     ble_ll_conn_req_pdu_update(m, adva, addr_type, txoffset);
     ble_phy_set_txend_cb(ble_ll_conn_req_txend, NULL);
-    rc = ble_phy_tx(m, BLE_PHY_TRANSITION_RX_TX, BLE_PHY_TRANSITION_NONE);
+    rc = ble_phy_tx(m, BLE_PHY_TRANSITION_NONE);
     return rc;
 }
 
@@ -1973,6 +1985,8 @@ void
 ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr)
 {
     uint8_t addr_type;
+    uint8_t payload_len;
+    uint32_t endtime;
     struct ble_ll_conn_sm *connsm;
 
     /* Get the connection state machine we are trying to create */
@@ -2002,7 +2016,9 @@ ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr)
         /* Connection has been created. Stop scanning */
         g_ble_ll_conn_create_sm = NULL;
         ble_ll_scan_sm_stop(0);
-        ble_ll_conn_created(connsm, ble_hdr->end_cputime);
+        payload_len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK;;
+        endtime = ble_hdr->beg_cputime + BLE_TX_DUR_USECS_M(payload_len);
+        ble_ll_conn_created(connsm, endtime);
     } else {
         ble_ll_scan_chk_resume();
     }
@@ -2030,6 +2046,8 @@ ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
     uint8_t *adv_addr;
     uint8_t *init_addr;
     uint8_t *rxbuf;
+    uint8_t pyld_len;
+    uint32_t endtime;
     struct ble_mbuf_hdr *ble_hdr;
 
     /*
@@ -2049,6 +2067,7 @@ ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
     /* Only interested in ADV IND or ADV DIRECT IND */
     rxbuf = rxpdu->om_data;
     pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
+    pyld_len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK;
 
     switch (pdu_type) {
     case BLE_ADV_PDU_TYPE_ADV_IND:
@@ -2098,8 +2117,8 @@ ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
         }
 
         /* Attempt to schedule new connection. Possible that this might fail */
-        if (!ble_ll_sched_master_new(g_ble_ll_conn_create_sm,
-                                     ble_hdr->end_cputime,
+        endtime = ble_hdr->beg_cputime + BLE_TX_DUR_USECS_M(pyld_len);
+        if (!ble_ll_sched_master_new(g_ble_ll_conn_create_sm, endtime,
                                      NIMBLE_OPT_LL_CONN_INIT_SLOTS)) {
             /* Setup to transmit the connect request */
             rc = ble_ll_conn_request_send(addr_type, adv_addr,
@@ -2339,7 +2358,8 @@ ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu, uint32_t aa)
     uint8_t reply;
     uint8_t rem_bytes;
     uint8_t opcode;
-    uint32_t ticks;
+    uint8_t pyld_len;
+    uint32_t endtime;
     struct os_mbuf *txpdu;
     struct ble_ll_conn_sm *connsm;
     struct ble_mbuf_hdr *rxhdr;
@@ -2365,6 +2385,8 @@ ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu, uint32_t aa)
     /* Set the handle in the ble mbuf header */
     rxhdr = BLE_MBUF_HDR_PTR(rxpdu);
     rxhdr->rxinfo.handle = connsm->conn_handle;
+    hdr_byte = rxpdu->om_data[0];
+    pyld_len = rxpdu->om_data[1];
 
     /*
      * Check the packet CRC. A connection event can continue even if the
@@ -2391,9 +2413,6 @@ ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu, uint32_t aa)
         /* Reset consecutively received bad crcs (since this one was good!) */
         connsm->cons_rxd_bad_crc = 0;
 
-        /* Store received header byte in state machine  */
-        hdr_byte = rxpdu->om_data[0];
-
         /* Check for valid LLID before proceeding. */
         if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == 0) {
             /*
@@ -2534,7 +2553,8 @@ chk_rx_terminate_ind:
 
     /* If reply flag set, send data pdu and continue connection event */
     rc = -1;
-    if (reply && ble_ll_conn_can_send_next_pdu(connsm, rxhdr->end_cputime)) {
+    endtime = rxhdr->beg_cputime + BLE_TX_DUR_USECS_M(pyld_len);
+    if (reply && ble_ll_conn_can_send_next_pdu(connsm, endtime)) {
         /*
          * While this is not perfect, we will just check to see if the
          * terminate timer will expire within two packet times. If it will,
@@ -2544,28 +2564,22 @@ chk_rx_terminate_ind:
          *  XXX: should we just skip this check?
          */
         if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_TERMINATE)) {
-            ticks = BLE_TX_DUR_USECS_M(0) +
-                BLE_TX_DUR_USECS_M(BLE_LL_CTRL_TERMINATE_IND_LEN + 1) +
-                BLE_LL_IFS;
-            ticks = cputime_usecs_to_ticks(ticks) + cputime_get32();
-            if ((int32_t)(connsm->terminate_timeout - ticks) < 0) {
+            endtime = BLE_TX_DUR_USECS_M(BLE_LL_CTRL_TERMINATE_IND_LEN + 1) +
+                      BLE_TX_DUR_USECS_M(0) + BLE_LL_IFS;
+            endtime = cputime_usecs_to_ticks(endtime) + cputime_get32();
+            if ((int32_t)(connsm->terminate_timeout - endtime) < 0) {
                 goto conn_rx_pdu_end;
             }
         }
-        rc = ble_ll_conn_tx_data_pdu(connsm, BLE_PHY_TRANSITION_RX_TX);
+        rc = ble_ll_conn_tx_data_pdu(connsm);
     }
 
 conn_rx_pdu_end:
     /* Set anchor point (and last) if 1st received frame in connection event */
     if (connsm->csmflags.cfbit.slave_set_last_anchor) {
         connsm->csmflags.cfbit.slave_set_last_anchor = 0;
-        /* XXX: For now, we just wont adjust the anchor point on crc error
-           until I fix this issue */
-        if (BLE_MBUF_HDR_CRC_OK(rxhdr)) {
-            connsm->last_anchor_point = rxhdr->end_cputime -
-                cputime_usecs_to_ticks(BLE_TX_DUR_USECS_M(rxpdu->om_data[1]));
-            connsm->anchor_point = connsm->last_anchor_point;
-        }
+        connsm->last_anchor_point = rxhdr->beg_cputime;
+        connsm->anchor_point = connsm->last_anchor_point;
     }
 
     /* Send link layer a connection end event if over */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/controller/src/ble_ll_scan.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_scan.c b/net/nimble/controller/src/ble_ll_scan.c
index dbcc63a..94a33e3 100644
--- a/net/nimble/controller/src/ble_ll_scan.c
+++ b/net/nimble/controller/src/ble_ll_scan.c
@@ -915,8 +915,7 @@ ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
         if (scansm->backoff_count == 0) {
             /* Setup to transmit the scan request */
             ble_ll_scan_req_pdu_make(scansm, adv_addr, addr_type);
-            rc = ble_phy_tx(scansm->scan_req_pdu, BLE_PHY_TRANSITION_RX_TX,
-                            BLE_PHY_TRANSITION_TX_RX);
+            rc = ble_phy_tx(scansm->scan_req_pdu, BLE_PHY_TRANSITION_TX_RX);
 
             /* Set "waiting for scan response" flag */
             scansm->scan_rsp_pending = 1;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/controller/src/ble_ll_sched.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_sched.c b/net/nimble/controller/src/ble_ll_sched.c
index 9b0ccea..82f4189 100644
--- a/net/nimble/controller/src/ble_ll_sched.c
+++ b/net/nimble/controller/src/ble_ll_sched.c
@@ -20,6 +20,7 @@
 #include <assert.h>
 #include <string.h>
 #include "os/os.h"
+#include "ble/xcvr.h"
 #include "controller/ble_phy.h"
 #include "controller/ble_ll.h"
 #include "controller/ble_ll_sched.h"

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/drivers/native/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/native/src/ble_phy.c b/net/nimble/drivers/native/src/ble_phy.c
index 3cdca69..4b132ca 100644
--- a/net/nimble/drivers/native/src/ble_phy.c
+++ b/net/nimble/drivers/native/src/ble_phy.c
@@ -257,7 +257,7 @@ ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg)
 }
 
 int
-ble_phy_tx(struct os_mbuf *txpdu, uint8_t beg_trans, uint8_t end_trans)
+ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
 {
     int rc;
     uint32_t state;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/drivers/nrf51/include/ble/xcvr.h
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/nrf51/include/ble/xcvr.h b/net/nimble/drivers/nrf51/include/ble/xcvr.h
new file mode 100644
index 0000000..34abd7a
--- /dev/null
+++ b/net/nimble/drivers/nrf51/include/ble/xcvr.h
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef H_BLE_XCVR_
+#define H_BLE_XCVR_
+
+/* Transceiver specific defintions */
+#define XCVR_RX_START_DELAY_USECS     (140)
+#define XCVR_TX_START_DELAY_USECS     (140)
+#define XCVR_PROC_DELAY_USECS         (100)
+#define XCVR_TX_SCHED_DELAY_USECS     \
+    (XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
+#define XCVR_RX_SCHED_DELAY_USECS     \
+    (XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
+
+#endif /* H_BLE_XCVR_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/drivers/nrf51/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/nrf51/src/ble_phy.c b/net/nimble/drivers/nrf51/src/ble_phy.c
index d95329a..70a7500 100644
--- a/net/nimble/drivers/nrf51/src/ble_phy.c
+++ b/net/nimble/drivers/nrf51/src/ble_phy.c
@@ -61,6 +61,7 @@
 /* Maximum length of frames */
 #define NRF_MAXLEN              (255)
 #define NRF_BALEN               (3)     /* For base address of 3 bytes */
+#define NRF_RX_START_OFFSET     (5)
 
 /* Maximum tx power */
 #define NRF_TX_PWR_MAX_DBM      (4)
@@ -76,6 +77,7 @@ struct ble_phy_obj
     uint8_t phy_transition;
     uint8_t phy_rx_started;
     uint8_t phy_encrypted;
+    uint8_t phy_tx_pyld_len;
     uint32_t phy_access_address;
     struct os_mbuf *rxpdu;
     void *txend_arg;
@@ -102,6 +104,7 @@ STATS_SECT_START(ble_phy_stats)
     STATS_SECT_ENTRY(rx_aborts)
     STATS_SECT_ENTRY(rx_valid)
     STATS_SECT_ENTRY(rx_crc_err)
+    STATS_SECT_ENTRY(rx_late)
     STATS_SECT_ENTRY(no_bufs)
     STATS_SECT_ENTRY(radio_state_errs)
     STATS_SECT_ENTRY(rx_hw_err)
@@ -119,6 +122,7 @@ STATS_NAME_START(ble_phy_stats)
     STATS_NAME(ble_phy_stats, rx_aborts)
     STATS_NAME(ble_phy_stats, rx_valid)
     STATS_NAME(ble_phy_stats, rx_crc_err)
+    STATS_NAME(ble_phy_stats, rx_late)
     STATS_NAME(ble_phy_stats, no_bufs)
     STATS_NAME(ble_phy_stats, radio_state_errs)
     STATS_NAME(ble_phy_stats, rx_hw_err)
@@ -250,6 +254,9 @@ ble_phy_rx_xcvr_setup(void)
     NRF_RADIO->PACKETPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data;
 #endif
 
+    /* We dont want to trigger TXEN on output compare match */
+    NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
+
     /* Reset the rx started flag. Used for the wait for response */
     g_ble_phy_data.phy_rx_started = 0;
     g_ble_phy_data.phy_state = BLE_PHY_STATE_RX;
@@ -285,7 +292,7 @@ ble_phy_tx_end_isr(void)
 
     /* Log the event */
     ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, (g_ble_phy_txrx_buf[0] >> 8) & 0xFF,
-               g_ble_phy_data.phy_encrypted, NRF_TIMER0->CC[2]);
+               g_ble_phy_data.phy_encrypted, NRF_TIMER0->CC[1]);
 
     /* Clear events and clear interrupt on disabled event */
     NRF_RADIO->EVENTS_DISABLED = 0;
@@ -318,14 +325,16 @@ ble_phy_tx_end_isr(void)
         }
 
         /*
-         * Enable the wait for response timer. Note that cc #2 on
-         * timer 0 contains the transmit end time
+         * Enable the wait for response timer. Note that cc #1 on
+         * timer 0 contains the transmit start time
          */
-        wfr_time = NRF_TIMER0->CC[2];
+        wfr_time = NRF_TIMER0->CC[1] - BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET);
+        wfr_time += BLE_TX_DUR_USECS_M(g_ble_phy_data.phy_tx_pyld_len);
         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! */
+        /* Disable automatic TXEN */
+        NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
         assert(transition == BLE_PHY_TRANSITION_NONE);
     }
 
@@ -336,152 +345,170 @@ ble_phy_tx_end_isr(void)
 }
 
 static void
-ble_phy_isr(void)
+ble_phy_rx_end_isr(void)
 {
     int rc;
-    uint8_t crcok;
-    uint32_t irq_en;
-    uint32_t state;
 #ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
     uint8_t *dptr;
 #endif
+    uint8_t crcok;
     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) {
-        ble_phy_tx_end_isr();
-    }
-
-    /* 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;
+    /* Clear events and clear interrupt */
+    NRF_RADIO->EVENTS_END = 0;
+    NRF_RADIO->INTENCLR = RADIO_INTENCLR_END_Msk;
 
-        assert(g_ble_phy_data.rxpdu != NULL);
+    /* Disable automatic RXEN */
+    NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
 
-        /* Wait to get 1st byte of frame */
-        while (1) {
-            state = NRF_RADIO->STATE;
-            if (NRF_RADIO->EVENTS_BCMATCH != 0) {
-                break;
+    /* 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;
+#ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
+    dptr = g_ble_phy_data.rxpdu->om_data;
+#endif
+    /* 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;
+#ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
+        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;
             }
 
             /*
-             * If state is disabled, we should have the BCMATCH. If not,
-             * something is wrong!
+             * 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 (state == RADIO_STATE_STATE_Disabled) {
-                NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
-                NRF_RADIO->SHORTS = 0;
-                goto phy_isr_exit;
+            if (NRF_CCM->EVENTS_ERROR) {
+                STATS_INC(ble_phy_stats, rx_hw_err);
+                ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK;
             }
-        }
 
-        /* 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) {
-            /* Set rx started flag and enable rx end ISR */
-            g_ble_phy_data.phy_rx_started = 1;
-            NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk;
-        } else {
-            /* Disable PHY */
-            ble_phy_disable();
-            irq_en = 0;
-            STATS_INC(ble_phy_stats, rx_aborts);
+            /*
+             * 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;
+            }
         }
-
-        /* Count rx starts */
-        STATS_INC(ble_phy_stats, rx_starts);
+#endif
     }
 
-    /* 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];
-#ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
-        dptr = g_ble_phy_data.rxpdu->om_data;
-#endif
-        /* 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;
+    /* Call Link Layer receive payload function */
+    rxpdu = g_ble_phy_data.rxpdu;
+    g_ble_phy_data.rxpdu = NULL;
+
 #ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
-            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;
-                }
-            }
+    if (g_ble_phy_data.phy_encrypted) {
+        /*
+         * XXX: This is a horrible ugly hack to deal with the RAM S1 byte.
+         * This should get fixed as we should not be handing up the header
+         * and length as part of the pdu.
+         */
+        dptr[2] = dptr[1];
+        dptr[1] = dptr[0];
+        rxpdu->om_data += 1;
+    }
 #endif
-        }
+    rc = ble_ll_rx_end(rxpdu, ble_hdr);
+    if (rc < 0) {
+        ble_phy_disable();
+    }
+}
 
-        /* Call Link Layer receive payload function */
-        rxpdu = g_ble_phy_data.rxpdu;
-        g_ble_phy_data.rxpdu = NULL;
+static void
+ble_phy_rx_start_isr(void)
+{
+    int rc;
+    uint32_t state;
+    struct ble_mbuf_hdr *ble_hdr;
 
-#ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
-        if (g_ble_phy_data.phy_encrypted) {
-            /*
-             * XXX: This is a horrible ugly hack to deal with the RAM S1 byte.
-             * This should get fixed as we should not be handing up the header
-             * and length as part of the pdu.
-             */
-            dptr[2] = dptr[1];
-            dptr[1] = dptr[0];
-            rxpdu->om_data += 1;
+    /* 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;
         }
-#endif
-        rc = ble_ll_rx_end(rxpdu, ble_hdr);
-        if (rc < 0) {
-            ble_phy_disable();
+
+        /*
+         * 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;
         }
     }
 
-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;
+    ble_hdr->beg_cputime = NRF_TIMER0->CC[1] -
+        BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET);
+
+    /* 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) {
+        /* Set rx started flag and enable rx end ISR */
+        g_ble_phy_data.phy_rx_started = 1;
+        NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk;
+    } 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)
+{
+    uint32_t irq_en;
+
+    /* 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) {
+        ble_phy_tx_end_isr();
+    }
+
+    /* We get this if we have started to receive a frame */
+    if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO->EVENTS_ADDRESS) {
+        ble_phy_rx_start_isr();
+    }
+
+    /* Receive packet end (we dont enable this for transmit) */
+    if ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO->EVENTS_END) {
+        ble_phy_rx_end_isr();
+    }
+
     /* Ensures IRQ is cleared */
-    state = NRF_RADIO->SHORTS;
+    irq_en = NRF_RADIO->SHORTS;
 
     /* Count # of interrupts */
     STATS_INC(ble_phy_stats, phy_isrs);
@@ -546,11 +573,8 @@ ble_phy_init(void)
     /* Configure IFS */
     NRF_RADIO->TIFS = BLE_LL_IFS;
 
-    /*
-     * Enable the pre-programmed PPI to capture the time when a receive
-     * or transmit ends
-     */
-    NRF_PPI->CHENSET = PPI_CHEN_CH27_Msk;
+    /* Captures tx/rx start in timer0 capture 1 */
+    NRF_PPI->CHENSET = PPI_CHEN_CH26_Msk;
 
 #ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
     NRF_CCM->INTENCLR = 0xffffffff;
@@ -611,8 +635,12 @@ ble_phy_rx(void)
     /* Setup for rx */
     ble_phy_rx_xcvr_setup();
 
-    /* Start the receive task in the radio */
-    NRF_RADIO->TASKS_RXEN = 1;
+    /* Start the receive task in the radio if not automatically going to rx */
+    if ((NRF_PPI->CHEN & PPI_CHEN_CH21_Msk) == 0) {
+        NRF_RADIO->TASKS_RXEN = 1;
+    }
+
+    ble_ll_log(BLE_LL_LOG_ID_PHY_RX, g_ble_phy_data.phy_encrypted, 0, 0);
 
     return 0;
 }
@@ -674,11 +702,76 @@ ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg)
     g_ble_phy_data.txend_arg = arg;
 }
 
+/**
+ * Called to set the start time of a transmission.
+ *
+ * This function is called to set the start time when we are not going from
+ * rx to tx automatically.
+ *
+ * NOTE: care must be taken when calling this function. The channel should
+ * already be set.
+ *
+ * @param cputime
+ *
+ * @return int
+ */
+int
+ble_phy_tx_set_start_time(uint32_t cputime)
+{
+    int rc;
+
+    NRF_TIMER0->CC[0] = cputime;
+    NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk;
+    NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
+    if ((int32_t)(cputime_get32() - cputime) >= 0) {
+        STATS_INC(ble_phy_stats, tx_late);
+        ble_phy_disable();
+        rc =  BLE_PHY_ERR_TX_LATE;
+    } else {
+        rc = 0;
+    }
+    return rc;
+}
+
+/**
+ * Called to set the start time of a reception
+ *
+ * This function acts a bit differently than transmit. If we are late getting
+ * here we will still attempt to receive.
+ *
+ * NOTE: care must be taken when calling this function. The channel should
+ * already be set.
+ *
+ * @param cputime
+ *
+ * @return int
+ */
 int
-ble_phy_tx(struct os_mbuf *txpdu, uint8_t beg_trans, uint8_t end_trans)
+ble_phy_rx_set_start_time(uint32_t cputime)
+{
+    int rc;
+
+    NRF_TIMER0->CC[0] = cputime;
+    NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
+    NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk;
+    if ((int32_t)(cputime_get32() - cputime) >= 0) {
+        STATS_INC(ble_phy_stats, rx_late);
+        NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
+        NRF_RADIO->TASKS_RXEN = 1;
+        rc =  BLE_PHY_ERR_TX_LATE;
+    } else {
+        rc = 0;
+    }
+    return rc;
+}
+
+
+int
+ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
 {
     int rc;
     uint8_t *dptr;
+    uint8_t payload_len;
     uint32_t state;
     uint32_t shortcuts;
     struct ble_mbuf_hdr *ble_hdr;
@@ -686,37 +779,24 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t beg_trans, uint8_t end_trans)
     /* Better have a pdu! */
     assert(txpdu != NULL);
 
-    /* If radio is not disabled, */
+    /*
+     * This check is to make sure that the radio is not in a state where
+     * it is moving to disabled state. If so, let it get there.
+     */
     nrf_wait_disabled();
 
-    if (beg_trans == BLE_PHY_TRANSITION_RX_TX) {
-        if ((NRF_RADIO->SHORTS & RADIO_SHORTS_DISABLED_TXEN_Msk) == 0) {
-            assert(0);
-        }
-        /* Radio better be in TXRU state or we are in bad shape */
-        state = RADIO_STATE_STATE_TxRu;
-    } else {
-        /* Radio should be in disabled state */
-        state = RADIO_STATE_STATE_Disabled;
-    }
-
-    if (NRF_RADIO->STATE != state) {
-        ble_phy_disable();
-        STATS_INC(ble_phy_stats, radio_state_errs);
-        return BLE_PHY_ERR_RADIO_STATE;
-    }
+    ble_hdr = BLE_MBUF_HDR_PTR(txpdu);
+    payload_len = ble_hdr->txinfo.pyld_len;
 
 #ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
     if (g_ble_phy_data.phy_encrypted) {
         /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */
-        ble_hdr = BLE_MBUF_HDR_PTR(txpdu);
         dptr = (uint8_t *)&g_ble_phy_enc_buf[0];
         dptr[0] = ble_hdr->txinfo.hdr_byte;
-        dptr[1] = ble_hdr->txinfo.pyld_len;
+        dptr[1] = payload_len;
         dptr[2] = 0;
         dptr += 3;
 
-        NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_txrx_buf[0];
         NRF_CCM->SHORTS = 1;
         NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0];
         NRF_CCM->OUTPTR = (uint32_t)&g_ble_phy_txrx_buf[0];
@@ -728,24 +808,19 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t beg_trans, uint8_t end_trans)
         NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk;
     } else {
         /* RAM representation has S0 and LENGTH fields (2 bytes) */
-        ble_hdr = BLE_MBUF_HDR_PTR(txpdu);
         dptr = (uint8_t *)&g_ble_phy_txrx_buf[0];
         dptr[0] = ble_hdr->txinfo.hdr_byte;
-        dptr[1] = ble_hdr->txinfo.pyld_len;
+        dptr[1] = payload_len;
         dptr += 2;
-
-        NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_txrx_buf[0];
     }
 #else
     /* RAM representation has S0 and LENGTH fields (2 bytes) */
-    ble_hdr = BLE_MBUF_HDR_PTR(txpdu);
     dptr = (uint8_t *)&g_ble_phy_txrx_buf[0];
     dptr[0] = ble_hdr->txinfo.hdr_byte;
-    dptr[1] = ble_hdr->txinfo.pyld_len;
+    dptr[1] = payload_len;
     dptr += 2;
-
-    NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_txrx_buf[0];
 #endif
+    NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_txrx_buf[0];
 
     /* Clear the ready, end and disabled events */
     NRF_RADIO->EVENTS_READY = 0;
@@ -763,36 +838,26 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t beg_trans, uint8_t end_trans)
     NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
     NRF_RADIO->SHORTS = shortcuts;
 
-    /* Trigger transmit if our state was disabled */
-    if (state == RADIO_STATE_STATE_Disabled) {
-        NRF_RADIO->TASKS_TXEN = 1;
-    }
+    /* Set transmitted payload length */
+    g_ble_phy_data.phy_tx_pyld_len = payload_len;
 
     /* Set the PHY transition */
     g_ble_phy_data.phy_transition = end_trans;
 
-    /* Read back radio state. If in TXRU, we are fine */
+    /* If we already started transmitting, abort it! */
     state = NRF_RADIO->STATE;
-    if (state == RADIO_STATE_STATE_TxRu) {
+    if (state != RADIO_STATE_STATE_Tx) {
         /* Copy data from mbuf into transmit buffer */
-        os_mbuf_copydata(txpdu, ble_hdr->txinfo.offset,
-                         ble_hdr->txinfo.pyld_len, dptr);
+        os_mbuf_copydata(txpdu, ble_hdr->txinfo.offset, payload_len, dptr);
 
         /* Set phy state to transmitting and count packet statistics */
         g_ble_phy_data.phy_state = BLE_PHY_STATE_TX;
         STATS_INC(ble_phy_stats, tx_good);
-        STATS_INCN(ble_phy_stats, tx_bytes,
-                   ble_hdr->txinfo.pyld_len + BLE_LL_PDU_HDR_LEN);
+        STATS_INCN(ble_phy_stats, tx_bytes, payload_len + BLE_LL_PDU_HDR_LEN);
         rc = BLE_ERR_SUCCESS;
     } else {
-        if (state == RADIO_STATE_STATE_Tx) {
-            STATS_INC(ble_phy_stats, tx_late);
-        } else {
-            STATS_INC(ble_phy_stats, tx_fail);
-        }
-
-        /* Frame failed to transmit */
         ble_phy_disable();
+        STATS_INC(ble_phy_stats, tx_late);
         rc = BLE_PHY_ERR_RADIO_STATE;
     }
 
@@ -932,6 +997,7 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit)
  *  -> Turn off all phy interrupts.
  *  -> Disable internal shortcuts.
  *  -> Disable the radio.
+ *  -> Make sure we wont automatically go to rx/tx on output compare
  *  -> Sets phy state to idle.
  *  -> Clears any pending irqs in the NVIC. Might not be necessary but we do
  *  it as a precaution.
@@ -944,6 +1010,7 @@ ble_phy_disable(void)
     NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
     NRF_RADIO->SHORTS = 0;
     NRF_RADIO->TASKS_DISABLE = 1;
+    NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk | PPI_CHEN_CH20_Msk;
     NVIC_ClearPendingIRQ(RADIO_IRQn);
     g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8ddc20ee/net/nimble/drivers/nrf52/include/ble/xcvr.h
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/nrf52/include/ble/xcvr.h b/net/nimble/drivers/nrf52/include/ble/xcvr.h
new file mode 100644
index 0000000..f3e60fa
--- /dev/null
+++ b/net/nimble/drivers/nrf52/include/ble/xcvr.h
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef H_BLE_XCVR_
+#define H_BLE_XCVR_
+
+/* Transceiver specific defintions */
+#define XCVR_RX_START_DELAY_USECS     (140)
+#define XCVR_TX_START_DELAY_USECS     (140)
+#define XCVR_PROC_DELAY_USECS         (50)
+#define XCVR_TX_SCHED_DELAY_USECS     \
+    (XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
+#define XCVR_RX_SCHED_DELAY_USECS     \
+    (XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
+
+#endif /* H_BLE_XCVR_ */