Checking in almost working code. Not quite there yet.
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/6db66772 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/6db66772 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/6db66772 Branch: refs/heads/nrf_cputime Commit: 6db66772cf077f1ac3cf84148bec47453e9b208c Parents: 94a59a3 Author: William San Filippo <[email protected]> Authored: Thu Mar 16 09:48:28 2017 -0700 Committer: William San Filippo <[email protected]> Committed: Thu Mar 16 09:48:28 2017 -0700 ---------------------------------------------------------------------- apps/bletest/src/main.c | 2 +- hw/drivers/nimble/nrf52/include/ble/xcvr.h | 22 +++ hw/drivers/nimble/nrf52/src/ble_phy.c | 17 ++ .../controller/include/controller/ble_ll.h | 25 ++- .../include/controller/ble_ll_sched.h | 5 + .../controller/include/controller/ble_ll_xcvr.h | 48 +++++ .../controller/include/controller/ble_phy.h | 10 + net/nimble/controller/src/ble_ll.c | 30 +++ net/nimble/controller/src/ble_ll_adv.c | 24 +++ net/nimble/controller/src/ble_ll_conn.c | 4 + net/nimble/controller/src/ble_ll_scan.c | 129 ++++++++++++- net/nimble/controller/src/ble_ll_sched.c | 106 +++++++++++ net/nimble/controller/src/ble_ll_xcvr.c | 183 +++++++++++++++++++ net/nimble/controller/syscfg.yml | 8 + net/nimble/host/src/ble_hs_hci_evt.c | 9 +- net/nimble/syscfg.yml | 2 +- 16 files changed, 612 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6db66772/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/6db66772/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 effe81d..45d2739 100644 --- a/hw/drivers/nimble/nrf52/include/ble/xcvr.h +++ b/hw/drivers/nimble/nrf52/include/ble/xcvr.h @@ -24,8 +24,30 @@ extern "C" { #endif +/* + * WWW: Need to think about this. Does this definition need to be in xcvr.h? + * 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 + /* * 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 http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6db66772/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 410e0dc..a3254ca 100644 --- a/hw/drivers/nimble/nrf52/src/ble_phy.c +++ b/hw/drivers/nimble/nrf52/src/ble_phy.c @@ -794,6 +794,8 @@ int ble_phy_init(void) { int rc; + +#if !defined(BLE_XCVR_RFCLK) uint32_t os_tmo; /* Make sure HFXO is started */ @@ -808,6 +810,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; @@ -1498,3 +1501,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/6db66772/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 d46f722..cdb170f 100644 --- a/net/nimble/controller/include/controller/ble_ll.h +++ b/net/nimble/controller/include/controller/ble_ll.h @@ -22,8 +22,10 @@ #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" { @@ -61,11 +63,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; @@ -382,6 +395,11 @@ int ble_ll_rand_data_get(uint8_t *buf, uint8_t len); void ble_ll_rand_prand_get(uint8_t *prand); int ble_ll_rand_start(void); +/* Clock management */ +#ifdef BLE_XCVR_RFCLK +void ble_ll_rfclk_start(uint32_t cputime); +#endif + /* * XXX: temporary LL debug log. Will get removed once we transition to real * log @@ -408,6 +426,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/6db66772/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 bf3bc6d..d2321b7 100644 --- a/net/nimble/controller/include/controller/ble_ll_sched.h +++ b/net/nimble/controller/include/controller/ble_ll_sched.h @@ -149,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/6db66772/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..0ede701 --- /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(uint32_t cputime); +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); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_LL_ */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6db66772/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 f300a13..e2b83e3 100644 --- a/net/nimble/controller/include/controller/ble_phy.h +++ b/net/nimble/controller/include/controller/ble_phy.h @@ -20,6 +20,8 @@ #ifndef H_BLE_PHY_ #define H_BLE_PHY_ +#include "ble/xcvr.h" + #ifdef __cplusplus extern "C" { #endif @@ -129,6 +131,14 @@ void ble_phy_wfr_enable(uint32_t wfr_usecs); #define ble_phy_stop_usec_timer() #endif +#ifdef BLE_XCVR_RFCLK +/* Starts rf clock */ +void ble_phy_rfclk_enable(void); + +/* Stops rf clock */ +void ble_phy_rfclk_disable(void); +#endif + /* * Used to restart reception on same channel after wfr timer expiration or * frame received. http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6db66772/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 0d1fa07..1a06d4e 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: @@ -224,6 +225,15 @@ ble_ll_log(uint8_t id, uint8_t arg8, uint16_t arg16, uint32_t arg32) os_sr_t sr; struct ble_ll_log *le; + /* WWW */ + if ((id >= 90) || (id == 10) || (id == 20)) { + goto good; + } else { + return; + } +good: + /* WWW */ + OS_ENTER_CRITICAL(sr); le = &g_ble_ll_log[g_ble_ll_log_index]; le->cputime = os_cputime_get32(); @@ -1181,6 +1191,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); @@ -1225,11 +1240,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; http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6db66772/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 dd27336..b478922 100644 --- a/net/nimble/controller/src/ble_ll_adv.c +++ b/net/nimble/controller/src/ble_ll_adv.c @@ -746,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) { @@ -753,6 +757,12 @@ 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 + /* WWW */ + ble_ll_log(201,0,0,0); + ble_ll_sched_rfclk_chk_restart(); +#endif } #endif OS_EXIT_CRITICAL(sr); @@ -1508,6 +1518,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); @@ -1600,6 +1615,14 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) /* Schedule advertising transmit */ ble_ll_adv_set_sched(advsm); + /* WWW: Need to look at direct advertising (HD) to see if I messed up + * the resched pdu call. + * + * For xcvr clock, we only need to worry when we schedule new adv + * event. We want to make sure we dont turn off the clock if we are + * not done with the advertising event. Think about this. + */ + /* * In the unlikely event we cant reschedule this, just post a done * event and we will reschedule the next advertising event @@ -1607,6 +1630,7 @@ 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) { http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6db66772/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 1f4ab8b..253e96e 100644 --- a/net/nimble/controller/src/ble_ll_conn.c +++ b/net/nimble/controller/src/ble_ll_conn.c @@ -2049,6 +2049,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)) { http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6db66772/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 306b8cc..5b81219 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" /* @@ -618,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 @@ -635,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); @@ -651,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; } } @@ -694,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); } @@ -763,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; /* @@ -792,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 { @@ -805,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 @@ -821,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; @@ -828,11 +884,72 @@ 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; + } + } + + /* WWW: This should just be an enable. No need to start + cputimer here! */ + /* + * 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); + } + 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); } @@ -1484,7 +1601,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 */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6db66772/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 2c18e0c..b5109dd 100644 --- a/net/nimble/controller/src/ble_ll_sched.c +++ b/net/nimble/controller/src/ble_ll_sched.c @@ -28,11 +28,17 @@ #include "controller/ble_ll_sched.h" #include "controller/ble_ll_adv.h" #include "controller/ble_ll_scan.h" +#include "controller/ble_ll_xcvr.h" #include "ble_ll_conn_priv.h" /* XXX: this is temporary. Not sure what I want to do here */ struct hal_timer g_ble_ll_sched_timer; +#ifdef BLE_XCVR_RFCLK +/* Settling time of crystal, in ticks */ +uint8_t g_ble_ll_sched_xtal_ticks; +#endif + #if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 uint8_t g_ble_ll_sched_offset_ticks; #endif @@ -253,8 +259,17 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm) entry = start_overlap; } +#ifdef BLE_XCVR_RFCLK + entry = TAILQ_FIRST(&g_ble_ll_sched_q); + if (entry == sch) { + ble_ll_rfclk_start(sch->start_time); + } else { + sch = entry; + } +#else /* Get first on list */ sch = TAILQ_FIRST(&g_ble_ll_sched_q); +#endif OS_EXIT_CRITICAL(sr); @@ -450,6 +465,15 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, return rc; } +/** + * Schedules a slave connection for the first time. + * + * Context: Link Layer + * + * @param connsm + * + * @return int + */ int ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm) { @@ -459,6 +483,11 @@ ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm) struct ble_ll_sched_item *next_sch; struct ble_ll_sched_item *sch; +#ifdef BLE_XCVR_RFCLK + int first; + first = 0; +#endif + /* Get schedule element from connection */ rc = -1; sch = &connsm->conn_sch; @@ -494,6 +523,9 @@ ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm) if (!entry) { /* Nothing in schedule. Schedule as soon as possible */ rc = 0; +#ifdef BLE_XCVR_RFCLK + first = 1; +#endif } else { os_cputime_timer_stop(&g_ble_ll_sched_timer); while (1) { @@ -526,9 +558,24 @@ ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm) if (!rc) { sch->enqueued = 1; } +#ifdef BLE_XCVR_RFCLK + next_sch = TAILQ_FIRST(&g_ble_ll_sched_q); + if (next_sch == sch) { + first = 1; + } else { + sch = next_sch; + } +#else sch = TAILQ_FIRST(&g_ble_ll_sched_q); +#endif } +#ifdef BLE_XCVR_RFCLK + if (first) { + ble_ll_rfclk_start(sch->start_time); + } +#endif + OS_EXIT_CRITICAL(sr); os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); @@ -590,6 +637,12 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch) ble_ll_adv_scheduled((struct ble_ll_adv_sm *)orig->cb_arg, adv_start); +#ifdef BLE_XCVR_RFCLK + if (orig == sch) { + ble_ll_rfclk_start(sch->start_time); + } +#endif + OS_EXIT_CRITICAL(sr); os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); @@ -708,6 +761,12 @@ ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start, } sch->end_time = sch->start_time + duration; *start = sch->start_time; + +#ifdef BLE_XCVR_RFCLK + if (sch == TAILQ_FIRST(&g_ble_ll_sched_q)) { + ble_ll_rfclk_start(sch->start_time); + } +#endif } OS_EXIT_CRITICAL(sr); @@ -899,6 +958,53 @@ ble_ll_sched_next_time(uint32_t *next_event_time) return rc; } +#ifdef BLE_XCVR_RFCLK +void +ble_ll_sched_rfclk_chk_restart(void) +{ + int stop; + os_sr_t sr; + uint8_t ll_state; + int32_t time_till_next; + uint32_t next_time; + + stop = 0; + OS_ENTER_CRITICAL(sr); + ll_state = ble_ll_state_get(); + if (ble_ll_sched_next_time(&next_time)) { + /* + * If the time until the next event is too close, no need to start + * the timer and leave the clock on + */ + time_till_next = (int32_t)(next_time - os_cputime_get32()); + if (time_till_next > g_ble_ll_data.ll_xtal_ticks) { + /* Stop the clock */ + stop = 1; + + /* + * Restart the timer as long as not advertising or in connection + * event + */ + if (!((ll_state == BLE_LL_STATE_ADV) || + (ll_state == BLE_LL_STATE_CONNECTION))) { + ble_ll_xcvr_rfclk_start(next_time - g_ble_ll_data.ll_xtal_ticks); + } + } + } else { + stop = 1; + } + + if (stop && (ll_state == BLE_LL_STATE_STANDBY)) { + ble_ll_log(BLE_LL_LOG_ID_RFCLK_SCHED_DIS, g_ble_ll_data.ll_rfclk_state, + 0, 0); + ble_ll_xcvr_rfclk_disable(); + } + OS_EXIT_CRITICAL(sr); +} + +#endif + + /** * Stop the scheduler * http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6db66772/net/nimble/controller/src/ble_ll_xcvr.c ---------------------------------------------------------------------- diff --git a/net/nimble/controller/src/ble_ll_xcvr.c b/net/nimble/controller/src/ble_ll_xcvr.c new file mode 100644 index 0000000..43a2e49 --- /dev/null +++ b/net/nimble/controller/src/ble_ll_xcvr.c @@ -0,0 +1,183 @@ +/* + * 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. + */ + +#include <stdint.h> +#include <assert.h> +#include "syscfg/syscfg.h" +#include "os/os_cputime.h" +#include "controller/ble_phy.h" +#include "controller/ble_ll.h" +#include "controller/ble_ll_xcvr.h" + +#if 0 +#include <string.h> +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "stats/stats.h" +#include "bsp/bsp.h" +#include "nimble/ble.h" +#include "nimble/nimble_opt.h" +#include "nimble/hci_common.h" +#include "nimble/ble_hci_trans.h" +#include "controller/ble_hw.h" +#include "controller/ble_ll_adv.h" +#include "controller/ble_ll_sched.h" +#include "controller/ble_ll_scan.h" +#include "controller/ble_ll_hci.h" +#include "controller/ble_ll_whitelist.h" +#include "controller/ble_ll_resolv.h" +#include "ble_ll_conn_priv.h" +#endif + +#ifdef BLE_XCVR_RFCLK +int +ble_ll_xcvr_rfclk_state(void) +{ + uint32_t expiry; + + if (g_ble_ll_data.ll_rfclk_state == BLE_RFCLK_STATE_ON) { + expiry = g_ble_ll_data.ll_rfclk_start_time; + if ((int32_t)(os_cputime_get32() - expiry) > + g_ble_ll_data.ll_xtal_ticks) { + g_ble_ll_data.ll_rfclk_state = BLE_RFCLK_STATE_SETTLED; + } + } + return g_ble_ll_data.ll_rfclk_state; +} + +/** + * Start the rf clock timer running at the specified cputime. The cputime + * is when the clock should start; it will be settled after xtal ticks have + * expired. + * + * If the clock is ON or SETTLED there is no need to start the timer. If the + * clock is OFF the timer might be set for some time in the future. If it is, + * we will reset the time if 'cputime' is earlier than the expiry time. + * + * @param cputime + */ +void +ble_ll_xcvr_rfclk_start(uint32_t cputime) +{ + if (g_ble_ll_data.ll_rfclk_state == BLE_RFCLK_STATE_OFF) { + + /* + * If the timer is on the list, we need to see if its expiry is before + * 'cputime'. If the expiry is before, no need to do anything. If it + * is after, we need to stop the timer and start at new time. + */ + if (g_ble_ll_data.ll_rfclk_timer.link.tqe_prev != NULL) { + if ((int32_t)(cputime - g_ble_ll_data.ll_rfclk_timer.expiry) >= 0) { + return; + } + os_cputime_timer_stop(&g_ble_ll_data.ll_rfclk_timer); + } + os_cputime_timer_start(&g_ble_ll_data.ll_rfclk_timer, cputime); + ble_ll_log(BLE_LL_LOG_ID_RFCLK_START, g_ble_ll_data.ll_rfclk_state, 0, + g_ble_ll_data.ll_rfclk_timer.expiry); + } +} + +void +ble_ll_xcvr_rfclk_enable(void) +{ + g_ble_ll_data.ll_rfclk_state = BLE_RFCLK_STATE_ON; + ble_phy_rfclk_enable(); +} + +void +ble_ll_xcvr_rfclk_disable(void) +{ + ble_phy_rfclk_disable(); + g_ble_ll_data.ll_rfclk_state = BLE_RFCLK_STATE_OFF; +} + +void +ble_ll_xcvr_rfclk_stop(void) +{ + ble_ll_log(BLE_LL_LOG_ID_RFCLK_STOP, g_ble_ll_data.ll_rfclk_state, 0,0); + os_cputime_timer_stop(&g_ble_ll_data.ll_rfclk_timer); + ble_ll_xcvr_rfclk_disable(); +} + +uint32_t +ble_ll_xcvr_rfclk_time_till_settled(void) +{ + int32_t dt; + uint32_t rc; + + rc = 0; + if (g_ble_ll_data.ll_rfclk_state == BLE_RFCLK_STATE_ON) { + dt = (int32_t)(os_cputime_get32() - g_ble_ll_data.ll_rfclk_start_time); + assert(dt >= 0); + if (dt < g_ble_ll_data.ll_xtal_ticks) { + rc = g_ble_ll_data.ll_xtal_ticks - (uint32_t)dt; + } + } + + return rc; +} + +/** + * Called when the timer to turn on the RF CLOCK expires + * + * Context: Interrupt + * + * @param arg + */ +void +ble_ll_xcvr_rfclk_timer_exp(void *arg) +{ + if (g_ble_ll_data.ll_rfclk_state == BLE_RFCLK_STATE_OFF) { + ble_ll_xcvr_rfclk_enable(); + g_ble_ll_data.ll_rfclk_start_time = g_ble_ll_data.ll_rfclk_timer.expiry; + ble_ll_log(BLE_LL_LOG_ID_RFCLK_ENABLE, g_ble_ll_data.ll_rfclk_state, 0, + g_ble_ll_data.ll_rfclk_start_time); + } +} + +/** + * This API is used to turn on the rfclock without setting the cputimer timer + * to start the clock at some later point. + * + * @param now + */ +void +ble_ll_xcvr_rfclk_start_now(uint32_t now) +{ + ble_ll_xcvr_rfclk_enable(); + g_ble_ll_data.ll_rfclk_start_time = now; + ble_ll_log(BLE_LL_LOG_ID_RFCLK_ENABLE, g_ble_ll_data.ll_rfclk_state, 0, + g_ble_ll_data.ll_rfclk_start_time); +} + +/* WWW: This is really confusing. This is called when we add something + * to schedule at the start. We want to stop the current cputime timer + * for the clock and restart it at the new time. + * + */ +void +ble_ll_rfclk_start(uint32_t cputime) +{ + /* If we are currently doing something, no need to start the clock */ + if (g_ble_ll_data.ll_state == BLE_LL_STATE_STANDBY) { + ble_ll_xcvr_rfclk_start(cputime - g_ble_ll_data.ll_xtal_ticks); + } +} +#endif http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6db66772/net/nimble/controller/syscfg.yml ---------------------------------------------------------------------- diff --git a/net/nimble/controller/syscfg.yml b/net/nimble/controller/syscfg.yml index 357decc..569010f 100644 --- a/net/nimble/controller/syscfg.yml +++ b/net/nimble/controller/syscfg.yml @@ -137,6 +137,14 @@ syscfg.defs: material often. value: '32' + # Crystal setting time + BLE_XTAL_SETTLE_TIME: + description: > + The settling time of the high-frequency oscillator. This is + used to turn on/off the clock used for the radio (assuming + the HW supports this). This value is in microseconds. + value: '0' + # Configuration for LL supported features. # # There are a total 8 features that the LL can support. These can be found http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6db66772/net/nimble/host/src/ble_hs_hci_evt.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_hs_hci_evt.c b/net/nimble/host/src/ble_hs_hci_evt.c index a2d7a52..664df7b 100644 --- a/net/nimble/host/src/ble_hs_hci_evt.c +++ b/net/nimble/host/src/ble_hs_hci_evt.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, @@ -622,15 +622,18 @@ ble_hs_hci_evt_acl_process(struct os_mbuf *om) goto err; } + /* WWW*/ +#if 0 #if (BLETEST_THROUGHPUT_TEST == 0) BLE_HS_LOG(DEBUG, "ble_hs_hci_evt_acl_process(): conn_handle=%u pb=%x " "len=%u data=", - BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc), - BLE_HCI_DATA_PB(hci_hdr.hdh_handle_pb_bc), + BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc), + BLE_HCI_DATA_PB(hci_hdr.hdh_handle_pb_bc), hci_hdr.hdh_len); ble_hs_log_mbuf(om); BLE_HS_LOG(DEBUG, "\n"); #endif +#endif /* WWW */ if (hci_hdr.hdh_len != OS_MBUF_PKTHDR(om)->omp_len) { rc = BLE_HS_EBADDATA; http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6db66772/net/nimble/syscfg.yml ---------------------------------------------------------------------- diff --git a/net/nimble/syscfg.yml b/net/nimble/syscfg.yml index f44da01..1f0aaf4 100644 --- a/net/nimble/syscfg.yml +++ b/net/nimble/syscfg.yml @@ -35,7 +35,7 @@ syscfg.defs: BLE_MAX_CONNECTIONS: description: 'The maximum number of concurrent connections.' - value: 1 + value: 8 BLE_WHITELIST: description: 'TBD' value: 1
