Skip to content

Commit 5fb3762

Browse files
committed
nimble/ll: Power Control Request feature support
1 parent b73cbab commit 5fb3762

File tree

11 files changed

+547
-0
lines changed

11 files changed

+547
-0
lines changed

nimble/controller/include/controller/ble_ll_conn.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ struct ble_ll_conn_sm_flags {
131131
#if MYNEWT_VAL(BLE_LL_CONN_INIT_AUTO_DLE)
132132
uint32_t pending_initiate_dle : 1;
133133
#endif
134+
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
135+
uint32_t power_request_host_w4event : 1;
136+
#endif
134137
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
135138
uint8_t subrate_trans : 1;
136139
uint8_t subrate_ind_txd : 1;
@@ -201,6 +204,38 @@ struct ble_ll_conn_subrate_req_params {
201204
uint16_t supervision_tmo;
202205
};
203206

207+
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
208+
struct ble_ll_conn_power_control_data {
209+
/*
210+
* Current local TxPower.
211+
* Updated when PHY is changed or when current PHY's TxPower is changed
212+
*/
213+
int8_t curr_local_tx_power;
214+
215+
/*
216+
* Stores remote TxPower for each PHY mode.
217+
* Updated when power control response PDU or power change IND is received
218+
*/
219+
int8_t remote_tx_power[BLE_PHY_NUM_MODE];
220+
221+
/* Stores local TxPower for each PHY mode */
222+
int8_t local_tx_power[BLE_PHY_NUM_MODE];
223+
224+
/* Stores min max flags for each PHY mode */
225+
int8_t local_min_max[BLE_PHY_NUM_MODE];
226+
227+
/* Indicates on which PHY we requested Power Control Request Procedure */
228+
uint8_t req_phy_mode;
229+
230+
/* Stores delta for Power Control Request */
231+
int8_t req_delta;
232+
233+
/* Flags that indicate if reports are enabled */
234+
uint8_t local_reports_enabled : 1;
235+
uint8_t remote_reports_enabled : 1;
236+
};
237+
#endif
238+
204239
/* Connection state machine */
205240
struct ble_ll_conn_sm
206241
{
@@ -397,6 +432,10 @@ struct ble_ll_conn_sm
397432
uint16_t css_slot_idx_pending;
398433
uint8_t css_period_idx;
399434
#endif
435+
436+
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
437+
struct ble_ll_conn_power_control_data pwr_ctrl;
438+
#endif
400439
};
401440

402441
/* Role */

nimble/controller/include/controller/ble_ll_ctrl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ extern "C" {
4444
#define BLE_LL_CTRL_PROC_SUBRATE_REQ (12)
4545
#define BLE_LL_CTRL_PROC_SUBRATE_UPDATE (13)
4646
#define BLE_LL_CTRL_PROC_NUM (14)
47+
#define BLE_LL_CTRL_PROC_POWER_CTRL_REQ (15)
4748
#define BLE_LL_CTRL_PROC_IDLE (255)
4849

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

342346
uint8_t ble_ll_ctrl_phy_tx_transition_get(uint8_t phy_mask);
343347
uint8_t ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask);

nimble/controller/src/ble_ll.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1935,6 +1935,10 @@ ble_ll_init(void)
19351935
features |= BLE_LL_FEAT_CS_PCT_QUALITY_IND;
19361936
#endif
19371937

1938+
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
1939+
features |= BLE_LL_FEAT_POWER_CTRL_REQ;
1940+
#endif
1941+
19381942
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT)
19391943
features |= BLE_LL_FEAT_PERIODIC_ADV_ADI;
19401944
#endif

nimble/controller/src/ble_ll_conn.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,8 +1526,12 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
15261526
ble_phy_mode_set(connsm->phy_data.tx_phy_mode, connsm->phy_data.rx_phy_mode);
15271527
#endif
15281528

1529+
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
1530+
ble_ll_tx_power_set(connsm->pwr_ctrl.curr_local_tx_power);
1531+
#else
15291532
/* Set the power */
15301533
ble_ll_tx_power_set(g_ble_ll_tx_power);
1534+
#endif
15311535

15321536
switch (connsm->conn_role) {
15331537
#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)
@@ -1746,6 +1750,21 @@ ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm)
17461750
}
17471751
#endif
17481752

1753+
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
1754+
static void
1755+
ble_ll_conn_init_tx_power(struct ble_ll_conn_sm *connsm)
1756+
{
1757+
int i;
1758+
1759+
for (i = 0; i < BLE_PHY_NUM_MODE; i++) {
1760+
connsm->pwr_ctrl.local_tx_power[i] = g_ble_ll_tx_power;
1761+
connsm->pwr_ctrl.remote_tx_power[i] = 127;
1762+
}
1763+
1764+
connsm->pwr_ctrl.curr_local_tx_power = g_ble_ll_tx_power;
1765+
}
1766+
#endif
1767+
17491768
#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)
17501769
static void
17511770
ble_ll_conn_central_common_init(struct ble_ll_conn_sm *connsm)
@@ -2018,6 +2037,10 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm)
20182037
connsm->phy_tx_transition = 0;
20192038
#endif
20202039

2040+
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
2041+
ble_ll_conn_init_tx_power(connsm);
2042+
#endif
2043+
20212044
/* Reset current control procedure */
20222045
connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
20232046
connsm->pending_ctrl_procs = 0;
@@ -2325,6 +2348,38 @@ ble_ll_conn_move_anchor(struct ble_ll_conn_sm *connsm, uint16_t offset)
23252348
}
23262349
#endif
23272350

2351+
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
2352+
void
2353+
ble_ll_conn_update_current_local_tx_power(struct ble_ll_conn_sm *connsm)
2354+
{
2355+
uint8_t curr_phy_mode;
2356+
int8_t new_tx_power;
2357+
int8_t delta;
2358+
2359+
#if MYNEWT_VAL(BLE_LL_PHY)
2360+
curr_phy_mode = connsm->phy_data.tx_phy_mode;
2361+
#else
2362+
curr_phy_mode = BLE_PHY_MODE_1M;
2363+
#endif
2364+
2365+
new_tx_power = connsm->pwr_ctrl.local_tx_power[curr_phy_mode];
2366+
if (connsm->pwr_ctrl.curr_local_tx_power == new_tx_power) {
2367+
return;
2368+
}
2369+
2370+
delta = new_tx_power - connsm->pwr_ctrl.curr_local_tx_power;
2371+
connsm->pwr_ctrl.curr_local_tx_power = new_tx_power;
2372+
2373+
if (connsm->pwr_ctrl.local_reports_enabled) {
2374+
ble_ll_hci_ev_transmit_power_report(connsm, BLE_ERR_SUCCESS, 0x00,
2375+
curr_phy_mode,
2376+
connsm->pwr_ctrl.curr_local_tx_power,
2377+
connsm->pwr_ctrl.local_min_max[curr_phy_mode],
2378+
delta);
2379+
}
2380+
}
2381+
#endif
2382+
23282383
/**
23292384
* Called to move to the next connection event.
23302385
*
@@ -2659,6 +2714,9 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
26592714
connsm->phy_data.tx_phy_mode =
26602715
ble_ll_phy_to_phy_mode(connsm->phy_data.cur_tx_phy,
26612716
connsm->phy_data.pref_opts);
2717+
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
2718+
ble_ll_conn_update_current_local_tx_power(connsm);
2719+
#endif
26622720
}
26632721

26642722
if (connsm->phy_data.new_rx_phy) {

nimble/controller/src/ble_ll_conn_hci.c

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2176,4 +2176,149 @@ ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len)
21762176
return BLE_ERR_SUCCESS;
21772177
}
21782178
#endif
2179+
2180+
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
2181+
int
2182+
ble_ll_conn_hci_enhanced_read_tx_power_level(const uint8_t *cmdbuf, uint8_t len,
2183+
uint8_t *rspbuf, uint8_t *rsplen)
2184+
{
2185+
const struct ble_hci_le_enh_read_transmit_power_level_cp *cmd = (const void *) cmdbuf;
2186+
struct ble_hci_le_enh_read_transmit_power_level_rp *rsp = (void *) rspbuf;
2187+
struct ble_ll_conn_sm *connsm;
2188+
uint8_t phy_mode;
2189+
int rc;
2190+
2191+
if (len != sizeof(*cmd)) {
2192+
rc = BLE_ERR_INV_HCI_CMD_PARMS;
2193+
goto done;
2194+
}
2195+
2196+
switch (cmd->phy) {
2197+
case 0x1:
2198+
phy_mode = BLE_PHY_MODE_1M;
2199+
break;
2200+
#if MYNEWT_VAL(BLE_PHY_2M)
2201+
case 0x2:
2202+
phy_mode = BLE_PHY_MODE_2M;
2203+
break;
2204+
#endif
2205+
#if MYNEWT_VAL(BLE_PHY_CODED)
2206+
case 0x3:
2207+
phy_mode = BLE_PHY_MODE_CODED_500KBPS;
2208+
break;
2209+
case 0x4:
2210+
phy_mode = BLE_PHY_MODE_CODED_125KBPS;
2211+
break;
2212+
#endif
2213+
default:
2214+
rc = BLE_ERR_UNSUPPORTED;
2215+
goto done;
2216+
}
2217+
2218+
connsm = ble_ll_conn_find_by_handle(le16toh(cmd->conn_handle));
2219+
if (!connsm) {
2220+
rc = BLE_ERR_UNK_CONN_ID;
2221+
goto done;
2222+
}
2223+
2224+
rsp->phy = cmd->phy;
2225+
rsp->curr_tx_power_level = connsm->pwr_ctrl.local_tx_power[phy_mode];
2226+
rsp->max_tx_power_level = ble_phy_tx_power_round(INT8_MAX);
2227+
2228+
rc = BLE_ERR_SUCCESS;
2229+
done:
2230+
*rsplen = sizeof(*rsp);
2231+
rsp->conn_handle = cmd->conn_handle;
2232+
return rc;
2233+
}
2234+
2235+
int
2236+
ble_ll_conn_hci_read_remote_tx_power_level(const uint8_t *cmdbuf, uint8_t len)
2237+
{
2238+
const struct ble_hci_le_read_remote_transmit_power_level_cp *cmd = (const void *) cmdbuf;
2239+
struct ble_ll_conn_sm *connsm;
2240+
2241+
if (len != sizeof(*cmd)) {
2242+
return BLE_ERR_INV_HCI_CMD_PARMS;
2243+
}
2244+
2245+
connsm = ble_ll_conn_find_by_handle(le16toh(cmd->conn_handle));
2246+
if (!connsm) {
2247+
return BLE_ERR_UNK_CONN_ID;
2248+
}
2249+
2250+
switch (cmd->phy) {
2251+
case 0x1:
2252+
connsm->pwr_ctrl.req_phy_mode = BLE_PHY_MODE_1M;
2253+
break;
2254+
#if MYNEWT_VAL(BLE_PHY_2M)
2255+
case 0x2:
2256+
connsm->pwr_ctrl.req_phy_mode = BLE_PHY_MODE_2M;
2257+
break;
2258+
#endif
2259+
#if MYNEWT_VAL(BLE_PHY_CODED)
2260+
case 0x3:
2261+
connsm->pwr_ctrl.req_phy_mode = BLE_PHY_MODE_CODED_500KBPS;
2262+
break;
2263+
case 0x4:
2264+
connsm->pwr_ctrl.req_phy_mode = BLE_PHY_MODE_CODED_125KBPS;
2265+
break;
2266+
#endif
2267+
default:
2268+
return BLE_ERR_UNSUPPORTED;
2269+
}
2270+
2271+
connsm->flags.power_request_host_w4event = 1;
2272+
2273+
ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_POWER_CTRL_REQ, NULL);
2274+
2275+
return BLE_ERR_SUCCESS;
2276+
}
2277+
2278+
int
2279+
ble_ll_conn_hci_set_tx_power_report_enable(const uint8_t *cmdbuf, uint8_t len,
2280+
uint8_t *rspbuf, uint8_t *rsplen)
2281+
{
2282+
const struct ble_hci_le_set_transmit_power_report_enable_cp *cmd = (const void *) cmdbuf;
2283+
struct ble_hci_le_set_transmit_power_report_enable_rp *rsp = (void *) rspbuf;
2284+
struct ble_ll_conn_sm *connsm;
2285+
uint8_t send_req;
2286+
int i;
2287+
int rc;
2288+
2289+
if (len != sizeof(*cmd)) {
2290+
rc = BLE_ERR_INV_HCI_CMD_PARMS;
2291+
goto done;
2292+
}
2293+
2294+
connsm = ble_ll_conn_find_by_handle(le16toh(cmd->conn_handle));
2295+
if (!connsm) {
2296+
rc = BLE_ERR_UNK_CONN_ID;
2297+
goto done;
2298+
}
2299+
2300+
connsm->pwr_ctrl.local_reports_enabled = cmd->local_enable;
2301+
connsm->pwr_ctrl.remote_reports_enabled = cmd->remote_enable;
2302+
2303+
send_req = 1;
2304+
for (i = 0; i < BLE_PHY_NUM_MODE; i++) {
2305+
if (connsm->pwr_ctrl.remote_tx_power[i] != 127) {
2306+
send_req = 0;
2307+
break;
2308+
}
2309+
}
2310+
2311+
if (send_req) {
2312+
connsm->pwr_ctrl.req_phy_mode = connsm->phy_data.rx_phy_mode;
2313+
ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_POWER_CTRL_REQ, NULL);
2314+
}
2315+
2316+
rc = BLE_ERR_SUCCESS;
2317+
2318+
done:
2319+
*rsplen = sizeof(*rsp);
2320+
rsp->conn_handle = cmd->conn_handle;
2321+
return rc;
2322+
}
2323+
#endif
21792324
#endif

nimble/controller/src/ble_ll_conn_priv.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,15 @@ int ble_ll_set_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len,
274274
int ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len);
275275
#endif
276276

277+
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_POWER_CONTROL)
278+
int ble_ll_conn_hci_enhanced_read_tx_power_level(const uint8_t *cmdbuf, uint8_t len,
279+
uint8_t *rspbuf, uint8_t *rsplen);
280+
int ble_ll_conn_hci_read_remote_tx_power_level(const uint8_t *cmdbuf, uint8_t len);
281+
int ble_ll_conn_hci_set_tx_power_report_enable(const uint8_t *cmdbuf, uint8_t len,
282+
uint8_t *rspbuf, uint8_t *rsplen);
283+
void ble_ll_conn_update_current_local_tx_power(struct ble_ll_conn_sm *connsm);
284+
#endif
285+
277286
#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED)
278287
void ble_ll_conn_css_set_next_slot(uint16_t slot_idx);
279288
uint16_t ble_ll_conn_css_get_next_slot(void);

0 commit comments

Comments
 (0)