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 2015/11/28 17:01:03 UTC
incubator-mynewt-larva git commit: Refactor connection handle code.
Place all connections on a free list and assign the handles on init. Add
active/free connection lists
Repository: incubator-mynewt-larva
Updated Branches:
refs/heads/master 48d5b34fc -> 15a4a8cf3
Refactor connection handle code. Place all connections on a free list and assign the handles on init. Add active/free connection lists
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/15a4a8cf
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/15a4a8cf
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/15a4a8cf
Branch: refs/heads/master
Commit: 15a4a8cf3c33c842ce409d70d0da9ea4c75c8e03
Parents: 48d5b34
Author: wes3 <wi...@micosa.io>
Authored: Sat Nov 28 08:00:33 2015 -0800
Committer: wes3 <wi...@micosa.io>
Committed: Sat Nov 28 08:00:49 2015 -0800
----------------------------------------------------------------------
.../controller/include/controller/ble_ll.h | 25 +-
.../controller/include/controller/ble_ll_conn.h | 4 +-
net/nimble/controller/src/ble_ll.c | 170 ++-
net/nimble/controller/src/ble_ll_adv.c | 1 -
net/nimble/controller/src/ble_ll_conn.c | 1077 +++++++++++++-----
net/nimble/drivers/native/src/ble_phy.c | 4 +-
net/nimble/drivers/nrf52/src/ble_phy.c | 16 +-
net/nimble/include/nimble/ble.h | 8 +
project/bletest/src/main.c | 4 +-
9 files changed, 942 insertions(+), 367 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/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 91ff4cf..a39f4a1 100644
--- a/net/nimble/controller/include/controller/ble_ll.h
+++ b/net/nimble/controller/include/controller/ble_ll.h
@@ -17,6 +17,11 @@
#ifndef H_BLE_LL_
#define H_BLE_LL_
+#include "hal/hal_cputime.h"
+
+/* Wait for response timer */
+typedef void (*ble_ll_wfr_func)(void *arg);
+
/*
* Global Link Layer data object. There is only one Link Layer data object
* per controller although there may be many instances of the link layer state
@@ -33,6 +38,10 @@ struct ble_ll_obj
/* Receive packet (from phy) event */
struct os_event ll_rx_pkt_ev;
+ /* Wait for response timer */
+ struct cpu_timer ll_wfr_timer;
+ ble_ll_wfr_func ll_wfr_func;
+
/* Packet receive queue */
STAILQ_HEAD(ll_rxpkt_qh, os_mbuf_pkthdr) ll_rx_pkt_q;
};
@@ -41,6 +50,10 @@ extern struct ble_ll_obj g_ble_ll_data;
/* Link layer statistics */
struct ble_ll_stats
{
+ uint32_t hci_cmds;
+ uint32_t hci_cmd_errs;
+ uint32_t hci_events_sent;
+ uint32_t bad_ll_state;
uint32_t rx_crc_ok;
uint32_t rx_crc_fail;
uint32_t rx_bytes;
@@ -53,10 +66,6 @@ struct ble_ll_stats
uint32_t rx_scan_ind;
uint32_t rx_unk_pdu;
uint32_t rx_malformed_pkts;
- uint32_t hci_cmds;
- uint32_t hci_cmd_errs;
- uint32_t hci_events_sent;
- uint32_t bad_ll_state;
};
extern struct ble_ll_stats g_ble_ll_stats;
@@ -404,7 +413,7 @@ int ble_ll_is_our_devaddr(uint8_t *addr, int addr_type);
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 crcok);
+int ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t chan, uint8_t crcok);
/*--- Controller API ---*/
/* Set the link layer state */
@@ -416,4 +425,10 @@ void ble_ll_event_send(struct os_event *ev);
/* Set random address */
int ble_ll_set_random_addr(uint8_t *addr);
+/* Enable wait for response timer */
+void ble_ll_wfr_enable(uint32_t cputime, ble_ll_wfr_func wfr_cb, void *arg);
+
+/* Disable wait for response timer */
+void ble_ll_wfr_disable(void);
+
#endif /* H_LL_ */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/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 4c3d535..f58a140 100644
--- a/net/nimble/controller/include/controller/ble_ll_conn.h
+++ b/net/nimble/controller/include/controller/ble_ll_conn.h
@@ -37,6 +37,8 @@ void ble_ll_conn_slave_start(uint8_t *rxbuf);
void ble_ll_conn_spvn_timeout(void *arg);
void ble_ll_conn_event_end(void *arg);
void ble_ll_conn_init(void);
-void ble_ll_conn_rsp_rxd(void);
+void ble_ll_conn_rx_pdu_start(void);
+int ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint8_t crcok);
+void ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, uint8_t crcok);
#endif /* H_BLE_LL_CONN_ */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/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 691a057..c196725 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -26,6 +26,7 @@
#include "controller/ble_ll_scan.h"
#include "controller/ble_ll_conn.h"
#include "controller/ble_ll_hci.h"
+#include "hal/hal_cputime.h"
/*
* XXX: Just thought of something! Can I always set the DEVMATCH bit at
@@ -67,12 +68,12 @@ struct os_task g_ble_ll_task;
os_stack_t g_ble_ll_stack[BLE_LL_STACK_SIZE];
/**
- * Counts received packets by type
+ * Counts the number of advertising PDU's by type.
*
* @param pdu_type
*/
static void
-ble_ll_count_rx_pkts(uint8_t pdu_type)
+ble_ll_count_rx_adv_pdus(uint8_t pdu_type)
{
/* Count received packet types */
switch (pdu_type) {
@@ -104,8 +105,6 @@ ble_ll_count_rx_pkts(uint8_t pdu_type)
++g_ble_ll_stats.rx_unk_pdu;
break;
}
-
- /* XXX: what about data packets? */
}
int
@@ -232,6 +231,48 @@ ble_ll_pdu_tx_time_get(uint16_t len)
}
/**
+ * Wait for response timeout function
+ *
+ * Context: interrupt (ble scheduler)
+ *
+ * @param arg
+ */
+void
+ble_ll_wfr_timer_exp(void *arg)
+{
+ struct ble_ll_obj *lldata;
+
+ lldata = &g_ble_ll_data;
+ lldata->ll_wfr_func(arg);
+}
+
+/**
+ * Enable the wait for response timer
+ *
+ * @param cputime
+ * @param wfr_cb
+ * @param arg
+ */
+void
+ble_ll_wfr_enable(uint32_t cputime, ble_ll_wfr_func wfr_cb, void *arg)
+{
+ /* XXX: should I reset func callback here too? Not use a global
+ ble_ll_wfr_timer expiration? */
+ g_ble_ll_data.ll_wfr_func = wfr_cb;
+ g_ble_ll_data.ll_wfr_timer.arg = arg;
+ cputime_timer_start(&g_ble_ll_data.ll_wfr_timer, cputime);
+}
+
+/**
+ * Disable the wait for response timer
+ */
+void
+ble_ll_wfr_disable(void)
+{
+ cputime_timer_stop(&g_ble_ll_data.ll_wfr_timer);
+}
+
+/**
* ll rx pkt in proc
*
* Process received packet from PHY.
@@ -260,61 +301,56 @@ ble_ll_rx_pkt_in_proc(void)
STAILQ_REMOVE_HEAD(&g_ble_ll_data.ll_rx_pkt_q, omp_next);
OS_EXIT_CRITICAL(sr);
- /* XXX: need to check if this is an adv channel or data channel */
-
/* Count statistics */
rxbuf = m->om_data;
- pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
ble_hdr = BLE_MBUF_HDR_PTR(m);
if (ble_hdr->crcok) {
/* The total bytes count the PDU header and PDU payload */
g_ble_ll_stats.rx_bytes += pkthdr->omp_len;
++g_ble_ll_stats.rx_crc_ok;
- ble_ll_count_rx_pkts(pdu_type);
} else {
++g_ble_ll_stats.rx_crc_fail;
}
- /*
- * XXX: The reason I dont bail earlier on bad CRC is that
- * there may be some connection stuff I need to do with a packet
- * that has failed the CRC.
- */
-
- /* Process the PDU */
- switch (g_ble_ll_data.ll_state) {
- case BLE_LL_STATE_ADV:
- if (ble_hdr->crcok && (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_REQ)) {
- ble_ll_adv_conn_req_rxd(rxbuf, ble_hdr->flags);
- }
- break;
- case BLE_LL_STATE_SCANNING:
+ if (ble_hdr->channel < BLE_PHY_NUM_DATA_CHANS) {
+ ble_ll_conn_rx_data_pdu(m, ble_hdr->crcok);
+ } else {
if (ble_hdr->crcok) {
- ble_ll_scan_rx_pdu_proc(pdu_type, rxbuf, ble_hdr->rssi,
- ble_hdr->flags);
+ /* Get advertising PDU type */
+ pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
+ ble_ll_count_rx_adv_pdus(pdu_type);
+
+ /* Process the PDU */
+ switch (g_ble_ll_data.ll_state) {
+ case BLE_LL_STATE_ADV:
+ if (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_REQ) {
+ ble_ll_adv_conn_req_rxd(rxbuf, ble_hdr->flags);
+ }
+ break;
+ case BLE_LL_STATE_SCANNING:
+ ble_ll_scan_rx_pdu_proc(pdu_type, rxbuf, ble_hdr->rssi,
+ ble_hdr->flags);
+
+ /* We need to re-enable the PHY if we are in idle state */
+ if (ble_phy_state_get() == BLE_PHY_STATE_IDLE) {
+ /* XXX: If this returns error, we will need to attempt
+ * to re-start scanning! */
+ ble_phy_rx();
+ }
+ break;
+ case BLE_LL_STATE_INITIATING:
+ ble_ll_init_rx_pdu_proc(rxbuf, ble_hdr);
+ break;
+ default:
+ /* Any other state should never occur */
+ assert(0);
+ break;
+ }
}
- /* We need to re-enable the PHY if we are in idle state */
- if (ble_phy_state_get() == BLE_PHY_STATE_IDLE) {
- /* XXX: If this returns error, we will need to attempt to
- re-start scanning! */
- ble_phy_rx();
- }
- break;
- case BLE_LL_STATE_INITIATING:
- ble_ll_init_rx_pdu_proc(rxbuf, ble_hdr);
- break;
- case BLE_LL_STATE_CONNECTION:
- /* XXX: implement */
- break;
- default:
- /* We should not receive packets in standby state! */
- assert(0);
- break;
+ /* Free the packet buffer */
+ os_mbuf_free(&g_mbuf_pool, m);
}
-
- /* Free the packet buffer */
- os_mbuf_free(&g_mbuf_pool, m);
}
}
@@ -351,7 +387,7 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
uint8_t pdu_type;
uint8_t *rxbuf;
- /* XXX: need to check if this is an adv channel or data channel */
+ /* Check channel type */
rxbuf = rxpdu->om_data;
if (chan < BLE_PHY_NUM_DATA_CHANS) {
/*
@@ -360,8 +396,8 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
*/
/* XXX: check access address for surety? What to do... */
if (g_ble_ll_data.ll_state == BLE_LL_STATE_CONNECTION) {
- /* Set flag in connection noting we have received a response */
- ble_ll_conn_rsp_rxd();
+ /* Call conection pdu rx start function */
+ ble_ll_conn_rx_pdu_start();
/* Set up to go from rx to tx */
rc = 1;
@@ -403,7 +439,7 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
rc = 0;
break;
default:
- /* Should not be in this state */
+ /* Should not be in this state! */
rc = -1;
++g_ble_ll_stats.bad_ll_state;
break;
@@ -425,7 +461,7 @@ 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 crcok)
+ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t chan, uint8_t crcok)
{
int rc;
int badpkt;
@@ -437,7 +473,34 @@ ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t crcok)
/* Set the rx buffer pointer to the start of the received data */
rxbuf = rxpdu->om_data;
- /* XXX: need to check if this is an adv channel or data channel */
+ /* Check channel type */
+ if (chan < BLE_PHY_NUM_DATA_CHANS) {
+ /* Better be in connection state */
+ assert(g_ble_ll_data.ll_state == BLE_LL_STATE_CONNECTION);
+
+ /* Set length in the received PDU */
+ mblen = rxbuf[1] + BLE_LL_PDU_HDR_LEN;
+ OS_MBUF_PKTHDR(rxpdu)->omp_len = mblen;
+ rxpdu->om_len = mblen;
+
+ /*
+ * NOTE: this looks a bit odd, and it is, but for now we place the
+ * received PDU on the Link Layer task before calling the rx end
+ * function. We do this to guarantee connection event end ordering
+ * and receive PDU processing.
+ */
+ ble_ll_rx_pdu_in(rxpdu);
+
+ /*
+ * Data channel pdu. We should be in CONNECTION state with an
+ * ongoing connection.
+ */
+ /* XXX: check access address for surety? What to do... */
+ rc = ble_ll_conn_rx_pdu_end(rxpdu, crcok);
+ return rc;
+ }
+
+ /* Get advertising PDU type */
pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK;
@@ -501,9 +564,10 @@ ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t crcok)
}
break;
case BLE_LL_STATE_CONNECTION:
- /* XXX */
+ /* XXX: we should never get here! What to do??? */
break;
default:
+ /* This is an invalid state. */
assert(0);
break;
}
@@ -610,6 +674,10 @@ ble_ll_init(void)
/* Initialize receive packet (from phy) event */
lldata->ll_rx_pkt_ev.ev_type = BLE_LL_EVENT_RX_PKT_IN;
+ /* Initialize wait for response timer */
+ cputime_timer_init(&g_ble_ll_data.ll_wfr_timer, ble_ll_wfr_timer_exp,
+ NULL);
+
/* Initialize LL HCI */
ble_ll_hci_init();
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/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 08eee0e..a04a395 100644
--- a/net/nimble/controller/src/ble_ll_adv.c
+++ b/net/nimble/controller/src/ble_ll_adv.c
@@ -345,7 +345,6 @@ ble_ll_adv_rx_cb(struct ble_ll_sched_item *sch)
return BLE_LL_SCHED_STATE_DONE;
}
-
/**
* Scheduler callback when an advertising PDU has been sent.
*
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/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 474af09..82700e1 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -31,45 +31,57 @@
#include "hal/hal_cputime.h"
/* XXX TODO
- * 1) Implemement connection supervisor timeout.
- * -> Need to re-start when we receive a packet and set the proper timeout.
- * 2) Add set channel map command and implement channel change procedure.
- * 3) Closing the connection: the MD bit.
- * 4) notifying host about connections: how often do we need to do this? On
- * creation, establishment and/or loss?
- * 5) Deal with window widening. Easy...
- * 6) Close connection if window widening gets too big! 4.5.7
- * 7) How does state get set to ESTABLISHED? Do that...
- * 8) Set up later connection schedule events.
- * 8.5) How do we set the end event? Especially if we are receiving? Need
- * to figure this out.
- * 9) Implement flow control and all that.
- * 10) Implement getting a data packet. How do we do that?
- * 11) Send connection complete event when connection dies.
- * 12) Data channel index and all that code. Must make sure we are setting this
- * correctly. Set for 1st connection event but not for other events.
- * 13) Add more statistics
- * 14) Update event counter with each event!
- * 15) Link layer control procedures and timers
- * 16) Did we implement what happens if we receive a connection request from
+ * 1) Add set channel map command and implement channel change procedure.
+ * 5) Implement getting a data packet. How do we do that?
+ * 6) Make sure we have implemented all ways a connection can die/end. Not
+ * a connection event; I mean the termination of a connection.
+ * 8) Link layer control procedures and timers
+ * 9) Did we implement what happens if we receive a connection request from
* a device we are already connected to? We also need to check to see if we
* were asked to create a connection when one already exists. Note that
* an initiator should only send connection requests to devices it is not
* already connected to. Make sure this cant happen.
- * 17) Dont forget to set pkt_rxd flag for slave latency. Needs to get reset
- * after each M-S transaction.
- * 18) Make sure we check incoming data packets for size and all that. You
+ * 10) Make sure we check incoming data packets for size and all that. You
* know, supported octets and all that. For both rx and tx.
- * 19) Make sure we handle rsp_rxd and pkt_rxd correctly (clearing/checking
- * setting them).
+ * 11) What kind of protection do I need on the conn_txq? The LL will need to
+ * disable interrupts... not sure about ISR's.
+ * 12) Add/remove connection from the active connection list.
+ * 13) Make sure we are setting the schedule end time properly for both slave
+ * and master. We should just set this to the end of the connection event.
+ * We might want to guarantee a IFS time as well since the next event needs
+ * to be scheduled prior to the start of the event to account for the time it
+ * takes to get a frame ready (which is pretty much the IFS time).
+ * 14) Make sure we set LLID correctly!
+ * 15) So what if I fail an empty pdu? Do I have to specifically retransmit
+ * that one? If I were to take a new data pdu and replace the empty pdu with
+ * the new data pdu? Could I do this or is that bad?
+ * 16) Make sure we are doing the right thing in the connection rx pdu start
+ * and end functions if we are a slave.
+ */
+
+/*
+ * XXX: Possible improvements
+ * 1) Not sure I like the fact that the wait for response timer will still
+ * fire off if we get a received packet. I need to look into that. I think
+ * I should disable the sucker if we get a reception and not have it fire off.
+ * 2) See what connection state machine elements are purely master and
+ * purely slave. We can make a union of them.
+ * 3) Do I need a memory pool of connection elements? Probably not.
*/
/* Connection event timing */
#define BLE_LL_CONN_ITVL_USECS (1250)
#define BLE_LL_CONN_TX_WIN_USECS (1250)
#define BLE_LL_CONN_CE_USECS (625)
+#define BLE_LL_CONN_TX_WIN_MIN (1) /* in tx win units */
+#define BLE_LL_CONN_SLAVE_LATENCY_MAX (499)
-/* XXX: probably should be moved and made more accurate */
+/*
+ * The amount of time that we will wait to hear the start of a receive
+ * packet in a connection event.
+ *
+ * XXX: move this definition and make it more accurate.
+ */
#define BLE_LL_WFR_USECS (100)
/* Channel map size */
@@ -80,6 +92,7 @@
#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 */
/* LL configuration definitions */
#define BLE_LL_CFG_SUPP_MAX_RX_BYTES (27)
@@ -103,13 +116,11 @@
/* Connection request */
#define BLE_LL_CONN_REQ_ADVA_OFF (BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN)
-/*
- * XXX: I just had a thought. Why do I need to allocate connection handles?
- * For every connection state machine I have I should just give it a handle
- * inside it. They can sit on the pool and I can use them in round robin
- * order. This might save some code! This works only if I create the pool
- * of connections to start.
- */
+/* Sleep clock accuracy table (in ppm) */
+static const uint16_t g_ble_sca_ppm_tbl[8] =
+{
+ 500, 250, 150, 100, 75, 50, 30, 20
+};
/* Global Link Layer connection parameters */
struct ble_ll_conn_global_params
@@ -153,11 +164,22 @@ struct ble_ll_conn_sm
uint8_t last_unmapped_chan;
uint8_t num_used_chans;
+ /* Ack/Flow Control */
+ uint8_t tx_seqnum; /* note: can be 1 bit */
+ uint8_t next_exp_seqnum; /* note: can be 1 bit */
+ uint8_t last_txd_md; /* note can be 1 bit */
+ uint8_t cons_rxd_bad_crc; /* note: can be 1 bit */
+ uint8_t last_rxd_sn; /* note: cant be 1 bit given current code */
+ uint8_t last_rxd_hdr_byte; /* note: possibly can make 1 bit since we
+ only use the MD bit now */
+
/* connection event timing/mgmt */
- uint8_t rsp_rxd;
- uint8_t pkt_rxd;
+ uint8_t rsp_rxd; /* note: can be 1 bit */
+ uint8_t pkt_rxd; /* note: can be 1 bit */
uint8_t master_sca;
uint8_t tx_win_size;
+ uint8_t allow_slave_latency; /* note: can be 1 bit */
+ uint8_t slave_set_last_anchor; /* note: can be 1 bit */
uint16_t conn_itvl;
uint16_t slave_latency;
uint16_t tx_win_off;
@@ -167,8 +189,12 @@ struct ble_ll_conn_sm
uint16_t supervision_tmo;
uint16_t conn_handle;
uint32_t access_addr;
- uint32_t crcinit; /* only low 24 bits used */
+ uint32_t crcinit; /* only low 24 bits used */
uint32_t anchor_point;
+ uint32_t last_anchor_point;
+ uint32_t ce_end_time; /* cputime at which connection event should end */
+ uint32_t slave_cur_tx_win_usecs;
+ uint32_t slave_cur_window_widening;
/* address information */
uint8_t own_addr_type;
@@ -186,6 +212,12 @@ struct ble_ll_conn_sm
/* Packet transmit queue */
STAILQ_HEAD(conn_txq_head, os_mbuf_pkthdr) conn_txq;
+
+ /* List entry for active connection pool */
+ union {
+ SLIST_ENTRY(ble_ll_conn_sm) conn_sle;
+ STAILQ_ENTRY(ble_ll_conn_sm) conn_stqe;
+ };
};
/* Pointer to connection state machine we are trying to create */
@@ -194,17 +226,16 @@ struct ble_ll_conn_sm *g_ble_ll_conn_create_sm;
/* Pointer to current connection */
struct ble_ll_conn_sm *g_ble_ll_conn_cur_sm;
-/* Connection handles */
-static uint8_t g_ble_ll_conn_handles[(BLE_LL_CONN_CFG_MAX_CONNS + 7) / 8];
-static uint16_t g_ble_ll_conn_handles_out;
-
/* Connection pool elements */
struct os_mempool g_ble_ll_conn_pool;
os_membuf_t g_ble_ll_conn_buf[OS_MEMPOOL_SIZE(BLE_LL_CONN_CFG_MAX_CONNS,
sizeof(struct ble_ll_conn_sm))];
/* List of active connections */
-static SLIST_HEAD(, ble_hs_conn) g_ble_ll_conn_active_list;
+static SLIST_HEAD(, ble_ll_conn_sm) g_ble_ll_conn_active_list;
+
+/* List of free connections */
+static STAILQ_HEAD(, ble_ll_conn_sm) g_ble_ll_conn_free_list;
/* Statistics */
struct ble_ll_conn_stats
@@ -212,16 +243,75 @@ struct ble_ll_conn_stats
uint32_t cant_set_sched;
uint32_t conn_ev_late;
uint32_t wfr_expirations;
+ uint32_t no_tx_pdu;
+ uint32_t no_conn_sm;
+ uint32_t no_free_conn_sm;
+ uint32_t slave_rxd_bad_conn_req_params;
+ uint32_t slave_ce_failures;
+ uint32_t rx_resent_pdus;
+ uint32_t data_pdu_rx_valid;
+ uint32_t data_pdu_rx_invalid;
+ uint32_t data_pdu_txg;
+ uint32_t data_pdu_txf;
};
struct ble_ll_conn_stats g_ble_ll_conn_stats;
/* "Dummy" mbuf containing an "Empty PDU" */
-#define BLE_LL_DUMMY_EMPTY_PDU_SIZE \
- ((sizeof(struct os_mbuf) + sizeof(struct os_mbuf_pkthdr) + 4) / 4)
+#define BLE_LL_DUMMY_EMPTY_PDU_SIZE ((BLE_MBUF_PKT_OVERHEAD + 4) / 4)
static uint32_t g_ble_ll_empty_pdu[BLE_LL_DUMMY_EMPTY_PDU_SIZE];
/**
+ * Get a connection state machine.
+ */
+struct ble_ll_conn_sm *
+ble_ll_conn_sm_get(void)
+{
+ struct ble_ll_conn_sm *connsm;
+
+ connsm = STAILQ_FIRST(&g_ble_ll_conn_free_list);
+ if (connsm) {
+ STAILQ_REMOVE_HEAD(&g_ble_ll_conn_free_list, conn_stqe);
+ } else {
+ ++g_ble_ll_conn_stats.no_free_conn_sm;
+ }
+
+ return connsm;
+}
+
+/**
+ * Calculate the amount of window widening for a given connection event. This
+ * is the amount of time that a slave has to account for when listening for
+ * the start of a connection event.
+ *
+ * @param connsm Pointer to connection state machine.
+ *
+ * @return uint32_t The current window widening amount (in microseconds)
+ */
+uint32_t
+ble_ll_conn_calc_window_widening(struct ble_ll_conn_sm *connsm)
+{
+ uint32_t total_sca_ppm;
+ uint32_t window_widening;
+ int32_t time_since_last_anchor;
+ uint32_t delta_msec;
+
+ window_widening = 0;
+
+ time_since_last_anchor = (int32_t)(connsm->anchor_point -
+ connsm->last_anchor_point);
+ 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;
+ window_widening = (total_sca_ppm * delta_msec) / 1000;
+ }
+
+ /* XXX: spec gives 16 usecs error btw. Probably should add that in */
+ return window_widening;
+}
+
+/**
* Calculates the number of used channels in the channel map
*
* @param chmap
@@ -257,70 +347,6 @@ ble_ll_conn_calc_used_chans(uint8_t *chmap)
return used_channels;
}
-/**
- * Free an allocated connection handle
- *
- * @param handle The connection handle to free.
- */
-static void
-ble_ll_conn_handle_free(uint16_t handle)
-{
- uint8_t bytepos;
- uint8_t mask;
-
- /* Make sure handle is valid */
- assert(handle < BLE_LL_CONN_CFG_MAX_CONNS);
- assert(g_ble_ll_conn_handles_out != 0);
-
- /* Get byte position and bit position */
- bytepos = handle / 8;
- mask = 1 << (handle & 0x7);
-
- assert((g_ble_ll_conn_handles[bytepos] & mask) != 0);
-
- g_ble_ll_conn_handles[bytepos] &= ~mask;
- --g_ble_ll_conn_handles_out;
-}
-
-/**
- * Allocate a connection handle. This will allocate an unused connection
- * handle.
- *
- * @return uint16_t
- */
-static uint16_t
-ble_ll_conn_handle_alloc(void)
-{
- uint8_t bytepos;
- uint8_t bitpos;
- int handle;
-
- /* Make sure there is a handle that exists */
- if (g_ble_ll_conn_handles_out == BLE_LL_CONN_CFG_MAX_CONNS) {
- /* Handles can only be in range 0 to 0x0EFF */
- return 0xFFFF;
- }
-
- /* Return an unused handle */
- for (handle = 0; handle < BLE_LL_CONN_CFG_MAX_CONNS; ++handle) {
- /* Get byte position and bit position */
- bytepos = handle / 8;
- bitpos = handle & 0x7;
-
- /* See if handle avaiable */
- if ((g_ble_ll_conn_handles[bytepos] & (1 << bitpos)) == 0) {
- g_ble_ll_conn_handles[bytepos] |= (1 << bitpos);
- ++g_ble_ll_conn_handles_out;
- break;
- }
- }
-
- /* We better have a free one! If not, something wrong! */
- assert(handle < BLE_LL_CONN_CFG_MAX_CONNS);
-
- return handle;
-}
-
static uint32_t
ble_ll_conn_calc_access_addr(void)
{
@@ -468,54 +494,190 @@ ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn)
}
/**
- * Connection end schedule callback. Called when the scheduled connection
- * event ends.
+ * Callback for connection wait for response timer.
*
* Context: Interrupt
+ *
+ * @param sch
+ *
+ */
+static void
+ble_ll_conn_wfr_timer_exp(void *arg)
+{
+ struct ble_ll_conn_sm *connsm;
+
+ connsm = (struct ble_ll_conn_sm *)arg;
+ if (connsm->rsp_rxd == 0) {
+ ble_ll_event_send(&connsm->conn_ev_end);
+ ++g_ble_ll_conn_stats.wfr_expirations;
+ }
+}
+
+/**
+ * Callback for slave when it transmits a data pdu and the connection event
+ * ends after the transmission.
*
+ * Context: Interrupt
+ *
* @param sch
*
- * @return int
*/
-static int
-ble_ll_conn_ev_end_sched_cb(struct ble_ll_sched_item *sch)
+static void
+ble_ll_conn_wait_txend(void *arg)
{
- int rc;
struct ble_ll_conn_sm *connsm;
- connsm = (struct ble_ll_conn_sm *)sch->cb_arg;
+ connsm = (struct ble_ll_conn_sm *)arg;
ble_ll_event_send(&connsm->conn_ev_end);
- rc = BLE_LL_SCHED_STATE_DONE;
+}
+
+/**
+ * Called when we want to send a data channel pdu inside a connection event.
+ *
+ * @param connsm
+ *
+ * @return int 0: success; otherwise failure to transmit
+ */
+static int
+ble_ll_conn_tx_data_pdu(struct ble_ll_conn_sm *connsm, int beg_transition)
+{
+ int rc;
+ uint8_t md;
+ uint8_t hdr_byte;
+ uint8_t end_transition;
+ uint32_t wfr_time;
+ uint32_t ticks;
+ struct os_mbuf *m;
+ struct ble_mbuf_hdr *ble_hdr;
+ struct os_mbuf_pkthdr *pkthdr;
+ struct os_mbuf_pkthdr *nextpkthdr;
+
+ /*
+ * Get packet off transmit queue. If not available, send empty PDU. Set
+ * the more data bit as well. For a slave, we will set it regardless of
+ * connection event end timing (master will deal with that for us or the
+ * connection event will be terminated locally). For a master, we only
+ * set the MD bit if we have enough time to send the current PDU, get
+ * a response and send the next packet and get a response.
+ */
+ md = 0;
+ pkthdr = STAILQ_FIRST(&connsm->conn_txq);
+ if (pkthdr) {
+ m = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
+ nextpkthdr = STAILQ_NEXT(pkthdr, omp_next);
+ if (nextpkthdr) {
+ md = 1;
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+ /*
+ * XXX: this calculation is based on using the current time
+ * and assuming the transmission will occur an IFS time from
+ * now. This is not the most accurate especially if we have
+ * received a frame and we are replying to it.
+ */
+ ticks = (BLE_LL_IFS * 4) + (2 * connsm->eff_max_rx_time) +
+ ble_ll_pdu_tx_time_get(pkthdr->omp_len) +
+ ble_ll_pdu_tx_time_get(nextpkthdr->omp_len);
+ ticks = cputime_usecs_to_ticks(ticks);
+ if ((cputime_get32() + ticks) >= connsm->ce_end_time) {
+ md = 0;
+ }
+ }
+ }
+ } else {
+ /* Send empty pdu */
+ m = (struct os_mbuf *)&g_ble_ll_empty_pdu;
+ }
+
+ /* Set SN, MD, NESN in transmit PDU */
+ hdr_byte = m->om_data[0];
+
+ /*
+ * If this is a retry, we keep the LLID and SN. If not, we presume
+ * that the LLID is set and all other bits are 0 in the first header
+ * byte.
+ */
+ ble_hdr = BLE_MBUF_HDR_PTR(m);
+ if (ble_hdr->flags & BLE_MBUF_HDR_F_TXD) {
+ hdr_byte &= ~(BLE_LL_DATA_HDR_MD_MASK | BLE_LL_DATA_HDR_NESN_MASK);
+ } else {
+ if (connsm->tx_seqnum) {
+ hdr_byte |= BLE_LL_DATA_HDR_SN_MASK;
+ }
+ ble_hdr->flags |= BLE_MBUF_HDR_F_TXD;
+ }
+
+ /* If we have more data, set the bit */
+ if (md) {
+ hdr_byte |= BLE_LL_DATA_HDR_MD_MASK;
+ }
+
+ /* Set NESN (next expected sequence number) bit */
+ if (connsm->next_exp_seqnum) {
+ hdr_byte |= BLE_LL_DATA_HDR_NESN_MASK;
+ }
+
+ /* Set the header byte in the outgoing frame */
+ m->om_data[0] = hdr_byte;
+
+ /*
+ * If we are a slave, check to see if this transmission will end the
+ * connection event. We will end the connection event if we have
+ * received a valid frame with the more data bit set to 0 and we dont
+ * have more data.
+ */
+ end_transition = BLE_PHY_TRANSITION_TX_RX;
+ if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && (md == 0) &&
+ (connsm->cons_rxd_bad_crc == 0) &&
+ ((connsm->last_rxd_hdr_byte & BLE_LL_DATA_HDR_MD_MASK) == 0)) {
+ end_transition = BLE_PHY_TRANSITION_NONE;
+ }
+
+ rc = ble_phy_tx(m, beg_transition, end_transition);
+ if (!rc) {
+ /* Set last transmitted MD bit */
+ connsm->last_txd_md = md;
+
+ /* Reset response received flag */
+ connsm->rsp_rxd = 0;
+
+ /* XXX: at some point I should implement the transmit end interrupt
+ from the PHY. When I do that I will change this code */
+ /* Set wait for response timer */
+ wfr_time = cputime_get32();
+ if (end_transition == BLE_PHY_TRANSITION_TX_RX) {
+ wfr_time += cputime_usecs_to_ticks(XCVR_TX_START_DELAY_USECS +
+ ble_ll_pdu_tx_time_get(m->om_len) +
+ BLE_LL_IFS +
+ BLE_LL_WFR_USECS);
+ ble_ll_wfr_enable(wfr_time, ble_ll_conn_wfr_timer_exp, connsm);
+ } else {
+ wfr_time += cputime_usecs_to_ticks(XCVR_TX_START_DELAY_USECS +
+ ble_ll_pdu_tx_time_get(m->om_len));
+ ble_ll_wfr_enable(wfr_time, ble_ll_conn_wait_txend, connsm);
+ }
+ }
+
return rc;
}
/**
- * Callback for connection wait for response timer.
+ * Connection end schedule callback. Called when the scheduled connection
+ * event ends.
*
* Context: Interrupt
- *
+ *
* @param sch
*
* @return int
*/
static int
-ble_ll_conn_wfr_sched_cb(struct ble_ll_sched_item *sch)
+ble_ll_conn_ev_end_sched_cb(struct ble_ll_sched_item *sch)
{
- int rc;
struct ble_ll_conn_sm *connsm;
connsm = (struct ble_ll_conn_sm *)sch->cb_arg;
- if (connsm->rsp_rxd) {
- /* For now just set to end time */
- sch->next_wakeup = sch->end_time;
- sch->sched_cb = ble_ll_conn_ev_end_sched_cb;
- rc = BLE_LL_SCHED_STATE_RUNNING;
- } else {
- ble_ll_event_send(&connsm->conn_ev_end);
- rc = BLE_LL_SCHED_STATE_DONE;
- ++g_ble_ll_conn_stats.wfr_expirations;
- }
- return rc;
+ ble_ll_event_send(&connsm->conn_ev_end);
+ return BLE_LL_SCHED_STATE_DONE;
}
/**
@@ -525,14 +687,14 @@ ble_ll_conn_wfr_sched_cb(struct ble_ll_sched_item *sch)
*
* @param sch
*
- * @return int
+ * @return int 0: scheduled item is still running. 1: schedule item is done.
*/
static int
ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
{
int rc;
- struct os_mbuf *m;
- struct os_mbuf_pkthdr *pkthdr;
+ uint32_t usecs;
+ uint32_t wfr_time;
struct ble_ll_conn_sm *connsm;
/* Set current connection state machine */
@@ -548,55 +710,41 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
assert(rc == 0);
if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
- /* Get packet off transmit queue. If none there, what to do? */
- pkthdr = STAILQ_FIRST(&connsm->conn_txq);
- if (pkthdr) {
- /* Remove from queue */
- m = (struct os_mbuf *)((uint8_t *)pkthdr - sizeof(struct os_mbuf));
- STAILQ_REMOVE_HEAD(&connsm->conn_txq, omp_next);
- } else {
- /* Send empty pdu */
- m = (struct os_mbuf *)&g_ble_ll_empty_pdu;
- }
-
- /* WWW: must modify the header */
-
- rc = ble_phy_tx(m, BLE_PHY_TRANSITION_NONE, BLE_PHY_TRANSITION_RX_TX);
+ rc = ble_ll_conn_tx_data_pdu(connsm, BLE_PHY_TRANSITION_NONE);
if (!rc) {
- /* Set next schedule wakeup to check for wait for response */
- sch->next_wakeup = cputime_get32() +
- cputime_usecs_to_ticks(XCVR_TX_START_DELAY_USECS +
- ble_ll_pdu_tx_time_get(m->om_len) +
- BLE_LL_IFS +
- BLE_LL_WFR_USECS);
- sch->sched_cb = ble_ll_conn_wfr_sched_cb;
+ sch->next_wakeup = sch->end_time;
+ sch->sched_cb = ble_ll_conn_ev_end_sched_cb;
rc = BLE_LL_SCHED_STATE_RUNNING;
} else {
- /* Error transmitting! Put back on transmit queue */
- STAILQ_INSERT_HEAD(&connsm->conn_txq, pkthdr, omp_next);
-
/* Inform LL task of connection event end */
ble_ll_event_send(&connsm->conn_ev_end);
rc = BLE_LL_SCHED_STATE_DONE;
-
- /* XXX: Is there anything else we need to do on failure? */
}
} else {
rc = ble_phy_rx();
if (rc) {
- /* XXX: what happens if this fails? */
- }
- }
-
- /* XXX: set state to connection here? */
+ /* 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 {
+ /*
+ * Set flag that tell slave to set last anchor point if a packet
+ * has been received.
+ */
+ connsm->slave_set_last_anchor = 1;
- /* XXX: make sure we set the end time of the event (if needed) not sure
- * it is for master role. Have to think about it.
- */
+ 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, ble_ll_conn_wfr_timer_exp, connsm);
- /* XXX: The return code here tells the scheduler whether
- * to use the next wakeup time or determines if the scheduled event is
- over. */
+ /* 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;
+ }
+ }
return rc;
}
@@ -631,15 +779,21 @@ ble_ll_conn_sched_set(struct ble_ll_conn_sm *connsm)
/* We will attempt to schedule the maximum CE length */
usecs = connsm->max_ce_len * BLE_LL_CONN_CE_USECS;
} else {
- /* XXX: account for window widening/drift */
+ /* 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(XCVR_RX_SCHED_DELAY_USECS);
+ cputime_usecs_to_ticks(usecs);
- /* XXX: what to do for slave? Not sure how much to schedule here.
- For now, just schedule entire connection interval */
+ /* Schedule entire connection interval for slave */
usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
}
+
+ /* XXX: we will need to subtract more than just the IFS since we need
+ * some time to deal with stuff. Gotta make sure we dont miss
+ next connection event. */
+ usecs -= BLE_LL_IFS;
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 */
@@ -656,76 +810,6 @@ ble_ll_conn_sched_set(struct ble_ll_conn_sm *connsm)
return sch;
}
-/* WWW:
- * -> deal with data channel index (calculation it).
- * -> deal with slave latency .
- */
-
-/**
- * Called upon end of connection event
- *
- * Context: Link-layer task
- *
- * @param void *arg Pointer to connection state machine
- *
- */
-void
-ble_ll_conn_event_end(void *arg)
-{
- uint16_t latency;
- uint32_t itvl;
- struct ble_ll_conn_sm *connsm;
-
- /*
- * XXX: if we received a response we can apply slave latency. I am not
- * sure how this applies to the master. I guess the master could possibly
- * keep sending each anchor if it does not receive a reply. Possible that
- * slave receives master but master does not get reply. This would cause
- * master to re-transmit every connection event even though slave was
- * asleep.
- */
- connsm = (struct ble_ll_conn_sm *)arg;
-
- /* 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->pkt_rxd) {
- latency += connsm->slave_latency;
- itvl = itvl * latency;
- connsm->pkt_rxd = 0;
- }
- 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 */
- 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;
- }
-
- /* XXX: window widening for slave */
-
- /* Link-layer is in standby state now */
- ble_ll_state_set(BLE_LL_STATE_STANDBY);
-
- /* Set current LL connection to NULL */
- g_ble_ll_conn_cur_sm = NULL;
-
- /* Schedule the next connection event */
- ble_ll_conn_sched_set(connsm);
-}
-
/**
* Connection supervision timer callback; means that the connection supervision
* timeout has been reached and we should perform the appropriate actions.
@@ -739,24 +823,19 @@ ble_ll_conn_spvn_timer_cb(void *arg)
{
struct ble_ll_conn_sm *connsm;
- /*
- * WWW: What should we do with the PHY here? We could be transmitting or
- * receiving. Need to figure out what to do.
- */
-
connsm = (struct ble_ll_conn_sm *)arg;
ble_ll_event_send(&connsm->conn_spvn_ev);
}
/**
- * Initialize the connection state machine. This is done once per connection
+ * 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,
*
* @param connsm
*/
static void
-ble_ll_conn_sm_init(struct ble_ll_conn_sm *connsm, struct hci_create_conn *hcc)
+ble_ll_conn_sm_start(struct ble_ll_conn_sm *connsm, struct hci_create_conn *hcc)
{
struct ble_ll_conn_global_params *conn_params;
@@ -764,10 +843,7 @@ ble_ll_conn_sm_init(struct ble_ll_conn_sm *connsm, struct hci_create_conn *hcc)
connsm->last_unmapped_chan = 0;
connsm->event_cntr = 0;
connsm->conn_state = BLE_LL_CONN_STATE_IDLE;
-
- /* We better have an unused handle or we are in trouble! */
- connsm->conn_handle = ble_ll_conn_handle_alloc();
- assert(connsm->conn_handle < BLE_LL_CONN_CFG_MAX_CONNS);
+ connsm->allow_slave_latency = 0;
if (hcc != NULL) {
/* Must be master */
@@ -838,8 +914,13 @@ ble_ll_conn_sm_init(struct ble_ll_conn_sm *connsm, struct hci_create_conn *hcc)
connsm->conn_ev_end.ev_queued = 0;
connsm->conn_ev_end.ev_type = BLE_LL_EVENT_CONN_EV_END;
- /* Initialize transmit queue */
+ /* Initialize transmit queue and ack/flow control elements */
STAILQ_INIT(&connsm->conn_txq);
+ connsm->tx_seqnum = 0;
+ connsm->next_exp_seqnum = 0;
+ connsm->last_txd_md = 0;
+ connsm->cons_rxd_bad_crc = 0;
+ connsm->last_rxd_sn = 1;
/* XXX: 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 */
@@ -859,6 +940,9 @@ ble_ll_conn_sm_init(struct ble_ll_conn_sm *connsm, struct hci_create_conn *hcc)
connsm->eff_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
/* XXX: Controller notifies host of changes to effective tx/rx time/bytes*/
+
+ /* Add to list of active connections */
+ SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, conn_sle);
}
/**
@@ -908,10 +992,21 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
struct os_mbuf_pkthdr *pkthdr;
/* XXX: stop any connection schedule timers we created */
- /* XXX: make sure phy interrupts are off and all that. We want to
- * make sure that if a scheduled event fires off here we dont care;
- * we just need to clean up properly
- */
+
+ /* Disable the PHY */
+ ble_phy_disable();
+
+ /* Remove scheduler events just in case */
+ ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_CONN, connsm);
+
+ /* Stop supervision timer */
+ cputime_timer_stop(&connsm->conn_spvn_timer);
+
+ /* Disable any wait for response interrupt that might be running */
+ ble_ll_wfr_disable();
+
+ /* Remove from the active connection list */
+ SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, conn_sle);
/* Free all packets on transmit queue */
while (1) {
@@ -922,15 +1017,14 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
}
STAILQ_REMOVE_HEAD(&connsm->conn_txq, omp_next);
+ /* XXX: what happens if the empty PDU is on this list? Should
+ we check to make sure it is not? */
+
m = (struct os_mbuf *)((uint8_t *)pkthdr - sizeof(struct os_mbuf));
os_mbuf_free(&g_mbuf_pool, m);
}
- /* Remove scheduler events just in case */
- ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_CONN, connsm);
-
- /* Make sure events off queue and connection supervison timer stopped */
- cputime_timer_stop(&connsm->conn_spvn_timer);
+ /* Make sure events off queue */
os_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_spvn_ev);
os_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_ev_end);
@@ -943,11 +1037,8 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
/* Send connection complete event */
ble_ll_conn_comp_event_send(connsm, ble_err);
- /* Free up the handle */
- ble_ll_conn_handle_free(connsm->conn_handle);
-
- /* Free the connection state machine */
- os_memblock_put(&g_ble_ll_conn_pool, connsm);
+ /* Put connection state machine back on free list */
+ STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, conn_stqe);
}
/**
@@ -986,12 +1077,17 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm)
/* Set first connection event time */
usecs = 1250 + (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS);
if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+ /* XXX: move this into the phy transmit pdu end callback for the
+ connect request */
+ /* We have yet to transmit the connect request so add that time */
usecs += ble_ll_pdu_tx_time_get(BLE_CONNECT_REQ_PDU_LEN) + BLE_LL_IFS;
} else {
- /* XXX: need to deal with drift/window widening here */
- usecs += 0;
+ connsm->slave_cur_tx_win_usecs =
+ connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
}
- connsm->anchor_point = cputime_get32() + cputime_usecs_to_ticks(usecs);
+ connsm->last_anchor_point = cputime_get32();
+ connsm->anchor_point = connsm->last_anchor_point +
+ cputime_usecs_to_ticks(usecs);
/* Send connection complete event to inform host of connection */
ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS);
@@ -1001,6 +1097,96 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm)
}
/**
+ * Called upon end of connection event
+ *
+ * Context: Link-layer task
+ *
+ * @param void *arg Pointer to connection state machine
+ *
+ */
+void
+ble_ll_conn_event_end(void *arg)
+{
+ uint16_t latency;
+ uint32_t itvl;
+ uint32_t cur_ww;
+ uint32_t max_ww;
+ struct ble_ll_conn_sm *connsm;
+
+ connsm = (struct ble_ll_conn_sm *)arg;
+
+ /* Disable the wfr timer */
+ ble_ll_wfr_disable();
+
+ /* Remove any scheduled items for this connection */
+ ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_CONN, connsm);
+ os_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_ev_end);
+
+ /*
+ * If we have received a packet, we can set the current transmit window
+ * usecs to 0 since we dont need to listen in the transmit window.
+ */
+ if (connsm->pkt_rxd) {
+ connsm->slave_cur_tx_win_usecs = 0;
+ }
+
+ /* 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 */
+ while (latency >= 0) {
+ --latency;
+ connsm->data_chan_index = ble_ll_conn_calc_dci(connsm);
+ }
+
+ /* XXX: we will need more time here for a slave I bet. IFS time is not
+ enough to re-schedule. End before it a bit.*/
+ /* 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;
+ }
+
+ /* Reset "per connection event" variables */
+ connsm->cons_rxd_bad_crc = 0;
+ connsm->pkt_rxd = 0;
+
+ /* Link-layer is in standby state now */
+ ble_ll_state_set(BLE_LL_STATE_STANDBY);
+
+ /* Set current LL connection to NULL */
+ g_ble_ll_conn_cur_sm = NULL;
+
+ /* 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) {
+ ble_ll_conn_end(connsm, BLE_ERR_CONN_TERM_LOCAL);
+ return;
+ }
+ connsm->slave_cur_window_widening = cur_ww;
+ }
+
+ /* Schedule the next connection event */
+ ble_ll_conn_sched_set(connsm);
+}
+
+/**
* Update the connection request PDU with the address type and address of
* advertiser we are going to send connect request to.
*
@@ -1096,8 +1282,8 @@ int
ble_ll_conn_create(uint8_t *cmdbuf)
{
int rc;
- uint32_t spvn_tmo_msecs;
- uint32_t min_spvn_tmo_msecs;
+ uint32_t spvn_tmo_usecs;
+ uint32_t min_spvn_tmo_usecs;
struct hci_create_conn ccdata;
struct hci_create_conn *hcc;
struct ble_ll_conn_sm *connsm;
@@ -1170,10 +1356,12 @@ ble_ll_conn_create(uint8_t *cmdbuf)
* Supervision timeout (in msecs) must be more than:
* (1 + connLatency) * connIntervalMax * 1.25 msecs * 2.
*/
- spvn_tmo_msecs = hcc->supervision_timeout * BLE_HCI_CONN_SPVN_TMO_UNITS;
- min_spvn_tmo_msecs = (hcc->conn_itvl_max << 1) + (hcc->conn_itvl_max >> 1);
- min_spvn_tmo_msecs *= (1 + hcc->conn_latency);
- if (spvn_tmo_msecs <= min_spvn_tmo_msecs) {
+ spvn_tmo_usecs = hcc->supervision_timeout;
+ spvn_tmo_usecs *= (BLE_HCI_CONN_SPVN_TMO_UNITS * 1000);
+ min_spvn_tmo_usecs = (uint32_t)hcc->conn_itvl_max * 2 *
+ BLE_LL_CONN_ITVL_USECS;
+ min_spvn_tmo_usecs *= (1 + hcc->conn_latency);
+ if (spvn_tmo_usecs <= min_spvn_tmo_usecs) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
@@ -1185,13 +1373,13 @@ ble_ll_conn_create(uint8_t *cmdbuf)
}
/* Make sure we can accept a connection! */
- connsm = (struct ble_ll_conn_sm *)os_memblock_get(&g_ble_ll_conn_pool);
+ connsm = ble_ll_conn_sm_get();
if (connsm == NULL) {
return BLE_ERR_CONN_LIMIT;
}
- /* Initialize the connection sm */
- ble_ll_conn_sm_init(connsm, hcc);
+ /* Start the connection sm */
+ ble_ll_conn_sm_start(connsm, hcc);
/* Create the connection request */
ble_ll_conn_req_pdu_make(connsm);
@@ -1199,7 +1387,8 @@ ble_ll_conn_create(uint8_t *cmdbuf)
/* Start scanning */
rc = ble_ll_scan_initiator_start(hcc);
if (rc) {
- os_memblock_put(&g_ble_ll_conn_pool, connsm);
+ SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, conn_sle);
+ STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, conn_stqe);
} else {
/* Set the connection state machine we are trying to create. */
g_ble_ll_conn_create_sm = connsm;
@@ -1302,7 +1491,7 @@ ble_ll_init_rx_pdu_proc(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr)
}
/* If we have sent a connect request, we need to enter CONNECTION state*/
- if (ble_hdr->crcok && (ble_hdr->flags & BLE_MBUF_HDR_F_CONN_REQ_TXD)) {
+ if (ble_hdr->flags & BLE_MBUF_HDR_F_CONN_REQ_TXD) {
/* Set address of advertiser to which we are connecting. */
if (!ble_ll_scan_whitelist_enabled()) {
/*
@@ -1464,14 +1653,252 @@ ble_ll_conn_spvn_timeout(void *arg)
* been checked yet.
*/
void
-ble_ll_conn_rsp_rxd(void)
+ble_ll_conn_rx_pdu_start(void)
{
- if (g_ble_ll_conn_cur_sm) {
- g_ble_ll_conn_cur_sm->rsp_rxd = 1;
+ struct ble_ll_conn_sm *connsm;
+
+ connsm = g_ble_ll_conn_cur_sm;
+ if (connsm) {
+ connsm->rsp_rxd = 1;
+ connsm->pkt_rxd = 1;
+
+ /* Set last anchor point if 1st received frame in connection event */
+ if (connsm->slave_set_last_anchor) {
+ connsm->slave_set_last_anchor = 0;
+ /*
+ * XXX: for now, just use the current time. Make more accurate.
+ * We subtract 40 usecs since we get the start 5 bytes after
+ * actual start. We add another 10 just in case.
+ */
+ connsm->last_anchor_point = cputime_get32() -
+ cputime_usecs_to_ticks(50);
+ }
}
}
/**
+ * Called from the Link Layer task when a data PDU has been received
+ *
+ * Context: Link layer task
+ *
+ * @param rxpdu
+ */
+void
+ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, uint8_t crcok)
+{
+ uint8_t hdr_byte;
+ uint8_t rxd_sn;
+ uint8_t *rxbuf;
+ uint16_t acl_len;
+ uint16_t acl_hdr;
+ uint32_t tmo;
+ struct ble_ll_conn_sm *connsm;
+
+ if (crcok) {
+ /* Count valid received data pdus */
+ ++g_ble_ll_conn_stats.data_pdu_rx_valid;
+
+ /* We better have a connection state machine */
+ connsm = g_ble_ll_conn_cur_sm;
+ if (connsm) {
+ /* Reset the connection supervision timeout */
+ cputime_timer_stop(&connsm->conn_spvn_timer);
+ tmo = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000;
+ cputime_timer_relative(&connsm->conn_spvn_timer, tmo);
+
+ /*
+ * If we are a slave, we can only start to use slave latency
+ * once we have received a NESN of 1 from the master
+ */
+ rxbuf = rxpdu->om_data;
+ hdr_byte = rxbuf[0];
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+ if (hdr_byte & BLE_LL_DATA_HDR_NESN_MASK) {
+ connsm->allow_slave_latency = 1;
+ }
+ }
+
+ /*
+ * Discard the received PDU if the sequence number is the same
+ * as the last received sequence number
+ */
+ rxd_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK;
+ if (rxd_sn != connsm->last_rxd_sn) {
+ /* Update last rxd sn */
+ connsm->last_rxd_sn = rxd_sn;
+
+ /* XXX: use the mbuf routine for this! */
+ /* Set ACL data packet header and send to host */
+ acl_len = rxbuf[1];
+ acl_hdr = (hdr_byte & BLE_LL_DATA_HDR_LLID_MASK);
+ acl_hdr = (acl_hdr << 12) | connsm->conn_handle;
+ rxpdu->om_data = rxpdu->om_data - 2;
+ rxbuf = rxpdu->om_data;
+ htole16(rxbuf, acl_hdr);
+ htole16(rxbuf + 2, acl_len);
+
+ /* Add to length of mbuf and packet header */
+ rxpdu->om_len += 2;
+ OS_MBUF_PKTHDR(rxpdu)->omp_len += 2;
+
+ /* XXX: send to host */
+ return;
+ }
+ } else {
+ ++g_ble_ll_conn_stats.no_conn_sm;
+ }
+ } else {
+ ++g_ble_ll_conn_stats.data_pdu_rx_invalid;
+ }
+
+ /* Free the packet buffer */
+ os_mbuf_free(&g_mbuf_pool, rxpdu);
+}
+
+/**
+ * Called when a packet has been received while in the connection state.
+ *
+ * Context: Interrupt
+ *
+ * @param rxpdu
+ * @param crcok
+ *
+ * @return int
+ * < 0: Disable the phy after reception.
+ * == 0: Success. Do not disable the PHY.
+ * > 0: Do not disable PHY as that has already been done.
+ */
+int
+ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint8_t crcok)
+{
+ int rc;
+ uint8_t hdr_byte;
+ uint8_t hdr_sn;
+ uint8_t hdr_nesn;
+ uint8_t conn_sn;
+ uint8_t conn_nesn;
+ uint8_t reply;
+ uint32_t ticks;
+ struct os_mbuf *txpdu;
+ struct os_mbuf_pkthdr *pkthdr;
+ struct ble_ll_conn_sm *connsm;
+
+ /*
+ * We should have a current connection state machine. If we dont, we just
+ * hand the packet to the higher layer to count it.
+ */
+ connsm = g_ble_ll_conn_cur_sm;
+ if (!connsm) {
+ return -1;
+ }
+
+ /*
+ * 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.
+ */
+ if (!crcok) {
+ /*
+ * Increment # of consecutively received CRC errors. If more than
+ * one we will end the connection event.
+ */
+ ++connsm->cons_rxd_bad_crc;
+ if (connsm->cons_rxd_bad_crc >= 2) {
+ reply = 0;
+ } else {
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+ reply = connsm->last_txd_md;
+ } else {
+ /* A slave always responds with a packet */
+ reply = 1;
+ }
+ }
+ } else {
+ /* Reset consecutively received bad crcs (since this one was good!) */
+ connsm->cons_rxd_bad_crc = 0;
+
+ /* Store received header byte in state machine */
+ hdr_byte = rxpdu->om_data[0];
+ connsm->last_rxd_hdr_byte = hdr_byte;
+
+ /*
+ * If SN bit from header does not match NESN in connection, this is
+ * a resent PDU and should be ignored.
+ */
+ hdr_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK;
+ conn_nesn = connsm->next_exp_seqnum;
+ if ((hdr_sn && conn_nesn) || (!hdr_sn && !conn_nesn)) {
+ connsm->next_exp_seqnum ^= 1;
+ } else {
+ /* Count re-sent PDUs. */
+ ++g_ble_ll_conn_stats.rx_resent_pdus;
+ }
+
+ /*
+ * Check NESN bit from header. If same as tx seq num, the transmission
+ * is acknowledged. Otherwise we need to resend this PDU.
+ */
+ hdr_nesn = hdr_byte & BLE_LL_DATA_HDR_NESN_MASK;
+ conn_sn = connsm->tx_seqnum;
+ if ((hdr_nesn && conn_sn) || (!hdr_nesn && !conn_sn)) {
+ /* We did not get an ACK. Must retry the PDU */
+ ++g_ble_ll_conn_stats.data_pdu_txf;
+ } else {
+ /* Transmit success */
+ connsm->tx_seqnum ^= 1;
+ ++g_ble_ll_conn_stats.data_pdu_txg;
+
+ /* We can remove this packet from the queue now */
+ pkthdr = STAILQ_FIRST(&connsm->conn_txq);
+ if (pkthdr) {
+ STAILQ_REMOVE_HEAD(&connsm->conn_txq, omp_next);
+ txpdu = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
+ os_mbuf_free(&g_mbuf_pool, txpdu);
+ /* XXX: deal with empty pdu's. Cant free them */
+ } else {
+ /* No packet on queue? This is an error! */
+ ++g_ble_ll_conn_stats.no_tx_pdu;
+ }
+ }
+
+ /* Should we continue connection event? */
+ if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+ reply = connsm->last_txd_md || (hdr_byte & BLE_LL_DATA_HDR_MD_MASK);
+ if (reply) {
+ pkthdr = STAILQ_FIRST(&connsm->conn_txq);
+ if (pkthdr) {
+ ticks = ble_ll_pdu_tx_time_get(pkthdr->omp_len);
+ } else {
+ /* We will send empty pdu (just a LL header) */
+ ticks = ble_ll_pdu_tx_time_get(BLE_LL_PDU_HDR_LEN);
+ }
+ ticks += (BLE_LL_IFS * 2) + connsm->eff_max_rx_time;
+ ticks = cputime_usecs_to_ticks(ticks);
+ /* XXX: should really use packet receive end time here */
+ if ((cputime_get32() + ticks) >= connsm->ce_end_time) {
+ reply = 0;
+ }
+ }
+ } else {
+ /* A slave always replies */
+ reply = 1;
+ }
+ }
+
+ /* If reply flag set, send data pdu and continue connection event */
+ rc = -1;
+ if (reply) {
+ rc = ble_ll_conn_tx_data_pdu(connsm, BLE_PHY_TRANSITION_RX_TX);
+ }
+
+ if (rc) {
+ ble_ll_event_send(&connsm->conn_ev_end);
+ }
+
+ return 0;
+}
+
+/**
* Called when a device has received a connect request while advertising and
* the connect request has passed the advertising filter policy and is for
* us. This will start a connection in the slave role.
@@ -1483,21 +1910,21 @@ ble_ll_conn_rsp_rxd(void)
void
ble_ll_conn_slave_start(uint8_t *rxbuf)
{
+ uint32_t temp;
uint32_t crcinit;
uint8_t *dptr;
struct ble_ll_conn_sm *connsm;
- /* XXX: Should we error check the parameters? */
-
/* Allocate a connection. If none available, dont do anything */
- connsm = (struct ble_ll_conn_sm *)os_memblock_get(&g_ble_ll_conn_pool);
- if (!connsm) {
+ connsm = ble_ll_conn_sm_get();
+ if (connsm == NULL) {
return;
}
/* Set the pointer at the start of the connection data */
dptr = rxbuf + BLE_LL_CONN_REQ_ADVA_OFF + BLE_DEV_ADDR_LEN;
+ /* Set connection state machine information */
connsm->access_addr = le32toh(dptr);
crcinit = dptr[4];
crcinit <<= 16;
@@ -1514,6 +1941,34 @@ ble_ll_conn_slave_start(uint8_t *rxbuf)
connsm->hop_inc = dptr[21] & 0x1F;
connsm->master_sca = dptr[21] >> 5;
+ /* Error check parameters */
+ if ((connsm->tx_win_off > connsm->conn_itvl) ||
+ (connsm->conn_itvl < BLE_HCI_CONN_ITVL_MIN) ||
+ (connsm->conn_itvl > BLE_HCI_CONN_ITVL_MAX) ||
+ (connsm->tx_win_size < BLE_LL_CONN_TX_WIN_MIN) ||
+ (connsm->slave_latency > BLE_LL_CONN_SLAVE_LATENCY_MAX)) {
+ goto err_slave_start;
+ }
+
+ /* Slave latency cannot cause a supervision timeout */
+ temp = (connsm->slave_latency + 1) * (connsm->conn_itvl * 2) *
+ BLE_LL_CONN_ITVL_USECS;
+ if ((connsm->supervision_tmo * 10000) <= temp ) {
+ goto err_slave_start;
+ }
+
+ /*
+ * The transmit window must be less than or equal to the lesser of 10
+ * msecs or the connection interval minus 1.25 msecs.
+ */
+ temp = connsm->conn_itvl - 1;
+ if (temp > 8) {
+ temp = 8;
+ }
+ if (connsm->tx_win_size > temp) {
+ goto err_slave_start;
+ }
+
/* XXX: might want to set this differently based on adv. filter policy! */
/* Set the address of device that we are connecting with */
memcpy(&connsm->peer_addr, rxbuf + BLE_LL_PDU_HDR_LEN, BLE_DEV_ADDR_LEN);
@@ -1523,13 +1978,24 @@ ble_ll_conn_slave_start(uint8_t *rxbuf)
connsm->peer_addr_type = BLE_ADDR_TYPE_PUBLIC;
}
+ /* Calculate number of used channels; make sure it meets min requirement */
connsm->num_used_chans = ble_ll_conn_calc_used_chans(connsm->chanmap);
+ if (connsm->num_used_chans < 2) {
+ goto err_slave_start;
+ }
- /* Need to initialize the connection state machine */
- ble_ll_conn_sm_init(connsm, NULL);
+ /* Start the connection state machine */
+ ble_ll_conn_sm_start(connsm, NULL);
/* The connection has been created. */
ble_ll_conn_created(connsm);
+
+ return;
+
+err_slave_start:
+ STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, conn_stqe);
+ ++g_ble_ll_conn_stats.slave_rxd_bad_conn_req_params;
+ return;
}
/* Initialize the connection module */
@@ -1537,8 +2003,10 @@ void
ble_ll_conn_init(void)
{
int rc;
+ uint16_t i;
uint16_t maxbytes;
struct os_mbuf *m;
+ struct ble_ll_conn_sm *connsm;
struct ble_ll_conn_global_params *conn_params;
/* Create connection memory pool */
@@ -1549,6 +2017,18 @@ ble_ll_conn_init(void)
/* Initialize list of active conections */
SLIST_INIT(&g_ble_ll_conn_active_list);
+ STAILQ_INIT(&g_ble_ll_conn_free_list);
+
+ /*
+ * Take all the connections off the free memory pool and add them to
+ * the free connection list, assigning handles in linear order. Note:
+ * the specification allows a handle of zero; we just avoid using it.
+ */
+ for (i = 1; i <= BLE_LL_CONN_CFG_MAX_CONNS; ++i) {
+ connsm = (struct ble_ll_conn_sm *)os_memblock_get(&g_ble_ll_conn_pool);
+ assert(connsm != NULL);
+ connsm->conn_handle = i;
+ }
/* Configure the global LL parameters */
conn_params = &g_ble_ll_conn_params;
@@ -1564,6 +2044,13 @@ ble_ll_conn_init(void)
conn_params->conn_init_max_tx_time = ble_ll_pdu_tx_time_get(maxbytes);
conn_params->conn_init_max_tx_octets = BLE_LL_CFG_SUPP_MAX_TX_BYTES;
+ /*
+ * XXX: This approach may not work as I may need to keep these on the
+ * transmit packet queue of a connsm. If there are multiple state machines,
+ * I will need multiple empty PDU's. This is only true if I need to keep
+ * the empty PDU on the transmit queue for retransmission across connection
+ * events.
+ */
/* Initialize dummy empty pdu */
m = (struct os_mbuf *)&g_ble_ll_empty_pdu;
m->om_data = (uint8_t *)&g_ble_ll_empty_pdu[0];
@@ -1571,5 +2058,7 @@ ble_ll_conn_init(void)
m->om_len = 2;
m->om_flags = OS_MBUF_F_MASK(OS_MBUF_F_PKTHDR);
OS_MBUF_PKTHDR(m)->omp_len = 2;
+ m->om_data[0] = BLE_LL_LLID_DATA_FRAG;
+ m->om_data[1] = 0;
}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/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 aa91a14..dff2b1d 100644
--- a/net/nimble/drivers/native/src/ble_phy.c
+++ b/net/nimble/drivers/native/src/ble_phy.c
@@ -174,7 +174,7 @@ ble_phy_isr(void)
/* Construct BLE header before handing up */
ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu);
ble_hdr->flags = 0;
- ble_hdr->rssi = -77;
+ ble_hdr->rssi = -77; /* XXX: dummy rssi */
ble_hdr->channel = g_ble_phy_data.phy_chan;
ble_hdr->crcok = 1;
@@ -188,7 +188,7 @@ ble_phy_isr(void)
/* 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->crcok);
+ rc = ble_ll_rx_end(rxpdu, ble_hdr->channel, ble_hdr->crcok);
if (rc < 0) {
/* Disable the PHY. */
ble_phy_disable();
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/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 43bde94..37731dd 100644
--- a/net/nimble/drivers/nrf52/src/ble_phy.c
+++ b/net/nimble/drivers/nrf52/src/ble_phy.c
@@ -100,6 +100,11 @@ ble_phy_rxpdu_get(void)
if (!m) {
++g_ble_phy_stats.no_bufs;
} else {
+ /*
+ * XXX: fix this later but we need to prepend the ACL header
+ * which is 4 bytes but we re-use 2 bytes of the PDU header.
+ */
+ m->om_data += 2;
g_ble_phy_data.rxpdu = m;
}
}
@@ -151,9 +156,6 @@ ble_phy_isr(void)
transition = g_ble_phy_data.phy_transition;
if (transition == BLE_PHY_TRANSITION_TX_RX) {
- /* XXX: for now, assume we receive on logical address 0 */
- NRF_RADIO->RXADDRESSES = 1;
-
/* Debug check to make sure we go from tx to rx */
assert((shortcuts & RADIO_SHORTS_DISABLED_RXEN_Msk) != 0);
@@ -262,7 +264,7 @@ ble_phy_isr(void)
/* 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->crcok);
+ rc = ble_ll_rx_end(rxpdu, ble_hdr->channel, ble_hdr->crcok);
if (rc < 0) {
/* Disable the PHY. */
ble_phy_disable();
@@ -359,12 +361,6 @@ ble_phy_rx(void)
return BLE_PHY_ERR_NO_BUFS;
}
- /* XXX: Assume that this is an advertising channel */
- NRF_RADIO->CRCINIT = BLE_LL_CRCINIT_ADV;
-
- /* XXX: for now, assume we receive on logical address 0 */
- NRF_RADIO->RXADDRESSES = 1;
-
/* Set packet pointer */
NRF_RADIO->PACKETPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/net/nimble/include/nimble/ble.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/ble.h b/net/nimble/include/nimble/ble.h
index e7d5c2f..8d98f5a 100644
--- a/net/nimble/include/nimble/ble.h
+++ b/net/nimble/include/nimble/ble.h
@@ -38,6 +38,7 @@ extern struct os_mempool g_hci_os_event_pool;
* flags: bitfield with the following values
* 0x01: Set if there was a match on the whitelist
* 0x02: Set if a connect request was transmitted upon receiving pdu
+ * 0x04: Set the first time we transmit the PDU (used to detect retry).
* channel: The logical BLE channel PHY channel # (0 - 39)
* crcok: flag denoting CRC check passed (1) or failed (0).
* rssi: RSSI, in dBm.
@@ -53,11 +54,18 @@ struct ble_mbuf_hdr
/* Flag definitions */
#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_PTR(om) \
(struct ble_mbuf_hdr *)((uint8_t *)om + sizeof(struct os_mbuf) + \
sizeof(struct os_mbuf_pkthdr))
+/* BLE mbuf overhead per packet header mbuf */
+#define BLE_MBUF_PKT_OVERHEAD (sizeof(struct os_mbuf) + \
+ sizeof(struct os_mbuf_pkthdr) + \
+ sizeof(struct ble_mbuf_hdr))
+
+
#define BLE_DEV_ADDR_LEN (6)
extern uint8_t g_dev_addr[BLE_DEV_ADDR_LEN];
extern uint8_t g_random_addr[BLE_DEV_ADDR_LEN];
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/project/bletest/src/main.c
----------------------------------------------------------------------
diff --git a/project/bletest/src/main.c b/project/bletest/src/main.c
index 9cbdcd8..43186fb 100755
--- a/project/bletest/src/main.c
+++ b/project/bletest/src/main.c
@@ -50,9 +50,7 @@ uint8_t g_host_adv_len;
/* Create a mbuf pool of BLE mbufs */
#define MBUF_NUM_MBUFS (16)
#define MBUF_BUF_SIZE (256)
-#define MBUF_MEMBLOCK_SIZE \
- (MBUF_BUF_SIZE + sizeof(struct os_mbuf) + sizeof(struct os_mbuf_pkthdr) + \
- sizeof(struct ble_mbuf_hdr))
+#define MBUF_MEMBLOCK_SIZE (MBUF_BUF_SIZE + BLE_MBUF_PKT_OVERHEAD)
#define MBUF_MEMPOOL_SIZE OS_MEMPOOL_SIZE(MBUF_NUM_MBUFS, MBUF_MEMBLOCK_SIZE)