You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by we...@apache.org on 2017/03/24 23:16:11 UTC
[49/50] [abbrv] incubator-mynewt-core git commit: Low power timer.
Only nrf52 right now.
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/34d90190/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 dd42c3f..ffe8ef3 100644
--- a/net/nimble/controller/src/ble_ll_sched.c
+++ b/net/nimble/controller/src/ble_ll_sched.c
@@ -21,24 +21,35 @@
#include <string.h>
#include "os/os.h"
#include "os/os_cputime.h"
+#include "bsp.h"
#include "ble/xcvr.h"
#include "controller/ble_phy.h"
#include "controller/ble_ll.h"
#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
+
#define BLE_LL_SCHED_ADV_WORST_CASE_USECS \
(BLE_LL_SCHED_MAX_ADV_PDU_USECS + BLE_LL_IFS + BLE_LL_SCHED_ADV_MAX_USECS \
+ XCVR_TX_SCHED_DELAY_USECS)
-
#if (BLE_LL_SCHED_DEBUG == 1)
int32_t g_ble_ll_sched_max_late;
+int32_t g_ble_ll_sched_max_early;
#endif
/* XXX: TODO:
@@ -155,6 +166,17 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
/* Get schedule element from connection */
sch = &connsm->conn_sch;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /* Set schedule start and end times */
+ sch->start_time = connsm->anchor_point - g_ble_ll_sched_offset_ticks;
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+ usecs = connsm->slave_cur_window_widening;
+ sch->start_time -= (os_cputime_usecs_to_ticks(usecs) + 1);
+ sch->remainder = 0;
+ } else {
+ sch->remainder = connsm->anchor_point_usecs;
+ }
+#else
/* Set schedule start and end times */
if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
usecs = XCVR_RX_SCHED_DELAY_USECS;
@@ -163,6 +185,7 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
usecs = XCVR_TX_SCHED_DELAY_USECS;
}
sch->start_time = connsm->anchor_point - os_cputime_usecs_to_ticks(usecs);
+#endif
sch->end_time = connsm->ce_end_time;
/* Better be past current time or we just leave */
@@ -236,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_xcvr_rfclk_timer_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);
@@ -247,67 +279,108 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
return rc;
}
+/**
+ * Called to schedule a connection when the current role is master.
+ *
+ * Context: Interrupt
+ *
+ * @param connsm
+ * @param ble_hdr
+ * @param pyld_len
+ *
+ * @return int
+ */
int
-ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, uint32_t adv_rxend,
- uint8_t req_slots)
+ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
+ struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len)
{
int rc;
os_sr_t sr;
- uint32_t tps;
+ uint8_t req_slots;
uint32_t initial_start;
uint32_t earliest_start;
uint32_t earliest_end;
uint32_t dur;
uint32_t itvl_t;
- uint32_t ce_end_time;
+ uint32_t adv_rxend;
struct ble_ll_sched_item *entry;
struct ble_ll_sched_item *sch;
- /* Better have a connsm */
- assert(connsm != NULL);
-
/* Get schedule element from connection */
rc = -1;
sch = &connsm->conn_sch;
-
+ req_slots = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS);
+
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /* XXX:
+ * The calculations for the 32kHz crystal bear alot of explanation. The
+ * earliest possible time that the master can start the connection with a
+ * slave is 1.25 msecs from the end of the connection request. The
+ * connection request is sent an IFS time from the end of the advertising
+ * packet that was received plus the time it takes to send the connection
+ * request. At 1 Mbps, this is 1752 usecs, or 57.41 ticks. Using 57 ticks
+ * makes us off ~13 usecs. Since we dont want to actually calculate the
+ * receive end time tick (this would take too long), we assume the end of
+ * the advertising PDU is 'now' (we call os_cputime_get32). We dont know
+ * how much time it will take to service the ISR but if we are more than the
+ * rx to tx time of the chip we will not be successful transmitting the
+ * connect request. All this means is that we presume that the slave will
+ * receive the connect request later than we expect but no earlier than
+ * 13 usecs before (this is important).
+ *
+ * The code then attempts to schedule the connection at the
+ * earliest time although this may not be possible. When the actual
+ * schedule start time is determined, the master has to determine if this
+ * time is more than a transmit window offset interval (1.25 msecs). The
+ * master has to tell the slave how many transmit window offsets there are
+ * from the earliest possible time to when the actual transmit start will
+ * occur. Later in this function you will see the calculation. The actual
+ * transmission start has to occur within the transmit window. The transmit
+ * window interval is in units of 1.25 msecs and has to be at least 1. To
+ * make things a bit easier (but less power efficient for the slave), we
+ * use a transmit window of 2. We do this because we dont quite know the
+ * exact start of the transmission and if we are too early or too late we
+ * could miss the transmit window. A final note: the actual transmission
+ * start (the anchor point) is sched offset ticks from the schedule start
+ * time. We dont add this to the calculation when calculating the window
+ * offset. The reason we dont do this is we want to insure we transmit
+ * after the window offset we tell the slave. For example, say we think
+ * we are transmitting 1253 usecs from the earliest start. This would cause
+ * us to send a transmit window offset of 1. Since we are actually
+ * transmitting earlier than the slave thinks we could end up transmitting
+ * before the window offset. Transmitting later is fine since we have the
+ * transmit window to do so. Transmitting before is bad, since the slave
+ * wont be listening. We could do better calculation if we wanted to use
+ * a transmit window of 1 as opposed to 2, but for now we dont care.
+ */
+ dur = req_slots * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT;
+ adv_rxend = os_cputime_get32();
+ earliest_start = adv_rxend + 57; /* XXX: only works for 1 Mbps */
+ earliest_end = earliest_start + dur;
+ itvl_t = connsm->conn_itvl_ticks;
+#else
+ adv_rxend = ble_hdr->beg_cputime +
+ os_cputime_usecs_to_ticks(BLE_TX_DUR_USECS_M(pyld_len));
/*
* The earliest start time is 1.25 msecs from the end of the connect
* request transmission. Note that adv_rxend is the end of the received
* advertisement, so we need to add an IFS plus the time it takes to send
- * the connection request
+ * the connection request. The 1.25 msecs starts from the end of the conn
+ * request.
*/
dur = os_cputime_usecs_to_ticks(req_slots * BLE_LL_SCHED_USECS_PER_SLOT);
earliest_start = adv_rxend +
os_cputime_usecs_to_ticks(BLE_LL_IFS + BLE_LL_CONN_REQ_DURATION +
BLE_LL_CONN_INITIAL_OFFSET);
earliest_end = earliest_start + dur;
-
itvl_t = os_cputime_usecs_to_ticks(connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS);
+#endif
/* We have to find a place for this schedule */
OS_ENTER_CRITICAL(sr);
/* The schedule item must occur after current running item (if any) */
sch->start_time = earliest_start;
-
- /*
- * If we are currently in a connection, we add one slot time to the
- * earliest start so we can end the connection reasonably.
- */
- if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) {
- tps = os_cputime_usecs_to_ticks(BLE_LL_SCHED_USECS_PER_SLOT);
- ce_end_time = ble_ll_conn_get_ce_end_time();
- while ((int32_t)(ce_end_time - os_cputime_get32()) < 0) {
- ce_end_time += tps;
- }
-
- /* Start at next slot boundary past earliest */
- while ((int32_t)(ce_end_time - earliest_start) < 0) {
- ce_end_time += tps;
- }
- earliest_start = ce_end_time;
- earliest_end = earliest_start + dur;
- }
initial_start = earliest_start;
if (!ble_ll_sched_insert_if_empty(sch)) {
@@ -338,6 +411,7 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, uint32_t adv_rxend,
}
}
+ /* Must be able to schedule within one connection interval */
if (!entry) {
if ((earliest_start - initial_start) <= itvl_t) {
rc = 0;
@@ -346,18 +420,38 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, uint32_t adv_rxend,
}
if (!rc) {
- /* calculate number of connection intervals before start */
+ /* calculate number of window offsets. Each offset is 1.25 ms */
sch->enqueued = 1;
- connsm->tx_win_off = (earliest_start - initial_start) /
- os_cputime_usecs_to_ticks(BLE_LL_CONN_ITVL_USECS);
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /*
+ * NOTE: we dont add sched offset ticks as we want to under-estimate
+ * the transmit window slightly since the window size is currently
+ * 2 when using a 32768 crystal.
+ */
+ dur = os_cputime_ticks_to_usecs(earliest_start - initial_start);
+ connsm->tx_win_off = dur / BLE_LL_CONN_TX_OFF_USECS;
+#else
+ dur = os_cputime_ticks_to_usecs(earliest_start - initial_start);
+ dur += XCVR_TX_SCHED_DELAY_USECS;
+ connsm->tx_win_off = dur / BLE_LL_CONN_TX_OFF_USECS;
+#endif
}
}
if (!rc) {
sch->start_time = earliest_start;
sch->end_time = earliest_end;
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /*
+ * Since we have the transmit window to transmit in, we dont need
+ * to set the anchor point usecs; just transmit to the nearest tick.
+ */
+ connsm->anchor_point = earliest_start + g_ble_ll_sched_offset_ticks;
+ connsm->anchor_point_usecs = 0;
+#else
connsm->anchor_point = earliest_start +
os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+#endif
connsm->ce_end_time = earliest_end;
}
@@ -371,6 +465,15 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, uint32_t adv_rxend,
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)
{
@@ -380,15 +483,32 @@ 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;
/* Set schedule start and end times */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ /*
+ * XXX: for now, we dont care about anchor point usecs for the slave. It
+ * does not matter if we turn on the receiver up to one tick before w
+ * need to. We also subtract one extra tick since the conversion from
+ * usecs to ticks could be off by up to 1 tick.
+ */
+ sch->start_time = connsm->anchor_point - g_ble_ll_sched_offset_ticks -
+ os_cputime_usecs_to_ticks(connsm->slave_cur_window_widening) - 1;
+#else
sch->start_time = connsm->anchor_point -
os_cputime_usecs_to_ticks(XCVR_RX_SCHED_DELAY_USECS +
connsm->slave_cur_window_widening);
+#endif
sch->end_time = connsm->ce_end_time;
+ sch->remainder = 0;
/* We have to find a place for this schedule */
OS_ENTER_CRITICAL(sr);
@@ -403,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) {
@@ -435,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_xcvr_rfclk_timer_start(sch->start_time);
+ }
+#endif
+
OS_EXIT_CRITICAL(sr);
os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
@@ -450,9 +588,6 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch)
{
int rc;
os_sr_t sr;
- uint8_t ll_state;
- int32_t ticks;
- uint32_t ce_end_time;
uint32_t adv_start;
uint32_t duration;
struct ble_ll_sched_item *entry;
@@ -463,39 +598,12 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch)
orig = sch;
OS_ENTER_CRITICAL(sr);
-
- /*
- * If we are currently in a connection, we add one slot time to the
- * earliest start so we can end the connection reasonably.
- */
- ll_state = ble_ll_state_get();
- if (ll_state == BLE_LL_STATE_CONNECTION) {
- ticks = (int32_t)os_cputime_usecs_to_ticks(BLE_LL_SCHED_MAX_TXRX_SLOT);
- ce_end_time = ble_ll_conn_get_ce_end_time();
- if ((int32_t)(ce_end_time - sch->start_time) < ticks) {
- ce_end_time += ticks;
- }
- sch->start_time = ce_end_time;
- sch->end_time = ce_end_time + duration;
- }
-#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
- else if ((ll_state == BLE_LL_STATE_ADV) && (BLE_LL_ADV_INSTANCES > 1)) {
- /*
- * Since we currently dont know how long this item might be scheduled
- * for we add what we think the worst-case time for the advertising
- * scheduled item to be over. We add in a IFS for good measure.
- */
- sch->start_time += BLE_LL_SCHED_MAX_ADV_PDU_USECS + BLE_LL_IFS +
- BLE_LL_SCHED_ADV_MAX_USECS + XCVR_TX_SCHED_DELAY_USECS;
- sch->end_time = sch->start_time + duration;
- }
-#endif
-
entry = ble_ll_sched_insert_if_empty(sch);
if (!entry) {
rc = 0;
adv_start = sch->start_time;
} else {
+ /* XXX: no need to stop timer if not first on list. Modify code? */
os_cputime_timer_stop(&g_ble_ll_sched_timer);
TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
/* We can insert if before entry in list */
@@ -529,13 +637,13 @@ 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);
- OS_EXIT_CRITICAL(sr);
+#ifdef BLE_XCVR_RFCLK
+ if (orig == sch) {
+ ble_ll_xcvr_rfclk_timer_start(sch->start_time);
+ }
+#endif
- /* XXX: some things to test. I am not sure that if we are passed the
- output compare that we actually get the interrupt. */
- /* XXX: 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! */
+ OS_EXIT_CRITICAL(sr);
os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
@@ -653,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_xcvr_rfclk_timer_start(sch->start_time);
+ }
+#endif
}
OS_EXIT_CRITICAL(sr);
@@ -784,26 +898,33 @@ ble_ll_sched_execute_item(struct ble_ll_sched_item *sch)
void
ble_ll_sched_run(void *arg)
{
- int32_t dt;
struct ble_ll_sched_item *sch;
/* Look through schedule queue */
- while ((sch = TAILQ_FIRST(&g_ble_ll_sched_q)) != NULL) {
+ sch = TAILQ_FIRST(&g_ble_ll_sched_q);
+ if (sch) {
+#if (BLE_LL_SCHED_DEBUG == 1)
+ int32_t dt;
+
/* Make sure we have passed the start time of the first event */
dt = (int32_t)(os_cputime_get32() - sch->start_time);
- if (dt >= 0) {
-#if (BLE_LL_SCHED_DEBUG == 1)
- if (dt > g_ble_ll_sched_max_late) {
- g_ble_ll_sched_max_late = dt;
- }
+ if (dt > g_ble_ll_sched_max_late) {
+ g_ble_ll_sched_max_late = dt;
+ }
+ if (dt < g_ble_ll_sched_max_early) {
+ g_ble_ll_sched_max_early = dt;
+ }
#endif
- /* Remove schedule item and execute the callback */
- TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link);
- sch->enqueued = 0;
- ble_ll_sched_execute_item(sch);
- } else {
+
+ /* Remove schedule item and execute the callback */
+ TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link);
+ sch->enqueued = 0;
+ ble_ll_sched_execute_item(sch);
+
+ /* Restart if there is an item on the schedule */
+ sch = TAILQ_FIRST(&g_ble_ll_sched_q);
+ if (sch) {
os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
- break;
}
}
}
@@ -837,6 +958,55 @@ ble_ll_sched_next_time(uint32_t *next_event_time)
return rc;
}
+#ifdef BLE_XCVR_RFCLK
+/**
+ * Checks to see if we need to restart the cputime timer which starts the
+ * rf clock settling.
+ *
+ * NOTE: Should only be called from the Link Layer task!
+ *
+ * Context: Link-Layer task.
+ *
+ */
+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. Leave 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;
+ ble_ll_xcvr_rfclk_timer_start(next_time);
+ }
+ } else {
+ stop = 1;
+ }
+
+ /* Only disable the rfclk if doing nothing */
+ 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
*
@@ -857,6 +1027,24 @@ ble_ll_sched_stop(void)
int
ble_ll_sched_init(void)
{
+ /*
+ * Initialize max early to large negative number. This is used
+ * to determine the worst-case "early" time the schedule was called. Dont
+ * expect this to be less than -3 or -4.
+ */
+#if (BLE_LL_SCHED_DEBUG == 1)
+ g_ble_ll_sched_max_early = -50000;
+#endif
+
+ /*
+ * This is the offset from the start of the scheduled item until the actual
+ * tx/rx should occur, in ticks. We also "round up" to the nearest tick.
+ */
+#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768
+ g_ble_ll_sched_offset_ticks =
+ os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS + 30);
+#endif
+
/* Initialize cputimer for the scheduler */
os_cputime_timer_init(&g_ble_ll_sched_timer, ble_ll_sched_run, NULL);
return 0;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/34d90190/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..50ab32e
--- /dev/null
+++ b/net/nimble/controller/src/ble_ll_xcvr.c
@@ -0,0 +1,153 @@
+/*
+ * 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"
+
+#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;
+}
+
+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. This function checks
+ * the state of the clock. If the clock is off, the clock is turned on.
+ * Otherwise, we just exit.
+ *
+ * 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_start_now(os_cputime_get32());
+ }
+}
+
+/**
+ * This API is used to turn on the rfclock without setting the cputime timer to
+ * start the clock at some later point.
+ *
+ * NOTE: presumes that the state of the rf clock was checked prior to calling.
+ *
+ * @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, 0, 0, now);
+}
+
+/**
+ * Starts the timer that will turn the rf clock on. The 'cputime' is
+ * the time at which the clock needs to be settled.
+ *
+ * @param cputime Time at which rfclock should be on and settled.
+ */
+void
+ble_ll_xcvr_rfclk_timer_start(uint32_t cputime)
+{
+ /*
+ * If we are currently in an advertising event or a connection event,
+ * no need to start the cputime timer
+ */
+ if ((g_ble_ll_data.ll_state == BLE_LL_STATE_ADV) ||
+ (g_ble_ll_data.ll_state == BLE_LL_STATE_CONNECTION)) {
+ return;
+ }
+
+ /* Account for the settling time */
+ cputime -= g_ble_ll_data.ll_xtal_ticks;
+
+ /*
+ * 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);
+}
+#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/34d90190/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/34d90190/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 cd98f7f..a9655e3 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,
@@ -624,8 +624,8 @@ ble_hs_hci_evt_acl_process(struct os_mbuf *om)
#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");
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/34d90190/net/nimble/include/nimble/ble.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/ble.h b/net/nimble/include/nimble/ble.h
index b514131..6f29fd4 100644
--- a/net/nimble/include/nimble/ble.h
+++ b/net/nimble/include/nimble/ble.h
@@ -96,6 +96,9 @@ struct ble_mbuf_hdr
struct ble_mbuf_hdr_txinfo txinfo;
};
uint32_t beg_cputime;
+#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768)
+ uint32_t rem_usecs;
+#endif
};
#define BLE_MBUF_HDR_CRC_OK(hdr) \