http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/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/507f493a/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/507f493a/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/507f493a/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/507f493a/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) \