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 2016/01/19 01:14:58 UTC
[1/2] incubator-mynewt-larva git commit: Many changes to the
scheduler and link layer to allow for scheduling of multiple connections.
Also allows concurrent connections and/or advertising and/or scanning and/or
initiating state machines
Repository: incubator-mynewt-larva
Updated Branches:
refs/heads/master ccc970cd7 -> b6e2b5ffa
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 c3ec3db..1b2ec0b 100644
--- a/net/nimble/controller/src/ble_ll_scan.c
+++ b/net/nimble/controller/src/ble_ll_scan.c
@@ -45,6 +45,11 @@
* 3) Interleave sending scan requests to different advertisers? I guess I need
* a list of advertisers to which I sent a scan request and have yet to
* receive a scan response from? Implement this.
+ *
+ * 4) The current way I do things, it is possible that keep rescheduling the
+ * scanning item but never get a chance to execute it. This means that the
+ * last scan win start time could get really old. If we keep the current
+ * way of doing things we will need to address this issue.
*/
/* The scanning state machine global object */
@@ -55,8 +60,7 @@ struct ble_ll_scan_stats
{
uint32_t scan_starts;
uint32_t scan_stops;
- uint32_t scan_win_misses;
- uint32_t cant_set_sched;
+ uint32_t scan_event_misses;
uint32_t scan_req_txf;
uint32_t scan_req_txg;
};
@@ -120,6 +124,46 @@ ble_ll_scan_req_backoff(struct ble_ll_scan_sm *scansm, int success)
}
/**
+ * 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
+ * on the scan channel.
+ *
+ * Context: Interrupt and Link Layer
+ *
+ * @param scansm
+ *
+ * @return int 0: inside scan window 1: outside scan window
+ */
+int
+ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm)
+{
+ int rc;
+ uint32_t now;
+ uint32_t itvl;
+
+ rc = 0;
+ itvl = cputime_usecs_to_ticks(scansm->scan_itvl * BLE_HCI_SCAN_ITVL);
+ now = cputime_get32();
+ while ((int32_t)(now - scansm->scan_win_start_time) >= itvl) {
+ scansm->scan_win_start_time += itvl;
+ ++scansm->scan_chan;
+ if (scansm->scan_chan == BLE_PHY_NUM_CHANS) {
+ scansm->scan_chan = BLE_PHY_ADV_CHAN_START;
+ }
+ }
+
+ if (scansm->scan_window != scansm->scan_itvl) {
+ itvl = cputime_usecs_to_ticks(scansm->scan_window *
+ BLE_HCI_SCAN_ITVL);
+ if ((now - scansm->scan_win_start_time) >= itvl) {
+ rc = 1;
+ }
+ }
+
+ return rc;
+}
+
+/**
* ble ll scan req pdu make
*
* Construct a SCAN_REQ PDU.
@@ -485,14 +529,6 @@ ble_ll_scan_chk_filter_policy(uint8_t pdu_type, uint8_t *rxbuf, uint8_t flags)
return 0;
}
-static int
-ble_ll_scan_win_end_cb(struct ble_ll_sched_item *sch)
-{
- ble_phy_disable();
- ble_ll_event_send(&g_ble_ll_scan_sm.scan_win_end_ev);
- return BLE_LL_SCHED_STATE_DONE;
-}
-
/**
* Schedule callback for the start of a scan window
*
@@ -503,43 +539,105 @@ ble_ll_scan_win_end_cb(struct ble_ll_sched_item *sch)
* @return int
*/
static int
-ble_ll_scan_start_cb(struct ble_ll_sched_item *sch)
+ble_ll_scan_start(struct ble_ll_scan_sm *scansm)
{
int rc;
- struct ble_ll_scan_sm *scansm;
-
- /* Toggle the LED */
- gpio_toggle(LED_BLINK_PIN);
-
- /* Get the state machine for the event */
- scansm = (struct ble_ll_scan_sm *)sch->cb_arg;
-
+
/* Set channel */
rc = ble_phy_setchan(scansm->scan_chan, 0, 0);
assert(rc == 0);
- /* Set callbacks in case we transmit scan request or connect request */
+ /*
+ * Set transmit end callback to NULL in case we transmit a scan request.
+ * There is a callback for the connect request.
+ */
ble_phy_set_txend_cb(NULL, NULL);
/* Start receiving */
rc = ble_phy_rx();
if (rc) {
- /* Failure to go into receive. Just call the window end function */
- ble_ll_event_send(&g_ble_ll_scan_sm.scan_win_end_ev);
rc = BLE_LL_SCHED_STATE_DONE;
} else {
/* Set link layer state to scanning */
- if (g_ble_ll_scan_sm.scan_type == BLE_SCAN_TYPE_INITIATE) {
+ if (scansm->scan_type == BLE_SCAN_TYPE_INITIATE) {
ble_ll_state_set(BLE_LL_STATE_INITIATING);
} else {
ble_ll_state_set(BLE_LL_STATE_SCANNING);
}
/* Set end time to end of scan window */
- sch->next_wakeup = sch->end_time;
- sch->sched_cb = ble_ll_scan_win_end_cb;
rc = BLE_LL_SCHED_STATE_RUNNING;
}
+ scansm->last_sched_time = cputime_get32();
+
+ /* If there is a still a scan response pending, we have failed! */
+ if (scansm->scan_rsp_pending) {
+ ble_ll_scan_req_backoff(scansm, 0);
+ }
+
+ return rc;
+}
+
+/**
+ * Called when the scanning schedule item executes
+ *
+ * Context: Interrupt
+ *
+ * @param sch
+ *
+ * @return int
+ */
+int
+ble_ll_scan_sched_cb(struct ble_ll_sched_item *sch)
+{
+ int rc;
+ struct ble_ll_scan_sm *scansm;
+
+ /*
+ * 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
+ * is post the scan schedule end event.
+ */
+ switch (ble_ll_state_get()) {
+ case BLE_LL_STATE_ADV:
+ case BLE_LL_STATE_CONNECTION:
+ rc = -1;
+ break;
+ case BLE_LL_STATE_INITIATING:
+ case BLE_LL_STATE_SCANNING:
+ /* Must disable PHY since we will move to a new channel */
+ ble_phy_disable();
+ rc = 0;
+ break;
+ case BLE_LL_STATE_STANDBY:
+ rc = 0;
+ break;
+ default:
+ rc = 0;
+ assert(0);
+ break;
+ }
+
+ scansm = (struct ble_ll_scan_sm *)sch->cb_arg;
+ if (rc) {
+ rc = BLE_LL_SCHED_STATE_DONE;
+ } else {
+ /* Determine if we should be off or receiving */
+ rc = ble_ll_scan_window_chk(scansm);
+ if (!rc) {
+ ble_ll_scan_start(scansm);
+ rc = BLE_LL_SCHED_STATE_RUNNING;
+ } else {
+ rc = BLE_LL_SCHED_STATE_DONE;
+ }
+ }
+
+ if (rc == BLE_LL_SCHED_STATE_DONE) {
+ scansm->last_sched_time = cputime_get32();
+ }
+
+ /* Post scanning scheduled done event */
+ ble_ll_event_send(&scansm->scan_sched_ev);
return rc;
}
@@ -548,10 +646,15 @@ ble_ll_scan_start_cb(struct ble_ll_sched_item *sch)
* Stop the scanning state machine
*/
void
-ble_ll_scan_sm_stop(struct ble_ll_scan_sm *scansm, int conn_created)
+ble_ll_scan_sm_stop(int chk_disable)
{
+ os_sr_t sr;
+ uint8_t lls;
+ struct ble_ll_scan_sm *scansm;
+
/* Remove any scheduled advertising items */
- ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_SCAN, NULL);
+ scansm = &g_ble_ll_scan_sm;
+ ble_ll_sched_rmv_elem(&scansm->scan_sch);
/* Disable scanning state machine */
scansm->scan_enabled = 0;
@@ -559,57 +662,28 @@ ble_ll_scan_sm_stop(struct ble_ll_scan_sm *scansm, int conn_created)
/* Count # of times stopped */
++g_ble_ll_scan_stats.scan_stops;
- /* Only set state if we are current in a scan window */
- if ((g_ble_ll_data.ll_state == BLE_LL_STATE_SCANNING) ||
- (g_ble_ll_data.ll_state == BLE_LL_STATE_INITIATING)) {
- /* Disable the PHY */
- if (!conn_created) {
+ /* Only set state if we are currently in a scan window */
+ if (chk_disable) {
+ OS_ENTER_CRITICAL(sr);
+ lls = ble_ll_state_get();
+ if ((lls == BLE_LL_STATE_SCANNING) || (lls == BLE_LL_STATE_INITIATING)) {
+ /* Disable phy */
ble_phy_disable();
- }
-
- /* Disable whitelisting */
- ble_ll_whitelist_disable();
-
- /* Set LL state to standby */
- ble_ll_state_set(BLE_LL_STATE_STANDBY);
- }
-}
-static struct ble_ll_sched_item *
-ble_ll_scan_sched_set(struct ble_ll_scan_sm *scansm)
-{
- int rc;
- struct ble_ll_sched_item *sch;
+ /* Disable whitelisting */
+ ble_ll_whitelist_disable();
- sch = ble_ll_sched_get_item();
- if (sch) {
- /* Set sched type */
- sch->sched_type = BLE_LL_SCHED_TYPE_SCAN;
-
- /* Set the start time of the event */
- sch->start_time = scansm->scan_win_start_time -
- cputime_usecs_to_ticks(XCVR_RX_SCHED_DELAY_USECS);
-
- /* Set the callback, arg, start and end time */
- sch->cb_arg = scansm;
- sch->sched_cb = ble_ll_scan_start_cb;
- sch->end_time = scansm->scan_win_start_time +
- cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
-
- /* XXX: for now, we cant get an overlap so assert on error. */
- /* Add the item to the scheduler */
- rc = ble_ll_sched_add(sch);
- assert(rc == 0);
- } else {
- ++g_ble_ll_scan_stats.cant_set_sched;
+ /* Set LL state to standby */
+ ble_ll_state_set(BLE_LL_STATE_STANDBY);
+ }
+ OS_EXIT_CRITICAL(sr);
}
-
- return sch;
}
static int
ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm)
{
+ os_sr_t sr;
struct ble_ll_sched_item *sch;
/*
@@ -650,73 +724,74 @@ ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm)
scansm->backoff_count = 1;
scansm->scan_rsp_pending = 0;
+ /* Set schedule elements */
+ sch = &scansm->scan_sch;
+ sch->sched_type = BLE_LL_SCHED_TYPE_SCAN;
+ sch->cb_arg = scansm;
+ sch->sched_cb = ble_ll_scan_sched_cb;
+
+ /* XXX: align to current or next slot???. */
/* Schedule start time now */
scansm->scan_win_start_time = cputime_get32();
- /* Set packet in schedule */
- sch = ble_ll_scan_sched_set(scansm);
- if (!sch) {
- /* XXX: set a wakeup timer to deal with this. For now, assert */
- assert(0);
+ /*
+ * If we are in standby, start scanning. Otherwise, scanning will resume
+ * when the currently scheduled event ends.
+ */
+ OS_ENTER_CRITICAL(sr);
+ if (ble_ll_state_get() == BLE_LL_STATE_STANDBY) {
+ ble_ll_scan_start(scansm);
}
+ OS_EXIT_CRITICAL(sr);
+
+ /* Post scanning scheduled done event */
+ ble_ll_event_send(&scansm->scan_sched_ev);
return BLE_ERR_SUCCESS;
}
void
-ble_ll_scan_win_end_proc(void *arg)
+ble_ll_scan_event_proc(void *arg)
{
- int32_t delta_t;
+ uint32_t now;
+ uint32_t scan_win_start;
uint32_t itvl;
uint32_t win_ticks;
struct ble_ll_scan_sm *scansm;
+ struct ble_ll_sched_item *sch;
- /* Toggle the LED */
- gpio_toggle(LED_BLINK_PIN);
-
- /* We are no longer scanning */
scansm = (struct ble_ll_scan_sm *)arg;
- ble_ll_state_set(BLE_LL_STATE_STANDBY);
+ sch = &scansm->scan_sch;
- /* Move to next channel */
- ++scansm->scan_chan;
- if (scansm->scan_chan == BLE_PHY_NUM_CHANS) {
- scansm->scan_chan = BLE_PHY_ADV_CHAN_START;
- }
+ assert((int32_t)(scansm->last_sched_time-scansm->scan_win_start_time) >= 0);
- /* If there is a scan response pending, it means we failed a scan req */
- if (scansm->scan_rsp_pending) {
- ble_ll_scan_req_backoff(scansm, 0);
- }
-
- /* Calculate # of ticks per scan window */
- win_ticks = cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
-
- /* Set next scan window start time */
itvl = cputime_usecs_to_ticks(scansm->scan_itvl * BLE_HCI_SCAN_ITVL);
- scansm->scan_win_start_time += itvl;
-
- /* Set next scanning window start. */
- delta_t = (int32_t)(cputime_get32() - scansm->scan_win_start_time);
- while (delta_t >= (int32_t)win_ticks) {
- /*
- * Since it is possible to scan continuously, it is possible
- * that we will be late here if the scan window is equal to the
- * scan interval (or very close). So what we will do here is only
- * increment a stat if we missed a scan window
- */
- /* Count times we were late */
- ++g_ble_ll_scan_stats.scan_win_misses;
+ scan_win_start = scansm->scan_win_start_time;
+ while ((int32_t)(scansm->last_sched_time - scan_win_start) >= itvl) {
+ scan_win_start += itvl;
+ }
- /* Calculate start time of next scan windowe */
- scansm->scan_win_start_time += itvl;
- delta_t -= (int32_t)itvl;
+ /* Determine what the next scheduled scanning item should be. */
+ if (scansm->scan_window == scansm->scan_itvl) {
+ scan_win_start += itvl;
+ } else {
+ win_ticks = cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
+ if ((scansm->last_sched_time - scansm->scan_win_start_time) < win_ticks) {
+ scan_win_start += win_ticks;
+ } else {
+ scan_win_start += itvl;
+ }
}
- if (!ble_ll_scan_sched_set(scansm)) {
- /* XXX: we will need to set a timer here to wake us up */
- assert(0);
+ now = cputime_get32();
+ if ((int32_t)(now - scan_win_start) <= 0) {
+ sch->start_time = scan_win_start;
+ } else {
+ ++g_ble_ll_scan_stats.scan_event_misses;
+ sch->start_time = now;
}
+ sch->end_time = sch->start_time;
+ ble_ll_sched_scan(sch);
}
/**
@@ -734,7 +809,7 @@ ble_ll_scan_win_end_proc(void *arg)
* 1: we may send a response to this frame.
*/
int
-ble_ll_scan_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
+ble_ll_scan_rx_isr_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
{
int rc;
struct ble_ll_scan_sm *scansm;
@@ -762,6 +837,9 @@ ble_ll_scan_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_SCAN_RSP_CHK;
}
+
+ /* Disable wfr if running */
+ ble_ll_wfr_disable();
break;
case BLE_SCAN_TYPE_PASSIVE:
default:
@@ -784,7 +862,7 @@ ble_ll_scan_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
* > 0: Do not disable PHY as that has already been done.
*/
int
-ble_ll_scan_rx_pdu_end(struct os_mbuf *rxpdu)
+ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
{
int rc;
int chk_send_req;
@@ -796,9 +874,29 @@ ble_ll_scan_rx_pdu_end(struct os_mbuf *rxpdu)
struct ble_mbuf_hdr *ble_hdr;
struct ble_ll_scan_sm *scansm;
- /* If passively scanning return (with -1) since no scan request is sent */
+ /* Get scanning state machine */
scansm = &g_ble_ll_scan_sm;
+ /*
+ * The reason we do something different here (as opposed to failed CRC) is
+ * that the received PDU will not be handed up in this case. So we have
+ * to restart scanning and handle a failed scan request. Note that we
+ * return 0 in this case because we dont want the phy disabled.
+ */
+ if (rxpdu == NULL) {
+ if (scansm->scan_rsp_pending) {
+ ble_ll_scan_req_backoff(scansm, 0);
+ }
+ ble_phy_rx();
+ return 0;
+ }
+
+ /* Just leave if the CRC is not OK. */
+ rc = -1;
+ if (!crcok) {
+ goto scan_rx_isr_exit;
+ }
+
/* Get pdu type, pointer to address and address "type" */
rxbuf = rxpdu->om_data;
pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
@@ -839,7 +937,6 @@ ble_ll_scan_rx_pdu_end(struct os_mbuf *rxpdu)
}
/* Should we send a scan request? */
- rc = -1;
if (chk_send_req) {
/*
* Check to see if we have received a scan response from this
@@ -865,29 +962,44 @@ ble_ll_scan_rx_pdu_end(struct os_mbuf *rxpdu)
}
}
+scan_rx_isr_exit:
+ if (rc) {
+ ble_ll_state_set(BLE_LL_STATE_STANDBY);
+ }
return rc;
}
/**
- * Called to resume scanning, usually after a packet has been received
- * while in the scanning or inititating state.
+ * Called to resume scanning. This is called after an advertising event or
+ * connection event has ended. It is also called if we receive a packet while
+ * in the initiating or scanning state.
+ *
+ * Context: Link Layer task
*/
void
-ble_ll_scan_resume(void)
+ble_ll_scan_chk_resume(void)
{
- /* We need to re-enable the PHY if we are in idle state */
- if (ble_phy_state_get() == BLE_PHY_STATE_IDLE) {
- if (ble_phy_rx()) {
- /* If we fail, we will end the current scan window. */
- ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_SCAN, NULL);
- ble_ll_event_send(&g_ble_ll_scan_sm.scan_win_end_ev);
+ os_sr_t sr;
+ struct ble_ll_scan_sm *scansm;
+
+ scansm = &g_ble_ll_scan_sm;
+ if (scansm->scan_enabled) {
+ OS_ENTER_CRITICAL(sr);
+ if (ble_ll_state_get() == BLE_LL_STATE_STANDBY) {
+ if (!ble_ll_scan_window_chk(scansm)) {
+ /* Turn on the receiver and set state */
+ ble_ll_scan_start(scansm);
+ }
}
+ OS_EXIT_CRITICAL(sr);
}
}
/**
* Called when the wait for response timer expires while in the scanning
* state.
+ *
+ * Context: Interrupt.
*/
void
ble_ll_scan_wfr_timer_exp(void)
@@ -898,14 +1010,13 @@ ble_ll_scan_wfr_timer_exp(void)
/*
* If we timed out waiting for a response, the scan response pending
- * flag should be set. Deal with scan backoff.
+ * flag should be set. Deal with scan backoff. Put device back into rx.
*/
scansm = &g_ble_ll_scan_sm;
if (scansm->scan_rsp_pending) {
ble_ll_scan_req_backoff(scansm, 0);
}
-
- ble_ll_scan_resume();
+ ble_phy_rx();
}
/**
@@ -931,7 +1042,7 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
scan_rsp_chk = hdr->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_CHK;
/* We dont care about scan requests or connect requests */
- if ((!hdr->rxinfo.crcok) || (ptype == BLE_ADV_PDU_TYPE_SCAN_REQ) ||
+ if (!BLE_MBUF_HDR_CRC_OK(hdr) || (ptype == BLE_ADV_PDU_TYPE_SCAN_REQ) ||
(ptype == BLE_ADV_PDU_TYPE_CONNECT_REQ)) {
goto scan_continue;
}
@@ -994,9 +1105,10 @@ scan_continue:
* pending flag if we received a valid response
*/
if (scansm->scan_rsp_pending && scan_rsp_chk) {
- ble_ll_scan_req_backoff(scansm, 1);
+ ble_ll_scan_req_backoff(scansm, 0);
}
- ble_ll_scan_resume();
+
+ ble_ll_scan_chk_resume();
return;
}
@@ -1095,7 +1207,7 @@ ble_ll_scan_set_enable(uint8_t *cmd)
}
} else {
if (scansm->scan_enabled) {
- ble_ll_scan_sm_stop(scansm, 0);
+ ble_ll_scan_sm_stop(1);
}
}
@@ -1184,7 +1296,7 @@ ble_ll_scan_reset(void)
/* If enabled, stop it. */
scansm = &g_ble_ll_scan_sm;
if (scansm->scan_enabled) {
- ble_ll_scan_sm_stop(scansm, 0);
+ ble_ll_scan_sm_stop(0);
}
/* Reset all statistics */
@@ -1220,8 +1332,8 @@ ble_ll_scan_init(void)
memset(scansm, 0, sizeof(struct ble_ll_scan_sm));
/* Initialize scanning window end event */
- scansm->scan_win_end_ev.ev_type = BLE_LL_EVENT_SCAN_WIN_END;
- scansm->scan_win_end_ev.ev_arg = scansm;
+ scansm->scan_sched_ev.ev_type = BLE_LL_EVENT_SCAN;
+ scansm->scan_sched_ev.ev_arg = scansm;
/* Set all non-zero default parameters */
scansm->scan_itvl = BLE_HCI_SCAN_ITVL_DEF;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 e131dff..9a639f1 100644
--- a/net/nimble/controller/src/ble_ll_sched.c
+++ b/net/nimble/controller/src/ble_ll_sched.c
@@ -20,119 +20,542 @@
#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 "ble_ll_conn_priv.h"
#include "hal/hal_cputime.h"
/* XXX: this is temporary. Not sure what I want to do here */
struct cpu_timer g_ble_ll_sched_timer;
/* XXX: TODO:
- * 1) Add a "priority" scheme possibly. This would allow items to be
- * added if they overlapped.
- * 2) Add some accounting to the schedule code to see how late we are
+ * 1) Add some accounting to the schedule code to see how late we are
* (min/max?)
+ *
+ * 2) Need to determine how we really want to handle the case when we execute
+ * a schedule item but there is a current event. We could:
+ * -> Reschedule the schedule item and let current event finish
+ * -> Kill the current event and run the scheduled item.
+ * -> Disable schedule timer while in an event; could cause us to be late.
+ * -> Wait for current event to finish hoping it does before schedule item.
*/
-#define BLE_LL_CFG_SCHED_ITEMS (8)
-#define BLE_LL_SCHED_POOL_SIZE \
- OS_MEMPOOL_SIZE(BLE_LL_CFG_SCHED_ITEMS, sizeof(struct ble_ll_sched_item))
-
-struct os_mempool g_ble_ll_sched_pool;
-os_membuf_t g_ble_ll_sched_mem[BLE_LL_SCHED_POOL_SIZE];
/* Queue for timers */
TAILQ_HEAD(ll_sched_qhead, ble_ll_sched_item) g_ble_ll_sched_q;
/**
- * Executes a schedule item by calling the schedule callback function.
+ * Checks if two events in the schedule will overlap in time. NOTE: consecutive
+ * schedule items can end and start at the same time.
*
- * @param sch Pointer to schedule item
+ * @param s1
+ * @param s2
*
- * @return int 0: schedule item is not over; otherwise schedule item is done.
+ * @return int
*/
-int
-ble_ll_sched_execute(struct ble_ll_sched_item *sch)
+static int
+ble_ll_sched_is_overlap(struct ble_ll_sched_item *s1,
+ struct ble_ll_sched_item *s2)
{
int rc;
- assert(sch->sched_cb);
- rc = sch->sched_cb(sch);
+ rc = 1;
+ if ((int32_t)(s1->start_time - s2->start_time) < 0) {
+ /* Make sure this event does not overlap current event */
+ if ((int32_t)(s1->end_time - s2->start_time) <= 0) {
+ rc = 0;
+ }
+ } else {
+ /* Check for overlap */
+ if ((int32_t)(s1->start_time - s2->end_time) >= 0) {
+ rc = 0;
+ }
+ }
+
return rc;
}
-
/**
- * Allocate a schedule item
+ * Checks if the scheduled item 'sch' overlaps the scanning schedule item
+ * 'scan'. If so, the scanning scheduled item is removed and we post the
+ * scan event so that we can reschedule the next scanning opportunity.
*
- * @return struct ble_ll_sched_item*
+ *
+ * @param scan
+ * @param sch
*/
-struct ble_ll_sched_item *
-ble_ll_sched_get_item(void)
+static void
+ble_ll_sched_chk_scan_overlap(struct ble_ll_sched_item *scan,
+ struct ble_ll_sched_item *sch)
{
- struct ble_ll_sched_item *sch;
+ struct ble_ll_scan_sm *scansm;
- sch = os_memblock_get(&g_ble_ll_sched_pool);
- if (sch) {
- memset(sch, 0, sizeof(struct ble_ll_sched_item));
+ if (ble_ll_sched_is_overlap(scan, sch)) {
+ scansm = (struct ble_ll_scan_sm *)scan->cb_arg;
+ ble_ll_event_send(&scansm->scan_sched_ev);
+ TAILQ_REMOVE(&g_ble_ll_sched_q, scan, link);
+ scan->enqueued = 0;
}
- return sch;
}
-/**
- * Free a schedule item
- *
- * @param sch
+/*
+ * Determines if the schedule item overlaps the currently running schedule
+ * item. We only care about connection schedule items
*/
-void
-ble_ll_sched_free_item(struct ble_ll_sched_item *sch)
+int
+ble_ll_sched_overlaps_current(struct ble_ll_sched_item *sch)
{
- os_error_t err;
- err = os_memblock_put(&g_ble_ll_sched_pool, sch);
- assert(err == OS_OK);
+ int rc;
+ uint32_t ce_end_time;
+
+ rc = 0;
+ if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) {
+ ce_end_time = ble_ll_conn_get_ce_end_time();
+ if ((int32_t)(ce_end_time - sch->start_time) > 0) {
+ rc = 1;
+ }
+ }
+ return rc;
+}
+
+static int
+ble_ll_sched_conn_overlap(struct ble_ll_sched_item *entry)
+{
+ int rc;
+ struct ble_ll_conn_sm *connsm;
+
+ /* Should only be advertising or a connection here */
+ if (entry->sched_type == BLE_LL_SCHED_TYPE_CONN) {
+ connsm = (struct ble_ll_conn_sm *)entry->cb_arg;
+ entry->enqueued = 0;
+ TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link);
+ ble_ll_event_send(&connsm->conn_ev_end);
+ rc = 0;
+ } else {
+ rc = -1;
+ }
+
+ return rc;
+}
+
+struct ble_ll_sched_item *
+ble_ll_sched_insert_if_empty(struct ble_ll_sched_item *sch)
+{
+ struct ble_ll_sched_item *entry;
+
+ entry = TAILQ_FIRST(&g_ble_ll_sched_q);
+ if (!entry) {
+ TAILQ_INSERT_HEAD(&g_ble_ll_sched_q, sch, link);
+ sch->enqueued = 1;
+ }
+ return entry;
}
-/**
- * Add a schedule item to the schedule list
- *
- * @param sch
- *
- * @return int
- */
int
-ble_ll_sched_add(struct ble_ll_sched_item *sch)
+ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
{
int rc;
os_sr_t sr;
+ uint32_t usecs;
+ struct ble_ll_sched_item *sch;
+ struct ble_ll_sched_item *start_overlap;
+ struct ble_ll_sched_item *end_overlap;
struct ble_ll_sched_item *entry;
+ struct ble_ll_conn_sm *tmp;
+ struct ble_ll_scan_sm *scansm;
+
+ /* Get schedule element from connection */
+ sch = &connsm->conn_sch;
+
+ /* Set schedule start and end times */
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+ usecs = XCVR_RX_SCHED_DELAY_USECS;
+ usecs += connsm->slave_cur_window_widening;
+ } else {
+ usecs = XCVR_TX_SCHED_DELAY_USECS;
+ }
+ sch->start_time = connsm->anchor_point - cputime_usecs_to_ticks(usecs);
+ sch->end_time = connsm->ce_end_time;
+
+ /* Better be past current time or we just leave */
+ if ((int32_t)(sch->start_time - cputime_get32()) < 0) {
+ return -1;
+ }
- /* Determine if we are able to add this to the schedule */
+ /* We have to find a place for this schedule */
OS_ENTER_CRITICAL(sr);
+ if (ble_ll_sched_overlaps_current(sch)) {
+ OS_EXIT_CRITICAL(sr);
+ return -1;
+ }
+
+ /* Stop timer since we will add an element */
+ cputime_timer_stop(&g_ble_ll_sched_timer);
+
+ start_overlap = NULL;
+ end_overlap = NULL;
rc = 0;
- if (TAILQ_EMPTY(&g_ble_ll_sched_q)) {
- TAILQ_INSERT_HEAD(&g_ble_ll_sched_q, sch, link);
+ TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
+ if (ble_ll_sched_is_overlap(sch, entry)) {
+ /* Only insert if this element is older than all that we overlap */
+ if ((entry->sched_type != BLE_LL_SCHED_TYPE_SCAN) &&
+ ((entry->sched_type == BLE_LL_SCHED_TYPE_ADV) ||
+ !ble_ll_conn_is_lru((struct ble_ll_conn_sm *)sch->cb_arg,
+ (struct ble_ll_conn_sm *)entry->cb_arg))) {
+ start_overlap = NULL;
+ rc = -1;
+ break;
+ }
+ if (start_overlap == NULL) {
+ start_overlap = entry;
+ end_overlap = entry;
+ } else {
+ end_overlap = entry;
+ }
+ } else {
+ if ((int32_t)(sch->end_time - entry->start_time) < 0) {
+ rc = 0;
+ TAILQ_INSERT_BEFORE(entry, sch, link);
+ break;
+ }
+ }
+ }
+
+ if (!rc) {
+ if (!entry) {
+ TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
+ }
+ sch->enqueued = 1;
+ }
+
+ /* Remove first to last scheduled elements */
+ entry = start_overlap;
+ while (entry) {
+ start_overlap = TAILQ_NEXT(entry,link);
+ if (entry->sched_type == BLE_LL_SCHED_TYPE_CONN) {
+ tmp = (struct ble_ll_conn_sm *)entry->cb_arg;
+ ble_ll_event_send(&tmp->conn_ev_end);
+ } else {
+ scansm = (struct ble_ll_scan_sm *)entry->cb_arg;
+ ble_ll_event_send(&scansm->scan_sched_ev);
+ }
+
+ TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link);
+ entry->enqueued = 0;
+
+ if (entry == end_overlap) {
+ break;
+ }
+ entry = start_overlap;
+ }
+
+ /* Get first on list */
+ sch = TAILQ_FIRST(&g_ble_ll_sched_q);
+
+ OS_EXIT_CRITICAL(sr);
+
+ /* Restart timer */
+ cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
+
+ return rc;
+}
+
+int
+ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, uint32_t adv_rxend,
+ uint8_t req_slots)
+{
+ int rc;
+ os_sr_t sr;
+ uint32_t initial_start;
+ uint32_t earliest_start;
+ uint32_t earliest_end;
+ uint32_t dur;
+ uint32_t itvl_t;
+ uint32_t ce_end_time;
+ struct ble_ll_sched_item *entry;
+ struct ble_ll_sched_item *sch;
+ struct ble_ll_sched_item *scan;
+
+ /* Better have a connsm */
+ assert(connsm != NULL);
+
+ /* Assume no scheduled item is a scanning item */
+ scan = NULL;
+
+ /* Get schedule element from connection */
+ rc = -1;
+ sch = &connsm->conn_sch;
+
+ /*
+ * 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
+ */
+ dur = cputime_usecs_to_ticks(req_slots * BLE_LL_SCHED_USECS_PER_SLOT);
+ earliest_start = adv_rxend +
+ cputime_usecs_to_ticks(BLE_LL_IFS + BLE_LL_CONN_REQ_DURATION +
+ BLE_LL_CONN_INITIAL_OFFSET);
+ earliest_end = earliest_start + dur;
+
+ itvl_t = cputime_usecs_to_ticks(connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS);
+
+ /* 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) {
+ ce_end_time = ble_ll_conn_get_ce_end_time();
+ if ((int32_t)(ce_end_time - sch->start_time) >= 0) {
+ earliest_start = ce_end_time;
+ earliest_end = earliest_start + dur;
+ }
+ }
+ initial_start = earliest_start;
+
+ if (!ble_ll_sched_insert_if_empty(sch)) {
+ /* Nothing in schedule. Schedule as soon as possible */
+ rc = 0;
+ connsm->tx_win_off = 0;
} else {
cputime_timer_stop(&g_ble_ll_sched_timer);
TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
- if ((int32_t)(sch->start_time - entry->start_time) < 0) {
- /* Make sure this event does not overlap current event */
+ /* Ignore scan/initiate types */
+ if (entry->sched_type == BLE_LL_SCHED_TYPE_SCAN) {
+ scan = entry;
+ continue;
+ }
+
+ /* Set these because the overlap function needs them to be set */
+ sch->start_time = earliest_start;
+ sch->end_time = earliest_end;
+
+ /* Check for overlapping events */
+ if (ble_ll_sched_is_overlap(sch, entry)) {
+ /* Earliest start is end of this event since we overlap */
+ earliest_start = entry->end_time;
+ earliest_end = earliest_start + dur;
+ } else {
+ /* We can insert if before entry in list */
+ if ((int32_t)(sch->end_time - entry->start_time) < 0) {
+ if ((earliest_start - initial_start) <= itvl_t) {
+ rc = 0;
+ TAILQ_INSERT_BEFORE(entry, sch, link);
+ }
+ break;
+ }
+ }
+ }
+
+ if (!entry) {
+ if ((earliest_start - initial_start) <= itvl_t) {
+ rc = 0;
+ TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
+ }
+ }
+
+ if (!rc) {
+ /* calculate number of connection intervals before start */
+ sch->enqueued = 1;
+ connsm->tx_win_off = (earliest_start - initial_start) /
+ cputime_usecs_to_ticks(BLE_LL_CONN_ITVL_USECS);
+ }
+
+ /* Restart with head of list */
+ sch = TAILQ_FIRST(&g_ble_ll_sched_q);
+ }
+
+ if (!rc) {
+ sch->start_time = earliest_start;
+ sch->end_time = earliest_end;
+ connsm->anchor_point = earliest_start +
+ cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+ connsm->ce_end_time = earliest_end;
+
+ /*
+ * If there was a scanning item it is possible that the order of the
+ * scanning item and the newly added connection are incorrect. So,
+ * we check for overlap and if there is one, we reschedule the
+ * scanning item
+ */
+ if (scan) {
+ ble_ll_sched_chk_scan_overlap(scan, sch);
+ }
+ }
+
+ OS_EXIT_CRITICAL(sr);
+
+ cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
+
+ return rc;
+}
+
+int
+ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm)
+{
+ int rc;
+ os_sr_t sr;
+ struct ble_ll_sched_item *entry;
+ struct ble_ll_sched_item *next_sch;
+ struct ble_ll_sched_item *sch;
+ struct ble_ll_sched_item *scan;
+
+ /* Get schedule element from connection */
+ rc = -1;
+ sch = &connsm->conn_sch;
+
+ /* Set schedule start and end times */
+ sch->start_time = connsm->anchor_point -
+ cputime_usecs_to_ticks(XCVR_RX_SCHED_DELAY_USECS +
+ connsm->slave_cur_window_widening);
+ sch->end_time = connsm->ce_end_time;
+
+ /* We have to find a place for this schedule */
+ OS_ENTER_CRITICAL(sr);
+
+ /* The schedule item must occur after current running item (if any) */
+ if (ble_ll_sched_overlaps_current(sch)) {
+ OS_EXIT_CRITICAL(sr);
+ return rc;
+ }
+
+ entry = ble_ll_sched_insert_if_empty(sch);
+ if (!entry) {
+ /* Nothing in schedule. Schedule as soon as possible */
+ rc = 0;
+ } else {
+ scan = NULL;
+ cputime_timer_stop(&g_ble_ll_sched_timer);
+ while (1) {
+ /* Skip scanning schedule items */
+ if (entry->sched_type == BLE_LL_SCHED_TYPE_SCAN) {
+ scan = entry;
+ continue;
+ }
+
+ next_sch = entry->link.tqe_next;
+ if (ble_ll_sched_is_overlap(sch, entry)) {
+ if (ble_ll_sched_conn_overlap(entry)) {
+ break;
+ }
+ } else {
if ((int32_t)(sch->end_time - entry->start_time) < 0) {
- TAILQ_INSERT_BEFORE(entry, sch, link);
- } else {
- rc = BLE_LL_SCHED_ERR_OVERLAP;
+ rc = 0;
+ TAILQ_INSERT_BEFORE(entry, sch, link);
+ break;
}
+ }
+
+ /* Move to next entry */
+ entry = next_sch;
+
+ /* Insert at tail if none left to check */
+ if (!entry) {
+ rc = 0;
+ TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
break;
+ }
+ }
+
+ if (!rc) {
+ sch->enqueued = 1;
+ if (scan) {
+ ble_ll_sched_chk_scan_overlap(scan, sch);
+ }
+ }
+ sch = TAILQ_FIRST(&g_ble_ll_sched_q);
+ }
+
+ OS_EXIT_CRITICAL(sr);
+
+ cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
+
+ return rc;
+}
+
+int
+ble_ll_sched_adv_new(struct ble_ll_sched_item *sch)
+{
+ int rc;
+ os_sr_t sr;
+ uint32_t ce_end_time;
+ uint32_t adv_start;
+ uint32_t duration;
+ struct ble_ll_sched_item *entry;
+ struct ble_ll_sched_item *scan;
+
+ /* Get length of schedule item */
+ duration = sch->end_time - sch->start_time;
+
+ 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.
+ */
+ if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) {
+ sch->start_time += cputime_usecs_to_ticks(BLE_LL_SCHED_USECS_PER_SLOT);
+ ce_end_time = ble_ll_conn_get_ce_end_time();
+ if ((int32_t)(ce_end_time - sch->start_time) >= 0) {
+ sch->start_time = ce_end_time;
+ }
+ sch->end_time = sch->start_time + duration;
+ }
+
+ entry = ble_ll_sched_insert_if_empty(sch);
+ if (!entry) {
+ rc = 0;
+ adv_start = sch->start_time;
+ } else {
+ scan = NULL;
+ cputime_timer_stop(&g_ble_ll_sched_timer);
+ TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
+ /* Ignore scan/initiate types */
+ if (entry->sched_type == BLE_LL_SCHED_TYPE_SCAN) {
+ scan = entry;
+ continue;
+ }
+
+ /* Check for overlapping events */
+ if (ble_ll_sched_is_overlap(sch, entry)) {
+ /* Earliest start is end of this event since we overlap */
+ sch->start_time = entry->end_time;
+ sch->end_time = sch->start_time + duration;
} else {
- /* Check for overlap */
- if ((int32_t)(sch->start_time - entry->end_time) < 0) {
- rc = BLE_LL_SCHED_ERR_OVERLAP;
+ /* We can insert if before entry in list */
+ if ((int32_t)(sch->end_time - entry->start_time) < 0) {
+ rc = 0;
+ TAILQ_INSERT_BEFORE(entry, sch, link);
break;
}
}
}
+
if (!entry) {
+ rc = 0;
TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
}
+ adv_start = sch->start_time;
+
+ if (!rc) {
+ sch->enqueued = 1;
+ if (scan) {
+ ble_ll_sched_chk_scan_overlap(scan, sch);
+ }
+ }
+
+ /* Restart with head of list */
+ sch = TAILQ_FIRST(&g_ble_ll_sched_q);
}
+ ble_ll_adv_scheduled(adv_start);
+
OS_EXIT_CRITICAL(sr);
cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
@@ -140,49 +563,198 @@ ble_ll_sched_add(struct ble_ll_sched_item *sch)
return rc;
}
-/**
- * Remove a schedule item. You can use this function to:
- * 1) Remove all schedule items of type 'sched_type' (cb_arg = NULL)
- * 2) Remove schedule items of type 'sched_type' and matching callback args
- *
- *
- * @param sched_type
- *
- * @return int
- */
int
-ble_ll_sched_rmv(uint8_t sched_type, void *cb_arg)
+ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch)
{
+ int rc;
os_sr_t sr;
struct ble_ll_sched_item *entry;
- struct ble_ll_sched_item *next;
+ struct ble_ll_sched_item *next_sch;
+ struct ble_ll_sched_item *scan;
OS_ENTER_CRITICAL(sr);
- entry = TAILQ_FIRST(&g_ble_ll_sched_q);
- if (entry) {
+ /* The schedule item must occur after current running item (if any) */
+ if (ble_ll_sched_overlaps_current(sch)) {
+ OS_EXIT_CRITICAL(sr);
+ return -1;
+ }
+
+ entry = ble_ll_sched_insert_if_empty(sch);
+ if (!entry) {
+ /* Nothing in schedule. Schedule as soon as possible */
+ rc = 0;
+ } else {
+ scan = NULL;
cputime_timer_stop(&g_ble_ll_sched_timer);
- while (entry) {
- next = TAILQ_NEXT(entry, link);
- if (entry->sched_type == sched_type) {
- if ((cb_arg == NULL) || (cb_arg == entry->cb_arg)) {
- TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link);
- os_memblock_put(&g_ble_ll_sched_pool, entry);
+ while (1) {
+ /* Skip scanning schedule items */
+ if (entry->sched_type == BLE_LL_SCHED_TYPE_SCAN) {
+ scan = entry;
+ continue;
+ }
+
+ next_sch = entry->link.tqe_next;
+ if (ble_ll_sched_is_overlap(sch, entry)) {
+ if (ble_ll_sched_conn_overlap(entry)) {
+ assert(0);
+ }
+ } else {
+ if ((int32_t)(sch->end_time - entry->start_time) < 0) {
+ rc = 0;
+ TAILQ_INSERT_BEFORE(entry, sch, link);
+ break;
}
- }
- entry = next;
+ }
+
+ /* Move to next entry */
+ entry = next_sch;
+
+ /* Insert at tail if none left to check */
+ if (!entry) {
+ rc = 0;
+ TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
+ break;
+ }
}
- /* Start the timer if there is an item */
- entry = TAILQ_FIRST(&g_ble_ll_sched_q);
- if (entry) {
- cputime_timer_start(&g_ble_ll_sched_timer, entry->start_time);
+ if (!rc) {
+ sch->enqueued = 1;
+ if (scan) {
+ ble_ll_sched_chk_scan_overlap(scan, sch);
+ }
}
+
+ sch = TAILQ_FIRST(&g_ble_ll_sched_q);
}
OS_EXIT_CRITICAL(sr);
- return 0;
+ cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
+
+ return rc;
+}
+
+void
+ble_ll_sched_scan(struct ble_ll_sched_item *sch)
+{
+ int insert_head;
+ os_sr_t sr;
+ struct ble_ll_sched_item *entry;
+
+ OS_ENTER_CRITICAL(sr);
+
+ entry = ble_ll_sched_insert_if_empty(sch);
+ if (!entry) {
+ insert_head = 1;
+ } else {
+ TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
+ /* No need to worry about overlap. */
+ if ((int32_t)(sch->start_time - entry->start_time) < 0) {
+ TAILQ_INSERT_BEFORE(entry, sch, link);
+ break;
+ }
+ }
+
+ insert_head = 0;
+ if (!entry) {
+ TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
+ } else {
+ if (sch == TAILQ_FIRST(&g_ble_ll_sched_q)) {
+ cputime_timer_stop(&g_ble_ll_sched_timer);
+ insert_head = 1;
+ }
+ }
+ sch->enqueued = 1;
+ }
+
+ OS_EXIT_CRITICAL(sr);
+
+ if (insert_head) {
+ cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
+ }
+}
+
+/**
+ * Remove a schedule element
+ *
+ * @param sched_type
+ *
+ * @return int
+ */
+void
+ble_ll_sched_rmv_elem(struct ble_ll_sched_item *sch)
+{
+ os_sr_t sr;
+ struct ble_ll_sched_item *first;
+
+ if (!sch) {
+ return;
+ }
+
+ OS_ENTER_CRITICAL(sr);
+ if (sch->enqueued) {
+ first = TAILQ_FIRST(&g_ble_ll_sched_q);
+ if (first == sch) {
+ cputime_timer_stop(&g_ble_ll_sched_timer);
+ }
+
+ TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link);
+ sch->enqueued = 0;
+
+ if (first == sch) {
+ first = TAILQ_FIRST(&g_ble_ll_sched_q);
+ if (first) {
+ cputime_timer_start(&g_ble_ll_sched_timer, first->start_time);
+ }
+ }
+ }
+ OS_EXIT_CRITICAL(sr);
+}
+
+/**
+ * Executes a schedule item by calling the schedule callback function.
+ *
+ * @param sch Pointer to schedule item
+ *
+ * @return int 0: schedule item is not over; otherwise schedule item is done.
+ */
+static int
+ble_ll_sched_execute_item(struct ble_ll_sched_item *sch)
+{
+ int rc;
+ uint8_t lls;
+
+ /*
+ * Scanning items are special. If this is one, just call the callback.
+ * If we are doing something else the callback will handle it.
+ */
+ if (sch->sched_type != BLE_LL_SCHED_TYPE_SCAN) {
+ /*
+ * This is either an advertising event or connection event start. If
+ * we are scanning or initiating just stop it.
+ */
+ lls = ble_ll_state_get();
+ if (lls != BLE_LL_STATE_STANDBY) {
+ /* We have to disable the PHY no matter what */
+ ble_phy_disable();
+ ble_ll_wfr_disable();
+ if ((lls == BLE_LL_STATE_SCANNING) ||
+ (lls == BLE_LL_STATE_INITIATING)) {
+ ble_ll_state_set(BLE_LL_STATE_STANDBY);
+ } else if (lls == BLE_LL_STATE_ADV) {
+ ++g_ble_ll_stats.sched_state_adv_errs;
+ ble_ll_adv_halt();
+ } else {
+ ble_ll_conn_event_halt();
+ ++g_ble_ll_stats.sched_state_conn_errs;
+ }
+ }
+ }
+
+ assert(sch->sched_cb);
+ rc = sch->sched_cb(sch);
+ return rc;
}
/**
@@ -195,23 +767,16 @@ ble_ll_sched_rmv(uint8_t sched_type, void *cb_arg)
void
ble_ll_sched_run(void *arg)
{
- int rc;
struct ble_ll_sched_item *sch;
/* Look through schedule queue */
while ((sch = TAILQ_FIRST(&g_ble_ll_sched_q)) != NULL) {
/* Make sure we have passed the start time of the first event */
if ((int32_t)(cputime_get32() - sch->start_time) >= 0) {
- /* Execute the schedule item */
- rc = ble_ll_sched_execute(sch);
- if (rc) {
- TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link);
- os_memblock_put(&g_ble_ll_sched_pool, sch);
- } else {
- /* Event is not over; schedule next wakeup time */
- cputime_timer_start(&g_ble_ll_sched_timer, sch->next_wakeup);
- break;
- }
+ /* Execute the schedule item and remove it when done */
+ ble_ll_sched_execute_item(sch);
+ TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link);
+ sch->enqueued = 0;
} else {
cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
break;
@@ -220,6 +785,17 @@ ble_ll_sched_run(void *arg)
}
/**
+ * Stop the scheduler
+ *
+ * Context: Link Layer task
+ */
+void
+ble_ll_sched_stop(void)
+{
+ cputime_timer_stop(&g_ble_ll_sched_timer);
+}
+
+/**
* Initialize the scheduler. Should only be called once and should be called
* before any of the scheduler API are called.
*
@@ -228,15 +804,7 @@ ble_ll_sched_run(void *arg)
int
ble_ll_sched_init(void)
{
- os_error_t err;
-
- err = os_mempool_init(&g_ble_ll_sched_pool, BLE_LL_CFG_SCHED_ITEMS,
- sizeof(struct ble_ll_sched_item),
- g_ble_ll_sched_mem, "ll_sched");
- assert(err == OS_OK);
-
/* Initialize cputimer for the scheduler */
cputime_timer_init(&g_ble_ll_sched_timer, ble_ll_sched_run, NULL);
-
- return err;
+ return 0;
}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/drivers/native/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/native/src/ble_phy.c b/net/nimble/drivers/native/src/ble_phy.c
index 9a39c5c..cf0a154 100644
--- a/net/nimble/drivers/native/src/ble_phy.c
+++ b/net/nimble/drivers/native/src/ble_phy.c
@@ -41,6 +41,7 @@ struct ble_phy_statistics
{
uint32_t tx_good;
uint32_t tx_fail;
+ uint32_t tx_late;
uint32_t tx_bytes;
uint32_t rx_starts;
uint32_t rx_aborts;
@@ -118,6 +119,7 @@ void
ble_phy_isr(void)
{
int rc;
+ uint8_t crcok;
uint8_t transition;
uint32_t irq_en;
struct os_mbuf *rxpdu;
@@ -180,19 +182,20 @@ ble_phy_isr(void)
ble_hdr->rxinfo.flags = 0;
ble_hdr->rxinfo.rssi = -77; /* XXX: dummy rssi */
ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
- ble_hdr->rxinfo.crcok = 1;
/* Count PHY crc errors and valid packets */
- if (ble_hdr->rxinfo.crcok == 0) {
+ crcok = 1;
+ if (!crcok) {
++g_ble_phy_stats.rx_crc_err;
} else {
++g_ble_phy_stats.rx_valid;
+ ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK;
}
/* Call Link Layer receive payload function */
rxpdu = g_ble_phy_data.rxpdu;
g_ble_phy_data.rxpdu = NULL;
- rc = ble_ll_rx_end(rxpdu,ble_hdr->rxinfo.channel,ble_hdr->rxinfo.crcok);
+ rc = ble_ll_rx_end(rxpdu, ble_hdr);
if (rc < 0) {
/* Disable the PHY. */
ble_phy_disable();
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/drivers/nrf52/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/nrf52/src/ble_phy.c b/net/nimble/drivers/nrf52/src/ble_phy.c
index a12336c..90463a6 100644
--- a/net/nimble/drivers/nrf52/src/ble_phy.c
+++ b/net/nimble/drivers/nrf52/src/ble_phy.c
@@ -23,6 +23,8 @@
#include "controller/ble_ll.h"
#include "mcu/nrf52_bitfields.h"
+/* XXX: 4) Make sure RF is higher priority interrupt than schedule */
+
/* To disable all radio interrupts */
#define NRF52_RADIO_IRQ_MASK_ALL (0x34FF)
@@ -154,6 +156,7 @@ ble_phy_isr(void)
{
int rc;
uint8_t transition;
+ uint8_t crcok;
uint32_t irq_en;
uint32_t state;
uint32_t wfr_time;
@@ -163,13 +166,14 @@ ble_phy_isr(void)
/* Read irq register to determine which interrupts are enabled */
irq_en = NRF_RADIO->INTENCLR;
- ble_ll_log(BLE_LL_LOG_ID_PHY_ISR, 0, 0, irq_en);
-
/* Check for disabled event. This only happens for transmits now */
if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) {
/* Better be in TX state! */
assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX);
+ ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, g_ble_phy_txrx_buf[1], 0,
+ NRF_TIMER0->CC[2]);
+
/* Clear events and clear interrupt on disabled event */
NRF_RADIO->EVENTS_DISABLED = 0;
NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk;
@@ -249,10 +253,11 @@ ble_phy_isr(void)
}
}
- /* Initialize flags and channel in ble header at rx start */
+ /* Initialize flags, channel and state in ble header at rx start */
ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu);
- ble_hdr->rxinfo.flags = 0;
+ ble_hdr->rxinfo.flags = ble_ll_state_get();
ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
+ ble_hdr->rxinfo.handle = 0;
/* Call Link Layer receive start function */
rc = ble_ll_rx_start(g_ble_phy_data.rxpdu, g_ble_phy_data.phy_chan);
@@ -291,21 +296,21 @@ ble_phy_isr(void)
ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu);
assert(NRF_RADIO->EVENTS_RSSIEND != 0);
ble_hdr->rxinfo.rssi = -1 * NRF_RADIO->RSSISAMPLE;
- ble_hdr->rxinfo.crcok = (uint8_t)NRF_RADIO->CRCSTATUS;
ble_hdr->end_cputime = NRF_TIMER0->CC[2];
/* Count PHY crc errors and valid packets */
- if (ble_hdr->rxinfo.crcok == 0) {
+ crcok = (uint8_t)NRF_RADIO->CRCSTATUS;
+ if (!crcok) {
++g_ble_phy_stats.rx_crc_err;
} else {
++g_ble_phy_stats.rx_valid;
+ ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK;
}
/* Call Link Layer receive payload function */
rxpdu = g_ble_phy_data.rxpdu;
g_ble_phy_data.rxpdu = NULL;
- rc = ble_ll_rx_end(rxpdu, ble_hdr->rxinfo.channel,
- ble_hdr->rxinfo.crcok);
+ rc = ble_ll_rx_end(rxpdu, ble_hdr);
if (rc < 0) {
/* Disable the PHY. */
ble_phy_disable();
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/include/nimble/ble.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/ble.h b/net/nimble/include/nimble/ble.h
index 170d6f4..bcb9ff5 100644
--- a/net/nimble/include/nimble/ble.h
+++ b/net/nimble/include/nimble/ble.h
@@ -47,7 +47,7 @@ struct ble_mbuf_hdr_rxinfo
{
uint8_t flags;
uint8_t channel;
- uint8_t crcok;
+ uint8_t handle;
int8_t rssi;
};
@@ -68,14 +68,24 @@ struct ble_mbuf_hdr
uint32_t end_cputime;
};
-/* Flag definitions. Apply to both txinfo and rxinfo */
-#define BLE_MBUF_HDR_F_DEVMATCH (0x01)
-#define BLE_MBUF_HDR_F_CONN_REQ_TXD (0x02)
-#define BLE_MBUF_HDR_F_TXD (0x04)
-#define BLE_MBUF_HDR_F_SCAN_RSP_TXD (0x08)
-#define BLE_MBUF_HDR_F_SCAN_RSP_CHK (0x10)
+/* Flag definitions for rxinfo */
+#define BLE_MBUF_HDR_F_CRC_OK (0x80)
+#define BLE_MBUF_HDR_F_DEVMATCH (0x40)
+#define BLE_MBUF_HDR_F_CONN_REQ_TXD (0x20)
+#define BLE_MBUF_HDR_F_SCAN_RSP_TXD (0x10)
+#define BLE_MBUF_HDR_F_SCAN_RSP_CHK (0x08)
+#define BLE_MBUF_HDR_F_RXSTATE_MASK (0x07)
-#define BLE_MBUF_HDR_PTR(om) \
+/* Flag definitions for txinfo */
+#define BLE_MBUF_HDR_F_TXD (0x01)
+
+#define BLE_MBUF_HDR_CRC_OK(hdr) \
+ ((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_CRC_OK)
+
+#define BLE_MBUF_HDR_RX_STATE(hdr) \
+ ((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_RXSTATE_MASK)
+
+#define BLE_MBUF_HDR_PTR(om) \
(struct ble_mbuf_hdr *)((uint8_t *)om + sizeof(struct os_mbuf) + \
sizeof(struct os_mbuf_pkthdr))
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/project/bletest/src/main.c
----------------------------------------------------------------------
diff --git a/project/bletest/src/main.c b/project/bletest/src/main.c
index 48555a3..a3c1466 100755
--- a/project/bletest/src/main.c
+++ b/project/bletest/src/main.c
@@ -30,6 +30,8 @@
#include "controller/ble_ll.h"
#include "controller/ble_ll_hci.h"
#include "controller/ble_ll_conn.h"
+#include "controller/ble_ll_scan.h"
+#include "controller/ble_ll_adv.h"
/* Init all tasks */
volatile int tasks_initialized;
@@ -51,7 +53,7 @@ uint8_t g_host_adv_data[BLE_HCI_MAX_ADV_DATA_LEN];
uint8_t g_host_adv_len;
/* Create a mbuf pool of BLE mbufs */
-#define MBUF_NUM_MBUFS (16)
+#define MBUF_NUM_MBUFS (20)
#define MBUF_BUF_SIZE \
((BLE_LL_CFG_ACL_DATA_PKT_LEN + sizeof(struct hci_data_hdr) + 3) & 0xFFFC)
#define MBUF_MEMBLOCK_SIZE (MBUF_BUF_SIZE + BLE_MBUF_PKT_OVERHEAD)
@@ -66,23 +68,25 @@ os_membuf_t g_mbuf_buffer[MBUF_MEMPOOL_SIZE];
#define BLETEST_ROLE_ADVERTISER (0)
#define BLETEST_ROLE_SCANNER (1)
#define BLETEST_ROLE_INITIATOR (2)
-#define BLETEST_CFG_ROLE (BLETEST_ROLE_INITIATOR)
+#define BLETEST_CFG_ROLE (BLETEST_ROLE_ADVERTISER)
#define BLETEST_CFG_FILT_DUP_ADV (0)
-#define BLETEST_CFG_ADV_ITVL (500000 / BLE_HCI_ADV_ITVL)
+#define BLETEST_CFG_ADV_ITVL (60000 / BLE_HCI_ADV_ITVL)
#define BLETEST_CFG_ADV_TYPE BLE_HCI_ADV_TYPE_ADV_IND
#define BLETEST_CFG_ADV_FILT_POLICY (BLE_HCI_ADV_FILT_NONE)
#define BLETEST_CFG_SCAN_ITVL (700000 / BLE_HCI_SCAN_ITVL)
-#define BLETEST_CFG_SCAN_WINDOW (650000 / BLE_HCI_SCAN_ITVL)
+#define BLETEST_CFG_SCAN_WINDOW (700000 / BLE_HCI_SCAN_ITVL)
#define BLETEST_CFG_SCAN_TYPE (BLE_HCI_SCAN_TYPE_ACTIVE)
#define BLETEST_CFG_SCAN_FILT_POLICY (BLE_HCI_SCAN_FILT_NO_WL)
-#define BLETEST_CFG_CONN_ITVL (1000) /* 1250 msecs */
+#define BLETEST_CFG_CONN_ITVL (1000) /* in 1.25 msec increments */
#define BLETEST_CFG_SLAVE_LATENCY (0)
#define BLETEST_CFG_INIT_FILTER_POLICY (BLE_HCI_CONN_FILT_NO_WL)
#define BLETEST_CFG_CONN_SPVN_TMO (1000) /* 10 seconds */
-#define BLETEST_CFG_MIN_CE_LEN (1000)
-#define BLETEST_CFG_MAX_CE_LEN (BLETEST_CFG_CONN_ITVL * 2)
+#define BLETEST_CFG_MIN_CE_LEN (6)
+#define BLETEST_CFG_MAX_CE_LEN (BLETEST_CFG_CONN_ITVL)
+#define BLETEST_CFG_CONCURRENT_CONNS (8)
/* BLETEST variables */
+#define BLETEST_PKT_SIZE (128)
#define BLETEST_STACK_SIZE (256)
#define BLETEST_TASK_PRIO (HOST_TASK_PRIO + 1)
uint32_t g_next_os_time;
@@ -92,8 +96,11 @@ struct os_callout_func g_bletest_timer;
struct os_task bletest_task;
os_stack_t bletest_stack[BLETEST_STACK_SIZE];
uint32_t g_bletest_conn_end;
-#define BLETEST_PKT_SIZE (128)
+uint8_t g_bletest_current_conns;
+uint8_t g_bletest_cur_peer_addr[BLE_DEV_ADDR_LEN];
+uint8_t g_last_handle_used;
+#if 0
void
bletest_inc_adv_pkt_num(void)
{
@@ -121,6 +128,13 @@ bletest_inc_adv_pkt_num(void)
host_hci_outstanding_opcode = 0;
}
}
+#else
+void
+bletest_inc_adv_pkt_num(void)
+{
+ return;
+}
+#endif
/**
* Sets the advertising data to be sent in advertising pdu's which contain
@@ -173,6 +187,7 @@ bletest_set_adv_data(uint8_t *dptr)
return len;
}
+#if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
void
bletest_init_advertising(void)
{
@@ -180,6 +195,9 @@ bletest_init_advertising(void)
uint8_t adv_len;
struct hci_adv_params adv;
+ /* Just zero out advertising */
+ memset(&adv, 0, sizeof(struct hci_adv_params));
+
/* Set advertising parameters */
adv.adv_type = BLETEST_CFG_ADV_TYPE;
adv.adv_channel_map = 0x07;
@@ -188,22 +206,21 @@ bletest_init_advertising(void)
adv.peer_addr_type = BLE_HCI_ADV_PEER_ADDR_PUBLIC;
if ((adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) ||
(adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD)) {
- adv.peer_addr[0] = 0x00;
- adv.peer_addr[1] = 0x00;
- adv.peer_addr[2] = 0x00;
- adv.peer_addr[3] = 0x99;
- adv.peer_addr[4] = 0x99;
- adv.peer_addr[5] = 0x09;
+ memcpy(adv.peer_addr, g_bletest_cur_peer_addr, BLE_DEV_ADDR_LEN);
adv_len = 0;
} else {
adv_len = bletest_set_adv_data(&g_host_adv_data[0]);
}
+ console_printf("Trying to connect to %x.%x.%x.%x.%x.%x\n",
+ adv.peer_addr[0], adv.peer_addr[1], adv.peer_addr[2],
+ adv.peer_addr[3], adv.peer_addr[4], adv.peer_addr[5]);
+
if (adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
adv.adv_itvl_min = 0;
adv.adv_itvl_max = 0;
} else {
- adv.adv_itvl_min = BLE_HCI_ADV_ITVL_NONCONN_MIN;
+ adv.adv_itvl_min = BLETEST_CFG_ADV_ITVL;
adv.adv_itvl_max = BLETEST_CFG_ADV_ITVL; /* Advertising interval */
}
@@ -224,6 +241,7 @@ bletest_init_advertising(void)
host_hci_outstanding_opcode = 0;
}
}
+#endif
#if (BLETEST_CFG_ROLE == BLETEST_ROLE_SCANNER)
void
@@ -256,6 +274,28 @@ bletest_init_scanner(void)
host_hci_outstanding_opcode = 0;
}
}
+
+void
+bletest_execute(void)
+{
+ int rc;
+
+ /* Enable scanning */
+ if ((int32_t)(os_time_get() - g_next_os_time) >= 0) {
+ if (g_bletest_state) {
+ rc = host_hci_cmd_le_set_scan_enable(0, BLETEST_CFG_FILT_DUP_ADV);
+ assert(rc == 0);
+ host_hci_outstanding_opcode = 0;
+ g_bletest_state = 0;
+ } else {
+ rc = host_hci_cmd_le_set_scan_enable(1, BLETEST_CFG_FILT_DUP_ADV);
+ assert(rc == 0);
+ host_hci_outstanding_opcode = 0;
+ g_bletest_state = 1;
+ }
+ g_next_os_time += (OS_TICKS_PER_SEC * 60);
+ }
+}
#endif
#if (BLETEST_CFG_ROLE == BLETEST_ROLE_INITIATOR)
@@ -276,20 +316,48 @@ bletest_init_initiator(void)
hcc->scan_itvl = BLETEST_CFG_SCAN_ITVL;
hcc->scan_window = BLETEST_CFG_SCAN_WINDOW;
hcc->peer_addr_type = BLE_HCI_CONN_PEER_ADDR_PUBLIC;
- hcc->peer_addr[0] = 0x00;
- hcc->peer_addr[1] = 0x00;
- hcc->peer_addr[2] = 0x00;
- hcc->peer_addr[3] = 0x88;
- hcc->peer_addr[4] = 0x88;
- hcc->peer_addr[5] = 0x08;
+ memcpy(hcc->peer_addr, g_bletest_cur_peer_addr, BLE_DEV_ADDR_LEN);
hcc->own_addr_type = BLE_HCI_CONN_PEER_ADDR_PUBLIC;
hcc->min_ce_len = BLETEST_CFG_MIN_CE_LEN;
hcc->max_ce_len = BLETEST_CFG_MAX_CE_LEN;
+ console_printf("Trying to connect to %x.%x.%x.%x.%x.%x\n",
+ hcc->peer_addr[0], hcc->peer_addr[1], hcc->peer_addr[2],
+ hcc->peer_addr[3], hcc->peer_addr[4], hcc->peer_addr[5]);
+
rc = host_hci_cmd_le_create_connection(hcc);
assert(rc == 0);
host_hci_outstanding_opcode = 0;
}
+
+void
+bletest_execute(void)
+{
+ uint16_t handle;
+
+ /*
+ * Determine if there is an active connection for the current handle
+ * we are trying to create. If so, start looking for the next one
+ */
+ if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
+ handle = g_bletest_current_conns + 1;
+ if (ble_ll_conn_find_active_conn(handle)) {
+ /* Scanning better be stopped! */
+ assert(ble_ll_scan_enabled() == 0);
+
+ /* Add to current connections */
+ ++g_bletest_current_conns;
+
+ /* Move to next connection */
+ if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
+ /* restart initiating */
+ g_bletest_cur_peer_addr[5] += 1;
+ g_dev_addr[5] += 1;
+ bletest_init_initiator();
+ }
+ }
+ }
+}
#endif
#if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
@@ -303,19 +371,18 @@ bletest_get_packet(void)
struct os_mbuf *om;
om = NULL;
- if (g_mbuf_pool.omp_pool->mp_num_free >= (MBUF_NUM_MBUFS / 2)) {
+ if (g_mbuf_pool.omp_pool->mp_num_free >= 5) {
ble_get_packet(om);
}
return om;
}
-#endif
+#if 0
void
bletest_execute(void)
{
int rc;
-#if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
int i;
uint16_t pktlen;
uint16_t handle;
@@ -334,7 +401,8 @@ bletest_execute(void)
connsm = ble_ll_conn_find_active_conn(handle);
if (connsm) {
/* Set connection end time */
- g_bletest_conn_end = os_time_get() + (OS_TICKS_PER_SEC * 17);
+ g_bletest_conn_end = os_time_get() +
+ (OS_TICKS_PER_SEC * (60 * 15));
g_bletest_state = 2;
}
} else if (g_bletest_state == 2) {
@@ -381,29 +449,87 @@ bletest_execute(void)
}
g_next_os_time += OS_TICKS_PER_SEC;
}
-#endif
+}
+#else
+void
+bletest_execute(void)
+{
+ int i,j;
+ int rc;
+ uint16_t handle;
+ uint16_t pktlen;
+ struct os_mbuf *om;
-#if (BLETEST_CFG_ROLE == BLETEST_ROLE_SCANNER)
- /* Enable scanning */
+ /* See if we should start advertising again */
+ if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
+ handle = g_bletest_current_conns + 1;
+ if (ble_ll_conn_find_active_conn(handle)) {
+ /* advertising better be stopped! */
+ assert(ble_ll_adv_enabled() == 0);
+
+ /* Add to current connections */
+ ++g_bletest_current_conns;
+
+ /* Move to next connection */
+ if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
+ /* restart initiating */
+ g_bletest_cur_peer_addr[5] += 1;
+ g_dev_addr[5] += 1;
+ bletest_init_advertising();
+ rc = host_hci_cmd_le_set_adv_enable(1);
+ host_hci_outstanding_opcode = 0;
+ assert(rc == 0);
+ }
+ }
+ }
+
+ /* See if it is time to hand a data packet to the connection */
if ((int32_t)(os_time_get() - g_next_os_time) >= 0) {
- if (g_bletest_state) {
- rc = host_hci_cmd_le_set_scan_enable(0, BLETEST_CFG_FILT_DUP_ADV);
- assert(rc == 0);
- host_hci_outstanding_opcode = 0;
- g_bletest_state = 0;
- } else {
- rc = host_hci_cmd_le_set_scan_enable(1, BLETEST_CFG_FILT_DUP_ADV);
- assert(rc == 0);
- host_hci_outstanding_opcode = 0;
- g_bletest_state = 1;
+ if (g_bletest_current_conns) {
+ for (i = 0; i < g_bletest_current_conns; ++i) {
+ if ((g_last_handle_used == 0) ||
+ (g_last_handle_used >= g_bletest_current_conns)) {
+ g_last_handle_used = 1;
+ }
+ handle = g_last_handle_used;
+ if (ble_ll_conn_find_active_conn(handle)) {
+ om = bletest_get_packet();
+ if (om) {
+ /* set payload length */
+ pktlen = BLETEST_PKT_SIZE;
+ om->om_len = BLETEST_PKT_SIZE + 4;
+
+ /* Put the HCI header in the mbuf */
+ htole16(om->om_data, handle);
+ htole16(om->om_data + 2, om->om_len);
+
+ /* Place L2CAP header in packet */
+ htole16(om->om_data + 4, pktlen);
+ om->om_data[6] = 0;
+ om->om_data[7] = 0;
+
+ /* Fill with incrementing pattern (starting from 1) */
+ for (j = 0; j < pktlen; ++j) {
+ om->om_data[8 + j] = (uint8_t)(j + 1);
+ }
+
+ /* Add length */
+ om->om_len += 4;
+ OS_MBUF_PKTHDR(om)->omp_len = om->om_len;
+ ble_hci_transport_host_acl_data_send(om);
+
+ /* Increment last handle used */
+ ++g_last_handle_used;
+ }
+ }
+ }
}
- g_next_os_time += (OS_TICKS_PER_SEC * 60);
+ g_next_os_time += OS_TICKS_PER_SEC;
}
+}
#endif
-#if (BLETEST_CFG_ROLE == BLETEST_ROLE_INITIATOR)
- (void)rc;
+
#endif
-}
/**
* Callback when BLE test timer expires.
@@ -486,6 +612,13 @@ bletest_task_handler(void *arg)
g_bletest_state = 0;
g_next_os_time = os_time_get();
+ /* Begin advertising if we are an advertiser */
+#if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
+ rc = host_hci_cmd_le_set_adv_enable(1);
+ assert(rc == 0);
+ host_hci_outstanding_opcode = 0;
+#endif
+
bletest_timer_cb(NULL);
while (1) {
@@ -557,6 +690,7 @@ main(void)
rc = os_mempool_init(&g_mbuf_mempool, MBUF_NUM_MBUFS,
MBUF_MEMBLOCK_SIZE, &g_mbuf_buffer[0], "mbuf_pool");
+ assert(rc == 0);
rc = os_mbuf_pool_init(&g_mbuf_pool, &g_mbuf_mempool, MBUF_MEMBLOCK_SIZE,
MBUF_NUM_MBUFS);
@@ -570,6 +704,13 @@ main(void)
g_dev_addr[3] = 0x88;
g_dev_addr[4] = 0x88;
g_dev_addr[5] = 0x08;
+
+ g_bletest_cur_peer_addr[0] = 0x00;
+ g_bletest_cur_peer_addr[1] = 0x00;
+ g_bletest_cur_peer_addr[2] = 0x00;
+ g_bletest_cur_peer_addr[3] = 0x99;
+ g_bletest_cur_peer_addr[4] = 0x99;
+ g_bletest_cur_peer_addr[5] = 0x09;
#else
g_dev_addr[0] = 0x00;
g_dev_addr[1] = 0x00;
@@ -577,6 +718,13 @@ main(void)
g_dev_addr[3] = 0x99;
g_dev_addr[4] = 0x99;
g_dev_addr[5] = 0x09;
+
+ g_bletest_cur_peer_addr[0] = 0x00;
+ g_bletest_cur_peer_addr[1] = 0x00;
+ g_bletest_cur_peer_addr[2] = 0x00;
+ g_bletest_cur_peer_addr[3] = 0x88;
+ g_bletest_cur_peer_addr[4] = 0x88;
+ g_bletest_cur_peer_addr[5] = 0x08;
#endif
/*
[2/2] incubator-mynewt-larva git commit: Many changes to the
scheduler and link layer to allow for scheduling of multiple connections.
Also allows concurrent connections and/or advertising and/or scanning and/or
initiating state machines
Posted by we...@apache.org.
Many changes to the scheduler and link layer to allow for scheduling of multiple connections. Also allows concurrent connections and/or advertising and/or scanning and/or initiating state machines
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/commit/b6e2b5ff
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/b6e2b5ff
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/b6e2b5ff
Branch: refs/heads/master
Commit: b6e2b5ffa358ad9696f71d30df4f94466f78ae67
Parents: ccc970c
Author: wes3 <wi...@micosa.io>
Authored: Mon Jan 18 16:14:37 2016 -0800
Committer: wes3 <wi...@micosa.io>
Committed: Mon Jan 18 16:14:50 2016 -0800
----------------------------------------------------------------------
.../controller/include/controller/ble_ll.h | 26 +-
.../controller/include/controller/ble_ll_adv.h | 13 +-
.../controller/include/controller/ble_ll_conn.h | 8 +-
.../controller/include/controller/ble_ll_hci.h | 2 +-
.../controller/include/controller/ble_ll_scan.h | 16 +-
.../include/controller/ble_ll_sched.h | 47 +-
net/nimble/controller/src/ble_ll.c | 125 +--
net/nimble/controller/src/ble_ll_adv.c | 264 ++++---
net/nimble/controller/src/ble_ll_conn.c | 682 +++++++++-------
net/nimble/controller/src/ble_ll_conn_hci.c | 4 +-
net/nimble/controller/src/ble_ll_conn_priv.h | 16 +-
net/nimble/controller/src/ble_ll_ctrl.c | 2 +-
net/nimble/controller/src/ble_ll_scan.c | 386 ++++++----
net/nimble/controller/src/ble_ll_sched.c | 770 ++++++++++++++++---
net/nimble/drivers/native/src/ble_phy.c | 9 +-
net/nimble/drivers/nrf52/src/ble_phy.c | 21 +-
net/nimble/include/nimble/ble.h | 26 +-
project/bletest/src/main.c | 232 +++++-
18 files changed, 1885 insertions(+), 764 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 6e5b6e1..948d8e6 100644
--- a/net/nimble/controller/include/controller/ble_ll.h
+++ b/net/nimble/controller/include/controller/ble_ll.h
@@ -70,6 +70,8 @@ struct ble_ll_stats
uint32_t hci_events_sent;
uint32_t bad_ll_state;
uint32_t bad_acl_hdr;
+ uint32_t sched_state_conn_errs;
+ uint32_t sched_state_adv_errs;
uint32_t rx_bytes;
uint32_t rx_valid_adv_pdus;
uint32_t rx_invalid_adv_pdus;
@@ -108,7 +110,7 @@ extern struct ble_ll_stats g_ble_ll_stats;
#define BLE_LL_EVENT_HCI_CMD (OS_EVENT_T_PERUSER)
#define BLE_LL_EVENT_ADV_EV_DONE (OS_EVENT_T_PERUSER + 1)
#define BLE_LL_EVENT_RX_PKT_IN (OS_EVENT_T_PERUSER + 2)
-#define BLE_LL_EVENT_SCAN_WIN_END (OS_EVENT_T_PERUSER + 3)
+#define BLE_LL_EVENT_SCAN (OS_EVENT_T_PERUSER + 3)
#define BLE_LL_EVENT_CONN_SPVN_TMO (OS_EVENT_T_PERUSER + 4)
#define BLE_LL_EVENT_CONN_EV_END (OS_EVENT_T_PERUSER + 5)
#define BLE_LL_EVENT_TX_PKT_IN (OS_EVENT_T_PERUSER + 6)
@@ -306,7 +308,8 @@ void ble_ll_acl_data_in(struct os_mbuf *txpkt);
int ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan);
/* Called by the PHY when a packet reception ends */
-int ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t chan, uint8_t crcok);
+struct ble_mbuf_hdr;
+int ble_ll_rx_end(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *ble_hdr);
/*--- Controller API ---*/
void ble_ll_mbuf_init(struct os_mbuf *m, uint8_t pdulen, uint8_t hdr);
@@ -336,10 +339,14 @@ uint8_t ble_ll_read_supp_features(void);
* XXX: temporary LL debug log. Will get removed once we transition to real
* log
*/
-#undef BLE_LL_LOG
-
-#define BLE_LL_LOG_ID_RX_START (1)
-#define BLE_LL_LOG_ID_RX_END (2)
+#define BLE_LL_LOG
+
+#define BLE_LL_LOG_ID_PHY_SETCHAN (1)
+#define BLE_LL_LOG_ID_RX_START (2)
+#define BLE_LL_LOG_ID_RX_END (3)
+#define BLE_LL_LOG_ID_WFR_EXP (4)
+#define BLE_LL_LOG_ID_PHY_TXEND (5)
+#define BLE_LL_LOG_ID_PHY_DISABLE (9)
#define BLE_LL_LOG_ID_CONN_EV_START (10)
#define BLE_LL_LOG_ID_CONN_TX (15)
#define BLE_LL_LOG_ID_CONN_RX (16)
@@ -347,11 +354,8 @@ uint8_t ble_ll_read_supp_features(void);
#define BLE_LL_LOG_ID_CONN_RX_ACK (18)
#define BLE_LL_LOG_ID_CONN_EV_END (20)
#define BLE_LL_LOG_ID_CONN_END (30)
-#define BLE_LL_LOG_ID_PHY_SETCHAN (200)
-#define BLE_LL_LOG_ID_PHY_DISABLE (201)
-#define BLE_LL_LOG_ID_PHY_ISR (202)
-#define BLE_LL_LOG_ID_PHY_RX (220)
-#define BLE_LL_LOG_ID_PHY_TX (221)
+#define BLE_LL_LOG_ID_ADV_TXBEG (50)
+#define BLE_LL_LOG_ID_ADV_TXDONE (60)
#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-larva/blob/b6e2b5ff/net/nimble/controller/include/controller/ble_ll_adv.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_adv.h b/net/nimble/controller/include/controller/ble_ll_adv.h
index a01df8c..b3bc298 100644
--- a/net/nimble/controller/include/controller/ble_ll_adv.h
+++ b/net/nimble/controller/include/controller/ble_ll_adv.h
@@ -129,10 +129,10 @@ void ble_ll_adv_init(void);
void ble_ll_adv_reset(void);
/* Called on rx pdu start when in advertising state */
-int ble_ll_adv_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu);
+int ble_ll_adv_rx_isr_start(uint8_t pdu_type, struct os_mbuf *rxpdu);
/* Called on rx pdu end when in advertising state */
-int ble_ll_adv_rx_pdu_end(uint8_t pdu_type, struct os_mbuf *rxpdu);
+int ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok);
/* Processes received packets at the link layer task */
void ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf,
@@ -144,4 +144,13 @@ int ble_ll_adv_can_chg_whitelist(void);
/* Called when a connection request has been received at the link layer */
int ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr);
+/* Called when an advertising event has been scheduled */
+void ble_ll_adv_scheduled(uint32_t sch_start);
+
+/* Called to halt currently running advertising event */
+void ble_ll_adv_halt(void);
+
+/* Called to determine if advertising is enabled */
+uint8_t ble_ll_adv_enabled(void);
+
#endif /* H_BLE_LL_ADV_ */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 a11e02d..444ee72 100644
--- a/net/nimble/controller/include/controller/ble_ll_conn.h
+++ b/net/nimble/controller/include/controller/ble_ll_conn.h
@@ -18,6 +18,8 @@
#define H_BLE_LL_CONN_
#include "os/os.h"
+#include "nimble/ble.h"
+#include "controller/ble_ll_sched.h"
#include "hal/hal_cputime.h"
/* Roles */
@@ -114,11 +116,12 @@ struct ble_ll_conn_sm
uint32_t access_addr;
uint32_t crcinit; /* only low 24 bits used */
uint32_t anchor_point;
- uint32_t last_anchor_point;
+ uint32_t last_anchor_point; /* slave only */
uint32_t ce_end_time; /* cputime at which connection event should end */
uint32_t terminate_timeout;
uint32_t slave_cur_tx_win_usecs;
uint32_t slave_cur_window_widening;
+ uint32_t last_scheduled;
/* address information */
uint8_t own_addr_type;
@@ -148,6 +151,9 @@ struct ble_ll_conn_sm
/* LL control procedure response timer */
struct os_callout_func ctrl_proc_rsp_timer;
+
+ /* For scheduling connections */
+ struct ble_ll_sched_item conn_sch;
};
/*
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/controller/include/controller/ble_ll_hci.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_hci.h b/net/nimble/controller/include/controller/ble_ll_hci.h
index e9d98a2..32a093a 100644
--- a/net/nimble/controller/include/controller/ble_ll_hci.h
+++ b/net/nimble/controller/include/controller/ble_ll_hci.h
@@ -32,7 +32,7 @@
* number of completed packets event to the host. This number is in
* milliseconds.
*/
-#define BLE_LL_CFG_NUM_COMP_PKT_RATE (1000) /* msecs */
+#define BLE_LL_CFG_NUM_COMP_PKT_RATE (2000) /* msecs */
/* Initialize LL HCI */
void ble_ll_hci_init(void);
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/controller/include/controller/ble_ll_scan.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_scan.h b/net/nimble/controller/include/controller/ble_ll_scan.h
index 31c57fe..75542c3 100644
--- a/net/nimble/controller/include/controller/ble_ll_scan.h
+++ b/net/nimble/controller/include/controller/ble_ll_scan.h
@@ -17,6 +17,8 @@
#ifndef H_BLE_LL_SCAN_
#define H_BLE_LL_SCAN_
+#include "controller/ble_ll_sched.h"
+
/*
* Configuration items for the number of duplicate advertisers and the
* number of advertisers from which we have heard a scan response
@@ -77,9 +79,11 @@ struct ble_ll_scan_sm
uint16_t backoff_count;
uint16_t scan_itvl;
uint16_t scan_window;
+ uint32_t last_sched_time;
uint32_t scan_win_start_time;
struct os_mbuf *scan_req_pdu;
- struct os_event scan_win_end_ev;
+ struct os_event scan_sched_ev;
+ struct ble_ll_sched_item scan_sch;
};
/* Scan types */
@@ -96,7 +100,7 @@ int ble_ll_scan_set_enable(uint8_t *cmd);
/*--- Controller Internal API ---*/
/* Process scan window end event */
-void ble_ll_scan_win_end_proc(void *arg);
+void ble_ll_scan_event_proc(void *arg);
/* Initialize the scanner */
void ble_ll_scan_init(void);
@@ -105,10 +109,10 @@ void ble_ll_scan_init(void);
void ble_ll_scan_reset(void);
/* Called when Link Layer starts to receive a PDU and is in scanning state */
-int ble_ll_scan_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu);
+int ble_ll_scan_rx_isr_start(uint8_t pdu_type, struct os_mbuf *rxpdu);
/* Called when Link Layer has finished receiving a PDU while scanning */
-int ble_ll_scan_rx_pdu_end(struct os_mbuf *rxpdu);
+int ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok);
/* Process a scan response PDU */
void ble_ll_scan_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf,
@@ -131,10 +135,10 @@ int ble_ll_scan_initiator_start(struct hci_create_conn *hcc);
struct os_mbuf *ble_ll_scan_get_pdu(void);
/* Stop the scanning state machine */
-void ble_ll_scan_sm_stop(struct ble_ll_scan_sm *scansm, int conn_created);
+void ble_ll_scan_sm_stop(int chk_disable);
/* Resume scanning */
-void ble_ll_scan_resume(void);
+void ble_ll_scan_chk_resume(void);
/* Called when wait for response timer expires in scanning mode */
void ble_ll_scan_wfr_timer_exp(void);
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 48914ae..eff9b2f 100644
--- a/net/nimble/controller/include/controller/ble_ll_sched.h
+++ b/net/nimble/controller/include/controller/ble_ll_sched.h
@@ -17,15 +17,16 @@
#ifndef H_BLE_LL_SCHED_
#define H_BLE_LL_SCHED_
+/* Time per BLE scheduler slot */
+#define BLE_LL_SCHED_USECS_PER_SLOT (1250)
+
/* BLE scheduler errors */
#define BLE_LL_SCHED_ERR_OVERLAP (1)
/* Types of scheduler events */
-#define BLE_LL_SCHED_TYPE_ADV (0)
-#define BLE_LL_SCHED_TYPE_SCAN (1)
-#define BLE_LL_SCHED_TYPE_TX (2)
-#define BLE_LL_SCHED_TYPE_RX (3)
-#define BLE_LL_SCHED_TYPE_CONN (4)
+#define BLE_LL_SCHED_TYPE_ADV (1)
+#define BLE_LL_SCHED_TYPE_SCAN (2)
+#define BLE_LL_SCHED_TYPE_CONN (3)
/* Return values for schedule callback. */
#define BLE_LL_SCHED_STATE_RUNNING (0)
@@ -37,28 +38,48 @@ typedef int (*sched_cb_func)(struct ble_ll_sched_item *sch);
struct ble_ll_sched_item
{
- int sched_type;
+ uint8_t sched_type;
+ uint8_t enqueued;
uint32_t start_time;
uint32_t end_time;
- uint32_t next_wakeup;
void *cb_arg;
sched_cb_func sched_cb;
TAILQ_ENTRY(ble_ll_sched_item) link;
};
-/* Add an item to the schedule */
-int ble_ll_sched_add(struct ble_ll_sched_item *sch);
-
-/* Remove item(s) from schedule */
-int ble_ll_sched_rmv(uint8_t sched_type, void *cb_arg);
-
/* Initialize the scheduler */
int ble_ll_sched_init(void);
+/* Remove item(s) from schedule */
+void ble_ll_sched_rmv_elem(struct ble_ll_sched_item *sch);
+
/* Get a schedule item */
struct ble_ll_sched_item *ble_ll_sched_get_item(void);
/* Free a schedule item */
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);
+
+/* Schedule a new slave connection */
+int ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm);
+
+/* Schedule a new advertising event */
+int ble_ll_sched_adv_new(struct ble_ll_sched_item *sch);
+
+/* Reschedule an advertising event */
+int ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch);
+
+/* Reschedule a connection that had previously been scheduled or that is over */
+int ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm * connsm);
+
+/* Schedule a scanning schedule item (start or stop) */
+void ble_ll_sched_scan(struct ble_ll_sched_item *sch);
+
+/* Stop the scheduler */
+void ble_ll_sched_stop(void);
+
#endif /* H_LL_SCHED_ */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 927d82d..eb44261 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -29,15 +29,6 @@
#include "ble_ll_conn_priv.h"
#include "hal/hal_cputime.h"
-/*
- * XXX: I need to re-think the whoele LL state code and how I deal with it.
- * I dont think I am handling it very well. The LL state should only change
- * at the LL task I think. I am also not sure how to make sure that any packets
- * handled by the LL are handled by the appropriate state. For example, can I
- * get a scan window end and then process packets? When the schedule event for
- * the scan window ends, what do I do to the LL state? Check all this out.
- */
-
/* XXX:
*
* 1) use the sanity task!
@@ -49,6 +40,11 @@
* start of a frame. Need to look at the various states to see if this is the
* right thing to do.
*
+ * 5) Make sure there is no way we can start a wfr timer and then have
+ * whatever event end and not stop the timer. We want to make sure the timer
+ * cant fire off unless we are sure that it will fire off when the device is
+ * in standby state. At least in standby we are sure no erroneous action will
+ * be taken
*/
/* Configuration for supported features */
@@ -259,12 +255,17 @@ ble_ll_is_our_devaddr(uint8_t *addr, int addr_type)
void
ble_ll_wfr_timer_exp(void *arg)
{
- struct ble_ll_obj *lldata;
+ int rx_start;
+ uint8_t lls;
+
+ rx_start = ble_phy_rx_started();
+ lls = g_ble_ll_data.ll_state;
+
+ ble_ll_log(BLE_LL_LOG_ID_WFR_EXP, lls, 0, (uint32_t)rx_start);
/* If we have started a reception, there is nothing to do here */
- if (!ble_phy_rx_started()) {
- lldata = &g_ble_ll_data;
- switch (lldata->ll_state) {
+ if (!rx_start) {
+ switch (lls) {
case BLE_LL_STATE_ADV:
ble_ll_adv_wfr_timer_exp();
break;
@@ -365,6 +366,7 @@ ble_ll_rx_pkt_in(void)
os_sr_t sr;
uint8_t pdu_type;
uint8_t *rxbuf;
+ uint8_t crcok;
struct os_mbuf_pkthdr *pkthdr;
struct ble_mbuf_hdr *ble_hdr;
struct os_mbuf *m;
@@ -383,17 +385,18 @@ ble_ll_rx_pkt_in(void)
/* Count statistics */
rxbuf = m->om_data;
ble_hdr = BLE_MBUF_HDR_PTR(m);
- if (ble_hdr->rxinfo.crcok) {
+ crcok = BLE_MBUF_HDR_CRC_OK(ble_hdr);
+ if (crcok) {
/* The total bytes count the PDU header and PDU payload */
g_ble_ll_stats.rx_bytes += pkthdr->omp_len;
}
if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) {
- ble_ll_conn_rx_data_pdu(m, ble_hdr->rxinfo.crcok);
+ ble_ll_conn_rx_data_pdu(m, ble_hdr);
} else {
/* Get advertising PDU type */
pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
- if (ble_hdr->rxinfo.crcok) {
+ if (crcok) {
/* Count by type only with valid crc */
++g_ble_ll_stats.rx_valid_adv_pdus;
ble_ll_count_rx_adv_pdus(pdu_type);
@@ -402,7 +405,7 @@ ble_ll_rx_pkt_in(void)
}
/* Process the PDU */
- switch (g_ble_ll_data.ll_state) {
+ switch (BLE_MBUF_HDR_RX_STATE(ble_hdr)) {
case BLE_LL_STATE_ADV:
ble_ll_adv_rx_pkt_in(pdu_type, rxbuf, ble_hdr);
break;
@@ -418,6 +421,7 @@ ble_ll_rx_pkt_in(void)
break;
}
+
/* Free the packet buffer */
os_mbuf_free(m);
}
@@ -488,7 +492,7 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
*/
if (g_ble_ll_data.ll_state == BLE_LL_STATE_CONNECTION) {
/* Call conection pdu rx start function */
- ble_ll_conn_rx_pdu_start();
+ ble_ll_conn_rx_isr_start();
/* Set up to go from rx to tx */
rc = 1;
@@ -504,7 +508,7 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
switch (g_ble_ll_data.ll_state) {
case BLE_LL_STATE_ADV:
- rc = ble_ll_adv_rx_pdu_start(pdu_type, rxpdu);
+ rc = ble_ll_adv_rx_isr_start(pdu_type, rxpdu);
break;
case BLE_LL_STATE_INITIATING:
if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) ||
@@ -515,7 +519,7 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
}
break;
case BLE_LL_STATE_SCANNING:
- rc = ble_ll_scan_rx_pdu_start(pdu_type, rxpdu);
+ rc = ble_ll_scan_rx_isr_start(pdu_type, rxpdu);
break;
case BLE_LL_STATE_CONNECTION:
/* Should not occur */
@@ -537,7 +541,8 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
*
* NOTE: Called from interrupt context!
*
- * @param rxbuf
+ * @param rxpdu Pointer to received PDU
+ * ble_hdr Pointer to BLE header of received mbuf
*
* @return int
* < 0: Disable the phy after reception.
@@ -545,18 +550,24 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
* > 0: Do not disable PHY as that has already been done.
*/
int
-ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t chan, uint8_t crcok)
+ble_ll_rx_end(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *ble_hdr)
{
int rc;
int badpkt;
uint8_t pdu_type;
uint8_t len;
+ uint8_t chan;
+ uint8_t crcok;
uint16_t mblen;
uint8_t *rxbuf;
/* Set the rx buffer pointer to the start of the received data */
rxbuf = rxpdu->om_data;
+ /* Get channel and CRC status from BLE header */
+ chan = ble_hdr->rxinfo.channel;
+ crcok = BLE_MBUF_HDR_CRC_OK(ble_hdr);
+
ble_ll_log(BLE_LL_LOG_ID_RX_END,
chan,
((uint16_t)crcok << 8) | rxbuf[1],
@@ -581,14 +592,19 @@ ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t chan, uint8_t crcok)
* Data channel pdu. We should be in CONNECTION state with an
* ongoing connection.
*/
- rc = ble_ll_conn_rx_pdu_end(rxpdu, ble_phy_access_addr_get());
+ rc = ble_ll_conn_rx_isr_end(rxpdu, ble_phy_access_addr_get());
return rc;
}
- /* Get advertising PDU type */
+ /* Get advertising PDU type and length */
pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK;
+ /* Setup the mbuf lengths */
+ mblen = len + BLE_LL_PDU_HDR_LEN;
+ OS_MBUF_PKTHDR(rxpdu)->omp_len = mblen;
+ rxpdu->om_len = mblen;
+
/* If the CRC checks, make sure lengths check! */
if (crcok) {
badpkt = 0;
@@ -621,38 +637,35 @@ ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t chan, uint8_t crcok)
if (badpkt) {
++g_ble_ll_stats.rx_adv_malformed_pkts;
os_mbuf_free(rxpdu);
- return -1;
+ rxpdu = NULL;
+ rc = -1;
}
}
- /* Setup the mbuf lengths */
- mblen = len + BLE_LL_PDU_HDR_LEN;
- OS_MBUF_PKTHDR(rxpdu)->omp_len = mblen;
- rxpdu->om_len = mblen;
/* Hand packet to the appropriate state machine (if crc ok) */
- rc = -1;
- if (crcok) {
- switch (g_ble_ll_data.ll_state) {
- case BLE_LL_STATE_ADV:
- rc = ble_ll_adv_rx_pdu_end(pdu_type, rxpdu);
- break;
- case BLE_LL_STATE_SCANNING:
- rc = ble_ll_scan_rx_pdu_end(rxpdu);
- break;
- case BLE_LL_STATE_INITIATING:
- rc = ble_ll_init_rx_pdu_end(rxpdu);
- break;
- /* Invalid states */
- case BLE_LL_STATE_CONNECTION:
- default:
- assert(0);
- break;
- }
+ switch (BLE_MBUF_HDR_RX_STATE(ble_hdr)) {
+ case BLE_LL_STATE_ADV:
+ rc = ble_ll_adv_rx_isr_end(pdu_type, rxpdu, crcok);
+ break;
+ case BLE_LL_STATE_SCANNING:
+ rc = ble_ll_scan_rx_isr_end(rxpdu, crcok);
+ break;
+ case BLE_LL_STATE_INITIATING:
+ rc = ble_ll_init_rx_isr_end(rxpdu, crcok);
+ break;
+ /* Invalid states */
+ case BLE_LL_STATE_CONNECTION:
+ default:
+ rc = -1;
+ assert(0);
+ break;
}
/* Hand packet up to higher layer (regardless of CRC failure) */
- ble_ll_rx_pdu_in(rxpdu);
+ if (rxpdu) {
+ ble_ll_rx_pdu_in(rxpdu);
+ }
return rc;
}
@@ -668,6 +681,7 @@ void
ble_ll_task(void *arg)
{
struct os_event *ev;
+ struct os_callout_func *cf;
/* Init ble phy */
ble_phy_init();
@@ -681,9 +695,11 @@ ble_ll_task(void *arg)
/* Wait for an event */
while (1) {
ev = os_eventq_get(&g_ble_ll_data.ll_evq);
-
switch (ev->ev_type) {
case OS_EVENT_T_TIMER:
+ cf = (struct os_callout_func *)ev;
+ assert(cf->cf_func);
+ cf->cf_func(cf->cf_arg);
break;
case BLE_LL_EVENT_HCI_CMD:
/* Process HCI command */
@@ -692,8 +708,8 @@ ble_ll_task(void *arg)
case BLE_LL_EVENT_ADV_EV_DONE:
ble_ll_adv_event_done(ev->ev_arg);
break;
- case BLE_LL_EVENT_SCAN_WIN_END:
- ble_ll_scan_win_end_proc(ev->ev_arg);
+ case BLE_LL_EVENT_SCAN:
+ ble_ll_scan_event_proc(ev->ev_arg);
break;
case BLE_LL_EVENT_RX_PKT_IN:
ble_ll_rx_pkt_in();
@@ -821,7 +837,8 @@ ble_ll_mbuf_init(struct os_mbuf *m, uint8_t pdulen, uint8_t hdr)
* layer; it does not perform a HW reset of the controller nor does it reset
* the HCI interface.
*
- *
+ * Context: Link Layer task (HCI command)
+ *
* @return int The ble error code to place in the command complete event that
* is returned when this command is issued.
*/
@@ -829,12 +846,16 @@ int
ble_ll_reset(void)
{
int rc;
+ os_sr_t sr;
/* Stop the phy */
ble_phy_disable();
/* Stop any wait for response timer */
+ OS_ENTER_CRITICAL(sr);
ble_ll_wfr_disable();
+ ble_ll_sched_stop();
+ OS_EXIT_CRITICAL(sr);
/* Stop any scanning */
ble_ll_scan_reset();
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 5302f66..d74b61a 100644
--- a/net/nimble/controller/src/ble_ll_adv.c
+++ b/net/nimble/controller/src/ble_ll_adv.c
@@ -46,14 +46,12 @@
* 2) Only public device addresses supported right now.
* 3) How do features get supported? What happens if device does not support
* advertising? (for example)
- * 4) Correct calculation of schedule start and end times for the various
- * scheduled advertising activities.
- * 5) How to determine the advertising interval we will actually use. As of
+ * 4) How to determine the advertising interval we will actually use. As of
* now, we set it to max.
- * 6) Currently, when we set scheduling events, we dont take into account
- * processor overhead/delays. We will want to do that.
- * 7) How does the advertising channel tx power get set? I dont implement
+ * 5) How does the advertising channel tx power get set? I dont implement
* that currently.
+ * 6) The time between transmissions inside an advertising event is set to
+ * max. Need to deal with this.
*/
/*
@@ -89,6 +87,7 @@ struct ble_ll_adv_sm
struct os_mbuf *adv_pdu;
struct os_mbuf *scan_rsp_pdu;
struct os_event adv_txdone_ev;
+ struct ble_ll_sched_item adv_sch;
};
/* The advertising state machine global object */
@@ -149,7 +148,6 @@ ble_ll_adv_first_chan(struct ble_ll_adv_sm *advsm)
return adv_chan;
}
-
/**
* Compares the advertiser address in an advertising PDU (scan request or
* connect request) with our address to see if there is a match
@@ -327,15 +325,24 @@ ble_ll_adv_scan_rsp_pdu_make(struct ble_ll_adv_sm *advsm)
}
/**
- * Scheduler callback when an advertising PDU has been sent.
+ * Called to indicate the advertising event is over.
+ *
+ * Context: Interrupt
+ *
+ * @param advsm
*
- * @param arg
*/
-static int
-ble_ll_adv_tx_done_cb(struct ble_ll_sched_item *sch)
+static void
+ble_ll_adv_tx_done(void *arg)
{
- os_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_adv_sm.adv_txdone_ev);
- return BLE_LL_SCHED_STATE_DONE;
+ struct ble_ll_adv_sm *advsm;
+
+ advsm = (struct ble_ll_adv_sm *)arg;
+ os_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
+
+ ble_ll_log(BLE_LL_LOG_ID_ADV_TXDONE, ble_ll_state_get(), 0, 0);
+
+ ble_ll_state_set(BLE_LL_STATE_STANDBY);
}
/**
@@ -363,24 +370,25 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch)
rc = ble_phy_setchan(advsm->adv_chan, 0, 0);
assert(rc == 0);
- /* Set the callbacks */
- ble_phy_set_txend_cb(NULL, NULL);
-
/* Set phy mode based on type of advertisement */
if (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
end_trans = BLE_PHY_TRANSITION_NONE;
+ ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm);
} else {
end_trans = BLE_PHY_TRANSITION_TX_RX;
+ ble_phy_set_txend_cb(NULL, NULL);
}
/* This is for debug */
start_time = cputime_get32();
+ /* XXX: transmit using an output compare */
/* Transmit advertisement */
rc = ble_phy_tx(advsm->adv_pdu, BLE_PHY_TRANSITION_NONE, end_trans);
if (rc) {
/* Transmit failed. */
- rc = ble_ll_adv_tx_done_cb(sch);
+ ble_ll_adv_tx_done(advsm);
+ rc = BLE_LL_SCHED_STATE_DONE;
} else {
/* Check if we were late getting here */
if ((int32_t)(start_time - (advsm->adv_pdu_start_time -
@@ -394,68 +402,71 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch)
/* Count # of adv. sent */
++g_ble_ll_adv_stats.adv_txg;
- /* Set next schedule wakeup time */
- sch->next_wakeup = sch->end_time;
- sch->sched_cb = ble_ll_adv_tx_done_cb;
-
+ /* This schedule item is now running */
rc = BLE_LL_SCHED_STATE_RUNNING;
}
return rc;
}
-static struct ble_ll_sched_item *
-ble_ll_adv_sched_set(struct ble_ll_adv_sm *advsm)
+static void
+ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm, int sched_new)
{
- int rc;
uint32_t max_usecs;
struct ble_ll_sched_item *sch;
- sch = ble_ll_sched_get_item();
- if (sch) {
- /* Set sched type */
- sch->sched_type = BLE_LL_SCHED_TYPE_ADV;
+ sch = &advsm->adv_sch;
+ sch->cb_arg = advsm;
+ sch->sched_cb = ble_ll_adv_tx_start_cb;
+ sch->sched_type = BLE_LL_SCHED_TYPE_ADV;
- /* XXX: HW output compare to trigger tx start? Look into this */
- /* Set the start time of the event */
- sch->start_time = advsm->adv_pdu_start_time -
- cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+ /* Set end time to maximum time this schedule item may take */
+ max_usecs = BLE_TX_DUR_USECS_M(advsm->adv_pdu_len);
+ switch (advsm->adv_type) {
+ case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD:
+ case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD:
+ max_usecs += BLE_LL_ADV_DIRECT_SCHED_MAX_USECS;
+ break;
+ case BLE_HCI_ADV_TYPE_ADV_IND:
+ case BLE_HCI_ADV_TYPE_ADV_SCAN_IND:
+ max_usecs += BLE_LL_ADV_SCHED_MAX_USECS;
+ break;
+ default:
+ break;
+ }
- /* Set the callback and argument */
- sch->cb_arg = advsm;
- sch->sched_cb = ble_ll_adv_tx_start_cb;
-
- /* Set end time to maximum time this schedule item may take */
- max_usecs = BLE_TX_DUR_USECS_M(advsm->adv_pdu_len);
- switch (advsm->adv_type) {
- case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD:
- case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD:
- max_usecs += BLE_LL_ADV_DIRECT_SCHED_MAX_USECS;
- break;
- case BLE_HCI_ADV_TYPE_ADV_IND:
- case BLE_HCI_ADV_TYPE_ADV_SCAN_IND:
- max_usecs += BLE_LL_ADV_SCHED_MAX_USECS;
- break;
- default:
- break;
- }
+ /*
+ * XXX: For now, just schedule some additional time so we insure we have
+ * enough time to do everything we want.
+ */
+ max_usecs += XCVR_PROC_DELAY_USECS;
+ if (sched_new) {
/*
- * We dont really care if this is super accurate; it really is only
- * used to block time in the scheduler.
- */
- sch->end_time = advsm->adv_pdu_start_time +
- cputime_usecs_to_ticks(max_usecs);
-
- /* XXX: for now, we cant get an overlap so assert on error. */
- /* Add the item to the scheduler */
- rc = ble_ll_sched_add(sch);
- assert(rc == 0);
+ * 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 = cputime_get32();
+ sch->end_time = sch->start_time + cputime_usecs_to_ticks(max_usecs);
} else {
- ++g_ble_ll_adv_stats.cant_set_sched;
+ sch->start_time = advsm->adv_pdu_start_time -
+ cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+ sch->end_time = advsm->adv_pdu_start_time +
+ cputime_usecs_to_ticks(max_usecs);
}
+}
- return sch;
+/**
+ * Called when advertising need to be halted. This normally should not be called
+ * and is only called when a scheduled item executes but advertising is still
+ * running.
+ *
+ */
+void
+ble_ll_adv_halt(void)
+{
+ ble_ll_adv_tx_done(&g_ble_ll_adv_sm);
}
/**
@@ -575,19 +586,23 @@ ble_ll_adv_set_adv_params(uint8_t *cmd)
static void
ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm)
{
+ os_sr_t sr;
+
if (advsm->enabled) {
/* Disable whitelisting (just in case) */
ble_ll_whitelist_disable();
/* Remove any scheduled advertising items */
- ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_ADV, NULL);
+ ble_ll_sched_rmv_elem(&advsm->adv_sch);
os_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
/* Set to standby if we are no longer advertising */
+ OS_ENTER_CRITICAL(sr);
if (ble_ll_state_get() == BLE_LL_STATE_ADV) {
ble_ll_wfr_disable();
ble_ll_state_set(BLE_LL_STATE_STANDBY);
}
+ OS_EXIT_CRITICAL(sr);
/* Disable advertising */
advsm->enabled = 0;
@@ -608,9 +623,7 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm)
static int
ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
{
- int rc;
uint8_t adv_chan;
- struct ble_ll_sched_item *sch;
/*
* XXX: not sure if I should do this or just report whatever random
@@ -661,12 +674,25 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
}
/*
- * Set start time for the advertising event. This time is the same
- * as the time we will send the first PDU. Since there does not seem
- * to be any requirements as to when we start, we do it asap.
- */
- advsm->adv_event_start_time = cputime_get32() +
- cputime_usecs_to_ticks(BLE_LL_IFS + XCVR_PROC_DELAY_USECS);
+ * 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_sched_adv_new(&advsm->adv_sch);
+
+ return BLE_ERR_SUCCESS;
+}
+
+void
+ble_ll_adv_scheduled(uint32_t sch_start)
+{
+ struct ble_ll_adv_sm *advsm;
+
+ advsm = &g_ble_ll_adv_sm;
+
+ /* The event start time is when we start transmission of the adv PDU */
+ advsm->adv_event_start_time = sch_start +
+ cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
advsm->adv_pdu_start_time = advsm->adv_event_start_time;
@@ -677,17 +703,6 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
*/
advsm->adv_dir_hd_end_time = advsm->adv_event_start_time +
cputime_usecs_to_ticks(BLE_LL_ADV_STATE_HD_MAX * 1000);
-
- /* Add to schedule. If we cant, we will just inform host we are too busy */
- rc = BLE_ERR_SUCCESS;
- sch = ble_ll_adv_sched_set(advsm);
- if (!sch) {
- advsm->enabled = 0;
- ble_ll_whitelist_disable();
- rc = BLE_ERR_CTLR_BUSY;
- }
-
- return rc;
}
/**
@@ -707,7 +722,9 @@ ble_ll_adv_read_txpwr(uint8_t *rspbuf, uint8_t *rsplen)
}
/**
- * Turn advertising on/off.
+ * Turn advertising on/off.
+ *
+ * Context: Link Layer task
*
* @param cmd
*
@@ -873,7 +890,7 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu)
/* Setup to transmit the scan response if appropriate */
rc = -1;
if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) {
- /* NOTE: no callback nneds to be set as it should be NULL already */
+ ble_phy_set_txend_cb(ble_ll_adv_tx_done, &g_ble_ll_adv_sm);
rc = ble_phy_tx(advsm->scan_rsp_pdu, BLE_PHY_TRANSITION_RX_TX,
BLE_PHY_TRANSITION_NONE);
if (!rc) {
@@ -964,15 +981,25 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
* > 0: Do not disable PHY as that has already been done.
*/
int
-ble_ll_adv_rx_pdu_end(uint8_t pdu_type, struct os_mbuf *rxpdu)
+ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok)
{
int rc;
rc = -1;
- if ((pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) ||
- (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_REQ)) {
- /* Process request */
- rc = ble_ll_adv_rx_req(pdu_type, rxpdu);
+ if (rxpdu == NULL) {
+ ble_ll_adv_tx_done(&g_ble_ll_adv_sm);
+ } else {
+ if (crcok) {
+ if ((pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) ||
+ (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_REQ)) {
+ /* Process request */
+ rc = ble_ll_adv_rx_req(pdu_type, rxpdu);
+ }
+ }
+ }
+
+ if (rc) {
+ ble_ll_state_set(BLE_LL_STATE_STANDBY);
}
return rc;
@@ -997,12 +1024,20 @@ ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
int adv_event_over;
/*
- * We should remove the schedule item in all cases except when we
- * are sending a scan response or we have stopped advertising due to
- * receiving a connect request
+ * If we have received a scan request and we are transmitting a response
+ * or we have received a valid connect request, dont "end" the advertising
+ * event. In the case of a connect request we will stop advertising. In
+ * the case of the scan response transmission we will get a transmit
+ * end callback.
+ *
+ * XXX: I dont know why I wait to reschedule after transmitting a scan
+ * response. I wont schedule over it and I can use the transmission time
+ * to schedule the next advertising event. I also get rid of the code to
+ * deal with the "scan response transmitted". All depends on how we
+ * schedule the next transmissions in the advertising event.
*/
adv_event_over = 1;
- if (hdr->rxinfo.crcok) {
+ if (BLE_MBUF_HDR_CRC_OK(hdr)) {
if (ptype == BLE_ADV_PDU_TYPE_CONNECT_REQ) {
if (ble_ll_adv_conn_req_rxd(rxbuf, hdr)) {
adv_event_over = 0;
@@ -1034,7 +1069,7 @@ ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
* > 0: Continue to receive frame and go from rx to tx when done
*/
int
-ble_ll_adv_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
+ble_ll_adv_rx_isr_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
{
int rc;
struct ble_ll_adv_sm *advsm;
@@ -1061,6 +1096,14 @@ ble_ll_adv_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
}
}
+ /*
+ * If we abort the frame, we need to post the LL task to check if the
+ * advertising event is over.
+ */
+ if (rc < 0) {
+ ble_ll_adv_tx_done(advsm);
+ }
+
return rc;
}
@@ -1078,15 +1121,19 @@ ble_ll_adv_event_done(void *arg)
uint8_t final_adv_chan;
int32_t delta_t;
uint32_t itvl;
+ uint32_t start_time;
struct ble_ll_adv_sm *advsm;
/* Stop advertising event */
advsm = (struct ble_ll_adv_sm *)arg;
assert(advsm->enabled);
- ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_ADV, NULL);
+ /* Check if we need to resume scanning */
+ ble_ll_scan_chk_resume();
+
+ /* Remove the element from the schedule if it is still there. */
+ ble_ll_sched_rmv_elem(&advsm->adv_sch);
os_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
- ble_ll_state_set(BLE_LL_STATE_STANDBY);
/* For debug purposes */
#ifdef BLETEST
@@ -1144,7 +1191,10 @@ ble_ll_adv_event_done(void *arg)
* count a statistic and close the current advertising event. We will
* then setup the next advertising event.
*/
- delta_t = (int32_t)(advsm->adv_pdu_start_time - cputime_get32());
+ start_time = advsm->adv_pdu_start_time -
+ cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+
+ delta_t = (int32_t)(start_time - cputime_get32());
if (delta_t < 0) {
/* Count times we were late */
++g_ble_ll_adv_stats.late_tx_done;
@@ -1179,9 +1229,14 @@ ble_ll_adv_event_done(void *arg)
}
}
- if (!ble_ll_adv_sched_set(advsm)) {
- /* XXX: we will need to set a timer here to wake us up */
- assert(0);
+ ble_ll_adv_set_sched(advsm, 0);
+
+ /*
+ * In the unlikely event we cant reschedule this, just post a done
+ * event and we will reschedule the next advertising event
+ */
+ if (ble_ll_sched_adv_reschedule(&advsm->adv_sch)) {
+ os_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
}
}
@@ -1217,7 +1272,7 @@ void
ble_ll_adv_wfr_timer_exp(void)
{
ble_phy_disable();
- os_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_adv_sm.adv_txdone_ev);
+ ble_ll_adv_tx_done(&g_ble_ll_adv_sm);
}
/**
@@ -1246,6 +1301,13 @@ ble_ll_adv_reset(void)
ble_ll_adv_init();
}
+/* Called to determine if advertising is enabled */
+uint8_t
+ble_ll_adv_enabled(void)
+{
+ return g_ble_ll_adv_sm.enabled;
+}
+
/**
* Initialize the advertising functionality of a BLE device. This should
* be called once on initialization
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 4566d10..373909b 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -32,6 +32,13 @@
#include "hal/hal_cputime.h"
#include "hal/hal_gpio.h"
+/*
+ * XXX: looks like the current code will allow the 1st packet in a
+ * connection to extend past the end of the allocated connection end
+ * time. That is not good. Need to deal with that. Need to extend connection
+ * end time.
+ */
+
/* XXX TODO
* 1) Add set channel map command and implement channel change procedure.
* 2) Make sure we have implemented all ways a connection can die/end. Not
@@ -56,8 +63,22 @@
* the host that issued the create connection.
* 9) How does peer address get set if we are using whitelist? Look at filter
* policy and make sure you are doing this correctly.
+ * 10) Right now I use a fixed definition for required slots. CHange this.
+ * 11) Use output compare for transmit.
+ */
+
+/*
+ * 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!
*/
+/* XXX: we need to make sure we hit the proper tx time for the anchor or we
+ could mess up the slave. Use output compare */
+
/* XXX: this does not belong here! Move to transport? */
extern int ble_hs_rx_data(struct os_mbuf *om);
@@ -76,19 +97,25 @@ extern int ble_hs_rx_data(struct os_mbuf *om);
* XXX: move this definition and figure out how we determine the worst-case
* jitter (spec. should have this).
*/
-#define BLE_LL_WFR_USECS (BLE_LL_IFS + 40 + 32)
+#define BLE_LL_WFR_USECS (BLE_LL_IFS + 40 + 32)
/* Configuration parameters */
-#define BLE_LL_CONN_CFG_TX_WIN_SIZE (1)
-#define BLE_LL_CONN_CFG_TX_WIN_OFF (0)
-#define BLE_LL_CONN_CFG_MASTER_SCA (BLE_MASTER_SCA_251_500_PPM << 5)
-#define BLE_LL_CONN_CFG_MAX_CONNS (8)
-#define BLE_LL_CONN_CFG_OUR_SCA (500) /* in ppm */
+#define BLE_LL_CFG_CONN_TX_WIN_SIZE (1)
+#define BLE_LL_CFG_CONN_TX_WIN_OFF (0)
+#define BLE_LL_CFG_CONN_MASTER_SCA (BLE_MASTER_SCA_251_500_PPM << 5)
+#define BLE_LL_CFG_CONN_MAX_CONNS (8)
+#define BLE_LL_CFG_CONN_OUR_SCA (60) /* in ppm */
+#define BLE_LL_CFG_CONN_INIT_SLOTS (8)
+
+/* We cannot have more than 254 connections given our current implementation */
+#if (BLE_LL_CFG_CONN_MAX_CONNS >= 255)
+ #error "Maximum # of connections is 254"
+#endif
/* LL configuration definitions */
#define BLE_LL_CFG_SUPP_MAX_RX_BYTES (251)
-#define BLE_LL_CFG_SUPP_MAX_TX_BYTES (251)
-#define BLE_LL_CFG_CONN_INIT_MAX_TX_BYTES (251)
+#define BLE_LL_CFG_SUPP_MAX_TX_BYTES (27)
+#define BLE_LL_CFG_CONN_INIT_MAX_TX_BYTES (27)
/* Sleep clock accuracy table (in ppm) */
static const uint16_t g_ble_sca_ppm_tbl[8] =
@@ -115,7 +142,7 @@ struct ble_ll_conn_sm *g_ble_ll_conn_create_sm;
struct ble_ll_conn_sm *g_ble_ll_conn_cur_sm;
/* Connection state machine array */
-struct ble_ll_conn_sm g_ble_ll_conn_sm[BLE_LL_CONN_CFG_MAX_CONNS];
+struct ble_ll_conn_sm g_ble_ll_conn_sm[BLE_LL_CFG_CONN_MAX_CONNS];
/* List of active connections */
struct ble_ll_conn_active_list g_ble_ll_conn_active_list;
@@ -149,6 +176,40 @@ struct ble_ll_conn_stats g_ble_ll_conn_stats;
/* Some helpful macros */
#define BLE_IS_RETRY_M(ble_hdr) ((ble_hdr)->txinfo.flags & BLE_MBUF_HDR_F_TXD)
+int
+ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2)
+{
+ int rc;
+
+ /* Set time that we last serviced the schedule */
+ if ((int32_t)(s1->last_scheduled - s2->last_scheduled) < 0) {
+ rc = 1;
+ } else {
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/**
+ * Called to return the currently running connection state machine end time.
+ * Always called when interrupts are disabled.
+ *
+ * @return uint32_t
+ */
+uint32_t
+ble_ll_conn_get_ce_end_time(void)
+{
+ uint32_t ce_end_time;
+
+ if (g_ble_ll_conn_cur_sm) {
+ ce_end_time = g_ble_ll_conn_cur_sm->ce_end_time;
+ } else {
+ ce_end_time = cputime_get32();
+ }
+ return ce_end_time;
+}
+
/**
* Checks if pdu is a L2CAP pdu, meaning it is not a control pdu nor an empty
* pdu. Called only for transmit PDU's.
@@ -192,9 +253,6 @@ ble_ll_conn_current_sm_over(void)
/* Disable the wfr timer */
ble_ll_wfr_disable();
- /* Remove any scheduled items for this connection */
- ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_CONN, g_ble_ll_conn_cur_sm);
-
/* Link-layer is in standby state now */
ble_ll_state_set(BLE_LL_STATE_STANDBY);
@@ -214,9 +272,11 @@ ble_ll_conn_find_active_conn(uint16_t handle)
{
struct ble_ll_conn_sm *connsm;
- SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) {
- if (connsm->conn_handle == handle) {
- break;
+ connsm = NULL;
+ if ((handle != 0) && (handle <= BLE_LL_CFG_CONN_MAX_CONNS)) {
+ connsm = &g_ble_ll_conn_sm[handle - 1];
+ if (connsm->conn_state == BLE_LL_CONN_STATE_IDLE) {
+ connsm = NULL;
}
}
return connsm;
@@ -264,7 +324,7 @@ ble_ll_conn_calc_window_widening(struct ble_ll_conn_sm *connsm)
if (time_since_last_anchor > 0) {
delta_msec = cputime_ticks_to_usecs(time_since_last_anchor) / 1000;
total_sca_ppm = g_ble_sca_ppm_tbl[connsm->master_sca] +
- BLE_LL_CONN_CFG_OUR_SCA;
+ BLE_LL_CFG_CONN_OUR_SCA;
window_widening = (total_sca_ppm * delta_msec) / 1000;
}
@@ -468,6 +528,7 @@ ble_ll_conn_wfr_timer_exp(void)
struct ble_ll_conn_sm *connsm;
connsm = g_ble_ll_conn_cur_sm;
+ ble_ll_conn_current_sm_over();
if (connsm) {
ble_ll_event_send(&connsm->conn_ev_end);
++g_ble_ll_conn_stats.wfr_expirations;
@@ -488,6 +549,8 @@ ble_ll_conn_wait_txend(void *arg)
{
struct ble_ll_conn_sm *connsm;
+ ble_ll_conn_current_sm_over();
+
connsm = (struct ble_ll_conn_sm *)arg;
ble_ll_event_send(&connsm->conn_ev_end);
}
@@ -679,26 +742,6 @@ ble_ll_conn_tx_data_pdu(struct ble_ll_conn_sm *connsm, int beg_transition)
}
/**
- * Connection end schedule callback. Called when the scheduled connection
- * event ends.
- *
- * Context: Interrupt
- *
- * @param sch
- *
- * @return int
- */
-static int
-ble_ll_conn_ev_end_sched_cb(struct ble_ll_sched_item *sch)
-{
- struct ble_ll_conn_sm *connsm;
-
- connsm = (struct ble_ll_conn_sm *)sch->cb_arg;
- ble_ll_event_send(&connsm->conn_ev_end);
- return BLE_LL_SCHED_STATE_DONE;
-}
-
-/**
* Schedule callback for start of connection event
*
* Context: Interrupt
@@ -715,18 +758,19 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
uint32_t wfr_time;
struct ble_ll_conn_sm *connsm;
- /* set led */
- gpio_clear(LED_BLINK_PIN);
+ /* XXX: note that we can extend end time here if we want. Look at this */
/* Set current connection state machine */
connsm = (struct ble_ll_conn_sm *)sch->cb_arg;
g_ble_ll_conn_cur_sm = connsm;
+ assert(connsm);
/* Set LL state */
ble_ll_state_set(BLE_LL_STATE_CONNECTION);
/* Log connection event start */
- ble_ll_log(BLE_LL_LOG_ID_CONN_EV_START, connsm->data_chan_index, 0, 0);
+ ble_ll_log(BLE_LL_LOG_ID_CONN_EV_START, connsm->data_chan_index, 0,
+ connsm->ce_end_time);
/* Set channel */
rc = ble_phy_setchan(connsm->data_chan_index, connsm->access_addr,
@@ -736,12 +780,9 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
rc = ble_ll_conn_tx_data_pdu(connsm, BLE_PHY_TRANSITION_NONE);
if (!rc) {
- sch->next_wakeup = sch->end_time;
- sch->sched_cb = ble_ll_conn_ev_end_sched_cb;
rc = BLE_LL_SCHED_STATE_RUNNING;
} else {
/* Inform LL task of connection event end */
- ble_ll_event_send(&connsm->conn_ev_end);
rc = BLE_LL_SCHED_STATE_DONE;
}
} else {
@@ -749,7 +790,6 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
if (rc) {
/* End the connection event as we have no more buffers */
++g_ble_ll_conn_stats.slave_ce_failures;
- ble_ll_event_send(&connsm->conn_ev_end);
rc = BLE_LL_SCHED_STATE_DONE;
} else {
/*
@@ -758,17 +798,32 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
*/
connsm->slave_set_last_anchor = 1;
+ /*
+ * 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
+ * -> Amount of time it takes to detect packet start.
+ */
usecs = connsm->slave_cur_tx_win_usecs + BLE_LL_WFR_USECS +
connsm->slave_cur_window_widening;
wfr_time = connsm->anchor_point + cputime_usecs_to_ticks(usecs);
ble_ll_wfr_enable(wfr_time);
/* Set next wakeup time to connection event end time */
- sch->next_wakeup = sch->end_time;
- sch->sched_cb = ble_ll_conn_ev_end_sched_cb;
rc = BLE_LL_SCHED_STATE_RUNNING;
}
}
+
+ if (rc == BLE_LL_SCHED_STATE_DONE) {
+ ble_ll_event_send(&connsm->conn_ev_end);
+ ble_ll_state_set(BLE_LL_STATE_STANDBY);
+ g_ble_ll_conn_cur_sm = NULL;
+ }
+
+ /* Set time that we last serviced the schedule */
+ connsm->last_scheduled = cputime_get32();
return rc;
}
@@ -821,71 +876,6 @@ ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime)
}
/**
- * Set the schedule for connection events
- *
- * Context: Link Layer task
- *
- * @param connsm
- *
- * @return struct ble_ll_sched_item *
- */
-static struct ble_ll_sched_item *
-ble_ll_conn_sched_set(struct ble_ll_conn_sm *connsm)
-{
- int rc;
- uint32_t usecs;
- struct ble_ll_sched_item *sch;
-
- sch = ble_ll_sched_get_item();
- if (sch) {
- /* Set sched type, arg and callback function */
- sch->sched_type = BLE_LL_SCHED_TYPE_CONN;
- sch->cb_arg = connsm;
- sch->sched_cb = ble_ll_conn_event_start_cb;
-
- /* Set the start time of the event */
- if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
- sch->start_time = connsm->anchor_point -
- cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
-
- /* We will attempt to schedule the maximum CE length */
- usecs = connsm->max_ce_len * BLE_LL_CONN_CE_USECS;
- } else {
- /* Include window widening and scheduling delay */
- usecs = connsm->slave_cur_window_widening +
- XCVR_RX_SCHED_DELAY_USECS;
-
- sch->start_time = connsm->anchor_point -
- cputime_usecs_to_ticks(usecs);
-
- /* Schedule entire connection interval for slave */
- usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
- }
-
- /*
- * We must end at least an IFS before the next scheduled event to
- * insure the minimum time between frames.
- */
- usecs -= (BLE_LL_IFS + BLE_LL_PROC_DELAY);
- sch->end_time = connsm->anchor_point + cputime_usecs_to_ticks(usecs);
- connsm->ce_end_time = sch->end_time;
-
- /* XXX: for now, we cant get an overlap so assert on error. */
- /* Add the item to the scheduler */
- rc = ble_ll_sched_add(sch);
- assert(rc == 0);
- } else {
- /* Count # of times we could not set schedule */
- ++g_ble_ll_conn_stats.cant_set_sched;
-
- /* XXX: for now just assert; must handle this later though */
- assert(0);
- }
-
- return sch;
-}
-
-/**
* Connection supervision timer callback; means that the connection supervision
* timeout has been reached and we should perform the appropriate actions.
*
@@ -915,11 +905,13 @@ void
ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm,
struct hci_create_conn *hcc)
{
- /* Must be master */
+ /* Set master role */
connsm->conn_role = BLE_LL_CONN_ROLE_MASTER;
- connsm->tx_win_size = BLE_LL_CONN_CFG_TX_WIN_SIZE;
- connsm->tx_win_off = BLE_LL_CONN_CFG_TX_WIN_OFF;
- connsm->master_sca = BLE_LL_CONN_CFG_MASTER_SCA;
+
+ /* Set default ce parameters */
+ connsm->tx_win_size = BLE_LL_CFG_CONN_TX_WIN_SIZE;
+ connsm->tx_win_off = BLE_LL_CFG_CONN_TX_WIN_OFF;
+ connsm->master_sca = BLE_LL_CFG_CONN_MASTER_SCA;
/* Hop increment is a random value between 5 and 16. */
connsm->hop_inc = (rand() % 12) + 5;
@@ -962,17 +954,22 @@ ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm,
/* Calculate random access address and crc initialization value */
connsm->access_addr = ble_ll_conn_calc_access_addr();
connsm->crcinit = rand() & 0xffffff;
+
+ /* Set initial schedule callback */
+ connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb;
}
/**
- * Start the connection state machine. This is done once per connection
- * when the HCI command "create connection" is issued to the controller or
- * when a slave receives a connect request,
+ * Create a new connection state machine. This is done once per
+ * connection when the HCI command "create connection" is issued to the
+ * controller or when a slave receives a connect request.
+ *
+ * Context: Link Layer task
*
* @param connsm
*/
void
-ble_ll_conn_sm_start(struct ble_ll_conn_sm *connsm)
+ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm)
{
struct ble_ll_conn_global_params *conn_params;
@@ -1030,20 +1027,6 @@ ble_ll_conn_sm_start(struct ble_ll_conn_sm *connsm)
connsm->eff_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
connsm->eff_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
- /*
- * Section 4.5.10 Vol 6 PART B. If the max tx/rx time or octets
- * exceeds the minimum, data length procedure needs to occur
- */
- if ((connsm->max_tx_octets > BLE_LL_CONN_SUPP_BYTES_MIN) ||
- (connsm->max_rx_octets > BLE_LL_CONN_SUPP_BYTES_MIN) ||
- (connsm->max_tx_time > BLE_LL_CONN_SUPP_TIME_MIN) ||
- (connsm->max_rx_time > BLE_LL_CONN_SUPP_TIME_MIN)) {
- /* Start the data length update procedure */
- if (ble_ll_read_supp_features() & BLE_LL_FEAT_DATA_LEN_EXT) {
- ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
- }
- }
-
/* Add to list of active connections */
SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle);
}
@@ -1114,13 +1097,8 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
struct os_mbuf *m;
struct os_mbuf_pkthdr *pkthdr;
- /* If this is the current state machine, we need to end it */
- if (connsm == g_ble_ll_conn_cur_sm) {
- ble_ll_conn_current_sm_over();
- } else {
- /* Remove scheduler events just in case */
- ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_CONN, connsm);
- }
+ /* Remove scheduler events just in case */
+ ble_ll_sched_rmv_elem(&connsm->conn_sch);
/* Stop supervision timer */
cputime_timer_stop(&connsm->conn_spvn_timer);
@@ -1173,6 +1151,75 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
ble_ll_log(BLE_LL_LOG_ID_CONN_END,connsm->conn_handle,0,connsm->event_cntr);
}
+static int
+ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
+{
+ uint16_t latency;
+ uint32_t itvl;
+ uint32_t cur_ww;
+ uint32_t max_ww;
+
+ /*
+ * XXX: not quite sure I am interpreting slave latency correctly here.
+ * The spec says if you applied slave latency and you dont hear a packet,
+ * you dont apply slave latency. Does that mean you dont apply slave
+ * latency until you hear a packet or on the next interval if you listen
+ * and dont hear anything, can you apply slave latency?
+ */
+ /* Set event counter to the next connection event that we will tx/rx in */
+ itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
+ latency = 1;
+ if (connsm->allow_slave_latency) {
+ if (connsm->pkt_rxd) {
+ latency += connsm->slave_latency;
+ itvl = itvl * latency;
+ }
+ }
+ connsm->event_cntr += latency;
+
+ /* Set next connection event start time */
+ connsm->anchor_point += cputime_usecs_to_ticks(itvl);
+
+ /* Calculate data channel index of next connection event */
+ connsm->last_unmapped_chan = connsm->unmapped_chan;
+ while (latency > 0) {
+ --latency;
+ connsm->data_chan_index = ble_ll_conn_calc_dci(connsm);
+ }
+
+ /*
+ * If we are trying to terminate connection, check if next wake time is
+ * passed the termination timeout. If so, no need to continue with
+ * connection as we will time out anyway.
+ */
+ if (connsm->pending_ctrl_procs & (1 << BLE_LL_CTRL_PROC_TERMINATE)) {
+ if ((int32_t)(connsm->terminate_timeout - connsm->anchor_point) <= 0) {
+ return -1;
+ }
+ }
+
+ /*
+ * Calculate ce end time. For a slave, we need to add window widening and
+ * the transmit window if we still have one.
+ */
+ itvl = BLE_LL_CFG_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;
+ 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 + cputime_usecs_to_ticks(itvl);
+
+ return 0;
+}
+
/**
* Called when a connection has been created. This function will
* -> Set the connection state to created.
@@ -1185,10 +1232,13 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
* Context: Link Layer
*
* @param connsm
+ *
+ * @ return 0: connection NOT created. 1: connection created
*/
-static void
+static int
ble_ll_conn_created(struct ble_ll_conn_sm *connsm, uint32_t endtime)
{
+ int rc;
uint32_t usecs;
/* Set state to created */
@@ -1201,34 +1251,56 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, uint32_t endtime)
/* Clear packet received flag */
connsm->pkt_rxd = 0;
+ /* Consider time created the last scheduled time */
+ connsm->last_scheduled = cputime_get32();
+
/*
- * Set first connection event time. If we are a master, the endtime
- * represents the end of the advertisement that we are transmitting the
- * connect request to. If a slave, it is the end time of connect request.
- * Thus, for the master, we need to add an IFS time plus the time it takes
- * to transmit the connection request. For both master and slave, the
- * actual connection starts 1.25 msecs plus the transmit window offset
- * from the end of the connection request.
+ * Set first connection event time. If slave the endtime is the receive end
+ * time of the connect request. The actual connection starts 1.25 msecs plus
+ * the transmit window offset from the end of the connection request.
*/
+ rc = 1;
connsm->last_anchor_point = endtime;
- if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
- usecs = BLE_LL_CONN_REQ_DURATION + BLE_LL_IFS;
- connsm->last_anchor_point += cputime_usecs_to_ticks(usecs);
-
- } else {
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
connsm->slave_cur_tx_win_usecs =
connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
- usecs = 0;
+ usecs = 1250 + (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS);
+ connsm->anchor_point = endtime + cputime_usecs_to_ticks(usecs);
+ usecs = connsm->slave_cur_tx_win_usecs + (BLE_LL_CFG_CONN_INIT_SLOTS *
+ BLE_LL_SCHED_USECS_PER_SLOT);
+ connsm->ce_end_time = connsm->anchor_point +
+ cputime_usecs_to_ticks(usecs);
+ connsm->slave_cur_window_widening = 0;
+
+ /* Start the scheduler for the first connection event */
+ while (ble_ll_sched_slave_new(connsm)) {
+ if (ble_ll_conn_next_event(connsm)) {
+ ++g_ble_ll_conn_stats.cant_set_sched;
+ rc = 0;
+ break;
+ }
+ }
}
- usecs += 1250 + (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS);
- connsm->anchor_point = endtime + cputime_usecs_to_ticks(usecs);
- connsm->slave_cur_window_widening = 0;
/* Send connection complete event to inform host of connection */
- ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS);
+ if (rc) {
+ /*
+ * Section 4.5.10 Vol 6 PART B. If the max tx/rx time or octets
+ * exceeds the minimum, data length procedure needs to occur
+ */
+ if ((connsm->max_tx_octets > BLE_LL_CONN_SUPP_BYTES_MIN) ||
+ (connsm->max_rx_octets > BLE_LL_CONN_SUPP_BYTES_MIN) ||
+ (connsm->max_tx_time > BLE_LL_CONN_SUPP_TIME_MIN) ||
+ (connsm->max_rx_time > BLE_LL_CONN_SUPP_TIME_MIN)) {
+ /* Start the data length update procedure */
+ if (ble_ll_read_supp_features() & BLE_LL_FEAT_DATA_LEN_EXT) {
+ ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
+ }
+ }
+ ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS);
+ }
- /* Start the scheduler for the first connection event */
- ble_ll_conn_sched_set(connsm);
+ return rc;
}
/**
@@ -1243,17 +1315,18 @@ void
ble_ll_conn_event_end(void *arg)
{
uint8_t ble_err;
- uint16_t latency;
- uint32_t itvl;
- uint32_t cur_ww;
- uint32_t max_ww;
struct ble_ll_conn_sm *connsm;
+ /* Better be a connection state machine! */
connsm = (struct ble_ll_conn_sm *)arg;
- assert(connsm && (connsm == g_ble_ll_conn_cur_sm));
+ assert(connsm);
- /* The current state machine is over */
- ble_ll_conn_current_sm_over();
+ /* Check if we need to resume scanning */
+ ble_ll_scan_chk_resume();
+
+ /* Log event end */
+ ble_ll_log(BLE_LL_LOG_ID_CONN_EV_END, 0, connsm->event_cntr,
+ connsm->ce_end_time);
/* If we have transmitted the terminate IND successfully, we are done */
if ((connsm->terminate_ind_txd) || (connsm->terminate_ind_rxd)) {
@@ -1281,79 +1354,30 @@ ble_ll_conn_event_end(void *arg)
connsm->slave_cur_tx_win_usecs = 0;
}
- /*
- * XXX: not quite sure I am interpreting slave latency correctly here.
- * The spec says if you applied slave latency and you dont hear a packet,
- * you dont apply slave latency. Does that mean you dont apply slave
- * latency until you hear a packet or on the next interval if you listen
- * and dont hear anything, can you apply slave latency?
- */
- /* Set event counter to the next connection event that we will tx/rx in */
- itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
- latency = 1;
- if (connsm->allow_slave_latency) {
- if (connsm->pkt_rxd) {
- latency += connsm->slave_latency;
- itvl = itvl * latency;
- }
- }
- connsm->event_cntr += latency;
-
- /* Set next connection event start time */
- connsm->anchor_point += cputime_usecs_to_ticks(itvl);
-
- /* Calculate data channel index of next connection event */
- connsm->last_unmapped_chan = connsm->unmapped_chan;
- while (latency > 0) {
- --latency;
- connsm->data_chan_index = ble_ll_conn_calc_dci(connsm);
- }
-
- /* We better not be late for the anchor point. If so, skip events */
- while ((int32_t)(connsm->anchor_point - cputime_get32()) <= 0) {
- ++connsm->event_cntr;
- connsm->data_chan_index = ble_ll_conn_calc_dci(connsm);
- connsm->anchor_point +=
- cputime_usecs_to_ticks(connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS);
- ++g_ble_ll_conn_stats.conn_ev_late;
+ /* Move to next connection event */
+ if (ble_ll_conn_next_event(connsm)) {
+ ble_ll_conn_end(connsm, BLE_ERR_CONN_TERM_LOCAL);
+ return;
}
/* Reset "per connection event" variables */
connsm->cons_rxd_bad_crc = 0;
connsm->pkt_rxd = 0;
- /*
- * If we are trying to terminate connection, check if next wake time is
- * passed the termination timeout. If so, no need to continue with
- * connection as we will time out anyway.
- */
- if (connsm->pending_ctrl_procs & (1 << BLE_LL_CTRL_PROC_TERMINATE)) {
- if ((int32_t)(connsm->terminate_timeout - connsm->anchor_point) <= 0) {
- ble_ll_conn_end(connsm, BLE_ERR_CONN_TERM_LOCAL);
- return;
- }
- }
+ /* See if we need to start any control procedures */
+ ble_ll_ctrl_chk_proc_start(connsm);
- /* Calculate window widening for next event. If too big, end conn */
- 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) {
+ /* Set initial schedule callback */
+ connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb;
+
+ /* Schedule the next connection event */
+ while (ble_ll_sched_conn_reschedule(connsm)) {
+ if (ble_ll_conn_next_event(connsm)) {
ble_ll_conn_end(connsm, BLE_ERR_CONN_TERM_LOCAL);
return;
}
- connsm->slave_cur_window_widening = cur_ww;
}
- /* Log event end */
- ble_ll_log(BLE_LL_LOG_ID_CONN_EV_END, 0, 0, connsm->event_cntr);
-
- /* See if we need to start any control procedures */
- ble_ll_ctrl_chk_proc_start(connsm);
-
- /* Schedule the next connection event */
- ble_ll_conn_sched_set(connsm);
-
/* If we have completed packets, send an event */
if (connsm->completed_pkts) {
ble_ll_conn_num_comp_pkts_event_send();
@@ -1367,9 +1391,11 @@ ble_ll_conn_event_end(void *arg)
* @param m
* @param adva
* @param addr_type
+ * @param txoffset The tx window offset for this connection
*/
-void
-ble_ll_conn_req_pdu_update(struct os_mbuf *m, uint8_t *adva, uint8_t addr_type)
+static void
+ble_ll_conn_req_pdu_update(struct os_mbuf *m, uint8_t *adva, uint8_t addr_type,
+ uint16_t txoffset)
{
uint8_t pdu_type;
uint8_t *dptr;
@@ -1391,7 +1417,8 @@ ble_ll_conn_req_pdu_update(struct os_mbuf *m, uint8_t *adva, uint8_t addr_type)
ble_hdr->txinfo.hdr_byte = pdu_type;
dptr = m->om_data;
- memcpy(dptr + BLE_DEV_ADDR_LEN, adva, BLE_DEV_ADDR_LEN);
+ memcpy(dptr + BLE_DEV_ADDR_LEN, adva, BLE_DEV_ADDR_LEN);
+ htole16(dptr + 20, txoffset);
}
/* Returns true if the address matches the connection peer address */
@@ -1414,6 +1441,19 @@ ble_ll_conn_is_peer_adv(uint8_t addr_type, uint8_t *adva)
}
/**
+ * Called when a connect request transmission is done.
+ *
+ * Context: ISR
+ *
+ * @param arg
+ */
+static void
+ble_ll_conn_req_txend(void *arg)
+{
+ ble_ll_state_set(BLE_LL_STATE_STANDBY);
+}
+
+/**
* Send a connection requestion to an advertiser
*
* Context: Interrupt
@@ -1422,18 +1462,38 @@ ble_ll_conn_is_peer_adv(uint8_t addr_type, uint8_t *adva)
* @param adva Address of advertiser
*/
static int
-ble_ll_conn_request_send(uint8_t addr_type, uint8_t *adva)
+ble_ll_conn_request_send(uint8_t addr_type, uint8_t *adva, uint16_t txoffset)
{
int rc;
struct os_mbuf *m;
m = ble_ll_scan_get_pdu();
- ble_ll_conn_req_pdu_update(m, adva, addr_type);
+ ble_ll_conn_req_pdu_update(m, adva, addr_type, txoffset);
+ ble_phy_set_txend_cb(ble_ll_conn_req_txend, NULL);
rc = ble_phy_tx(m, BLE_PHY_TRANSITION_RX_TX, BLE_PHY_TRANSITION_NONE);
return rc;
}
/**
+ * Called when a schedule item overlaps the currently running connection
+ * event. This generally should not happen, but if it does we stop the
+ * current connection event to let the schedule item run.
+ *
+ * NOTE: the phy has been disabled as well as the wfr timer before this is
+ * called.
+ */
+void
+ble_ll_conn_event_halt(void)
+{
+ ble_ll_state_set(BLE_LL_STATE_STANDBY);
+ if (g_ble_ll_conn_cur_sm) {
+ g_ble_ll_conn_cur_sm->pkt_rxd = 0;
+ ble_ll_event_send(&g_ble_ll_conn_cur_sm->conn_ev_end);
+ g_ble_ll_conn_cur_sm = NULL;
+ }
+}
+
+/**
* Process a received PDU while in the initiating state.
*
* Context: Link Layer task.
@@ -1449,12 +1509,9 @@ ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr)
/* Get the connection state machine we are trying to create */
connsm = g_ble_ll_conn_create_sm;
- if (!connsm) {
- return;
- }
/* If we have sent a connect request, we need to enter CONNECTION state*/
- if (ble_hdr->rxinfo.crcok &&
+ if (connsm && BLE_MBUF_HDR_CRC_OK(ble_hdr) &&
(ble_hdr->rxinfo.flags & BLE_MBUF_HDR_F_CONN_REQ_TXD)) {
/* Set address of advertiser to which we are connecting. */
if (!ble_ll_scan_whitelist_enabled()) {
@@ -1477,15 +1534,15 @@ ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr)
/* Connection has been created. Stop scanning */
g_ble_ll_conn_create_sm = NULL;
- ble_ll_scan_sm_stop(ble_ll_scan_sm_get(), 1);
+ ble_ll_scan_sm_stop(0);
ble_ll_conn_created(connsm, ble_hdr->end_cputime);
} else {
- ble_ll_scan_resume();
+ ble_ll_scan_chk_resume();
}
}
/**
- * Called when a receive PDU has ended.
+ * Called when a receive PDU has ended and we are in the initiating state.
*
* Context: Interrupt
*
@@ -1497,7 +1554,7 @@ ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr)
* > 0: Do not disable PHY as that has already been done.
*/
int
-ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu)
+ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
{
int rc;
int chk_send_req;
@@ -1508,6 +1565,20 @@ ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu)
uint8_t *rxbuf;
struct ble_mbuf_hdr *ble_hdr;
+ /*
+ * We have to restart receive if we cant hand up pdu. We return 0 so that
+ * the phy does not get disabled.
+ */
+ if (!rxpdu) {
+ ble_phy_rx();
+ return 0;
+ }
+
+ rc = -1;
+ if (!crcok) {
+ goto init_rx_isr_exit;
+ }
+
/* Only interested in ADV IND or ADV DIRECT IND */
rxbuf = rxpdu->om_data;
pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
@@ -1531,7 +1602,6 @@ ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu)
}
/* Should we send a connect request? */
- rc = -1;
if (chk_send_req) {
/* Check filter policy */
adv_addr = rxbuf + BLE_LL_PDU_HDR_LEN;
@@ -1560,18 +1630,63 @@ ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu)
}
}
- /* Setup to transmit the connect request */
- rc = ble_ll_conn_request_send(addr_type, adv_addr);
- if (!rc) {
- ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONN_REQ_TXD;
- ++g_ble_ll_conn_stats.conn_req_txd;
+ /* Attempt to schedule new connection. Possible that this might fail */
+ if (!ble_ll_sched_master_new(g_ble_ll_conn_create_sm,
+ ble_hdr->end_cputime,
+ BLE_LL_CFG_CONN_INIT_SLOTS)) {
+ /* Setup to transmit the connect request */
+ rc = ble_ll_conn_request_send(addr_type, adv_addr,
+ g_ble_ll_conn_create_sm->tx_win_off);
+ if (!rc) {
+ ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONN_REQ_TXD;
+ ++g_ble_ll_conn_stats.conn_req_txd;
+ }
+ } else {
+ /* Count # of times we could not set schedule */
+ ++g_ble_ll_conn_stats.cant_set_sched;
}
}
+init_rx_isr_exit:
+ if (rc) {
+ ble_ll_state_set(BLE_LL_STATE_STANDBY);
+ }
return rc;
}
/**
+ * Function called when a timeout has occurred for a connection. There are
+ * two types of timeouts: a connection supervision timeout and control
+ * procedure timeout.
+ *
+ * Context: Link Layer task
+ *
+ * @param connsm
+ * @param ble_err
+ */
+void
+ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
+{
+ int was_current;
+ os_sr_t sr;
+
+ was_current = 0;
+ OS_ENTER_CRITICAL(sr);
+ if (g_ble_ll_conn_cur_sm == connsm) {
+ ble_ll_conn_current_sm_over();
+ was_current = 1;
+ }
+ OS_EXIT_CRITICAL(sr);
+
+ /* Check if we need to resume scanning */
+ if (was_current) {
+ ble_ll_scan_chk_resume();
+ }
+
+ ble_ll_conn_end(connsm, ble_err);
+}
+
+/**
* Connection supervision timeout. When called, it means that the connection
* supervision timeout has been reached. If reached, we end the connection.
*
@@ -1582,16 +1697,18 @@ ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu)
void
ble_ll_conn_spvn_timeout(void *arg)
{
- ble_ll_conn_end((struct ble_ll_conn_sm *)arg, BLE_ERR_CONN_SPVN_TMO);
+ ble_ll_conn_timeout((struct ble_ll_conn_sm *)arg, BLE_ERR_CONN_SPVN_TMO);
}
/**
* Called when a data channel PDU has started that matches the access
* address of the current connection. Note that the CRC of the PDU has not
- * been checked yet.
+ * been checked yet.
+ *
+ * Context: Interrupt
*/
void
-ble_ll_conn_rx_pdu_start(void)
+ble_ll_conn_rx_isr_start(void)
{
struct ble_ll_conn_sm *connsm;
@@ -1613,10 +1730,11 @@ ble_ll_conn_rx_pdu_start(void)
*
* Context: Link layer task
*
- * @param rxpdu
+ * @param rxpdu Pointer to received pdu
+ * @param rxpdu Pointer to ble mbuf header of received pdu
*/
void
-ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, uint8_t crcok)
+ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
{
uint8_t hdr_byte;
uint8_t rxd_sn;
@@ -1625,13 +1743,15 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, uint8_t crcok)
uint16_t acl_hdr;
uint32_t tmo;
struct ble_ll_conn_sm *connsm;
-
- if (crcok) {
+
+ if (BLE_MBUF_HDR_CRC_OK(hdr)) {
/* Count valid received data pdus */
++g_ble_ll_stats.rx_valid_data_pdus;
+ /* XXX: there is a chance that the connection was thrown away and
+ re-used before processing packets here. Fix this. */
/* We better have a connection state machine */
- connsm = g_ble_ll_conn_cur_sm;
+ connsm = ble_ll_conn_find_active_conn(hdr->rxinfo.handle);
if (connsm) {
/* Reset the connection supervision timeout */
cputime_timer_stop(&connsm->conn_spvn_timer);
@@ -1724,7 +1844,7 @@ conn_rx_data_pdu_end:
* > 0: Do not disable PHY as that has already been done.
*/
int
-ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint32_t aa)
+ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu, uint32_t aa)
{
int rc;
uint8_t hdr_byte;
@@ -1744,26 +1864,29 @@ ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint32_t aa)
* We should have a current connection state machine. If we dont, we just
* hand the packet to the higher layer to count it.
*/
+ rc = -1;
connsm = g_ble_ll_conn_cur_sm;
if (!connsm) {
++g_ble_ll_conn_stats.rx_data_pdu_no_conn;
- return -1;
+ goto conn_exit;
}
/* Double check access address. Better match connection state machine! */
if (aa != connsm->access_addr) {
++g_ble_ll_conn_stats.rx_data_pdu_bad_aa;
- ble_ll_event_send(&connsm->conn_ev_end);
- return -1;
+ goto conn_exit;
}
+ /* Set the handle in the ble mbuf header */
+ rxhdr = BLE_MBUF_HDR_PTR(rxpdu);
+ rxhdr->rxinfo.handle = connsm->conn_handle;
+
/*
* Check the packet CRC. A connection event can continue even if the
* received PDU does not pass the CRC check. If we receive two consecutive
* CRC errors we end the conection event.
*/
- rxhdr = BLE_MBUF_HDR_PTR(rxpdu);
- if (!rxhdr->rxinfo.crcok) {
+ if (!BLE_MBUF_HDR_CRC_OK(rxhdr)) {
/*
* Increment # of consecutively received CRC errors. If more than
* one we will end the connection event.
@@ -1894,19 +2017,24 @@ ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint32_t aa)
}
conn_rx_pdu_end:
- /* Set last anchor point if 1st received frame in connection event */
+ /* Set anchor point (and last) if 1st received frame in connection event */
if (connsm->slave_set_last_anchor) {
connsm->slave_set_last_anchor = 0;
connsm->last_anchor_point = rxhdr->end_cputime -
BLE_TX_DUR_USECS_M(rxpdu->om_data[1]);
+ connsm->anchor_point = connsm->last_anchor_point;
}
/* Send link layer a connection end event if over */
+conn_exit:
if (rc) {
- ble_ll_event_send(&connsm->conn_ev_end);
+ ble_ll_conn_current_sm_over();
+ if (connsm) {
+ ble_ll_event_send(&connsm->conn_ev_end);
+ }
}
- return 0;
+ return rc;
}
/**
@@ -1999,12 +2127,14 @@ ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t length)
* Context: Link Layer
*
* @param rxbuf Pointer to received PDU
+ * @param conn_req_end receive end time of connect request
*
* @return 0: connection not started; 1 connecton started
*/
int
ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t conn_req_end)
{
+ int rc;
uint32_t temp;
uint32_t crcinit;
uint8_t *inita;
@@ -2096,11 +2226,17 @@ ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t conn_req_end)
/* Start the connection state machine */
connsm->conn_role = BLE_LL_CONN_ROLE_SLAVE;
- ble_ll_conn_sm_start(connsm);
+ ble_ll_conn_sm_new(connsm);
- /* The connection has been created. */
- ble_ll_conn_created(connsm, conn_req_end);
- return 1;
+ /* Set initial schedule callback */
+ connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb;
+
+ rc = ble_ll_conn_created(connsm, conn_req_end);
+ if (!rc) {
+ SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, act_sle);
+ STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
+ }
+ return rc;
err_slave_start:
STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
@@ -2109,7 +2245,9 @@ err_slave_start:
}
/**
- * Called to reset the connection module.
+ * Called to reset the connection module. When this function is called the
+ * scheduler has been stopped and the phy has been disabled. The LL should
+ * be in the standby state.
*
* Context: Link Layer task
*/
@@ -2121,7 +2259,7 @@ ble_ll_conn_reset(void)
/* Kill the current one first (if one is running) */
if (g_ble_ll_conn_cur_sm) {
connsm = g_ble_ll_conn_cur_sm;
- ble_ll_conn_current_sm_over();
+ g_ble_ll_conn_cur_sm = NULL;
ble_ll_conn_end(connsm, BLE_ERR_SUCCESS);
}
@@ -2155,7 +2293,7 @@ ble_ll_conn_module_init(void)
* the specification allows a handle of zero; we just avoid using it.
*/
connsm = &g_ble_ll_conn_sm[0];
- for (i = 0; i < BLE_LL_CONN_CFG_MAX_CONNS; ++i) {
+ for (i = 0; i < BLE_LL_CFG_CONN_MAX_CONNS; ++i) {
connsm->conn_handle = i + 1;
STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
@@ -2170,6 +2308,9 @@ ble_ll_conn_module_init(void)
ble_ll_mbuf_init(m, 0, BLE_LL_LLID_DATA_FRAG);
+ /* Initialize fixed schedule elements */
+ connsm->conn_sch.sched_type = BLE_LL_SCHED_TYPE_CONN;
+ connsm->conn_sch.cb_arg = connsm;
++connsm;
}
@@ -2187,3 +2328,4 @@ ble_ll_conn_module_init(void)
conn_params->conn_init_max_tx_time = BLE_TX_DUR_USECS_M(maxbytes);
conn_params->conn_init_max_tx_octets = BLE_LL_CFG_CONN_INIT_MAX_TX_BYTES;
}
+
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/controller/src/ble_ll_conn_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_hci.c b/net/nimble/controller/src/ble_ll_conn_hci.c
index a4ac46c..a051318 100644
--- a/net/nimble/controller/src/ble_ll_conn_hci.c
+++ b/net/nimble/controller/src/ble_ll_conn_hci.c
@@ -358,7 +358,7 @@ ble_ll_conn_create(uint8_t *cmdbuf)
/* Initialize state machine in master role and start state machine */
ble_ll_conn_master_init(connsm, hcc);
- ble_ll_conn_sm_start(connsm);
+ ble_ll_conn_sm_new(connsm);
/* Create the connection request */
ble_ll_conn_req_pdu_make(connsm);
@@ -400,7 +400,7 @@ ble_ll_conn_create_cancel(void)
if (connsm && (connsm->conn_state == BLE_LL_CONN_STATE_IDLE)) {
/* stop scanning and end the connection event */
g_ble_ll_conn_create_sm = NULL;
- ble_ll_scan_sm_stop(ble_ll_scan_sm_get(), 0);
+ ble_ll_scan_sm_stop(1);
ble_ll_conn_end(connsm, BLE_ERR_UNK_CONN_ID);
rc = BLE_ERR_SUCCESS;
} else {
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 48304b2..47015a3 100644
--- a/net/nimble/controller/src/ble_ll_conn_priv.h
+++ b/net/nimble/controller/src/ble_ll_conn_priv.h
@@ -32,6 +32,7 @@
#define BLE_LL_CONN_SUPP_BYTES_MAX (251) /* bytes */
/* Connection event timing */
+#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_CE_USECS (625)
@@ -60,7 +61,7 @@ extern struct ble_ll_conn_sm *g_ble_ll_conn_create_sm;
struct ble_ll_len_req;
struct hci_create_conn;
struct ble_mbuf_hdr;
-void ble_ll_conn_sm_start(struct ble_ll_conn_sm *connsm);
+void ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm);
void ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err);
void ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om,
uint8_t hdr_byte, uint8_t length);
@@ -80,12 +81,15 @@ void ble_ll_conn_reset(void);
void ble_ll_conn_event_end(void *arg);
void ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t len);
void ble_ll_conn_spvn_timeout(void *arg);
-void ble_ll_conn_rx_pdu_start(void);
-int ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint32_t aa);
-void ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, uint8_t crcok);
+void ble_ll_conn_rx_isr_start(void);
+int ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu, uint32_t aa);
+void ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr);
void ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr);
-int ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu);
+int ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok);
void ble_ll_conn_wfr_timer_exp(void);
+int ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2);
+uint32_t ble_ll_conn_get_ce_end_time(void);
+void ble_ll_conn_event_halt(void);
/* HCI */
void ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm,
@@ -96,5 +100,7 @@ int ble_ll_conn_create(uint8_t *cmdbuf);
int ble_ll_conn_create_cancel(void);
void ble_ll_conn_num_comp_pkts_event_send(void);
void ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status);
+void ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err);
+
#endif /* H_BLE_LL_CONN_PRIV_ */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/controller/src/ble_ll_ctrl.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_ctrl.c b/net/nimble/controller/src/ble_ll_ctrl.c
index 2a06265..0e5df2d 100644
--- a/net/nimble/controller/src/ble_ll_ctrl.c
+++ b/net/nimble/controller/src/ble_ll_ctrl.c
@@ -197,7 +197,7 @@ void
ble_ll_ctrl_proc_rsp_timer_cb(void *arg)
{
/* Control procedure has timed out. Kill the connection */
- ble_ll_conn_end((struct ble_ll_conn_sm *)arg, BLE_ERR_LMP_LL_RSP_TMO);
+ ble_ll_conn_timeout((struct ble_ll_conn_sm *)arg, BLE_ERR_LMP_LL_RSP_TMO);
}
/**