Bluetooth: controller: Data Length Update port to ULL/LLL arch
Ported implementation of Data Length Update Procedure to ULL/LLL architecture of the Link Layer. Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
parent
6fc655351c
commit
705515c092
8 changed files with 436 additions and 139 deletions
|
@ -97,12 +97,10 @@ struct lll_conn {
|
|||
/* FIXME: END: Move to ULL? */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
u16_t default_tx_octets;
|
||||
u16_t max_tx_octets;
|
||||
u16_t max_rx_octets;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
u16_t default_tx_time;
|
||||
u16_t max_tx_time;
|
||||
u16_t max_rx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
|
|
@ -614,6 +614,12 @@ void lll_conn_pdu_tx_prep(struct lll_conn *lll, struct pdu_data **pdu_data_tx)
|
|||
}
|
||||
}
|
||||
|
||||
p->rfu = 0U;
|
||||
|
||||
#if !defined(CONFIG_BT_CTLR_DATA_LENGTH_CLEAR)
|
||||
p->resv = 0U;
|
||||
#endif /* !CONFIG_BT_CTLR_DATA_LENGTH_CLEAR */
|
||||
|
||||
*pdu_data_tx = p;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include "pdu.h"
|
||||
#include "ll.h"
|
||||
#include "ll_feat.h"
|
||||
#include "lll.h"
|
||||
#include "lll_filter.h"
|
||||
#include "lll_adv.h"
|
||||
|
@ -146,8 +147,6 @@ static MFIFO_DEFINE(ll_pdu_rx_free, sizeof(void *), LL_PDU_RX_CNT);
|
|||
|
||||
#if defined(CONFIG_BT_RX_BUF_LEN)
|
||||
#define PDU_RX_OCTETS_MAX (CONFIG_BT_RX_BUF_LEN - 11)
|
||||
#else
|
||||
#define PDU_RX_OCTETS_MAX 0
|
||||
#endif
|
||||
|
||||
#define NODE_RX_HEADER_SIZE (offsetof(struct node_rx_pdu, pdu))
|
||||
|
|
|
@ -571,6 +571,19 @@ u8_t ll_adv_enable(u8_t enable)
|
|||
conn_lll->enc_tx = 0;
|
||||
#endif /* CONFIG_BT_CTLR_LE_ENC */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
conn_lll->max_tx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
|
||||
conn_lll->max_rx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
/* Use the default 1M packet max time. Value of 0 is
|
||||
* equivalent to using BIT(0).
|
||||
*/
|
||||
conn_lll->max_tx_time = PKT_US(PDU_DC_PAYLOAD_SIZE_MIN, 0);
|
||||
conn_lll->max_rx_time = PKT_US(PDU_DC_PAYLOAD_SIZE_MIN, 0);
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
conn_lll->phy_tx = BIT(0);
|
||||
conn_lll->phy_flags = 0;
|
||||
|
@ -625,6 +638,16 @@ u8_t ll_adv_enable(u8_t enable)
|
|||
conn->llcp_conn_param.disabled = 0;
|
||||
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
conn->llcp_length.req = conn->llcp_length.ack = 0U;
|
||||
conn->llcp_length.pause_tx = 0U;
|
||||
conn->default_tx_octets = ull_conn_default_tx_octets_get();
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
conn->default_tx_time = ull_conn_default_tx_time_get();
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
conn->llcp_phy.req = conn->llcp_phy.ack = 0;
|
||||
conn->phy_pref_tx = ull_conn_default_phy_tx_get();
|
||||
|
|
|
@ -111,8 +111,7 @@ static void ticker_op_cb(u32_t status, void *params);
|
|||
sizeof(struct pdu_data_llctrl)) * \
|
||||
CONN_TX_CTRL_BUFFERS)
|
||||
|
||||
static MFIFO_DEFINE(conn_tx, sizeof(struct lll_tx),
|
||||
CONFIG_BT_CTLR_TX_BUFFERS);
|
||||
static MFIFO_DEFINE(conn_tx, sizeof(struct lll_tx), CONFIG_BT_CTLR_TX_BUFFERS);
|
||||
|
||||
static struct {
|
||||
void *free;
|
||||
|
@ -133,6 +132,11 @@ static struct {
|
|||
static u8_t data_chan_map[5] = {0xFF, 0xFF, 0xFF, 0xFF, 0x1F};
|
||||
static u8_t data_chan_count = 37U;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
static u16_t default_tx_octets;
|
||||
static u16_t default_tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
static u8_t default_phy_tx;
|
||||
static u8_t default_phy_rx;
|
||||
|
@ -395,6 +399,67 @@ u8_t ll_version_ind_send(u16_t handle)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
u32_t ll_length_req_send(u16_t handle, u16_t tx_octets, u16_t tx_time)
|
||||
{
|
||||
struct ll_conn *conn;
|
||||
|
||||
conn = ll_connected_get(handle);
|
||||
if (!conn) {
|
||||
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
||||
}
|
||||
|
||||
if ((conn->llcp_req != conn->llcp_ack) ||
|
||||
(conn->llcp_length.req != conn->llcp_length.ack)) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
/* TODO: parameter check tx_octets and tx_time */
|
||||
|
||||
conn->llcp_length.state = LLCP_LENGTH_STATE_REQ;
|
||||
conn->llcp_length.tx_octets = tx_octets;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
conn->llcp_length.tx_time = tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
conn->llcp_length.req++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ll_length_default_get(u16_t *max_tx_octets, u16_t *max_tx_time)
|
||||
{
|
||||
*max_tx_octets = default_tx_octets;
|
||||
*max_tx_time = default_tx_time;
|
||||
}
|
||||
|
||||
u32_t ll_length_default_set(u16_t max_tx_octets, u16_t max_tx_time)
|
||||
{
|
||||
/* TODO: parameter check (for BT 5.0 compliance) */
|
||||
|
||||
default_tx_octets = max_tx_octets;
|
||||
default_tx_time = max_tx_time;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ll_length_max_get(u16_t *max_tx_octets, u16_t *max_tx_time,
|
||||
u16_t *max_rx_octets, u16_t *max_rx_time)
|
||||
{
|
||||
*max_tx_octets = LL_LENGTH_OCTETS_RX_MAX;
|
||||
*max_rx_octets = LL_LENGTH_OCTETS_RX_MAX;
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
*max_tx_time = PKT_US(LL_LENGTH_OCTETS_RX_MAX, BIT(2));
|
||||
*max_rx_time = PKT_US(LL_LENGTH_OCTETS_RX_MAX, BIT(2));
|
||||
#else /* !CONFIG_BT_CTLR_PHY */
|
||||
/* Default is 1M packet timing */
|
||||
*max_tx_time = PKT_US(LL_LENGTH_OCTETS_RX_MAX, 0);
|
||||
*max_rx_time = PKT_US(LL_LENGTH_OCTETS_RX_MAX, 0);
|
||||
#endif /* !CONFIG_BT_CTLR_PHY */
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
u8_t ll_phy_get(u16_t handle, u8_t *tx, u8_t *rx)
|
||||
{
|
||||
|
@ -556,6 +621,20 @@ void ull_conn_chan_map_set(u8_t *chan_map)
|
|||
sizeof(data_chan_map));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
u16_t ull_conn_default_tx_octets_get(void)
|
||||
{
|
||||
return default_tx_octets;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
u16_t ull_conn_default_tx_time_get(void)
|
||||
{
|
||||
return default_tx_time;
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
u8_t ull_conn_default_phy_tx_get(void)
|
||||
{
|
||||
|
@ -1223,8 +1302,8 @@ static int init_reset(void)
|
|||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
/* Initialize the DLE defaults */
|
||||
_radio.default_tx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
|
||||
_radio.default_tx_time = RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0);
|
||||
default_tx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
|
||||
default_tx_time = PKT_US(PDU_DC_PAYLOAD_SIZE_MIN, 0);
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
|
@ -1329,7 +1408,7 @@ static void conn_cleanup(struct ll_conn *conn)
|
|||
lll->handle = 0xFFFF;
|
||||
}
|
||||
|
||||
static void ctrl_tx_data_last_enqueue(struct ll_conn *conn,
|
||||
static void ctrl_tx_last_enqueue(struct ll_conn *conn,
|
||||
struct node_tx *tx)
|
||||
{
|
||||
tx->next = conn->tx_ctrl_last->next;
|
||||
|
@ -1370,7 +1449,7 @@ static void ctrl_tx_enqueue(struct ll_conn *conn, struct node_tx *tx)
|
|||
conn->tx_ctrl = tx;
|
||||
conn->tx_ctrl_last = tx;
|
||||
} else {
|
||||
ctrl_tx_data_last_enqueue(conn, tx);
|
||||
ctrl_tx_last_enqueue(conn, tx);
|
||||
}
|
||||
} else {
|
||||
/* No packet needing ACK. */
|
||||
|
@ -1384,7 +1463,7 @@ static void ctrl_tx_enqueue(struct ll_conn *conn, struct node_tx *tx)
|
|||
conn->tx_ctrl = tx;
|
||||
conn->tx_ctrl_last = tx;
|
||||
} else {
|
||||
ctrl_tx_data_last_enqueue(conn, tx);
|
||||
ctrl_tx_last_enqueue(conn, tx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2420,32 +2499,20 @@ static inline void event_len_prep(struct ll_conn *conn)
|
|||
struct pdu_data_llctrl_length_req *lr;
|
||||
struct pdu_data *pdu_ctrl_tx;
|
||||
struct node_tx *tx;
|
||||
struct lll_conn *lll;
|
||||
u16_t free_count_rx;
|
||||
|
||||
free_count_rx = ll_rx_acquired_count_get() +
|
||||
ll_rx_free_count_get();
|
||||
LL_ASSERT(free_count_rx <= 0xFF);
|
||||
|
||||
if (ll_rx_total_count_get() != free_count_rx) {
|
||||
break;
|
||||
}
|
||||
|
||||
tx = mem_acquire(&mem_conn_tx_ctrl.free);
|
||||
if (!tx) {
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
/* wait for resp before completing the procedure */
|
||||
conn->llcp_length.state = LLCP_LENGTH_STATE_ACK_WAIT;
|
||||
|
||||
lll = &conn->lll;
|
||||
|
||||
/* set the default tx octets/time to requested value */
|
||||
lll->default_tx_octets = conn->llcp_length.tx_octets;
|
||||
conn->default_tx_octets = conn->llcp_length.tx_octets;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
lll->default_tx_time = conn->llcp_length.tx_time;
|
||||
conn->default_tx_time = conn->llcp_length.tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
/* place the length req packet as next in tx queue */
|
||||
|
@ -2458,12 +2525,13 @@ static inline void event_len_prep(struct ll_conn *conn)
|
|||
|
||||
lr = &pdu_ctrl_tx->llctrl.length_req;
|
||||
lr->max_rx_octets = LL_LENGTH_OCTETS_RX_MAX;
|
||||
lr->max_tx_octets = lll->default_tx_octets;
|
||||
lr->max_rx_time = PKT_US(LL_LENGTH_OCTETS_RX_MAX, BIT(2));
|
||||
lr->max_tx_octets = conn->default_tx_octets;
|
||||
#if !defined(CONFIG_BT_CTLR_PHY)
|
||||
lr->max_tx_time = PKT_US(lll->default_tx_octets, 0);
|
||||
lr->max_rx_time = PKT_US(LL_LENGTH_OCTETS_RX_MAX, 0);
|
||||
lr->max_tx_time = PKT_US(conn->default_tx_octets, 0);
|
||||
#else /* CONFIG_BT_CTLR_PHY */
|
||||
lr->max_tx_time = lll->default_tx_time;
|
||||
lr->max_rx_time = PKT_US(LL_LENGTH_OCTETS_RX_MAX, BIT(2));
|
||||
lr->max_tx_time = conn->default_tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
ctrl_tx_enqueue(conn, tx);
|
||||
|
@ -2480,26 +2548,7 @@ static inline void event_len_prep(struct ll_conn *conn)
|
|||
struct pdu_data_llctrl_length_rsp *lr;
|
||||
struct pdu_data *pdu_ctrl_rx;
|
||||
struct node_rx_pdu *rx;
|
||||
u16_t packet_rx_data_size;
|
||||
u16_t free_count_conn;
|
||||
struct lll_conn *lll;
|
||||
u16_t free_count_rx;
|
||||
|
||||
/* Ensure the rx pool is not in use.
|
||||
* This is important to be able to re-size the pool
|
||||
* ensuring there is no chance that an operation on
|
||||
* the pool is pre-empted causing memory corruption.
|
||||
*/
|
||||
free_count_rx = ll_rx_acquired_count_get() +
|
||||
ll_rx_free_count_get();
|
||||
LL_ASSERT(free_count_rx <= 0xFF);
|
||||
|
||||
if (ll_rx_total_count_get() != free_count_rx) {
|
||||
/** TODO another role instance has obtained
|
||||
* memory from rx pool.
|
||||
*/
|
||||
LL_ASSERT(0);
|
||||
}
|
||||
|
||||
/* Procedure complete */
|
||||
conn->llcp_length.ack = conn->llcp_length.req;
|
||||
|
@ -2515,94 +2564,14 @@ static inline void event_len_prep(struct ll_conn *conn)
|
|||
lll->max_rx_time = conn->llcp_length.rx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
/** TODO This design is exception as memory initialization
|
||||
* and allocation is done in radio context here, breaking the
|
||||
* rule that the rx buffers are allocated in application
|
||||
* context.
|
||||
* Design mem_* such that mem_init could interrupt mem_acquire,
|
||||
* when the pool is full?
|
||||
*/
|
||||
free_count_conn = mem_free_count_get(conn_free);
|
||||
/* TODO:*/
|
||||
#if 0
|
||||
if (_radio.advertiser.conn) {
|
||||
free_count_conn++;
|
||||
}
|
||||
if (_radio.scanner.conn) {
|
||||
free_count_conn++;
|
||||
}
|
||||
#endif
|
||||
packet_rx_data_size = MROUND(offsetof(struct node_rx_pdu, pdu) +
|
||||
offsetof(struct pdu_data, lldata) +
|
||||
lll->max_rx_octets);
|
||||
/* Resize to lower or higher size if this is the only active
|
||||
* connection, or resize to only higher sizes as there may be
|
||||
* other connections using the current size.
|
||||
*/
|
||||
if (((free_count_conn + 1) == CONFIG_BT_MAX_CONN) ||
|
||||
(packet_rx_data_size > ll_rx_data_size_get())) {
|
||||
/* as rx mem is to be re-sized, release acquired
|
||||
* memq link.
|
||||
*/
|
||||
/* TODO: */
|
||||
#if 0
|
||||
while (_radio.packet_rx_acquire !=
|
||||
_radio.packet_rx_last) {
|
||||
if (_radio.packet_rx_acquire == 0) {
|
||||
_radio.packet_rx_acquire =
|
||||
_radio.packet_rx_count - 1;
|
||||
} else {
|
||||
_radio.packet_rx_acquire -= 1;
|
||||
}
|
||||
|
||||
node_rx = _radio.packet_rx[
|
||||
_radio.packet_rx_acquire];
|
||||
mem_release(node_rx->hdr.link,
|
||||
&_radio.link_rx_free);
|
||||
|
||||
LL_ASSERT(_radio.link_rx_data_quota <
|
||||
(_radio.packet_rx_count - 1));
|
||||
_radio.link_rx_data_quota++;
|
||||
|
||||
/* no need to release node_rx as we mem_init
|
||||
* later down in code.
|
||||
*/
|
||||
}
|
||||
|
||||
/* calculate the new rx node size and new count */
|
||||
if (lll->max_rx_octets < (PDU_AC_SIZE_MAX +
|
||||
PDU_AC_SIZE_EXTRA)) {
|
||||
_radio.packet_rx_data_size =
|
||||
MROUND(offsetof(struct node_rx_pdu, pdu) +
|
||||
(PDU_AC_SIZE_MAX +
|
||||
PDU_AC_SIZE_EXTRA));
|
||||
} else {
|
||||
_radio.packet_rx_data_size =
|
||||
packet_rx_data_size;
|
||||
}
|
||||
_radio.packet_rx_data_count =
|
||||
_radio.packet_rx_data_pool_size /
|
||||
_radio.packet_rx_data_size;
|
||||
LL_ASSERT(_radio.packet_rx_data_count);
|
||||
|
||||
/* re-size (re-init) the free rx pool */
|
||||
mem_init(_radio.pkt_rx_data_pool,
|
||||
_radio.packet_rx_data_size,
|
||||
_radio.packet_rx_data_count,
|
||||
&_radio.pkt_rx_data_free);
|
||||
|
||||
/* allocate the rx queue include one extra for
|
||||
* generating event in following lines.
|
||||
*/
|
||||
packet_rx_allocate(4);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Prepare the rx packet structure */
|
||||
/* TODO: */
|
||||
LL_ASSERT(rx);
|
||||
rx = conn->llcp_rx;
|
||||
conn->llcp_rx = NULL;
|
||||
|
||||
LL_ASSERT(rx && rx->hdr.link);
|
||||
|
||||
rx->hdr.handle = conn->lll.handle;
|
||||
node_rx->hdr.type = NODE_RX_TYPE_DC_PDU;
|
||||
rx->hdr.type = NODE_RX_TYPE_DC_PDU;
|
||||
|
||||
/* prepare length rsp structure */
|
||||
pdu_ctrl_rx = (void *)rx->pdu;
|
||||
|
@ -2623,8 +2592,9 @@ static inline void event_len_prep(struct ll_conn *conn)
|
|||
lr->max_tx_time = lll->max_tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
/* enqueue version ind structure into rx queue */
|
||||
/* TODO: */
|
||||
/* enqueue rx node towards Thread */
|
||||
ll_rx_put(rx->hdr.link, rx);
|
||||
ll_rx_sched();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -3467,6 +3437,46 @@ reject_ind_conn_upd_recv_exit:
|
|||
}
|
||||
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
static inline void reject_ind_dle_recv(struct ll_conn *conn,
|
||||
struct node_rx_pdu *rx,
|
||||
struct pdu_data *pdu_rx)
|
||||
{
|
||||
struct pdu_data_llctrl_reject_ext_ind *rej_ext_ind;
|
||||
|
||||
rej_ext_ind = (void *)&pdu_rx->llctrl.reject_ext_ind;
|
||||
if (rej_ext_ind->reject_opcode == PDU_DATA_LLCTRL_TYPE_LENGTH_REQ) {
|
||||
struct pdu_data_llctrl_length_req *lr;
|
||||
|
||||
/* Procedure complete */
|
||||
conn->llcp_length.ack = conn->llcp_length.req;
|
||||
conn->llcp_length.pause_tx = 0U;
|
||||
conn->procedure_expire = 0U;
|
||||
|
||||
/* prepare length rsp structure */
|
||||
pdu_rx->len = offsetof(struct pdu_data_llctrl, length_rsp) +
|
||||
sizeof(struct pdu_data_llctrl_length_rsp);
|
||||
pdu_rx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_LENGTH_RSP;
|
||||
|
||||
lr = (void *)&pdu_rx->llctrl.length_req;
|
||||
lr->max_rx_octets = conn->lll.max_rx_octets;
|
||||
lr->max_tx_octets = conn->lll.max_tx_octets;
|
||||
#if !defined(CONFIG_BT_CTLR_PHY)
|
||||
lr->max_rx_time = PKT_US(conn->lll.max_rx_octets, 0);
|
||||
lr->max_tx_time = PKT_US(conn->lll.max_tx_octets, 0);
|
||||
#else /* CONFIG_BT_CTLR_PHY */
|
||||
lr->max_rx_time = conn->lll.max_rx_time;
|
||||
lr->max_tx_time = conn->lll.max_tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Mark for buffer for release */
|
||||
rx->hdr.type = NODE_RX_TYPE_DC_PDU_RELEASE;
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
static inline void reject_ind_phy_upd_recv(struct ll_conn *conn,
|
||||
struct node_rx_pdu *rx,
|
||||
|
@ -3532,7 +3542,7 @@ static void reject_ext_ind_recv(struct ll_conn *conn, struct node_rx_pdu *rx,
|
|||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
} else if (conn->llcp_length.ack != conn->llcp_length.req) {
|
||||
isr_rx_conn_pkt_ctrl_rej_dle(rx, rx_enqueue);
|
||||
reject_ind_dle_recv(conn, rx, pdu_rx);
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_LE_ENC)
|
||||
|
@ -3567,6 +3577,237 @@ static void reject_ext_ind_recv(struct ll_conn *conn, struct node_rx_pdu *rx,
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
#if !defined(CONFIG_BT_CTLR_PHY)
|
||||
static void length_resp_send(struct ll_conn *conn, struct node_tx *tx,
|
||||
u16_t eff_rx_octets, u16_t eff_tx_octets)
|
||||
#else /* CONFIG_BT_CTLR_PHY */
|
||||
static void length_resp_send(struct ll_conn *conn, struct node_tx *tx,
|
||||
u16_t eff_rx_octets, u16_t eff_rx_time,
|
||||
u16_t eff_tx_octets, u16_t eff_tx_time)
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
{
|
||||
struct pdu_data *pdu_tx;
|
||||
|
||||
pdu_tx = (void *)tx->pdu;
|
||||
pdu_tx->ll_id = PDU_DATA_LLID_CTRL;
|
||||
pdu_tx->len = offsetof(struct pdu_data_llctrl, length_rsp) +
|
||||
sizeof(struct pdu_data_llctrl_length_rsp);
|
||||
pdu_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_LENGTH_RSP;
|
||||
pdu_tx->llctrl.length_rsp.max_rx_octets = eff_rx_octets;
|
||||
pdu_tx->llctrl.length_rsp.max_tx_octets = eff_tx_octets;
|
||||
|
||||
#if !defined(CONFIG_BT_CTLR_PHY)
|
||||
pdu_tx->llctrl.length_rsp.max_rx_time = PKT_US(eff_rx_octets, 0);
|
||||
pdu_tx->llctrl.length_rsp.max_tx_time = PKT_US(eff_tx_octets, 0);
|
||||
#else /* CONFIG_BT_CTLR_PHY */
|
||||
pdu_tx->llctrl.length_rsp.max_rx_time = eff_rx_time;
|
||||
pdu_tx->llctrl.length_rsp.max_tx_time = eff_tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
ctrl_tx_enqueue(conn, tx);
|
||||
}
|
||||
|
||||
static inline int length_req_rsp_recv(struct ll_conn *conn, memq_link_t *link,
|
||||
struct node_rx_pdu **rx,
|
||||
struct pdu_data *pdu_rx)
|
||||
{
|
||||
struct node_tx *tx = NULL;
|
||||
u16_t eff_rx_octets;
|
||||
u16_t eff_tx_octets;
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
u16_t eff_rx_time;
|
||||
u16_t eff_tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
u8_t nack = 0U;
|
||||
|
||||
/* Check for free ctrl tx PDU */
|
||||
if (pdu_rx->llctrl.opcode == PDU_DATA_LLCTRL_TYPE_LENGTH_REQ) {
|
||||
tx = mem_acquire(&mem_conn_tx_ctrl.free);
|
||||
if (!tx) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
}
|
||||
|
||||
eff_rx_octets = conn->lll.max_rx_octets;
|
||||
eff_tx_octets = conn->lll.max_tx_octets;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
eff_rx_time = conn->lll.max_rx_time;
|
||||
eff_tx_time = conn->lll.max_tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
if (/* Local idle, and Peer request then complete the Peer procedure
|
||||
* with response.
|
||||
*/
|
||||
((conn->llcp_length.req == conn->llcp_length.ack) &&
|
||||
(pdu_rx->llctrl.opcode == PDU_DATA_LLCTRL_TYPE_LENGTH_REQ)) ||
|
||||
/* or Local has active... */
|
||||
((conn->llcp_length.req != conn->llcp_length.ack) &&
|
||||
/* with Local requested and Peer request then complete the
|
||||
* Peer procedure with response.
|
||||
*/
|
||||
((((conn->llcp_length.state == LLCP_LENGTH_STATE_REQ) ||
|
||||
(conn->llcp_length.state == LLCP_LENGTH_STATE_ACK_WAIT)) &&
|
||||
(pdu_rx->llctrl.opcode ==
|
||||
PDU_DATA_LLCTRL_TYPE_LENGTH_REQ)) ||
|
||||
/* with Local waiting for response, and Peer response then
|
||||
* complete the Local procedure or Peer request then complete the
|
||||
* Peer procedure with response.
|
||||
*/
|
||||
((conn->llcp_length.state == LLCP_LENGTH_STATE_RSP_WAIT) &&
|
||||
((pdu_rx->llctrl.opcode ==
|
||||
PDU_DATA_LLCTRL_TYPE_LENGTH_RSP) ||
|
||||
(pdu_rx->llctrl.opcode ==
|
||||
PDU_DATA_LLCTRL_TYPE_LENGTH_REQ)))))) {
|
||||
struct pdu_data_llctrl_length_req *lr;
|
||||
|
||||
lr = &pdu_rx->llctrl.length_req;
|
||||
|
||||
/* use the minimal of our default_tx_octets and
|
||||
* peer max_rx_octets
|
||||
*/
|
||||
if (lr->max_rx_octets >= PDU_DC_PAYLOAD_SIZE_MIN) {
|
||||
eff_tx_octets = MIN(lr->max_rx_octets,
|
||||
conn->default_tx_octets);
|
||||
}
|
||||
|
||||
/* use the minimal of our max supported and
|
||||
* peer max_tx_octets
|
||||
*/
|
||||
if (lr->max_tx_octets >= PDU_DC_PAYLOAD_SIZE_MIN) {
|
||||
eff_rx_octets = MIN(lr->max_tx_octets,
|
||||
LL_LENGTH_OCTETS_RX_MAX);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
/* use the minimal of our default_tx_time and
|
||||
* peer max_rx_time
|
||||
*/
|
||||
if (lr->max_rx_time >= PKT_US(PDU_DC_PAYLOAD_SIZE_MIN, 0)) {
|
||||
eff_tx_time = MIN(lr->max_rx_time,
|
||||
conn->default_tx_time);
|
||||
#if defined(CONFIG_BT_CTLR_PHY_CODED)
|
||||
eff_tx_time = MAX(eff_tx_time,
|
||||
PKT_US(PDU_DC_PAYLOAD_SIZE_MIN,
|
||||
conn->lll.phy_tx));
|
||||
#endif /* CONFIG_BT_CTLR_PHY_CODED */
|
||||
}
|
||||
|
||||
/* use the minimal of our max supported and
|
||||
* peer max_tx_time
|
||||
*/
|
||||
if (lr->max_tx_time >= PKT_US(PDU_DC_PAYLOAD_SIZE_MIN, 0)) {
|
||||
#if defined(CONFIG_BT_CTLR_PHY_CODED)
|
||||
eff_rx_time = MIN(lr->max_tx_time,
|
||||
PKT_US(LL_LENGTH_OCTETS_RX_MAX,
|
||||
BIT(2)));
|
||||
eff_rx_time = MAX(eff_rx_time,
|
||||
PKT_US(PDU_DC_PAYLOAD_SIZE_MIN,
|
||||
conn->lll.phy_rx));
|
||||
#else /* !CONFIG_BT_CTLR_PHY_CODED */
|
||||
eff_rx_time = MIN(lr->max_tx_time,
|
||||
PKT_US(LL_LENGTH_OCTETS_RX_MAX, 0));
|
||||
#endif /* !CONFIG_BT_CTLR_PHY_CODED */
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
/* check if change in rx octets */
|
||||
if (eff_rx_octets != conn->lll.max_rx_octets) {
|
||||
/* accept the effective tx */
|
||||
conn->lll.max_tx_octets = eff_tx_octets;
|
||||
|
||||
/* trigger or retain the ctrl procedure so as
|
||||
* to resize the rx buffers.
|
||||
*/
|
||||
conn->llcp_length.rx_octets = eff_rx_octets;
|
||||
conn->llcp_length.tx_octets = eff_tx_octets;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
/* accept the effective tx time */
|
||||
conn->lll.max_tx_time = eff_tx_time;
|
||||
|
||||
conn->llcp_length.rx_time = eff_rx_time;
|
||||
conn->llcp_length.tx_time = eff_tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
conn->llcp_length.ack = (conn->llcp_length.req -
|
||||
1);
|
||||
conn->llcp_length.state =
|
||||
LLCP_LENGTH_STATE_RESIZE;
|
||||
|
||||
LL_ASSERT(!conn->llcp_rx);
|
||||
|
||||
(*rx)->hdr.link = link;
|
||||
conn->llcp_rx = *rx;
|
||||
*rx = NULL;
|
||||
|
||||
/* FIXME: Close current event */
|
||||
} else {
|
||||
/* Procedure complete */
|
||||
conn->llcp_length.ack = conn->llcp_length.req;
|
||||
conn->llcp_length.pause_tx = 0U;
|
||||
conn->procedure_expire = 0U;
|
||||
|
||||
/* No change in effective octets or time */
|
||||
if (eff_tx_octets == conn->lll.max_tx_octets &&
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
eff_tx_time == conn->lll.max_tx_time &&
|
||||
eff_rx_time == conn->lll.max_rx_time &&
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
(1)) {
|
||||
goto send_length_resp;
|
||||
}
|
||||
|
||||
/* accept the effective tx */
|
||||
conn->lll.max_tx_octets = eff_tx_octets;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
/* accept the effective rx time */
|
||||
conn->lll.max_rx_time = eff_rx_time;
|
||||
|
||||
/* accept the effective tx time */
|
||||
conn->lll.max_tx_time = eff_tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
|
||||
/* prepare event params */
|
||||
lr->max_rx_octets = eff_rx_octets;
|
||||
lr->max_tx_octets = eff_tx_octets;
|
||||
|
||||
#if !defined(CONFIG_BT_CTLR_PHY)
|
||||
lr->max_rx_time = PKT_US(eff_rx_octets, 0);
|
||||
lr->max_tx_time = PKT_US(eff_tx_octets, 0);
|
||||
#else /* CONFIG_BT_CTLR_PHY */
|
||||
lr->max_rx_time = eff_rx_time;
|
||||
lr->max_tx_time = eff_tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
}
|
||||
} else {
|
||||
/* Drop response with no Local initiated request. */
|
||||
LL_ASSERT(pdu_rx->llctrl.opcode ==
|
||||
PDU_DATA_LLCTRL_TYPE_LENGTH_RSP);
|
||||
}
|
||||
|
||||
send_length_resp:
|
||||
if (tx) {
|
||||
if (nack) {
|
||||
mem_release(tx, &mem_conn_tx_ctrl.free);
|
||||
} else {
|
||||
#if !defined(CONFIG_BT_CTLR_PHY)
|
||||
length_resp_send(conn, tx, eff_rx_octets,
|
||||
eff_tx_octets);
|
||||
#else /* CONFIG_BT_CTLR_PHY */
|
||||
length_resp_send(conn, tx, eff_rx_octets,
|
||||
eff_rx_time, eff_tx_octets,
|
||||
eff_tx_time);
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
}
|
||||
}
|
||||
|
||||
return nack;
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_LE_PING)
|
||||
static int ping_resp_send(struct ll_conn *conn, struct node_rx_pdu *rx)
|
||||
{
|
||||
|
@ -4701,7 +4942,7 @@ static inline int ctrl_rx(memq_link_t *link, struct node_rx_pdu **rx,
|
|||
goto ull_conn_rx_unknown_rsp_send;
|
||||
}
|
||||
|
||||
nack = isr_rx_conn_pkt_ctrl_dle(pdu, rx_enqueue);
|
||||
nack = length_req_rsp_recv(conn, link, rx, pdu_rx);
|
||||
break;
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ int ull_conn_init(void);
|
|||
int ull_conn_reset(void);
|
||||
u8_t ull_conn_chan_map_cpy(u8_t *chan_map);
|
||||
void ull_conn_chan_map_set(u8_t *chan_map);
|
||||
u16_t ull_conn_default_tx_octets_get(void);
|
||||
u16_t ull_conn_default_tx_time_get(void);
|
||||
u8_t ull_conn_default_phy_tx_get(void);
|
||||
u8_t ull_conn_default_phy_rx_get(void);
|
||||
void ull_conn_setup(memq_link_t *link, struct node_rx_hdr *rx);
|
||||
|
|
|
@ -22,6 +22,14 @@ struct ll_conn {
|
|||
u16_t apto_expire;
|
||||
#endif /* CONFIG_BT_CTLR_LE_PING */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
u16_t default_tx_octets;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
u16_t default_tx_time;
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
union {
|
||||
struct {
|
||||
u8_t fex_valid:1;
|
||||
|
|
|
@ -126,6 +126,16 @@ u8_t ll_create_connection(u16_t scan_interval, u16_t scan_window,
|
|||
conn_lll->enc_tx = 0;
|
||||
#endif /* CONFIG_BT_CTLR_LE_ENC */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
conn_lll->max_tx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
|
||||
conn_lll->max_rx_octets = PDU_DC_PAYLOAD_SIZE_MIN;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
conn_lll->max_tx_time = PKT_US(PDU_DC_PAYLOAD_SIZE_MIN, 0);
|
||||
conn_lll->max_rx_time = PKT_US(PDU_DC_PAYLOAD_SIZE_MIN, 0);
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
conn_lll->phy_tx = BIT(0);
|
||||
conn_lll->phy_flags = 0;
|
||||
|
@ -199,6 +209,16 @@ u8_t ll_create_connection(u16_t scan_interval, u16_t scan_window,
|
|||
conn->llcp_conn_param.disabled = 0U;
|
||||
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
conn->llcp_length.req = conn->llcp_length.ack = 0U;
|
||||
conn->llcp_length.pause_tx = 0U;
|
||||
conn->default_tx_octets = ull_conn_default_tx_octets_get();
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
conn->default_tx_time = ull_conn_default_tx_time_get();
|
||||
#endif /* CONFIG_BT_CTLR_PHY */
|
||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
conn->llcp_phy.req = conn->llcp_phy.ack = 0U;
|
||||
conn->phy_pref_tx = ull_conn_default_phy_tx_get();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue