Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nimble/ll: Power Control Request feature support #1883

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions nimble/controller/include/controller/ble_ll_conn.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ struct ble_ll_conn_sm_flags {
#if MYNEWT_VAL(BLE_LL_CONN_INIT_AUTO_DLE)
uint32_t pending_initiate_dle : 1;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
uint32_t power_request_host_w4event : 1;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
uint8_t subrate_trans : 1;
uint8_t subrate_ind_txd : 1;
Expand Down Expand Up @@ -201,6 +204,38 @@ struct ble_ll_conn_subrate_req_params {
uint16_t supervision_tmo;
};

#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
struct ble_ll_conn_power_control_data {
/*
* Current local TxPower.
* Updated when PHY is changed or when current PHY's TxPower is changed
*/
int8_t curr_local_tx_power;

/*
* Stores remote TxPower for each PHY mode.
* Updated when power control response PDU or power change IND is received
*/
int8_t remote_tx_power[BLE_PHY_NUM_MODE];

/* Stores local TxPower for each PHY mode */
int8_t local_tx_power[BLE_PHY_NUM_MODE];

/* Stores min max flags for each PHY mode */
int8_t local_min_max[BLE_PHY_NUM_MODE];

/* Indicates on which PHY we requested Power Control Request Procedure */
uint8_t req_phy_mode;

/* Stores delta for Power Control Request */
int8_t req_delta;

/* Flags that indicate if reports are enabled */
uint8_t local_reports_enabled : 1;
uint8_t remote_reports_enabled : 1;
};
#endif

/* Connection state machine */
struct ble_ll_conn_sm
{
Expand Down Expand Up @@ -397,6 +432,10 @@ struct ble_ll_conn_sm
uint16_t css_slot_idx_pending;
uint8_t css_period_idx;
#endif

#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
struct ble_ll_conn_power_control_data pwr_ctrl;
#endif
};

/* Role */
Expand Down
4 changes: 4 additions & 0 deletions nimble/controller/include/controller/ble_ll_ctrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ extern "C" {
#define BLE_LL_CTRL_PROC_SUBRATE_REQ (12)
#define BLE_LL_CTRL_PROC_SUBRATE_UPDATE (13)
#define BLE_LL_CTRL_PROC_NUM (14)
#define BLE_LL_CTRL_PROC_POWER_CTRL_REQ (15)
#define BLE_LL_CTRL_PROC_IDLE (255)

/* Checks if a particular control procedure is running */
Expand Down Expand Up @@ -338,6 +339,9 @@ void ble_ll_hci_ev_send_vs_assert(const char *file, uint32_t line);
void ble_ll_hci_ev_send_vs_printf(uint8_t id, const char *fmt, ...);
void ble_ll_hci_ev_send_vs_llcp_trace(uint8_t type, uint16_t handle, uint16_t count,
void *pdu, size_t length);
void ble_ll_hci_ev_transmit_power_report(struct ble_ll_conn_sm *connsm, uint8_t status,
uint8_t reason, uint8_t phy_mode, int8_t tx_power,
uint8_t tx_power_flags, int8_t delta);

uint8_t ble_ll_ctrl_phy_tx_transition_get(uint8_t phy_mask);
uint8_t ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask);
Expand Down
4 changes: 4 additions & 0 deletions nimble/controller/src/ble_ll.c
Original file line number Diff line number Diff line change
Expand Up @@ -1935,6 +1935,10 @@ ble_ll_init(void)
features |= BLE_LL_FEAT_CS_PCT_QUALITY_IND;
#endif

#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
features |= BLE_LL_FEAT_POWER_CTRL_REQ;
#endif

#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT)
features |= BLE_LL_FEAT_PERIODIC_ADV_ADI;
#endif
Expand Down
58 changes: 58 additions & 0 deletions nimble/controller/src/ble_ll_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1526,8 +1526,12 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
ble_phy_mode_set(connsm->phy_data.tx_phy_mode, connsm->phy_data.rx_phy_mode);
#endif

#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
ble_ll_tx_power_set(connsm->pwr_ctrl.curr_local_tx_power);
#else
/* Set the power */
ble_ll_tx_power_set(g_ble_ll_tx_power);
#endif

switch (connsm->conn_role) {
#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)
Expand Down Expand Up @@ -1746,6 +1750,21 @@ ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm)
}
#endif

#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
static void
ble_ll_conn_init_tx_power(struct ble_ll_conn_sm *connsm)
{
int i;

for (i = 0; i < BLE_PHY_NUM_MODE; i++) {
connsm->pwr_ctrl.local_tx_power[i] = g_ble_ll_tx_power;
connsm->pwr_ctrl.remote_tx_power[i] = 127;
}

connsm->pwr_ctrl.curr_local_tx_power = g_ble_ll_tx_power;
}
#endif

#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)
static void
ble_ll_conn_central_common_init(struct ble_ll_conn_sm *connsm)
Expand Down Expand Up @@ -2018,6 +2037,10 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm)
connsm->phy_tx_transition = 0;
#endif

#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
ble_ll_conn_init_tx_power(connsm);
#endif

/* Reset current control procedure */
connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
connsm->pending_ctrl_procs = 0;
Expand Down Expand Up @@ -2325,6 +2348,38 @@ ble_ll_conn_move_anchor(struct ble_ll_conn_sm *connsm, uint16_t offset)
}
#endif

#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
void
ble_ll_conn_update_current_local_tx_power(struct ble_ll_conn_sm *connsm)
{
uint8_t curr_phy_mode;
int8_t new_tx_power;
int8_t delta;

#if MYNEWT_VAL(BLE_LL_PHY)
curr_phy_mode = connsm->phy_data.tx_phy_mode;
#else
curr_phy_mode = BLE_PHY_MODE_1M;
#endif

new_tx_power = connsm->pwr_ctrl.local_tx_power[curr_phy_mode];
if (connsm->pwr_ctrl.curr_local_tx_power == new_tx_power) {
return;
}

delta = new_tx_power - connsm->pwr_ctrl.curr_local_tx_power;
connsm->pwr_ctrl.curr_local_tx_power = new_tx_power;

if (connsm->pwr_ctrl.local_reports_enabled) {
ble_ll_hci_ev_transmit_power_report(connsm, BLE_ERR_SUCCESS, 0x00,
curr_phy_mode,
connsm->pwr_ctrl.curr_local_tx_power,
connsm->pwr_ctrl.local_min_max[curr_phy_mode],
delta);
}
}
#endif

/**
* Called to move to the next connection event.
*
Expand Down Expand Up @@ -2659,6 +2714,9 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
connsm->phy_data.tx_phy_mode =
ble_ll_phy_to_phy_mode(connsm->phy_data.cur_tx_phy,
connsm->phy_data.pref_opts);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
ble_ll_conn_update_current_local_tx_power(connsm);
#endif
}

if (connsm->phy_data.new_rx_phy) {
Expand Down
150 changes: 150 additions & 0 deletions nimble/controller/src/ble_ll_conn_hci.c
Original file line number Diff line number Diff line change
Expand Up @@ -2176,4 +2176,154 @@ ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len)
return BLE_ERR_SUCCESS;
}
#endif

#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
int
ble_ll_conn_hci_enhanced_read_tx_power_level(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen)
{
const struct ble_hci_le_enh_read_transmit_power_level_cp *cmd = (const void *) cmdbuf;
struct ble_hci_le_enh_read_transmit_power_level_rp *rsp = (void *) rspbuf;
struct ble_ll_conn_sm *connsm;
uint8_t phy_mode;
int rc;

if (len != sizeof(*cmd)) {
rc = BLE_ERR_INV_HCI_CMD_PARMS;
goto done;
}

switch (cmd->phy) {
case 0x1:
phy_mode = BLE_PHY_MODE_1M;
break;
#if MYNEWT_VAL(BLE_PHY_2M)
case 0x2:
phy_mode = BLE_PHY_MODE_2M;
break;
#endif
#if MYNEWT_VAL(BLE_PHY_CODED)
case 0x3:
phy_mode = BLE_PHY_MODE_CODED_500KBPS;
break;
case 0x4:
phy_mode = BLE_PHY_MODE_CODED_125KBPS;
break;
#endif
default:
rc = BLE_ERR_UNSUPPORTED;
goto done;
}

connsm = ble_ll_conn_find_by_handle(le16toh(cmd->conn_handle));
if (!connsm) {
rc = BLE_ERR_UNK_CONN_ID;
goto done;
}

rsp->phy = cmd->phy;
rsp->curr_tx_power_level = connsm->pwr_ctrl.local_tx_power[phy_mode];
rsp->max_tx_power_level = ble_phy_tx_power_round(INT8_MAX);

rc = BLE_ERR_SUCCESS;
done:
*rsplen = sizeof(*rsp);
rsp->conn_handle = cmd->conn_handle;
return rc;
}

int
ble_ll_conn_hci_read_remote_tx_power_level(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_read_remote_transmit_power_level_cp *cmd = (const void *) cmdbuf;
struct ble_ll_conn_sm *connsm;

if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}

connsm = ble_ll_conn_find_by_handle(le16toh(cmd->conn_handle));
if (!connsm) {
return BLE_ERR_UNK_CONN_ID;
}

switch (cmd->phy) {
case 0x1:
connsm->pwr_ctrl.req_phy_mode = BLE_PHY_MODE_1M;
break;
#if MYNEWT_VAL(BLE_PHY_2M)
case 0x2:
connsm->pwr_ctrl.req_phy_mode = BLE_PHY_MODE_2M;
break;
#endif
#if MYNEWT_VAL(BLE_PHY_CODED)
case 0x3:
connsm->pwr_ctrl.req_phy_mode = BLE_PHY_MODE_CODED_500KBPS;
break;
case 0x4:
connsm->pwr_ctrl.req_phy_mode = BLE_PHY_MODE_CODED_125KBPS;
break;
#endif
default:
return BLE_ERR_UNSUPPORTED;
}

connsm->flags.power_request_host_w4event = 1;

ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_POWER_CTRL_REQ, NULL);

return BLE_ERR_SUCCESS;
}

int
ble_ll_conn_hci_set_tx_power_report_enable(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen)
{
const struct ble_hci_le_set_transmit_power_report_enable_cp *cmd = (const void *) cmdbuf;
struct ble_hci_le_set_transmit_power_report_enable_rp *rsp = (void *) rspbuf;
struct ble_ll_conn_sm *connsm;
uint8_t send_req;
int i;
int rc;

if (len != sizeof(*cmd)) {
rc = BLE_ERR_INV_HCI_CMD_PARMS;
goto done;
}

connsm = ble_ll_conn_find_by_handle(le16toh(cmd->conn_handle));
if (!connsm) {
rc = BLE_ERR_UNK_CONN_ID;
goto done;
}

if (cmd->local_enable & 0xfe || cmd->remote_enable & 0xfe) {
rc = BLE_ERR_INV_HCI_CMD_PARMS;
goto done;
}

connsm->pwr_ctrl.local_reports_enabled = cmd->local_enable;
connsm->pwr_ctrl.remote_reports_enabled = cmd->remote_enable;

send_req = 1;
for (i = 0; i < BLE_PHY_NUM_MODE; i++) {
if (connsm->pwr_ctrl.remote_tx_power[i] != 127) {
send_req = 0;
break;
}
}

if (send_req) {
connsm->pwr_ctrl.req_phy_mode = connsm->phy_data.rx_phy_mode;
ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_POWER_CTRL_REQ, NULL);
}

rc = BLE_ERR_SUCCESS;

done:
*rsplen = sizeof(*rsp);
rsp->conn_handle = cmd->conn_handle;
return rc;
}
#endif
#endif
9 changes: 9 additions & 0 deletions nimble/controller/src/ble_ll_conn_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,15 @@ int ble_ll_set_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len,
int ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len);
#endif

#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
int ble_ll_conn_hci_enhanced_read_tx_power_level(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_read_remote_tx_power_level(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_set_tx_power_report_enable(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
void ble_ll_conn_update_current_local_tx_power(struct ble_ll_conn_sm *connsm);
#endif

#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED)
void ble_ll_conn_css_set_next_slot(uint16_t slot_idx);
uint16_t ble_ll_conn_css_get_next_slot(void);
Expand Down
Loading
Loading