summaryrefslogtreecommitdiff
path: root/net/nimble/drivers/nrf51/src/ble_phy.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/nimble/drivers/nrf51/src/ble_phy.c')
-rw-r--r--net/nimble/drivers/nrf51/src/ble_phy.c201
1 files changed, 121 insertions, 80 deletions
diff --git a/net/nimble/drivers/nrf51/src/ble_phy.c b/net/nimble/drivers/nrf51/src/ble_phy.c
index 0c050119..a24a434e 100644
--- a/net/nimble/drivers/nrf51/src/ble_phy.c
+++ b/net/nimble/drivers/nrf51/src/ble_phy.c
@@ -28,17 +28,12 @@
#include "controller/ble_ll.h"
#include "mcu/nrf51_bitfields.h"
-/*
- * XXX: need to make the copy from mbuf into the PHY data structures 32-bit
- * copies or we are screwed.
- */
-
/* XXX: 4) Make sure RF is higher priority interrupt than schedule */
/*
* XXX: Maximum possible transmit time is 1 msec for a 60ppm crystal
* and 16ms for a 30ppm crystal! We need to limit PDU size based on
- * crystal accuracy
+ * crystal accuracy. Look at this in the spec.
*/
/* XXX: private header file? */
@@ -82,9 +77,10 @@ struct ble_phy_obj
uint8_t phy_encrypted;
uint8_t phy_privacy;
uint8_t phy_tx_pyld_len;
+ uint8_t *rxdptr;
uint32_t phy_aar_scratch;
uint32_t phy_access_address;
- struct os_mbuf *rxpdu;
+ struct ble_mbuf_hdr rxhdr;
void *txend_arg;
ble_phy_tx_end_func txend_cb;
};
@@ -92,7 +88,8 @@ struct ble_phy_obj g_ble_phy_data;
/* XXX: if 27 byte packets desired we can make this smaller */
/* Global transmit/receive buffer */
-static uint32_t g_ble_phy_txrx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4];
+static uint32_t g_ble_phy_tx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4];
+static uint32_t g_ble_phy_rx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4];
#if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1)
/* Make sure word-aligned for faster copies */
@@ -111,7 +108,6 @@ STATS_SECT_START(ble_phy_stats)
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)
STATS_SECT_ENTRY(tx_hw_err)
@@ -129,7 +125,6 @@ STATS_NAME_START(ble_phy_stats)
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)
STATS_NAME(ble_phy_stats, tx_hw_err)
@@ -183,33 +178,81 @@ struct nrf_ccm_data g_nrf_ccm_data;
#endif
/**
- * ble phy rxpdu get
+ * Copies the data from the phy receive buffer into a mbuf chain.
*
- * Gets a mbuf for PDU reception.
+ * @param dptr Pointer to receive buffer
+ * @param rxpdu Pointer to already allocated mbuf chain
+ *
+ * NOTE: the packet header already has the total mbuf length in it. The
+ * lengths of the individual mbufs are not set prior to calling.
*
- * @return struct os_mbuf* Pointer to retrieved mbuf or NULL if none available
*/
-static struct os_mbuf *
-ble_phy_rxpdu_get(void)
+void
+ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu)
{
+ uint16_t rem_bytes;
+ uint16_t mb_bytes;
+ uint16_t copylen;
+ uint32_t *dst;
+ uint32_t *src;
struct os_mbuf *m;
+ struct ble_mbuf_hdr *ble_hdr;
+ struct os_mbuf_pkthdr *pkthdr;
+
+ /* Better be aligned */
+ assert(((uint32_t)dptr & 3) == 0);
+
+ pkthdr = OS_MBUF_PKTHDR(rxpdu);
+ rem_bytes = pkthdr->omp_len;
+
+ /* Fill in the mbuf pkthdr first. */
+ dst = (uint32_t *)(rxpdu->om_data);
+ src = (uint32_t *)dptr;
+
+ mb_bytes = (rxpdu->om_omp->omp_databuf_len - rxpdu->om_pkthdr_len - 4);
+ copylen = min(mb_bytes, rem_bytes);
+ copylen &= 0xFFFC;
+ rem_bytes -= copylen;
+ mb_bytes -= copylen;
+ rxpdu->om_len = copylen;
+ while (copylen > 0) {
+ *dst = *src;
+ ++dst;
+ ++src;
+ copylen -= 4;
+ }
- m = g_ble_phy_data.rxpdu;
- if (m == NULL) {
- m = os_msys_get_pkthdr(BLE_MBUF_PAYLOAD_SIZE, sizeof(struct ble_mbuf_hdr));
- if (!m) {
- STATS_INC(ble_phy_stats, no_bufs);
- } else {
- /*
- * NOTE: we add two bytes to the data pointer as we will prepend
- * two bytes if we hand this received pdu up to host.
- */
- m->om_data += 2;
- g_ble_phy_data.rxpdu = m;
+ /* Copy remaining bytes */
+ m = rxpdu;
+ while (rem_bytes > 0) {
+ /* If there are enough bytes in the mbuf, copy them and leave */
+ if (rem_bytes <= mb_bytes) {
+ memcpy(m->om_data + m->om_len, src, rem_bytes);
+ m->om_len += rem_bytes;
+ break;
+ }
+
+ m = SLIST_NEXT(m, om_next);
+ assert(m != NULL);
+
+ mb_bytes = m->om_omp->omp_databuf_len;
+ copylen = min(mb_bytes, rem_bytes);
+ copylen &= 0xFFFC;
+ rem_bytes -= copylen;
+ mb_bytes -= copylen;
+ m->om_len = copylen;
+ dst = (uint32_t *)m->om_data;
+ while (copylen > 0) {
+ *dst = *src;
+ ++dst;
+ ++src;
+ copylen -= 4;
}
}
- return m;
+ /* Copy ble header */
+ ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
+ memcpy(ble_hdr, &g_ble_phy_data.rxhdr, sizeof(struct ble_mbuf_hdr));
}
/**
@@ -241,11 +284,16 @@ nrf_wait_disabled(void)
static void
ble_phy_rx_xcvr_setup(void)
{
+ uint8_t *dptr;
+
+ dptr = (uint8_t *)&g_ble_phy_rx_buf[0];
+
#if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1)
if (g_ble_phy_data.phy_encrypted) {
+ dptr += 3;
NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0];
NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0];
- NRF_CCM->OUTPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data;
+ NRF_CCM->OUTPTR = (uint32_t)dptr;
NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0];
NRF_CCM->MODE = CCM_MODE_MODE_Decryption;
NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data;
@@ -254,20 +302,22 @@ ble_phy_rx_xcvr_setup(void)
NRF_CCM->EVENTS_ENDCRYPT = 0;
NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk | PPI_CHEN_CH25_Msk;
} else {
- NRF_RADIO->PACKETPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data;
+ NRF_RADIO->PACKETPTR = (uint32_t)dptr;
}
#else
- NRF_RADIO->PACKETPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data;
+ NRF_RADIO->PACKETPTR = (uint32_t)dptr;
#endif
#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
if (g_ble_phy_data.phy_privacy) {
+ dptr += 3;
+ NRF_RADIO->PACKETPTR = (uint32_t)dptr;
NRF_RADIO->PCNF0 = (6 << RADIO_PCNF0_LFLEN_Pos) |
(2 << RADIO_PCNF0_S1LEN_Pos) |
(NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos);
NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled;
NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
- NRF_AAR->ADDRPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data;
+ NRF_AAR->ADDRPTR = (uint32_t)dptr;
NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch;
NRF_AAR->EVENTS_END = 0;
NRF_AAR->EVENTS_RESOLVED = 0;
@@ -289,6 +339,7 @@ ble_phy_rx_xcvr_setup(void)
/* 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;
+ g_ble_phy_data.rxdptr = dptr;
/* I want to know when 1st byte received (after address) */
NRF_RADIO->BCC = 8; /* in bits */
@@ -313,16 +364,28 @@ ble_phy_rx_xcvr_setup(void)
static void
ble_phy_tx_end_isr(void)
{
+ uint8_t was_encrypted;
uint8_t transition;
uint8_t txlen;
uint32_t wfr_time;
+ uint32_t txstart;
+
+ /*
+ * Read captured tx start time. This is not the actual transmit start
+ * time but it is the time at which the address event occurred
+ * (after transmission of access address)
+ */
+ txstart = NRF_TIMER0->CC[1];
+
+ /* If this transmission was encrypted we need to remember it */
+ was_encrypted = g_ble_phy_data.phy_encrypted;
/* Better be in TX state! */
assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX);
/* Log the event */
- ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, (g_ble_phy_txrx_buf[0] >> 8) & 0xFF,
- g_ble_phy_data.phy_encrypted, NRF_TIMER0->CC[1]);
+ ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, (g_ble_phy_tx_buf[0] >> 8) & 0xFF,
+ was_encrypted, txstart);
/* Clear events and clear interrupt on disabled event */
NRF_RADIO->EVENTS_DISABLED = 0;
@@ -335,7 +398,7 @@ ble_phy_tx_end_isr(void)
* XXX: not sure what to do. We had a HW error during transmission.
* For now I just count a stat but continue on like all is good.
*/
- if (g_ble_phy_data.phy_encrypted) {
+ if (was_encrypted) {
if (NRF_CCM->EVENTS_ERROR) {
STATS_INC(ble_phy_stats, tx_hw_err);
NRF_CCM->EVENTS_ERROR = 0;
@@ -343,26 +406,25 @@ ble_phy_tx_end_isr(void)
}
#endif
+ /* Call transmit end callback */
+ if (g_ble_phy_data.txend_cb) {
+ g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg);
+ }
+
transition = g_ble_phy_data.phy_transition;
if (transition == BLE_PHY_TRANSITION_TX_RX) {
/* Packet pointer needs to be reset. */
- if (g_ble_phy_data.rxpdu != NULL) {
- ble_phy_rx_xcvr_setup();
- } else {
- /* Disable the phy */
- STATS_INC(ble_phy_stats, no_bufs);
- ble_phy_disable();
- }
+ ble_phy_rx_xcvr_setup();
/*
* Enable the wait for response timer. Note that cc #1 on
* timer 0 contains the transmit start time
*/
txlen = g_ble_phy_data.phy_tx_pyld_len;
- if (txlen && g_ble_phy_data.phy_encrypted) {
+ if (txlen && was_encrypted) {
txlen += BLE_LL_DATA_MIC_LEN;
}
- wfr_time = NRF_TIMER0->CC[1] - BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET);
+ wfr_time = txstart - BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET);
wfr_time += BLE_TX_DUR_USECS_M(txlen);
wfr_time += cputime_usecs_to_ticks(BLE_LL_WFR_USECS);
ble_ll_wfr_enable(wfr_time);
@@ -371,22 +433,14 @@ ble_phy_tx_end_isr(void)
NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
assert(transition == BLE_PHY_TRANSITION_NONE);
}
-
- /* Call transmit end callback */
- if (g_ble_phy_data.txend_cb) {
- g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg);
- }
}
static void
ble_phy_rx_end_isr(void)
{
int rc;
-#if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1)
uint8_t *dptr;
-#endif
uint8_t crcok;
- struct os_mbuf *rxpdu;
struct ble_mbuf_hdr *ble_hdr;
/* Clear events and clear interrupt */
@@ -397,12 +451,12 @@ ble_phy_rx_end_isr(void)
NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
/* Set RSSI and CRC status flag in header */
- ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu);
+ ble_hdr = &g_ble_phy_data.rxhdr;
assert(NRF_RADIO->EVENTS_RSSIEND != 0);
ble_hdr->rxinfo.rssi = -1 * NRF_RADIO->RSSISAMPLE;
-#if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1)
- dptr = g_ble_phy_data.rxpdu->om_data;
-#endif
+
+ dptr = g_ble_phy_data.rxdptr;
+
/* Count PHY crc errors and valid packets */
crcok = (uint8_t)NRF_RADIO->CRCSTATUS;
if (!crcok) {
@@ -441,10 +495,6 @@ ble_phy_rx_end_isr(void)
#endif
}
- /* Call Link Layer receive payload function */
- rxpdu = g_ble_phy_data.rxpdu;
- g_ble_phy_data.rxpdu = NULL;
-
#if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1) || (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
if (g_ble_phy_data.phy_encrypted || g_ble_phy_data.phy_privacy) {
/*
@@ -454,10 +504,10 @@ ble_phy_rx_end_isr(void)
*/
dptr[2] = dptr[1];
dptr[1] = dptr[0];
- rxpdu->om_data += 1;
+ ++dptr;
}
#endif
- rc = ble_ll_rx_end(rxpdu, ble_hdr);
+ rc = ble_ll_rx_end(dptr, ble_hdr);
if (rc < 0) {
ble_phy_disable();
}
@@ -474,8 +524,6 @@ ble_phy_rx_start_isr(void)
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;
@@ -495,7 +543,7 @@ ble_phy_rx_start_isr(void)
}
/* Initialize flags, channel and state in ble header at rx start */
- ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu);
+ ble_hdr = &g_ble_phy_data.rxhdr;
ble_hdr->rxinfo.flags = ble_ll_state_get();
ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
ble_hdr->rxinfo.handle = 0;
@@ -503,7 +551,8 @@ ble_phy_rx_start_isr(void)
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);
+ rc = ble_ll_rx_start(g_ble_phy_data.rxdptr, g_ble_phy_data.phy_chan,
+ &g_ble_phy_data.rxhdr);
if (rc >= 0) {
/* Set rx started flag and enable rx end ISR */
g_ble_phy_data.phy_rx_started = 1;
@@ -672,11 +721,6 @@ ble_phy_rx(void)
return BLE_PHY_ERR_RADIO_STATE;
}
- /* If no pdu, get one */
- if (ble_phy_rxpdu_get() == NULL) {
- return BLE_PHY_ERR_NO_BUFS;
- }
-
/* Make sure all interrupts are disabled */
NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
@@ -855,7 +899,7 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
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];
+ NRF_CCM->OUTPTR = (uint32_t)&g_ble_phy_tx_buf[0];
NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0];
NRF_CCM->EVENTS_ERROR = 0;
NRF_CCM->MODE = CCM_MODE_MODE_Encryption;
@@ -872,7 +916,7 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
#endif
/* RAM representation has S0 and LENGTH fields (2 bytes) */
- dptr = (uint8_t *)&g_ble_phy_txrx_buf[0];
+ dptr = (uint8_t *)&g_ble_phy_tx_buf[0];
dptr[0] = ble_hdr->txinfo.hdr_byte;
dptr[1] = payload_len;
dptr += 2;
@@ -887,13 +931,13 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
#endif
/* RAM representation has S0 and LENGTH fields (2 bytes) */
- dptr = (uint8_t *)&g_ble_phy_txrx_buf[0];
+ dptr = (uint8_t *)&g_ble_phy_tx_buf[0];
dptr[0] = ble_hdr->txinfo.hdr_byte;
dptr[1] = payload_len;
dptr += 2;
#endif
- NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_txrx_buf[0];
+ NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_tx_buf[0];
/* Clear the ready, end and disabled events */
NRF_RADIO->EVENTS_READY = 0;
@@ -903,13 +947,10 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
/* Enable shortcuts for transmit start/end. */
shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk;
if (end_trans == BLE_PHY_TRANSITION_TX_RX) {
- /* If we are going into receive after this, try to get a buffer. */
- if (ble_phy_rxpdu_get()) {
- shortcuts |= RADIO_SHORTS_DISABLED_RXEN_Msk;
- }
+ shortcuts |= RADIO_SHORTS_DISABLED_RXEN_Msk;
}
- NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
NRF_RADIO->SHORTS = shortcuts;
+ NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
/* Set transmitted payload length */
g_ble_phy_data.phy_tx_pyld_len = payload_len;