You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2017/04/07 18:44:40 UTC
[06/50] [abbrv] incubator-mynewt-core git commit: Low power timer.
Only nrf52 right now.
Low power timer. Only nrf52 right now.
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/507f493a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/507f493a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/507f493a
Branch: refs/heads/master
Commit: 507f493ab86266528c7f921784978e63a07ddd33
Parents: 8158805
Author: William San Filippo <wi...@runtime.io>
Authored: Thu Feb 16 16:12:39 2017 -0800
Committer: William San Filippo <wi...@runtime.io>
Committed: Thu Mar 30 14:09:52 2017 -0700
----------------------------------------------------------------------
apps/bletest/src/main.c | 2 +-
hw/drivers/nimble/nrf52/include/ble/xcvr.h | 12 +-
hw/drivers/nimble/nrf52/src/ble_phy.c | 438 +++++++++++++++++--
kernel/os/include/os/os_cputime.h | 8 +
kernel/os/src/os_cputime.c | 50 +++
.../controller/include/controller/ble_ll.h | 51 ++-
.../controller/include/controller/ble_ll_conn.h | 5 +
.../include/controller/ble_ll_sched.h | 32 +-
.../controller/include/controller/ble_ll_xcvr.h | 48 ++
.../controller/include/controller/ble_phy.h | 31 +-
net/nimble/controller/src/ble_ll.c | 37 ++
net/nimble/controller/src/ble_ll_adv.c | 86 +++-
net/nimble/controller/src/ble_ll_conn.c | 265 +++++++++--
net/nimble/controller/src/ble_ll_conn_priv.h | 3 +-
net/nimble/controller/src/ble_ll_scan.c | 145 +++++-
net/nimble/controller/src/ble_ll_sched.c | 354 +++++++++++----
net/nimble/controller/src/ble_ll_xcvr.c | 153 +++++++
net/nimble/controller/syscfg.yml | 8 +
net/nimble/host/src/ble_hs_hci_evt.c | 6 +-
net/nimble/include/nimble/ble.h | 3 +
20 files changed, 1531 insertions(+), 206 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/apps/bletest/src/main.c
----------------------------------------------------------------------
diff --git a/apps/bletest/src/main.c b/apps/bletest/src/main.c
index e2519eb..efb3fd4 100755
--- a/apps/bletest/src/main.c
+++ b/apps/bletest/src/main.c
@@ -172,7 +172,7 @@ bletest_multi_adv_instances[BLETEST_CFG_ADV_TEST_INSTANCES] = {
#define BLETEST_CFG_MAX_CE_LEN (BLETEST_CFG_CONN_ITVL)
#define BLETEST_CFG_CONN_PEER_ADDR_TYPE (BLE_HCI_CONN_PEER_ADDR_PUBLIC)
#define BLETEST_CFG_CONN_OWN_ADDR_TYPE (BLE_HCI_ADV_OWN_ADDR_PUBLIC)
-#define BLETEST_CFG_CONCURRENT_CONNS (1)
+#define BLETEST_CFG_CONCURRENT_CONNS (8)
/* Test packet config */
#define BLETEST_CFG_RAND_PKT_SIZE (1)
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/hw/drivers/nimble/nrf52/include/ble/xcvr.h
----------------------------------------------------------------------
diff --git a/hw/drivers/nimble/nrf52/include/ble/xcvr.h b/hw/drivers/nimble/nrf52/include/ble/xcvr.h
index 6a35124..2b6d7ea 100644
--- a/hw/drivers/nimble/nrf52/include/ble/xcvr.h
+++ b/hw/drivers/nimble/nrf52/include/ble/xcvr.h
@@ -24,10 +24,18 @@
extern "C" {
#endif
-/* Transceiver specific definitions */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+/*
+ * NOTE: we have to account for the RTC output compare issue, which is why
+ * this number is much larger when using the 32.768 crystal for cputime. We
+ * want it to be 5 ticks.
+ */
+#define XCVR_PROC_DELAY_USECS (153)
+#else
+#define XCVR_PROC_DELAY_USECS (50)
+#endif
#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 \
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/hw/drivers/nimble/nrf52/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/hw/drivers/nimble/nrf52/src/ble_phy.c b/hw/drivers/nimble/nrf52/src/ble_phy.c
index 8771f49..8d8b0e1 100644
--- a/hw/drivers/nimble/nrf52/src/ble_phy.c
+++ b/hw/drivers/nimble/nrf52/src/ble_phy.c
@@ -78,6 +78,9 @@ struct ble_phy_obj
struct ble_mbuf_hdr rxhdr;
void *txend_arg;
ble_phy_tx_end_func txend_cb;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ uint32_t phy_start_cputime;
+#endif
};
struct ble_phy_obj g_ble_phy_data;
@@ -280,6 +283,133 @@ nrf_wait_disabled(void)
}
}
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+/**
+ *
+ *
+ */
+int
+ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs)
+{
+ uint32_t next_cc;
+ uint32_t cur_cc;
+ uint32_t cntr;
+ uint32_t delta;
+
+ /*
+ * XXX: The TXEN time is 140 usecs but there may be additional delays
+ * Need to look at this.
+ */
+
+ /*
+ * With the 32.768 kHz crystal, we may need to adjust the RTC compare
+ * value by 1 tick due to the time it takes for TXEN. The code uses a 5 RTC
+ * tick offset, which is 152.5 usecs. The TXEN time is 140 usecs. This
+ * means that with a remainder of 0, TIMER0 should be set to 12 or 13 (as
+ * TIMER0 counts at 1MHz). A remainder of 19 or more we will need to add
+ * 1 tick. We dont need to add 1 tick per se, but it does give us slightly
+ * more time and thus less of a chance to miss a tick. Another note: we
+ * cant set TIMER0 CC to 0 as the compare wont occur; it must be 1 or more.
+ * This is why we subtract 18 (as opposed to 19) as rem_uses will be >= 1.
+ */
+ if (rem_usecs <= 18) {
+ cputime -= 5;
+ rem_usecs += 12;
+ } else {
+ cputime -= 4;
+ rem_usecs -= 18;
+ }
+
+ /*
+ * Can we set the RTC compare to start TIMER0? We can do it if:
+ * a) Current compare value is not N+1 or N+2 ticks from current
+ * counter.
+ * b) The value we want to set is not at least N+2 from current
+ * counter.
+ *
+ * NOTE: since the counter can tick 1 while we do these calculations we
+ * need to account for it.
+ */
+ next_cc = cputime & 0xffffff;
+ cur_cc = NRF_RTC0->CC[0];
+ cntr = NRF_RTC0->COUNTER;
+
+ delta = (cur_cc - cntr) & 0xffffff;
+ if ((delta <= 3) && (delta != 0)) {
+ return -1;
+ }
+ delta = (next_cc - cntr) & 0xffffff;
+ if ((delta & 0x800000) || (delta < 3)) {
+ return -1;
+ }
+
+ /* Clear and set TIMER0 to fire off at proper time */
+ NRF_TIMER0->TASKS_CLEAR = 1;
+ NRF_TIMER0->CC[0] = rem_usecs;
+ NRF_TIMER0->EVENTS_COMPARE[0] = 0;
+
+ /* Set RTC compare to start TIMER0 */
+ NRF_RTC0->EVENTS_COMPARE[0] = 0;
+ NRF_RTC0->CC[0] = next_cc;
+ NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk;
+
+ /* Enable PPI */
+ NRF_PPI->CHENSET = PPI_CHEN_CH31_Msk;
+
+ /* Store the cputime at which we set the RTC */
+ g_ble_phy_data.phy_start_cputime = cputime;
+
+ return 0;
+}
+
+/**
+ * Function is used to set PPI so that we can time out waiting for a reception
+ * to occur. This happens for two reasons: we have sent a packet and we are
+ * waiting for a respons (txrx should be set to ENABLE_TXRX) or we are
+ * starting a connection event and we are a slave and we are waiting for the
+ * master to send us a packet (txrx should be set to ENABLE_RX).
+ *
+ * NOTE: when waiting for a txrx turn-around, wfr_usecs is not used as there
+ * is no additional time to wait; we know when we should receive the address of
+ * the received frame.
+ *
+ * @param txrx Flag denoting if this wfr is a txrx turn-around or not.
+ * @param wfr_usecs Amount of usecs to wait.
+ */
+void
+ble_phy_wfr_enable(int txrx, uint32_t wfr_usecs)
+{
+ uint32_t end_time;
+
+ if (txrx == BLE_PHY_WFR_ENABLE_TXRX) {
+ /*
+ * Timeout occurs an IFS time plus time it takes to receive address
+ * from the transmit end. We add additional time to make sure the
+ * address event comes before the compare. Note that transmit end
+ * is captured in CC[2]
+ *
+ * XXX: this assumes 1Mbps as 40 usecs is header rx time for 1Mbps
+ */
+ end_time = NRF_TIMER0->CC[2] + BLE_LL_IFS + 40 + 16;
+ } else {
+ /* CC[0] is set to when RXEN occurs. NOTE: the extra 16 usecs is
+ jitter */
+ end_time = NRF_TIMER0->CC[0] + XCVR_RX_START_DELAY_USECS + wfr_usecs +
+ 40 + 16;
+ }
+
+ /* wfr_secs is the time from rxen until timeout */
+ NRF_TIMER0->CC[3] = end_time;
+ NRF_TIMER0->EVENTS_COMPARE[3] = 0;
+
+ /* Enable wait for response PPI */
+ NRF_PPI->CHENSET = (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
+
+ /* Enable the disabled interrupt so we time out on events compare */
+ NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
+}
+#endif
+
/**
* Setup transceiver for receive.
*/
@@ -360,14 +490,18 @@ ble_phy_tx_end_isr(void)
uint8_t transition;
uint8_t txlen;
uint32_t wfr_time;
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768)
uint32_t txstart;
+#endif
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768)
/*
* 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];
+#endif
/* If this transmission was encrypted we need to remember it */
was_encrypted = g_ble_phy_data.phy_encrypted;
@@ -376,14 +510,20 @@ ble_phy_tx_end_isr(void)
assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX);
/* Log the event */
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+ ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, g_ble_phy_data.phy_tx_pyld_len,
+ was_encrypted, NRF_TIMER0->CC[2]);
+#else
ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, g_ble_phy_data.phy_tx_pyld_len,
was_encrypted, txstart);
+#endif
/* Clear events and clear interrupt on disabled event */
NRF_RADIO->EVENTS_DISABLED = 0;
NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk;
NRF_RADIO->EVENTS_END = 0;
wfr_time = NRF_RADIO->SHORTS;
+ (void)wfr_time;
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
/*
@@ -416,13 +556,28 @@ ble_phy_tx_end_isr(void)
if (txlen && was_encrypted) {
txlen += BLE_LL_DATA_MIC_LEN;
}
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+ ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_TXRX, 0);
+#else
wfr_time = BLE_LL_WFR_USECS - BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET);
wfr_time += BLE_TX_DUR_USECS_M(txlen);
wfr_time = os_cputime_usecs_to_ticks(wfr_time);
ble_ll_wfr_enable(txstart + wfr_time);
+#endif
} else {
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+ /*
+ * XXX: not sure we need to stop the timer here all the time. Or that
+ * it should be stopped here.
+ */
+ NRF_TIMER0->TASKS_STOP = 1;
+ NRF_TIMER0->TASKS_SHUTDOWN = 1;
+ NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
+ PPI_CHEN_CH20_Msk | PPI_CHEN_CH31_Msk;
+#else
/* Disable automatic TXEN */
NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
+#endif
assert(transition == BLE_PHY_TRANSITION_NONE);
}
}
@@ -506,12 +661,48 @@ ble_phy_rx_start_isr(void)
{
int rc;
uint32_t state;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ uint32_t usecs;
+ uint32_t ticks;
+#endif
struct ble_mbuf_hdr *ble_hdr;
/* Clear events and clear interrupt */
NRF_RADIO->EVENTS_ADDRESS = 0;
+
+ /* Clear wfr timer channels and DISABLED interrupt */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk | RADIO_INTENCLR_ADDRESS_Msk;
+ NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk;
+#else
NRF_RADIO->INTENCLR = RADIO_INTENCLR_ADDRESS_Msk;
+#endif
+ /* Initialize the ble mbuf header */
+ 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;
+
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+ /*
+ * Calculate receive start time. We assume that the header time is
+ * 40 usecs (only 1 mbps supported right now).
+ *
+ * XXX: possibly use other routine with remainder!
+ */
+ usecs = NRF_TIMER0->CC[1] - 40;
+ ticks = os_cputime_usecs_to_ticks(usecs);
+ ble_hdr->rem_usecs = usecs - os_cputime_ticks_to_usecs(ticks);
+ ble_hdr->beg_cputime = g_ble_phy_data.phy_start_cputime + ticks;
+#else
+ ble_hdr->beg_cputime = NRF_TIMER0->CC[1] -
+ os_cputime_usecs_to_ticks(BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET));
+#endif
+
+ /* XXX: I wonder if we always have the 1st byte. If we need to wait for
+ * rx chain delay, it could be 18 usecs from address interrupt. The
+ nrf52 may be able to get here early. */
/* Wait to get 1st byte of frame */
while (1) {
state = NRF_RADIO->STATE;
@@ -530,14 +721,6 @@ ble_phy_rx_start_isr(void)
}
}
- /* Initialize flags, channel and state in ble header at rx start */
- ble_hdr = &g_ble_phy_data.rxhdr;
- ble_hdr->rxinfo.flags = ble_ll_state_get();
- ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
- ble_hdr->rxinfo.handle = 0;
- ble_hdr->beg_cputime = NRF_TIMER0->CC[1] -
- os_cputime_usecs_to_ticks(BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET));
-
/* Call Link Layer receive start function */
rc = ble_ll_rx_start((uint8_t *)&g_ble_phy_rx_buf[0] + 3,
g_ble_phy_data.phy_chan,
@@ -573,16 +756,34 @@ ble_phy_isr(void)
/* 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();
- }
+ /*
+ * NOTE: order of checking is important! Possible, if things get delayed,
+ * we have both an ADDRESS and DISABLED interrupt in rx state. If we get
+ * an address, we disable the DISABLED interrupt.
+ */
/* We get this if we have started to receive a frame */
if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO->EVENTS_ADDRESS) {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ irq_en &= ~RADIO_INTENCLR_DISABLED_Msk;
+#endif
ble_phy_rx_start_isr();
}
+ /* Check for disabled event. This only happens for transmits now */
+ if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ if (g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) {
+ NRF_RADIO->EVENTS_DISABLED = 0;
+ ble_ll_wfr_timer_exp(NULL);
+ } else {
+ ble_phy_tx_end_isr();
+ }
+#else
+ ble_phy_tx_end_isr();
+#endif
+ }
+
/* 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();
@@ -606,6 +807,8 @@ int
ble_phy_init(void)
{
int rc;
+
+#if !defined(BLE_XCVR_RFCLK)
uint32_t os_tmo;
/* Make sure HFXO is started */
@@ -620,6 +823,7 @@ ble_phy_init(void)
return BLE_PHY_ERR_INIT;
}
}
+#endif
/* Set phy channel to an invalid channel so first set channel works */
g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS;
@@ -657,8 +861,13 @@ ble_phy_init(void)
/* Configure IFS */
NRF_RADIO->TIFS = BLE_LL_IFS;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */
+ NRF_PPI->CHENSET = PPI_CHEN_CH26_Msk | PPI_CHEN_CH27_Msk;
+#else
/* Captures tx/rx start in timer0 capture 1 */
NRF_PPI->CHENSET = PPI_CHEN_CH26_Msk;
+#endif
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
NRF_CCM->INTENCLR = 0xffffffff;
@@ -677,6 +886,27 @@ ble_phy_init(void)
NRF_AAR->NIRK = 0;
#endif
+ /* TIMER0 setup for PHY when using RTC */
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+ NRF_TIMER0->TASKS_STOP = 1;
+ NRF_TIMER0->TASKS_SHUTDOWN = 1;
+ NRF_TIMER0->BITMODE = 3; /* 32-bit timer */
+ NRF_TIMER0->MODE = 0; /* Timer mode */
+ NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */
+
+ /*
+ * PPI setup.
+ * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used
+ * to cancel the wait for response timer.
+ * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait
+ * for response timer.
+ */
+ NRF_PPI->CH[4].EEP = (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS);
+ NRF_PPI->CH[4].TEP = (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3]);
+ NRF_PPI->CH[5].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]);
+ NRF_PPI->CH[5].TEP = (uint32_t)&(NRF_RADIO->TASKS_DISABLE);
+#endif
+
/* Set isr in vector table and enable interrupt */
NVIC_SetPriority(RADIO_IRQn, 0);
NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr);
@@ -785,6 +1015,7 @@ ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg)
g_ble_phy_data.txend_arg = arg;
}
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
/**
* Called to set the start time of a transmission.
*
@@ -794,28 +1025,38 @@ ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg)
* NOTE: care must be taken when calling this function. The channel should
* already be set.
*
- * @param cputime
- *
+ * @param cputime This is the tick at which the 1st bit of the preamble
+ * should be transmitted
+ * @param rem_usecs This is used only when the underlying timing uses a 32.768
+ * kHz crystal. It is the # of usecs from the cputime tick
+ * at which the first bit of the preamble should be
+ * transmitted.
* @return int
*/
int
-ble_phy_tx_set_start_time(uint32_t cputime)
+ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
{
int rc;
- NRF_TIMER0->CC[0] = cputime;
- NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk;
+ /* XXX: This should not be necessary, but paranoia is good! */
+ /* Clear timer0 compare to RXEN since we are transmitting */
NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
- if ((int32_t)(os_cputime_get32() - cputime) >= 0) {
+
+ /*
+ * XXX: The TXEN time is 140 usecs but there may be additional delays
+ * Need to look at this.
+ */
+ if (ble_phy_set_start_time(cputime, rem_usecs) != 0) {
STATS_INC(ble_phy_stats, tx_late);
ble_phy_disable();
- rc = BLE_PHY_ERR_TX_LATE;
+ rc = BLE_PHY_ERR_TX_LATE;
} else {
+ /* Enable PPI to automatically start TXEN */
+ NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk;
rc = 0;
}
return rc;
}
-
/**
* Called to set the start time of a reception
*
@@ -830,23 +1071,90 @@ ble_phy_tx_set_start_time(uint32_t cputime)
* @return int
*/
int
-ble_phy_rx_set_start_time(uint32_t cputime)
+ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
{
int rc;
+ /* XXX: This should not be necessary, but paranoia is good! */
+ /* Clear timer0 compare to TXEN since we are transmitting */
+ NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
+
+ /*
+ * XXX: The RXEN time is 138 usecs but there may be additional delays
+ * Need to look at this.
+ */
+ if (ble_phy_set_start_time(cputime, rem_usecs) != 0) {
+ STATS_INC(ble_phy_stats, rx_late);
+ NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
+ NRF_RADIO->TASKS_RXEN = 1;
+ rc = BLE_PHY_ERR_RX_LATE;
+ } else {
+ /* Enable PPI to automatically start RXEN */
+ NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk;
+
+ /* Start rx */
+ rc = ble_phy_rx();
+ }
+ return rc;
+}
+#else
+/**
+ * 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 This is the tick at which the 1st bit of the preamble
+ * should be transmitted
+ * @return int
+ */
+int
+ble_phy_tx_set_start_time(uint32_t cputime)
+{
+ int rc;
+
+ cputime -= os_cputime_usecs_to_ticks(XCVR_TX_START_DELAY_USECS);
+ NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
NRF_TIMER0->CC[0] = cputime;
+ NRF_TIMER0->EVENTS_COMPARE[0] = 0;
+ NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk;
+ if ((int32_t)(os_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;
+}
+
+#if 0
+int
+ble_phy_rx_set_start_time(void)
+{
+ /*
+ * XXX: For now, we dont use this function if we are not using the
+ * RTC. Keeping the code around just in case we want to use it later.
+ */
NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
+ NRF_TIMER0->CC[0] = cputime;
+ NRF_TIMER0->EVENTS_COMPARE[0] = 0;
NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk;
if ((int32_t)(os_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;
+ rc = BLE_PHY_ERR_RX_LATE;
} else {
rc = 0;
}
- return rc;
}
+#endif
+#endif
int
ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
@@ -871,6 +1179,16 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
ble_hdr = BLE_MBUF_HDR_PTR(txpdu);
payload_len = ble_hdr->txinfo.pyld_len;
+ /*
+ * XXX: Although we may not have to do this here, I clear all the PPI
+ * that should not be used when transmitting. Some of them are only enabled
+ * if encryption and/or privacy is on, but I dont care. Better to be
+ * paranoid, and if you are going to clear one, might as well clear them
+ * all.
+ */
+ NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH23_Msk |
+ PPI_CHEN_CH25_Msk;
+
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
if (g_ble_phy_data.phy_encrypted) {
dptr = (uint8_t *)&g_ble_phy_enc_buf[0];
@@ -883,11 +1201,9 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
NRF_CCM->EVENTS_ERROR = 0;
NRF_CCM->MODE = CCM_MODE_LENGTH_Msk;
NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data;
- NRF_PPI->CHENCLR = PPI_CHEN_CH25_Msk | PPI_CHEN_CH23_Msk;
NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk;
} else {
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
- NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk;
NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
#endif
dptr = (uint8_t *)&g_ble_phy_tx_buf[0];
@@ -895,9 +1211,6 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
pktptr = dptr;
}
#else
-#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
- NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk;
-#endif
dptr = (uint8_t *)&g_ble_phy_tx_buf[0];
++dptr;
pktptr = dptr;
@@ -1077,29 +1390,62 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit)
return 0;
}
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
/**
- * Disable the PHY. This will do the following:
- * -> 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.
+ * Stop the timer used to count microseconds when using RTC for cputime
*/
void
-ble_phy_disable(void)
+ble_phy_stop_usec_timer(void)
{
- ble_ll_log(BLE_LL_LOG_ID_PHY_DISABLE, g_ble_phy_data.phy_state, 0, 0);
+ NRF_TIMER0->TASKS_STOP = 1;
+ NRF_TIMER0->TASKS_SHUTDOWN = 1;
+ NRF_RTC0->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk;
+}
+#endif
+/**
+ * ble phy disable irq and ppi
+ *
+ * This routine is to be called when reception was stopped due to either a
+ * wait for response timeout or a packet being received and the phy is to be
+ * restarted in receive mode. Generally, the disable routine is called to stop
+ * the phy.
+ */
+void
+ble_phy_disable_irq_and_ppi(void)
+{
NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
NRF_RADIO->SHORTS = 0;
NRF_RADIO->TASKS_DISABLE = 1;
- NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk | PPI_CHEN_CH21_Msk | PPI_CHEN_CH20_Msk;
+ NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH20_Msk |
+ PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk | PPI_CHEN_CH24_Msk |
+ PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk;
NVIC_ClearPendingIRQ(RADIO_IRQn);
g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
}
+void
+ble_phy_restart_rx(void)
+{
+ ble_phy_disable_irq_and_ppi();
+ ble_phy_rx();
+}
+
+/**
+ * ble phy disable
+ *
+ * Disables the PHY. This should be called when an event is over. It stops
+ * the usec timer (if used), disables interrupts, disables the RADIO, disables
+ * PPI and sets state to idle.
+ */
+void
+ble_phy_disable(void)
+{
+ ble_ll_log(BLE_LL_LOG_ID_PHY_DISABLE, g_ble_phy_data.phy_state, 0, 0);
+ ble_phy_stop_usec_timer();
+ ble_phy_disable_irq_and_ppi();
+}
+
/* Gets the current access address */
uint32_t ble_phy_access_addr_get(void)
{
@@ -1168,3 +1514,17 @@ ble_phy_resolv_list_disable(void)
g_ble_phy_data.phy_privacy = 0;
}
#endif
+
+#ifdef BLE_XCVR_RFCLK
+void
+ble_phy_rfclk_enable(void)
+{
+ NRF_CLOCK->TASKS_HFCLKSTART = 1;
+}
+
+void
+ble_phy_rfclk_disable(void)
+{
+ NRF_CLOCK->TASKS_HFCLKSTOP = 1;
+}
+#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/kernel/os/include/os/os_cputime.h
----------------------------------------------------------------------
diff --git a/kernel/os/include/os/os_cputime.h b/kernel/os/include/os/os_cputime.h
index f44c941..022efdc 100644
--- a/kernel/os/include/os/os_cputime.h
+++ b/kernel/os/include/os/os_cputime.h
@@ -45,6 +45,10 @@ extern "C" {
#define OS_CPUTIME_FREQ_1MHZ
#endif
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+#define OS_CPUTIME_FREQ_32768
+#endif
+
/* CPUTIME data. */
struct os_cputime_data
{
@@ -80,6 +84,7 @@ int os_cputime_init(uint32_t clock_freq);
*/
uint32_t os_cputime_get32(void);
+#if !defined(OS_CPUTIME_FREQ_32768)
/**
* os cputime nsecs to ticks
*
@@ -101,6 +106,7 @@ uint32_t os_cputime_nsecs_to_ticks(uint32_t nsecs);
* @return uint32_t The number of nanoseconds corresponding to 'ticks'
*/
uint32_t os_cputime_ticks_to_nsecs(uint32_t ticks);
+#endif
#if defined(OS_CPUTIME_FREQ_1MHZ)
#define os_cputime_usecs_to_ticks(x) (x)
@@ -138,6 +144,7 @@ uint32_t os_cputime_ticks_to_usecs(uint32_t ticks);
*/
void os_cputime_delay_ticks(uint32_t ticks);
+#if !defined(OS_CPUTIME_FREQ_32768)
/**
* os cputime delay nsecs
*
@@ -146,6 +153,7 @@ void os_cputime_delay_ticks(uint32_t ticks);
* @param nsecs The number of nanoseconds to wait.
*/
void os_cputime_delay_nsecs(uint32_t nsecs);
+#endif
/**
* os cputime delay usecs
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/kernel/os/src/os_cputime.c
----------------------------------------------------------------------
diff --git a/kernel/os/src/os_cputime.c b/kernel/os/src/os_cputime.c
index 067f1a1..01b15fe 100644
--- a/kernel/os/src/os_cputime.c
+++ b/kernel/os/src/os_cputime.c
@@ -30,7 +30,9 @@
* @{
*/
+#if !defined(OS_CPUTIME_FREQ_32768) && !defined(OS_CPUTIME_FREQ_1MHZ)
struct os_cputime_data g_os_cputime;
+#endif
/**
* os cputime init
@@ -49,11 +51,14 @@ os_cputime_init(uint32_t clock_freq)
int rc;
/* Set the ticks per microsecond. */
+#if !defined(OS_CPUTIME_FREQ_32768) && !defined(OS_CPUTIME_FREQ_1MHZ)
g_os_cputime.ticks_per_usec = clock_freq / 1000000U;
+#endif
rc = hal_timer_config(MYNEWT_VAL(OS_CPUTIME_TIMER_NUM), clock_freq);
return rc;
}
+#if !defined(OS_CPUTIME_FREQ_32768)
/**
* os cputime nsecs to ticks
*
@@ -99,8 +104,50 @@ os_cputime_ticks_to_nsecs(uint32_t ticks)
return nsecs;
}
+#endif
#if !defined(OS_CPUTIME_FREQ_1MHZ)
+#if defined(OS_CPUTIME_FREQ_32768)
+/**
+ * os 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
+os_cputime_usecs_to_ticks(uint32_t usecs)
+{
+ uint64_t ticks;
+
+ ticks = ((uint64_t)usecs << 9) / 15625;
+ return (uint32_t)ticks;
+}
+
+/**
+ * cputime ticks to usecs
+ *
+ * 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'
+ *
+ * NOTE: This calculation will overflow if the value for ticks is greater
+ * than 140737488. I am not going to check that here because that many ticks
+ * is about 4222 seconds, way more than what this routine should be used for.
+ */
+uint32_t
+os_cputime_ticks_to_usecs(uint32_t ticks)
+{
+ uint32_t usecs;
+
+ usecs = ((ticks >> 9) * 15625) + (((ticks & 0x1ff) * 15625) >> 9);
+ return usecs;
+}
+#else
/**
* os cputime usecs to ticks
*
@@ -138,6 +185,7 @@ os_cputime_ticks_to_usecs(uint32_t ticks)
return us;
}
#endif
+#endif
/**
* os cputime delay ticks
@@ -157,6 +205,7 @@ os_cputime_delay_ticks(uint32_t ticks)
}
}
+#if !defined(OS_CPUTIME_FREQ_32768)
/**
* os cputime delay nsecs
*
@@ -172,6 +221,7 @@ os_cputime_delay_nsecs(uint32_t nsecs)
ticks = os_cputime_nsecs_to_ticks(nsecs);
os_cputime_delay_ticks(ticks);
}
+#endif
/**
* os cputime delay usecs
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/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 e349d71..acc201d 100644
--- a/net/nimble/controller/include/controller/ble_ll.h
+++ b/net/nimble/controller/include/controller/ble_ll.h
@@ -22,13 +22,41 @@
#include "stats/stats.h"
#include "os/os_eventq.h"
+#include "os/os_callout.h"
#include "os/os_cputime.h"
#include "nimble/nimble_opt.h"
+#include "controller/ble_phy.h"
#ifdef __cplusplus
extern "C" {
#endif
+/*
+ * XXX:
+ * I guess this should not depend on the 32768 crystal to be honest. This
+ * should be done for TIMER0 as well since the rf clock chews up more current.
+ * Deal with this later.
+ *
+ * Another note: BLE_XTAL_SETTLE_TIME should be bsp related (I guess). There
+ * should be a note in there that the converted usecs to ticks value of this
+ * should not be 0. Thus: if you are using a 32.768 os cputime freq, the min
+ * value of settle time should be 31 usecs. I would suspect all settling times
+ * would exceed 31 usecs.
+ */
+
+/* Determines if we need to turn on/off rf clock */
+#undef BLE_XCVR_RFCLK
+
+/* Transceiver specific definitions */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+
+/* We will turn on/off rf clock */
+#if MYNEWT_VAL(BLE_XTAL_SETTLE_TIME) != 0
+#define BLE_XCVR_RFCLK
+#endif
+
+#endif
+
/* Controller revision. */
#define BLE_LL_SUB_VERS_NR (0x0000)
@@ -61,11 +89,22 @@ struct ble_ll_obj
/* Number of ACL data packets supported */
uint8_t ll_num_acl_pkts;
+
+#ifdef BLE_XCVR_RFCLK
+ uint8_t ll_rfclk_state;
+ uint16_t ll_xtal_ticks;
+#else
uint8_t _pad;
+ uint16_t _pad16;
+#endif
/* ACL data packet size */
uint16_t ll_acl_pkt_size;
- uint16_t _pad16;
+
+#ifdef BLE_XCVR_RFCLK
+ uint32_t ll_rfclk_start_time;
+ struct hal_timer ll_rfclk_timer;
+#endif
/* Task event queue */
struct os_eventq ll_evq;
@@ -362,6 +401,9 @@ void ble_ll_wfr_enable(uint32_t cputime);
/* Disable wait for response timer */
void ble_ll_wfr_disable(void);
+/* Wait for response timer expiration callback */
+void ble_ll_wfr_timer_exp(void *arg);
+
/* Read set of features supported by the Link Layer */
uint8_t ble_ll_read_supp_features(void);
@@ -383,7 +425,7 @@ int ble_ll_rand_start(void);
* XXX: temporary LL debug log. Will get removed once we transition to real
* log
*/
-#undef BLE_LL_LOG
+#define BLE_LL_LOG
#include "console/console.h"
#define BLE_LL_LOG_ID_PHY_SETCHAN (1)
@@ -405,6 +447,11 @@ int ble_ll_rand_start(void);
#define BLE_LL_LOG_ID_ADV_TXBEG (50)
#define BLE_LL_LOG_ID_ADV_TXDONE (60)
#define BLE_LL_LOG_ID_SCHED (80)
+#define BLE_LL_LOG_ID_RFCLK_START (90)
+#define BLE_LL_LOG_ID_RFCLK_ENABLE (91)
+#define BLE_LL_LOG_ID_RFCLK_STOP (95)
+#define BLE_LL_LOG_ID_RFCLK_SCHED_DIS (96)
+#define BLE_LL_LOG_ID_RFCLK_SCAN_DIS (97)
#ifdef BLE_LL_LOG
void ble_ll_log(uint8_t id, uint8_t arg8, uint16_t arg16, uint32_t arg32);
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/net/nimble/controller/include/controller/ble_ll_conn.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_conn.h b/net/nimble/controller/include/controller/ble_ll_conn.h
index b2e6410..041504d 100644
--- a/net/nimble/controller/include/controller/ble_ll_conn.h
+++ b/net/nimble/controller/include/controller/ble_ll_conn.h
@@ -202,6 +202,11 @@ struct ble_ll_conn_sm
uint16_t max_ce_len;
uint16_t tx_win_off;
uint32_t anchor_point;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ uint8_t anchor_point_usecs; /* XXX: can this be uint8_t ?*/
+ uint8_t conn_itvl_usecs;
+ uint32_t conn_itvl_ticks;
+#endif
uint32_t last_anchor_point; /* Slave only */
uint32_t slave_cur_tx_win_usecs;
uint32_t slave_cur_window_widening;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/net/nimble/controller/include/controller/ble_ll_sched.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_sched.h b/net/nimble/controller/include/controller/ble_ll_sched.h
index 3a05cfe..d2321b7 100644
--- a/net/nimble/controller/include/controller/ble_ll_sched.h
+++ b/net/nimble/controller/include/controller/ble_ll_sched.h
@@ -25,7 +25,8 @@ extern "C" {
#endif
/* Time per BLE scheduler slot */
-#define BLE_LL_SCHED_USECS_PER_SLOT (1250)
+#define BLE_LL_SCHED_USECS_PER_SLOT (1250)
+#define BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT (41) /* 1 tick = 30.517 usecs */
/*
* Worst case time needed for scheduled advertising item. This is the longest
@@ -46,6 +47,17 @@ extern "C" {
#define BLE_LL_SCHED_DIRECT_ADV_MAX_USECS (502)
#define BLE_LL_SCHED_MAX_ADV_PDU_USECS (376)
+/* BLE Jitter (+/- 16 useecs) */
+#define BLE_LL_JITTER_USECS (16)
+
+/*
+ * This is the offset from the start of the scheduled item until the actual
+ * tx/rx should occur, in ticks.
+ */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+extern uint8_t g_ble_ll_sched_offset_ticks;
+#endif
+
/*
* This is the number of slots needed to transmit and receive a maximum
* size PDU, including an IFS time before each. The actual time is
@@ -69,10 +81,19 @@ extern "C" {
struct ble_ll_sched_item;
typedef int (*sched_cb_func)(struct ble_ll_sched_item *sch);
+/*
+ * Schedule item
+ * sched_type: This is the type of the schedule item.
+ * enqueued: Flag denoting if item is on the scheduler list. 0: no, 1:yes
+ * remainder: # of usecs from offset till tx/rx should occur
+ * txrx_offset: Number of ticks from start time until tx/rx should occur.
+ *
+ */
struct ble_ll_sched_item
{
uint8_t sched_type;
uint8_t enqueued;
+ uint8_t remainder;
uint32_t start_time;
uint32_t end_time;
void *cb_arg;
@@ -94,8 +115,8 @@ void ble_ll_sched_free_item(struct ble_ll_sched_item *sch);
/* Schedule a new master connection */
struct ble_ll_conn_sm;
-int ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, uint32_t adv_rxend,
- uint8_t req_slots);
+int ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
+ struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len);
/* Schedule a new slave connection */
int ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm);
@@ -128,6 +149,11 @@ int ble_ll_sched_next_time(uint32_t *next_event_time);
/* Stop the scheduler */
void ble_ll_sched_stop(void);
+#ifdef BLE_XCVR_RFCLK
+/* Check if RF clock needs to be restarted */
+void ble_ll_sched_rfclk_chk_restart(void);
+#endif
+
#ifdef __cplusplus
}
#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/net/nimble/controller/include/controller/ble_ll_xcvr.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_xcvr.h b/net/nimble/controller/include/controller/ble_ll_xcvr.h
new file mode 100644
index 0000000..c59b009
--- /dev/null
+++ b/net/nimble/controller/include/controller/ble_ll_xcvr.h
@@ -0,0 +1,48 @@
+/*
+ * 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_LL_XCVR_
+#define H_BLE_LL_XCVR_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef BLE_XCVR_RFCLK
+
+/* RF clock states */
+#define BLE_RFCLK_STATE_OFF (0)
+#define BLE_RFCLK_STATE_ON (1)
+#define BLE_RFCLK_STATE_SETTLED (2)
+
+int ble_ll_xcvr_rfclk_state(void);
+void ble_ll_xcvr_rfclk_start_now(uint32_t now);
+void ble_ll_xcvr_rfclk_stop(void);
+void ble_ll_xcvr_rfclk_enable(void);
+void ble_ll_xcvr_rfclk_disable(void);
+uint32_t ble_ll_xcvr_rfclk_time_till_settled(void);
+void ble_ll_xcvr_rfclk_timer_exp(void *arg);
+void ble_ll_xcvr_rfclk_timer_start(uint32_t cputime);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_LL_ */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/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 674cbc5..e62b216 100644
--- a/net/nimble/controller/include/controller/ble_phy.h
+++ b/net/nimble/controller/include/controller/ble_phy.h
@@ -70,6 +70,7 @@ struct os_mbuf;
#define BLE_PHY_ERR_INV_PARAM (3)
#define BLE_PHY_ERR_NO_BUFS (4)
#define BLE_PHY_ERR_TX_LATE (5)
+#define BLE_PHY_ERR_RX_LATE (6)
/* Maximun PDU length. Includes LL header of 2 bytes and 255 bytes payload. */
#define BLE_PHY_MAX_PDU_LEN (257)
@@ -86,11 +87,16 @@ int ble_phy_reset(void);
/* Set the PHY channel */
int ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit);
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
/* Set transmit start time */
-int ble_phy_tx_set_start_time(uint32_t cputime);
+int ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs);
/* Set receive start time */
-int ble_phy_rx_set_start_time(uint32_t cputime);
+int ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs);
+#else
+/* Set transmit start time */
+int ble_phy_tx_set_start_time(uint32_t cputime);
+#endif
/* Set the transmit end callback and argument */
void ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg);
@@ -116,6 +122,27 @@ int ble_phy_txpwr_get(void);
/* Disable the PHY */
void ble_phy_disable(void);
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+void ble_phy_stop_usec_timer(void);
+void ble_phy_wfr_enable(int txrx, uint32_t wfr_usecs);
+#define BLE_PHY_WFR_ENABLE_RX (0)
+#define BLE_PHY_WFR_ENABLE_TXRX (1)
+#else
+#define ble_phy_stop_usec_timer()
+#endif
+
+/* Starts rf clock */
+void ble_phy_rfclk_enable(void);
+
+/* Stops rf clock */
+void ble_phy_rfclk_disable(void);
+
+/*
+ * Used to restart reception on same channel after wfr timer expiration or
+ * frame received.
+ */
+void ble_phy_restart_rx(void);
+
/* Gets the current state of the PHY */
int ble_phy_state_get(void);
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/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 6071d3c..3204ff2 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -39,6 +39,7 @@
#include "controller/ble_ll_hci.h"
#include "controller/ble_ll_whitelist.h"
#include "controller/ble_ll_resolv.h"
+#include "controller/ble_ll_xcvr.h"
#include "ble_ll_conn_priv.h"
/* XXX:
@@ -51,6 +52,11 @@
* 4) Should look into always disabled the wfr interrupt if we receive the
* start of a frame. Need to look at the various states to see if this is the
* right thing to do.
+ * 5) I am not sure that if we are passed the output compare that we actually
+ * get the interrupt. Test this.
+ * 6) I am not sure that if we receive a packet while scanning that we actually
+ * go back to scanning. I need to make sure we re-enable the receive.
+ * Put an event in the log!
*/
/* Supported states */
@@ -536,7 +542,9 @@ ble_ll_wfr_timer_exp(void *arg)
void
ble_ll_wfr_enable(uint32_t cputime)
{
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768
os_cputime_timer_start(&g_ble_ll_data.ll_wfr_timer, cputime);
+#endif
}
/**
@@ -545,7 +553,9 @@ ble_ll_wfr_enable(uint32_t cputime)
void
ble_ll_wfr_disable(void)
{
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768
os_cputime_timer_stop(&g_ble_ll_data.ll_wfr_timer);
+#endif
}
/**
@@ -786,7 +796,12 @@ ble_ll_rx_start(uint8_t *rxbuf, uint8_t chan, struct ble_mbuf_hdr *rxhdr)
int rc;
uint8_t pdu_type;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ ble_ll_log(BLE_LL_LOG_ID_RX_START, chan, rxhdr->rem_usecs,
+ rxhdr->beg_cputime);
+#else
ble_ll_log(BLE_LL_LOG_ID_RX_START, chan, 0, rxhdr->beg_cputime);
+#endif
/* Check channel type */
if (chan < BLE_PHY_NUM_DATA_CHANS) {
@@ -1167,6 +1182,11 @@ ble_ll_reset(void)
/* Set state to standby */
ble_ll_state_set(BLE_LL_STATE_STANDBY);
+#ifdef BLE_XCVR_RFCLK
+ /* Stops rf clock and rfclock timer */
+ ble_ll_xcvr_rfclk_stop();
+#endif
+
/* Reset our random address */
memset(g_random_addr, 0, BLE_DEV_ADDR_LEN);
@@ -1211,11 +1231,26 @@ ble_ll_init(void)
{
int rc;
uint8_t features;
+#ifdef BLE_XCVR_RFCLK
+ uint32_t xtal_ticks;
+#endif
struct ble_ll_obj *lldata;
/* Ensure this function only gets called by sysinit. */
SYSINIT_ASSERT_ACTIVE();
+#ifdef BLE_XCVR_RFCLK
+ /* Settling time of crystal, in ticks */
+ xtal_ticks = MYNEWT_VAL(BLE_XTAL_SETTLE_TIME);
+ assert(xtal_ticks != 0);
+ g_ble_ll_data.ll_xtal_ticks = os_cputime_usecs_to_ticks(xtal_ticks);
+
+ /* Initialize rf clock timer */
+ os_cputime_timer_init(&g_ble_ll_data.ll_rfclk_timer,
+ ble_ll_xcvr_rfclk_timer_exp, NULL);
+
+#endif
+
/* Get pointer to global data object */
lldata = &g_ble_ll_data;
@@ -1241,9 +1276,11 @@ ble_ll_init(void)
ble_ll_hw_err_timer_cb,
NULL);
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768
/* Initialize wait for response timer */
os_cputime_timer_init(&g_ble_ll_data.ll_wfr_timer, ble_ll_wfr_timer_exp,
NULL);
+#endif
/* Initialize LL HCI */
ble_ll_hci_init();
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/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 203f13a..8240d7a 100644
--- a/net/nimble/controller/src/ble_ll_adv.c
+++ b/net/nimble/controller/src/ble_ll_adv.c
@@ -430,8 +430,14 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch)
assert(rc == 0);
/* Set transmit start time. */
- txstart = sch->start_time + os_cputime_usecs_to_ticks(XCVR_PROC_DELAY_USECS);
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ txstart = sch->start_time + g_ble_ll_sched_offset_ticks;
+ rc = ble_phy_tx_set_start_time(txstart, sch->remainder);
+#else
+ txstart = sch->start_time +
+ os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
rc = ble_phy_tx_set_start_time(txstart);
+#endif
if (rc) {
STATS_INC(ble_ll_stats, adv_late_starts);
goto adv_tx_done;
@@ -498,7 +504,7 @@ adv_tx_done:
}
static void
-ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm, int sched_new)
+ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm)
{
uint32_t max_usecs;
struct ble_ll_sched_item *sch;
@@ -529,20 +535,15 @@ ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm, int sched_new)
*/
max_usecs += XCVR_PROC_DELAY_USECS;
- if (sched_new) {
- /*
- * We have to add the scheduling delay and tx start delay to the max
- * time of the event since the pdu does not start at the scheduled start.
- */
- max_usecs += XCVR_TX_SCHED_DELAY_USECS;
- sch->start_time = os_cputime_get32();
- sch->end_time = sch->start_time + os_cputime_usecs_to_ticks(max_usecs);
- } else {
- sch->start_time = advsm->adv_pdu_start_time -
- os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
- sch->end_time = advsm->adv_pdu_start_time +
- os_cputime_usecs_to_ticks(max_usecs);
- }
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ sch->start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks;
+ sch->remainder = 0;
+#else
+ sch->start_time = advsm->adv_pdu_start_time -
+ os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+#endif
+ sch->end_time = advsm->adv_pdu_start_time +
+ os_cputime_usecs_to_ticks(max_usecs);
}
/**
@@ -745,6 +746,10 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm)
ble_ll_wfr_disable();
ble_ll_state_set(BLE_LL_STATE_STANDBY);
g_ble_ll_cur_adv_sm = NULL;
+ ble_ll_scan_chk_resume();
+#ifdef BLE_XCVR_RFCLK
+ ble_ll_sched_rfclk_chk_restart();
+#endif
}
#else
if (ble_ll_state_get() == BLE_LL_STATE_ADV) {
@@ -752,6 +757,10 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm)
ble_ll_wfr_disable();
ble_ll_state_set(BLE_LL_STATE_STANDBY);
g_ble_ll_cur_adv_sm = NULL;
+ ble_ll_scan_chk_resume();
+#ifdef BLE_XCVR_RFCLK
+ ble_ll_sched_rfclk_chk_restart();
+#endif
}
#endif
OS_EXIT_CRITICAL(sr);
@@ -872,10 +881,23 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
advsm->adv_chan = adv_chan;
/*
+ * XXX: while this may not be the most efficient, schedule the first
+ * advertising event some time in the future (5 msecs). This will give
+ * time to start up any clocks or anything and also avoid a bunch of code
+ * to check if we are currently doing anything. Just makes this simple.
+ *
+ * Might also want to align this on a slot in the future.
+ *
+ * NOTE: adv_event_start_time gets set by the sched_adv_new
+ */
+ advsm->adv_pdu_start_time = os_cputime_get32() +
+ os_cputime_usecs_to_ticks(BLE_LL_SCHED_MAX_TXRX_SLOT);
+
+ /*
* Schedule advertising. We set the initial schedule start and end
* times to the earliest possible start/end.
*/
- ble_ll_adv_set_sched(advsm, 1);
+ ble_ll_adv_set_sched(advsm);
ble_ll_sched_adv_new(&advsm->adv_sch);
return BLE_ERR_SUCCESS;
@@ -884,9 +906,14 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
void
ble_ll_adv_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start)
{
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /* The event start time is when we start transmission of the adv PDU */
+ advsm->adv_event_start_time = sch_start + g_ble_ll_sched_offset_ticks;
+#else
/* The event start time is when we start transmission of the adv PDU */
advsm->adv_event_start_time = sch_start +
os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+#endif
advsm->adv_pdu_start_time = advsm->adv_event_start_time;
@@ -1489,6 +1516,11 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
/* Check if we need to resume scanning */
ble_ll_scan_chk_resume();
+ /* Turn off the clock if not doing anything else */
+#ifdef BLE_XCVR_RFCLK
+ ble_ll_sched_rfclk_chk_restart();
+#endif
+
/* This event is over. Set adv channel to first one */
advsm->adv_chan = ble_ll_adv_first_chan(advsm);
@@ -1511,8 +1543,12 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
* The scheduled time better be in the future! If it is not, we will
* just keep advancing until we the time is in the future
*/
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks;
+#else
start_time = advsm->adv_pdu_start_time -
os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+#endif
delta_t = (int32_t)(start_time - os_cputime_get32());
if (delta_t < 0) {
@@ -1543,9 +1579,13 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
* We will transmit right away. Set next pdu start time to now
* plus a xcvr start delay just so we dont count late adv starts
*/
- advsm->adv_pdu_start_time = os_cputime_get32() +
+ advsm->adv_pdu_start_time = os_cputime_get32();
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ advsm->adv_pdu_start_time += g_ble_ll_sched_offset_ticks;
+#else
+ advsm->adv_pdu_start_time +=
os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
-
+#endif
resched_pdu = 1;
}
@@ -1571,7 +1611,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
#endif
/* Schedule advertising transmit */
- ble_ll_adv_set_sched(advsm, 0);
+ ble_ll_adv_set_sched(advsm);
/*
* In the unlikely event we cant reschedule this, just post a done
@@ -1580,9 +1620,15 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
if (resched_pdu) {
rc = ble_ll_sched_adv_resched_pdu(&advsm->adv_sch);
} else {
+ /* Reschedule advertising event */
rc = ble_ll_sched_adv_reschedule(&advsm->adv_sch, &start_time,
max_delay_ticks);
if (!rc) {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ start_time += g_ble_ll_sched_offset_ticks;
+#else
+ start_time += os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+#endif
advsm->adv_event_start_time = start_time;
advsm->adv_pdu_start_time = start_time;
}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/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 1d2714a..d7f926e 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -95,15 +95,26 @@ extern void bletest_completed_pkt(uint16_t handle);
* response. Well, it should. If this packet will overrun the next scheduled
* event, what should we do? Transmit anyway? Not transmit? For now, we just
* transmit.
+ *
+ * 32kHz crystal
+ * 1) When scheduling, I need to make sure I have time between
+ * this one and the next. Should I deal with this in the sched. Or
+ * is this basically accounted for given a slot? I really just need to
+ * make sure everything is over N ticks before the next sched start!
+ * Just add to end time?
+ *
+ * 2) I think one way to handle the problem of losing up to a microsecond
+ * every time we call ble_ll_conn_next_event in a loop is to do everything by
+ * keeping track of last anchor point. Would need last anchor usecs too. I guess
+ * we could also keep last anchor usecs as a uint32 or something and when we
+ * do the next event keep track of the residual using a different ticks to
+ * usecs calculation. Not sure.
*/
/*
* XXX: How should we deal with a late connection event? We need to determine
* what we want to do under the following cases:
* 1) The current connection event has not ended but a schedule item starts
- * 2) The connection event start cb is called but we are later than we
- * expected. What to do? If we cant transmit at correct point in slot we
- * are hosed. Well, anchor point can get really messed up!
*/
/*
@@ -218,6 +229,25 @@ STATS_NAME_END(ble_ll_conn_stats)
static void ble_ll_conn_event_end(struct os_event *ev);
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+static void
+ble_ll_conn_calc_itvl_ticks(struct ble_ll_conn_sm *connsm)
+{
+ uint32_t ticks;
+ uint32_t usecs;
+
+ /*
+ * Precalculate the number of ticks and remaining microseconds for
+ * the connection interval
+ */
+ usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
+ ticks = os_cputime_usecs_to_ticks(usecs);
+ connsm->conn_itvl_ticks = ticks;
+ connsm->conn_itvl_usecs = (uint8_t)(usecs -
+ os_cputime_ticks_to_usecs(ticks));
+}
+#endif
+
/**
* Get the event buffer allocated to send the connection complete event
* when we are initiating.
@@ -402,7 +432,6 @@ ble_ll_conn_calc_window_widening(struct ble_ll_conn_sm *connsm)
window_widening = (total_sca_ppm * delta_msec) / 1000;
}
- /* XXX: spec gives 16 usecs error btw. Probably should add that in */
return window_widening;
}
@@ -689,7 +718,10 @@ ble_ll_conn_continue_rx_encrypt(void *arg)
* the current connection event. The current connection event must end before
* the next scheduled item. However, the current connection itself is not
* in the scheduler list! Thus, we need to calculate the time at which the
- * next connection will start and not overrun it.
+ * next connection will start (the schedule start time; not the anchor point)
+ * and not overrun it.
+ *
+ * Context: Interrupt
*
* @param connsm
*
@@ -698,13 +730,25 @@ ble_ll_conn_continue_rx_encrypt(void *arg)
static uint32_t
ble_ll_conn_get_next_sched_time(struct ble_ll_conn_sm *connsm)
{
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768
uint32_t itvl;
+#endif
uint32_t ce_end;
uint32_t next_sched_time;
/* Calculate time at which next connection event will start */
- itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /* NOTE: We dont care if this time is tick short. */
+ ce_end = connsm->anchor_point + connsm->conn_itvl_ticks -
+ g_ble_ll_sched_offset_ticks;
+ if ((connsm->anchor_point_usecs + connsm->conn_itvl_usecs) >= 31) {
+ ++ce_end;
+ }
+#else
+ itvl = (connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS) -
+ XCVR_TX_SCHED_DELAY_USECS;
ce_end = connsm->anchor_point + os_cputime_usecs_to_ticks(itvl);
+#endif
if (ble_ll_sched_next_time(&next_sched_time)) {
if (CPUTIME_LT(next_sched_time, ce_end)) {
@@ -1121,8 +1165,10 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
{
int rc;
uint32_t usecs;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768
uint32_t wfr_time;
- uint32_t txstart;
+#endif
+ uint32_t start;
struct ble_ll_conn_sm *connsm;
/* XXX: note that we can extend end time here if we want. Look at this */
@@ -1151,9 +1197,15 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
#endif
if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /* Set start time of transmission */
+ start = sch->start_time + g_ble_ll_sched_offset_ticks;
+ rc = ble_phy_tx_set_start_time(start, sch->remainder);
+#else
/* Set start time of transmission */
- txstart = sch->start_time + os_cputime_usecs_to_ticks(XCVR_PROC_DELAY_USECS);
- rc = ble_phy_tx_set_start_time(txstart);
+ start = sch->start_time + os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+ rc = ble_phy_tx_set_start_time(start);
+#endif
if (!rc) {
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
if (CONN_F_ENCRYPTED(connsm)) {
@@ -1187,11 +1239,13 @@ 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.
- */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /* XXX: what is this really for the slave? */
+ start = sch->start_time + g_ble_ll_sched_offset_ticks;
+ rc = ble_phy_rx_set_start_time(start, sch->remainder);
+#else
rc = ble_phy_rx();
+#endif
if (rc) {
/* End the connection event as we have no more buffers */
STATS_INC(ble_ll_conn_stats, slave_ce_failures);
@@ -1207,15 +1261,35 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
* Set the wait for response time. The anchor point is when we
* expect the master to start transmitting. Worst-case, we expect
* to hear a reply within the anchor point plus:
- * -> the current tx window size
- * -> The current window widening amount
+ * -> current tx window size
+ * -> current window widening amount (includes +/- 16 usec jitter)
* -> Amount of time it takes to detect packet start.
+ * -> Some extra time (16 usec) to insure timing is OK
+ */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /*
+ * For the 32 kHz crystal, the amount of usecs we have to wait
+ * is not from the anchor point; we have to account for the time
+ * from when the receiver is enabled until the anchor point. The
+ * time we start before the anchor point is this:
+ * -> current window widening.
+ * -> up to one 32 kHz tick since we discard remainder.
+ * -> Up to one tick since the usecs to ticks calc can be off
+ * by up to one tick.
+ * NOTES:
+ * 1) the 61 we add is for the two ticks mentioned above.
+ * 2) The address rx time and jitter is accounted for in the
+ * phy function
*/
+ usecs = connsm->slave_cur_tx_win_usecs + 61 +
+ (2 * connsm->slave_cur_window_widening);
+ ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, usecs);
+#else
usecs = connsm->slave_cur_tx_win_usecs + BLE_LL_WFR_USECS +
connsm->slave_cur_window_widening;
wfr_time = connsm->anchor_point + os_cputime_usecs_to_ticks(usecs);
ble_ll_wfr_enable(wfr_time);
-
+#endif
/* Set next wakeup time to connection event end time */
rc = BLE_LL_SCHED_STATE_RUNNING;
}
@@ -1246,15 +1320,20 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
* @return int 0: not allowed to send 1: allowed to send
*/
static int
-ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime)
+ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime,
+ uint32_t add_usecs)
{
int rc;
uint8_t rem_bytes;
uint32_t ticks;
+ uint32_t usecs;
uint32_t next_sched_time;
struct os_mbuf *txpdu;
struct os_mbuf_pkthdr *pkthdr;
struct ble_mbuf_hdr *txhdr;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ uint32_t allowed_usecs;
+#endif
rc = 1;
if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
@@ -1277,16 +1356,25 @@ ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime)
if (rem_bytes > connsm->eff_max_tx_octets) {
rem_bytes = connsm->eff_max_tx_octets;
}
- ticks = BLE_TX_DUR_USECS_M(rem_bytes);
+ usecs = BLE_TX_DUR_USECS_M(rem_bytes);
} else {
/* We will send empty pdu (just a LL header) */
- ticks = BLE_TX_DUR_USECS_M(0);
+ usecs = BLE_TX_DUR_USECS_M(0);
}
- ticks += (BLE_LL_IFS * 2) + connsm->eff_max_rx_time;
- ticks = os_cputime_usecs_to_ticks(ticks);
+ usecs += (BLE_LL_IFS * 2) + connsm->eff_max_rx_time;
+
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ ticks = (uint32_t)(next_sched_time - begtime);
+ allowed_usecs = os_cputime_ticks_to_usecs(ticks);
+ if ((usecs + add_usecs) >= allowed_usecs) {
+ rc = 0;
+ }
+#else
+ ticks = os_cputime_usecs_to_ticks(usecs);
if ((begtime + ticks) >= next_sched_time) {
rc = 0;
}
+#endif
}
return rc;
@@ -1347,7 +1435,15 @@ ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm,
connsm->conn_role = BLE_LL_CONN_ROLE_MASTER;
/* Set default ce parameters */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /*
+ * XXX: for now, we need twice the transmit window as our calculations
+ * for the transmit window offset could be off.
+ */
+ connsm->tx_win_size = BLE_LL_CONN_TX_WIN_MIN + 1;
+#else
connsm->tx_win_size = BLE_LL_CONN_TX_WIN_MIN;
+#endif
connsm->tx_win_off = 0;
connsm->master_sca = MYNEWT_VAL(BLE_LL_MASTER_SCA);
@@ -1482,6 +1578,10 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm)
connsm);
#endif
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ ble_ll_conn_calc_itvl_ticks(connsm);
+#endif
+
/* Add to list of active connections */
SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle);
}
@@ -1629,6 +1729,11 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
uint32_t cur_ww;
uint32_t max_ww;
struct ble_ll_conn_upd_req *upd;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ uint32_t ticks;
+ uint32_t usecs;
+#endif
+
/* XXX: deal with connection request procedure here as well */
ble_ll_conn_chk_csm_flags(connsm);
@@ -1647,7 +1752,24 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
connsm->event_cntr += latency;
/* Set next connection event start time */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /* We can use pre-calculated values for one interval if latency is 1. */
+ if (latency == 1) {
+ connsm->anchor_point += connsm->conn_itvl_ticks;
+ connsm->anchor_point_usecs += connsm->conn_itvl_usecs;
+ } else {
+ uint32_t ticks;
+ ticks = os_cputime_usecs_to_ticks(itvl);
+ connsm->anchor_point += ticks;
+ connsm->anchor_point_usecs += (itvl - os_cputime_ticks_to_usecs(ticks));
+ }
+ if (connsm->anchor_point_usecs >= 31) {
+ ++connsm->anchor_point;
+ connsm->anchor_point_usecs -= 31;
+ }
+#else
connsm->anchor_point += os_cputime_usecs_to_ticks(itvl);
+#endif
/*
* If a connection update has been scheduled and the event counter
@@ -1669,15 +1791,30 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
connsm->csmflags.cfbit.host_expects_upd_event = 1;
}
- connsm->conn_itvl = upd->interval;
connsm->supervision_tmo = upd->timeout;
connsm->slave_latency = upd->latency;
connsm->tx_win_size = upd->winsize;
connsm->slave_cur_tx_win_usecs =
connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
connsm->tx_win_off = upd->winoffset;
+ connsm->conn_itvl = upd->interval;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ ble_ll_conn_calc_itvl_ticks(connsm);
+ if (upd->winoffset != 0) {
+ usecs = upd->winoffset * BLE_LL_CONN_ITVL_USECS;
+ ticks = os_cputime_usecs_to_ticks(usecs);
+ connsm->anchor_point += ticks;
+ usecs = usecs - os_cputime_ticks_to_usecs(ticks);
+ connsm->anchor_point_usecs += usecs;
+ if (connsm->anchor_point_usecs >= 31) {
+ ++connsm->anchor_point;
+ connsm->anchor_point_usecs -= 31;
+ }
+ }
+#else
connsm->anchor_point +=
os_cputime_usecs_to_ticks(upd->winoffset * BLE_LL_CONN_ITVL_USECS);
+#endif
/* Reset the starting point of the connection supervision timeout */
connsm->last_rxd_pdu_cputime = connsm->anchor_point;
@@ -1736,20 +1873,35 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
* Calculate ce end time. For a slave, we need to add window widening and
* the transmit window if we still have one.
*/
- itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_USECS_PER_SLOT;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT;
if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
cur_ww = ble_ll_conn_calc_window_widening(connsm);
max_ww = (connsm->conn_itvl * (BLE_LL_CONN_ITVL_USECS/2)) - BLE_LL_IFS;
if (cur_ww >= max_ww) {
return -1;
}
+ cur_ww += BLE_LL_JITTER_USECS;
connsm->slave_cur_window_widening = cur_ww;
+ itvl += os_cputime_usecs_to_ticks(cur_ww + connsm->slave_cur_tx_win_usecs);
+ }
+ itvl -= g_ble_ll_sched_offset_ticks;
+ connsm->ce_end_time = connsm->anchor_point + itvl;
+#else
+ itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_USECS_PER_SLOT;
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+ cur_ww = ble_ll_conn_calc_window_widening(connsm);
+ max_ww = (connsm->conn_itvl * (BLE_LL_CONN_ITVL_USECS/2)) - BLE_LL_IFS;
+ if (cur_ww >= max_ww) {
+ return -1;
+ }
+ connsm->slave_cur_window_widening = cur_ww + BLE_LL_JITTER_USECS;
itvl += cur_ww + connsm->slave_cur_tx_win_usecs;
} else {
- /* We adjust end time for connection to end of time slot */
itvl -= XCVR_TX_SCHED_DELAY_USECS;
}
connsm->ce_end_time = connsm->anchor_point + os_cputime_usecs_to_ticks(itvl);
+#endif
return 0;
}
@@ -1799,9 +1951,38 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr)
*/
rc = 1;
if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /*
+ * With a 32.768 kHz crystal we dont care about the remaining usecs
+ * when setting last anchor point. The only thing last anchor is used
+ * for is to calculate window widening. The effect of this is
+ * negligible.
+ */
+ connsm->last_anchor_point = rxhdr->beg_cputime;
+
+ usecs = rxhdr->rem_usecs + 1250 +
+ (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS) +
+ BLE_TX_DUR_USECS_M(BLE_CONNECT_REQ_LEN);
+
+ /* Anchor point is cputime. */
+ endtime = os_cputime_usecs_to_ticks(usecs);
+ connsm->anchor_point = rxhdr->beg_cputime + endtime;
+ connsm->anchor_point_usecs = usecs - os_cputime_ticks_to_usecs(endtime);
+ if (connsm->anchor_point_usecs == 31) {
+ ++connsm->anchor_point;
+ connsm->anchor_point_usecs = 0;
+ }
+
+ connsm->slave_cur_tx_win_usecs =
+ connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
+
+ connsm->ce_end_time = connsm->anchor_point +
+ (MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT)
+ + os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1;
+#else
+ connsm->last_anchor_point = rxhdr->beg_cputime;
endtime = rxhdr->beg_cputime +
os_cputime_usecs_to_ticks(BLE_TX_DUR_USECS_M(BLE_CONNECT_REQ_LEN));
- connsm->last_anchor_point = endtime;
connsm->slave_cur_tx_win_usecs =
connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
usecs = 1250 + (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS);
@@ -1810,7 +1991,8 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr)
(MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_USECS_PER_SLOT);
connsm->ce_end_time = connsm->anchor_point +
os_cputime_usecs_to_ticks(usecs);
- connsm->slave_cur_window_widening = 0;
+#endif
+ connsm->slave_cur_window_widening = BLE_LL_JITTER_USECS;
/* Start the scheduler for the first connection event */
while (ble_ll_sched_slave_new(connsm)) {
@@ -1870,6 +2052,10 @@ ble_ll_conn_event_end(struct os_event *ev)
/* Check if we need to resume scanning */
ble_ll_scan_chk_resume();
+#ifdef BLE_XCVR_RFCLK
+ ble_ll_sched_rfclk_chk_restart();
+#endif
+
/* If we have transmitted the terminate IND successfully, we are done */
if ((connsm->csmflags.cfbit.terminate_ind_txd) ||
(connsm->csmflags.cfbit.terminate_ind_rxd)) {
@@ -1958,6 +2144,7 @@ ble_ll_conn_event_end(struct os_event *ev)
} else {
tmo = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000UL;
}
+ /* XXX: Convert to ticks to usecs calculation instead??? */
tmo = os_cputime_usecs_to_ticks(tmo);
if ((int32_t)(connsm->anchor_point - connsm->last_rxd_pdu_cputime) >= tmo) {
ble_ll_conn_end(connsm, BLE_ERR_CONN_SPVN_TMO);
@@ -2251,7 +2438,6 @@ ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok,
uint8_t *init_addr = NULL;
uint8_t pyld_len;
uint8_t inita_is_rpa;
- uint32_t endtime;
struct os_mbuf *rxpdu;
struct ble_ll_conn_sm *connsm;
@@ -2366,10 +2552,7 @@ ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok,
}
/* Attempt to schedule new connection. Possible that this might fail */
- endtime = ble_hdr->beg_cputime +
- os_cputime_usecs_to_ticks(BLE_TX_DUR_USECS_M(pyld_len));
- if (!ble_ll_sched_master_new(connsm, endtime,
- MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS))) {
+ if (!ble_ll_sched_master_new(connsm, ble_hdr, pyld_len)) {
/* Setup to transmit the connect request */
rc = ble_ll_conn_request_send(addr_type, adv_addr,
connsm->tx_win_off, index);
@@ -2392,8 +2575,6 @@ init_rx_isr_exit:
*/
rxpdu = ble_ll_rxpdu_alloc(pyld_len + BLE_LL_PDU_HDR_LEN);
if (rxpdu == NULL) {
- ble_phy_disable();
-
/*
* XXX: possible allocate the PDU when we start initiating?
* I cannot say I like this solution, but if we cannot allocate a PDU
@@ -2405,8 +2586,7 @@ init_rx_isr_exit:
CONN_F_CONN_REQ_TXD(connsm) = 0;
ble_ll_sched_rmv_elem(&connsm->conn_sch);
}
-
- ble_phy_rx();
+ ble_phy_restart_rx();
rc = 0;
} else {
ble_phy_rxpdu_copy(rxbuf, rxpdu);
@@ -2498,6 +2678,9 @@ ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa)
connsm->csmflags.cfbit.slave_set_last_anchor = 0;
connsm->last_anchor_point = rxhdr->beg_cputime;
connsm->anchor_point = connsm->last_anchor_point;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ connsm->anchor_point_usecs = rxhdr->rem_usecs;
+#endif
}
}
return 1;
@@ -2659,6 +2842,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
uint8_t opcode = 0;
uint8_t rx_pyld_len;
uint32_t endtime;
+ uint32_t add_usecs;
struct os_mbuf *txpdu;
struct ble_ll_conn_sm *connsm;
struct os_mbuf *rxpdu;
@@ -2689,8 +2873,14 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
}
/* Calculate the end time of the received PDU */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ endtime = rxhdr->beg_cputime;
+ add_usecs = rxhdr->rem_usecs + BLE_TX_DUR_USECS_M(rx_pyld_len);
+#else
endtime = rxhdr->beg_cputime +
os_cputime_usecs_to_ticks(BLE_TX_DUR_USECS_M(rx_pyld_len));
+ add_usecs = 0;
+#endif
/*
* Check the packet CRC. A connection event can continue even if the
@@ -2861,7 +3051,7 @@ chk_rx_terminate_ind:
if (rx_pyld_len && CONN_F_ENCRYPTED(connsm)) {
rx_pyld_len += BLE_LL_DATA_MIC_LEN;
}
- if (reply && ble_ll_conn_can_send_next_pdu(connsm, endtime)) {
+ if (reply && ble_ll_conn_can_send_next_pdu(connsm, endtime, add_usecs)) {
rc = ble_ll_conn_tx_data_pdu(connsm);
}
@@ -3045,7 +3235,6 @@ ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, uint8_t *chanmap)
* Context: Link Layer
*
* @param rxbuf Pointer to received Connect Request PDU
- * @param conn_req_end receive end time of connect request
*
* @return 0: connection not started; 1 connecton started
*/
@@ -3269,3 +3458,5 @@ ble_ll_conn_module_init(void)
/* Call reset to finish reset of initialization */
ble_ll_conn_module_reset();
}
+
+
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/net/nimble/controller/src/ble_ll_conn_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_priv.h b/net/nimble/controller/src/ble_ll_conn_priv.h
index 0913892..02cac60 100644
--- a/net/nimble/controller/src/ble_ll_conn_priv.h
+++ b/net/nimble/controller/src/ble_ll_conn_priv.h
@@ -42,12 +42,13 @@ extern "C" {
#define BLE_LL_CONN_INITIAL_OFFSET (1250)
#define BLE_LL_CONN_ITVL_USECS (1250)
#define BLE_LL_CONN_TX_WIN_USECS (1250)
+#define BLE_LL_CONN_TX_OFF_USECS (1250)
#define BLE_LL_CONN_CE_USECS (625)
#define BLE_LL_CONN_TX_WIN_MIN (1) /* in tx win units */
#define BLE_LL_CONN_SLAVE_LATENCY_MAX (499)
/* Connection request duration (in usecs) */
-#define BLE_LL_CONN_REQ_DURATION (352)
+#define BLE_LL_CONN_REQ_DURATION (352) /* 1 Mbps only */
/* Connection handle range */
#define BLE_LL_CONN_MAX_CONN_HANDLE (0x0EFF)
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/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 f732753..f5eca7f 100644
--- a/net/nimble/controller/src/ble_ll_scan.c
+++ b/net/nimble/controller/src/ble_ll_scan.c
@@ -37,6 +37,7 @@
#include "controller/ble_ll_hci.h"
#include "controller/ble_ll_whitelist.h"
#include "controller/ble_ll_resolv.h"
+#include "controller/ble_ll_xcvr.h"
#include "hal/hal_gpio.h"
/*
@@ -588,8 +589,14 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm, uint8_t chan)
}
#endif
- /* Start receiving */
- rc = ble_phy_rx();
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /* XXX: probably need to make sure hfxo is running too */
+ /* XXX: can make this better; want to just start asap. */
+ rc = ble_phy_rx_set_start_time(os_cputime_get32() +
+ g_ble_ll_sched_offset_ticks, 0);
+#else
+ rc = ble_phy_rx();
+#endif
if (!rc) {
/* Enable/disable whitelisting */
if (scansm->scan_filt_policy & 1) {
@@ -612,6 +619,37 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm, uint8_t chan)
}
}
+#ifdef BLE_XCVR_RFCLK
+static void
+ble_ll_scan_rfclk_chk_stop(void)
+{
+ int stop;
+ int32_t time_till_next;
+ os_sr_t sr;
+ uint32_t next_time;
+
+ stop = 0;
+ OS_ENTER_CRITICAL(sr);
+ if (ble_ll_sched_next_time(&next_time)) {
+ /*
+ * If the time until the next event is too close, dont bother to turn
+ * off the clock
+ */
+ time_till_next = (int32_t)(next_time - os_cputime_get32());
+ if (time_till_next > g_ble_ll_data.ll_xtal_ticks) {
+ stop = 1;
+ }
+ } else {
+ stop = 1;
+ }
+ if (stop) {
+ ble_ll_log(BLE_LL_LOG_ID_RFCLK_SCAN_DIS, g_ble_ll_data.ll_rfclk_state,0,0);
+ ble_ll_xcvr_rfclk_disable();
+ }
+ OS_EXIT_CRITICAL(sr);
+}
+#endif
+
/**
* Called to determine if we are inside or outside the scan window. If we
* are inside the scan window it means that the device should be receiving
@@ -629,6 +667,7 @@ ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm, uint32_t cputime)
int rc;
uint8_t chan;
uint32_t itvl;
+ uint32_t dt;
uint32_t win_start;
itvl = os_cputime_usecs_to_ticks(scansm->scan_itvl * BLE_HCI_SCAN_ITVL);
@@ -645,7 +684,13 @@ ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm, uint32_t cputime)
rc = 0;
if (scansm->scan_window != scansm->scan_itvl) {
itvl = os_cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
- if ((cputime - win_start) >= itvl) {
+ dt = cputime - win_start;
+ if (dt >= itvl) {
+#ifdef BLE_XCVR_RFCLK
+ if (dt < (scansm->scan_itvl - g_ble_ll_data.ll_xtal_ticks)) {
+ ble_ll_scan_rfclk_chk_stop();
+ }
+#endif
rc = 1;
}
}
@@ -688,6 +733,11 @@ ble_ll_scan_sm_stop(int chk_disable)
/* Set LL state to standby */
ble_ll_state_set(BLE_LL_STATE_STANDBY);
+
+ /* May need to stop the rfclk */
+#ifdef BLE_XCVR_RFCLK
+ ble_ll_scan_rfclk_chk_stop();
+#endif
}
OS_EXIT_CRITICAL(sr);
}
@@ -757,6 +807,9 @@ ble_ll_scan_event_proc(struct os_event *ev)
uint32_t win_start;
uint32_t scan_itvl;
uint32_t next_event_time;
+#ifdef BLE_XCVR_RFCLK
+ uint32_t xtal_ticks;
+#endif
struct ble_ll_scan_sm *scansm;
/*
@@ -786,12 +839,19 @@ ble_ll_scan_event_proc(struct os_event *ev)
dt = now - win_start;
scansm->scan_chan = chan;
scansm->scan_win_start_time = win_start;
+ if (scansm->scan_window != scansm->scan_itvl) {
+ win = os_cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
+ } else {
+ win = 0;
+ }
/* Determine on/off state based on scan window */
rxstate = 1;
next_event_time = win_start + scan_itvl;
- if (scansm->scan_window != scansm->scan_itvl) {
- win = os_cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
+
+ OS_ENTER_CRITICAL(sr);
+
+ if (win != 0) {
if (dt >= win) {
rxstate = 0;
} else {
@@ -799,7 +859,6 @@ ble_ll_scan_event_proc(struct os_event *ev)
}
}
- OS_ENTER_CRITICAL(sr);
/*
* If we are not in the standby state it means that the scheduled
* scanning event was overlapped in the schedule. In this case all we do
@@ -815,6 +874,9 @@ ble_ll_scan_event_proc(struct os_event *ev)
case BLE_LL_STATE_SCANNING:
/* Must disable PHY since we will move to a new channel */
ble_phy_disable();
+ if (!rxstate) {
+ ble_ll_state_set(BLE_LL_STATE_STANDBY);
+ }
break;
case BLE_LL_STATE_STANDBY:
break;
@@ -822,11 +884,70 @@ ble_ll_scan_event_proc(struct os_event *ev)
assert(0);
break;
}
+
+#ifdef BLE_XCVR_RFCLK
+ if (rxstate == 0) {
+ /*
+ * We need to wake up before we need to start scanning in order
+ * to make sure the rfclock is on. If we are close to being on,
+ * enable the rfclock. If not, set wakeup time.
+ */
+ if (dt >= (scan_itvl - g_ble_ll_data.ll_xtal_ticks)) {
+ /* Start the clock if necessary */
+ if (start_scan) {
+ if (ble_ll_xcvr_rfclk_state() == BLE_RFCLK_STATE_OFF) {
+ ble_ll_xcvr_rfclk_start_now(now);
+ next_event_time = now + g_ble_ll_data.ll_xtal_ticks;
+ }
+ }
+ } else {
+ next_event_time -= g_ble_ll_data.ll_xtal_ticks;
+ if (start_scan) {
+ ble_ll_scan_rfclk_chk_stop();
+ }
+ }
+ }
+#endif
+
if (start_scan && rxstate) {
+#ifdef BLE_XCVR_RFCLK
+ /* NOTE: reuse rxstate */
+ rxstate = ble_ll_xcvr_rfclk_state();
+ if (rxstate != BLE_RFCLK_STATE_SETTLED) {
+ if (rxstate == BLE_RFCLK_STATE_OFF) {
+ xtal_ticks = g_ble_ll_data.ll_xtal_ticks;
+ } else {
+ xtal_ticks = ble_ll_xcvr_rfclk_time_till_settled();
+ }
+
+ /*
+ * Only bother if we have enough time to receive anything
+ * here. The next event time will turn off the clock.
+ */
+ if (win != 0) {
+ if ((win - dt) <= xtal_ticks) {
+ goto rfclk_not_settled;
+ }
+ }
+
+ /*
+ * If clock off, start clock. Set next event time to now plus
+ * the clock setting time.
+ */
+ if (rxstate == BLE_RFCLK_STATE_OFF) {
+ ble_ll_xcvr_rfclk_start_now(now);
+ }
+ next_event_time = now + xtal_ticks;
+ goto rfclk_not_settled;
+ }
+#endif
ble_ll_scan_start(scansm, scansm->scan_chan);
}
- OS_EXIT_CRITICAL(sr);
+#ifdef BLE_XCVR_RFCLK
+rfclk_not_settled:
+#endif
+ OS_EXIT_CRITICAL(sr);
os_cputime_timer_start(&scansm->scan_timer, next_event_time);
}
@@ -929,8 +1050,7 @@ ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
if (scansm->scan_rsp_pending) {
ble_ll_scan_req_backoff(scansm, 0);
}
- ble_phy_disable();
- ble_phy_rx();
+ ble_phy_restart_rx();
return 0;
}
@@ -1081,8 +1201,6 @@ ble_ll_scan_wfr_timer_exp(void)
{
struct ble_ll_scan_sm *scansm;
- ble_phy_disable();
-
/*
* If we timed out waiting for a response, the scan response pending
* flag should be set. Deal with scan backoff. Put device back into rx.
@@ -1091,7 +1209,8 @@ ble_ll_scan_wfr_timer_exp(void)
if (scansm->scan_rsp_pending) {
ble_ll_scan_req_backoff(scansm, 0);
}
- ble_phy_rx();
+
+ ble_phy_restart_rx();
}
/**
@@ -1480,7 +1599,7 @@ ble_ll_scan_init(void)
scansm->scan_itvl = BLE_HCI_SCAN_ITVL_DEF;
scansm->scan_window = BLE_HCI_SCAN_WINDOW_DEF;
- /* Initialize connection supervision timer */
+ /* Initialize scanning timer */
os_cputime_timer_init(&scansm->scan_timer, ble_ll_scan_timer_cb, scansm);
/* Get a scan request mbuf (packet header) and attach to state machine */