Bluetooth: Controller: Implement missing DLE commands

Implement the 3 missing HCI commands required to support
Data Length Extensions:

- LE Read Suggested Default Data Length
- LE Write Suggested Default Data Length
- LE Read Maximum Data Length

Note: Only octets are actually used at this time, not time.

Jira: ZEP-1246

Change-Id: Id76d8fedb5ecaf0001c8429cf22f9a3e2c910a44
Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
Carles Cufi 2016-11-16 12:52:48 +01:00 committed by Johan Hedberg
commit c969e757bc
5 changed files with 122 additions and 18 deletions

View file

@ -141,9 +141,23 @@ struct bt_hci_cmd_hdr {
#define BT_FEAT_SC(feat) BT_FEAT_TEST(feat, 2, 1, 0)
/* LE features */
#define BT_FEAT_LE_ENCR(feat) BT_FEAT_TEST(feat, 0, 0, 0)
#define BT_FEAT_LE_CONN_PARAM_REQ_PROC(feat) BT_FEAT_TEST(feat, 0, 0, 1)
#define BT_FEAT_LE_SLAVE_FEATURE_XCHG(feat) BT_FEAT_TEST(feat, 0, 0, 3)
#define BT_LE_FEAT_BIT_ENC 0
#define BT_LE_FEAT_BIT_CONN_PARAM_REQ 1
#define BT_LE_FEAT_BIT_EXT_REJ_IND 2
#define BT_LE_FEAT_BIT_SLAVE_FEAT_REQ 3
#define BT_LE_FEAT_BIT_PING 4
#define BT_LE_FEAT_BIT_DLE 5
#define BT_LE_FEAT_BIT_PRIVACY 6
#define BT_LE_FEAT_BIT_EXT_SCAN 7
#define BT_FEAT_LE_ENCR(feat) BT_FEAT_TEST(feat, 0, 0, \
BT_LE_FEAT_BIT_ENC)
#define BT_FEAT_LE_CONN_PARAM_REQ_PROC(feat) BT_FEAT_TEST(feat, 0, 0, \
BT_LE_FEAT_BIT_CONN_PARAM_REQ)
#define BT_FEAT_LE_SLAVE_FEATURE_XCHG(feat) BT_FEAT_TEST(feat, 0, 0, \
BT_LE_FEAT_BIT_SLAVE_FEAT_REQ)
#define BT_FEAT_LE_DLE(feat) BT_FEAT_TEST(feat, 0, 0, \
BT_LE_FEAT_BIT_DLE)
/* LE States */
#define BT_LE_STATES_SLAVE_CONN_ADV(states) (states & 0x0000004000000000)

View file

@ -679,6 +679,39 @@ static void le_set_data_len(struct net_buf *buf, struct net_buf *evt)
rp->handle = cmd->handle;
}
static void le_read_default_data_len(struct net_buf *buf, struct net_buf *evt)
{
struct bt_hci_rp_le_read_default_data_len *rp;
rp = cmd_complete(evt, sizeof(*rp));
radio_length_default_get(&rp->max_tx_octets, &rp->max_tx_time);
rp->status = 0x00;
}
static void le_write_default_data_len(struct net_buf *buf, struct net_buf *evt)
{
struct bt_hci_cp_le_write_default_data_len *cmd = (void *)buf->data;
struct bt_hci_evt_cc_status *ccst;
uint32_t status;
status = radio_length_default_set(cmd->max_tx_octets, cmd->max_tx_time);
ccst = cmd_complete(evt, sizeof(*ccst));
ccst->status = (!status) ? 0x00 : BT_HCI_ERR_INVALID_LL_PARAMS;
}
static void le_read_max_data_len(struct net_buf *buf, struct net_buf *evt)
{
struct bt_hci_rp_le_read_max_data_len *rp;
rp = cmd_complete(evt, sizeof(*rp));
radio_length_max_get(&rp->max_tx_octets, &rp->max_tx_time,
&rp->max_rx_octets, &rp->max_rx_time);
rp->status = 0x00;
}
static int controller_cmd_handle(uint8_t ocf, struct net_buf *cmd,
struct net_buf *evt)
{
@ -799,6 +832,18 @@ static int controller_cmd_handle(uint8_t ocf, struct net_buf *cmd,
le_set_data_len(cmd, evt);
break;
case BT_OCF(BT_HCI_OP_LE_READ_DEFAULT_DATA_LEN):
le_read_default_data_len(cmd, evt);
break;
case BT_OCF(BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN):
le_write_default_data_len(cmd, evt);
break;
case BT_OCF(BT_HCI_OP_LE_READ_MAX_DATA_LEN):
le_read_max_data_len(cmd, evt);
break;
default:
return -EINVAL;
}

View file

@ -159,6 +159,10 @@ static struct {
uint8_t data_channel_count;
uint8_t sca;
/* DLE global settings */
uint16_t default_tx_octets;
uint16_t default_tx_time;
/** @todo below members to be made role specific and quota managed for
* Rx-es.
*/
@ -475,6 +479,10 @@ static void common_init(void)
_radio.data_channel_map[4] = 0x1F;
_radio.data_channel_count = 37;
/* Initialize the DLE defaults */
_radio.default_tx_octets = RADIO_LL_LENGTH_OCTETS_RX_MIN;
_radio.default_tx_time = RADIO_LL_LENGTH_TIME_RX_MIN;
/* allocate the rx queue */
packet_rx_allocate(0xFF);
}
@ -1249,11 +1257,11 @@ static inline void isr_rx_conn_pkt_ctrl_dle(struct pdu_data *pdu_data_rx,
lr = (struct pdu_data_llctrl_length_req_rsp *)
&pdu_data_rx->payload.llctrl.ctrldata.length_req;
/* use the minimal of our sugg_tx_octets and
/* use the minimal of our default_tx_octets and
* peer max_rx_octets
*/
if (lr->max_rx_octets > _radio.conn_curr->sug_tx_octets) {
eff_tx_octets = _radio.conn_curr->sug_tx_octets;
if (lr->max_rx_octets > _radio.conn_curr->default_tx_octets) {
eff_tx_octets = _radio.conn_curr->default_tx_octets;
} else {
eff_tx_octets = lr->max_rx_octets;
}
@ -4907,8 +4915,8 @@ static inline void event_len_prep(struct connection *conn)
/* wait for resp before completing the procedure */
conn->llcp_length.state = LLCP_LENGTH_STATE_ACK_WAIT;
/* set the suggested tx octets to requested value */
conn->sug_tx_octets = conn->llcp_length.tx_octets;
/* set the default tx octets to requested value */
conn->default_tx_octets = conn->llcp_length.tx_octets;
/* place the length req packet as next in tx queue */
pdu_ctrl_tx = (struct pdu_data *) node_tx->pdu_data;
@ -4922,8 +4930,8 @@ static inline void event_len_prep(struct connection *conn)
&pdu_ctrl_tx->payload.llctrl.ctrldata.length_req;
lr->max_rx_octets = RADIO_LL_LENGTH_OCTETS_RX_MAX;
lr->max_rx_time = ((RADIO_LL_LENGTH_OCTETS_RX_MAX + 14) << 3);
lr->max_tx_octets = conn->sug_tx_octets;
lr->max_tx_time = ((conn->sug_tx_octets + 14) << 3);
lr->max_tx_octets = conn->default_tx_octets;
lr->max_tx_time = ((conn->default_tx_octets + 14) << 3);
ctrl_tx_enqueue(conn, node_tx);
@ -6656,7 +6664,7 @@ uint32_t radio_adv_enable(uint16_t interval, uint8_t chl_map,
conn->event_counter = 0;
conn->latency_prepare = 0;
conn->latency_event = 0;
conn->sug_tx_octets = RADIO_LL_LENGTH_OCTETS_RX_MIN;
conn->default_tx_octets = _radio.default_tx_octets;
conn->max_tx_octets = RADIO_LL_LENGTH_OCTETS_RX_MIN;
conn->max_rx_octets = RADIO_LL_LENGTH_OCTETS_RX_MIN;
conn->role.slave.role = 1;
@ -6977,7 +6985,7 @@ uint32_t radio_connect_enable(uint8_t adv_addr_type, uint8_t *adv_addr,
conn->latency_prepare = 0;
conn->latency_event = 0;
conn->latency = _radio.observer.conn_latency;
conn->sug_tx_octets = RADIO_LL_LENGTH_OCTETS_RX_MIN;
conn->default_tx_octets = _radio.default_tx_octets;
conn->max_tx_octets = RADIO_LL_LENGTH_OCTETS_RX_MIN;
conn->max_rx_octets = RADIO_LL_LENGTH_OCTETS_RX_MIN;
conn->role.master.role = 0;
@ -7315,6 +7323,35 @@ uint32_t radio_length_req_send(uint16_t handle, uint16_t tx_octets)
return 0;
}
void radio_length_default_get(uint16_t *max_tx_octets, uint16_t *max_tx_time)
{
*max_tx_octets = _radio.default_tx_octets;
*max_tx_time = _radio.default_tx_time;
}
uint32_t radio_length_default_set(uint16_t max_tx_octets, uint16_t max_tx_time)
{
if (max_tx_octets > RADIO_LL_LENGTH_OCTETS_RX_MAX ||
max_tx_time > RADIO_LL_LENGTH_TIME_RX_MAX) {
return 1;
}
_radio.default_tx_octets = max_tx_octets;
_radio.default_tx_time = max_tx_time;
return 0;
}
void radio_length_max_get(uint16_t *max_tx_octets, uint16_t *max_tx_time,
uint16_t *max_rx_octets, uint16_t *max_rx_time)
{
*max_tx_octets = RADIO_LL_LENGTH_OCTETS_RX_MAX;
*max_tx_time = RADIO_LL_LENGTH_TIME_RX_MAX;
*max_rx_octets = RADIO_LL_LENGTH_OCTETS_RX_MAX;
*max_rx_time = RADIO_LL_LENGTH_TIME_RX_MAX;
}
static uint8_t tx_cmplt_get(uint16_t *handle, uint8_t *first, uint8_t last)
{
uint8_t _first;

View file

@ -18,6 +18,8 @@
#ifndef _CTRL_H_
#define _CTRL_H_
#include <bluetooth/hci.h>
/*****************************************************************************
* Zephyr Kconfig defined
****************************************************************************/
@ -81,11 +83,13 @@
#define RADIO_BLE_VERSION_NUMBER (0x08)
#define RADIO_BLE_COMPANY_ID (0xFFFF)
#define RADIO_BLE_SUB_VERSION_NUMBER (0xFFFF)
#define RADIO_BLE_FEATURES (0x1F) /* LE Ping, Slave Initiated
* Feature request, Extended
* Reject Indication, Conn Param
* Req Procedure, LE encryption.
*/
#define RADIO_BLE_FEATURES (BT_LE_FEAT_BIT_ENC | \
BT_LE_FEAT_BIT_CONN_PARAM_REQ | \
BT_LE_FEAT_BIT_EXT_REJ_IND | \
BT_LE_FEAT_BIT_SLAVE_FEAT_REQ | \
BT_LE_FEAT_BIT_PING | \
BT_LE_FEAT_BIT_DLE)
/*****************************************************************************
* Controller Reference Defines (compile time override-able)
@ -241,6 +245,10 @@ uint32_t radio_feature_req_send(uint16_t handle);
uint32_t radio_version_ind_send(uint16_t handle);
uint32_t radio_terminate_ind_send(uint16_t handle, uint8_t reason);
uint32_t radio_length_req_send(uint16_t handle, uint16_t tx_octets);
void radio_length_default_get(uint16_t *max_tx_octets, uint16_t *max_tx_time);
uint32_t radio_length_default_set(uint16_t max_tx_octets, uint16_t max_tx_time);
void radio_length_max_get(uint16_t *max_tx_octets, uint16_t *max_tx_time,
uint16_t *max_rx_octets, uint16_t *max_rx_time);
uint8_t radio_rx_get(struct radio_pdu_node_rx **radio_pdu_node_rx,
uint16_t *handle);
void radio_rx_dequeue(void);

View file

@ -55,7 +55,7 @@ struct connection {
uint16_t latency;
uint16_t latency_prepare;
uint16_t latency_event;
uint16_t sug_tx_octets;
uint16_t default_tx_octets;
uint16_t max_tx_octets;
uint16_t max_rx_octets;
uint16_t supervision_reload;