diff --git a/nimble/controller/include/controller/ble_ll_hci.h b/nimble/controller/include/controller/ble_ll_hci.h index 7421e77a0..ff6680504 100644 --- a/nimble/controller/include/controller/ble_ll_hci.h +++ b/nimble/controller/include/controller/ble_ll_hci.h @@ -38,7 +38,7 @@ extern "C" { */ #define BLE_LL_CFG_NUM_HCI_CMD_PKTS (1) -typedef void (*ble_ll_hci_post_cmd_complete_cb)(void); +typedef void (*ble_ll_hci_post_cmd_complete_cb)(void *user_data); #if MYNEWT_VAL(BLE_LL_HCI_VS) typedef int (* ble_ll_hci_vs_cb_t)(uint16_t ocf, @@ -81,6 +81,9 @@ int ble_ll_hci_check_dle(uint16_t max_octets, uint16_t max_time); void ble_ll_hci_supp_cmd_get(uint8_t *buf); +/* Used to set post HCI command hook */ +void ble_ll_hci_post_cmd_cb_set(ble_ll_hci_post_cmd_complete_cb cb, void *user_data); + #if MYNEWT_VAL(BLE_LL_HCI_VS) void ble_ll_hci_vs_register(struct ble_ll_hci_vs_cmd *cmds, uint32_t num_cmds); #endif diff --git a/nimble/controller/include/controller/ble_ll_sync.h b/nimble/controller/include/controller/ble_ll_sync.h index 8002d2a31..b4f9e944d 100644 --- a/nimble/controller/include/controller/ble_ll_sync.h +++ b/nimble/controller/include/controller/ble_ll_sync.h @@ -34,7 +34,7 @@ struct ble_ll_scan_addr_data; struct ble_ll_sync_sm; int ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb); +int ble_ll_sync_cancel(void); int ble_ll_sync_terminate(const uint8_t *cmdbuf, uint8_t len); int ble_ll_sync_list_add(const uint8_t *cmdbuf, uint8_t len); int ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len); diff --git a/nimble/controller/src/ble_ll_conn_hci.c b/nimble/controller/src/ble_ll_conn_hci.c index 5aea53b87..175a64266 100644 --- a/nimble/controller/src/ble_ll_conn_hci.c +++ b/nimble/controller/src/ble_ll_conn_hci.c @@ -946,6 +946,34 @@ ble_ll_conn_hci_read_rem_features(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_SUCCESS; } +static bool +ble_ll_conn_params_in_range(struct ble_ll_conn_sm *connsm, + const struct ble_hci_le_conn_update_cp *cmd) +{ + if (!IN_RANGE(connsm->conn_itvl, le16toh(cmd->conn_itvl_min), + le16toh(cmd->conn_itvl_max))) { + return false; + } + + if (connsm->periph_latency != le16toh(cmd->conn_latency)) { + return false; + } + + if (connsm->supervision_tmo != le16toh(cmd->supervision_timeout)) { + return false; + } + + return true; +} + +static void +ble_ll_conn_hci_update_complete_event(void *user_data) +{ + struct ble_ll_conn_sm *connsm = user_data; + + ble_ll_hci_ev_conn_update(connsm, BLE_ERR_SUCCESS); +} + /** * Called to process a connection update command. * @@ -962,6 +990,7 @@ ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) uint16_t handle; struct ble_ll_conn_sm *connsm; struct hci_conn_update *hcu; + uint16_t max_ce_len; /* * XXX: must deal with peripheral not supporting this feature and using @@ -979,6 +1008,26 @@ ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_UNK_CONN_ID; } + /* if current connection parameters fit updated values we don't have to + * trigger LL procedure and just update local values (Min/Max CE Length) + * + * Note that this is also allowed for CSS as nothing changes WRT connections + * scheduling. + */ + if (ble_ll_conn_params_in_range(connsm, cmd)) { + max_ce_len = le16toh(cmd->max_ce_len); + + if (le16toh(cmd->min_ce_len) > max_ce_len) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + connsm->max_ce_len_ticks = ble_ll_tmr_u2t_up(max_ce_len * BLE_LL_CONN_CE_USECS); + + ble_ll_hci_post_cmd_cb_set(ble_ll_conn_hci_update_complete_event, connsm); + + return BLE_ERR_SUCCESS; + } + #if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) /* Do not allow connection update if css in enabled, we only allow to move * anchor point (i.e. change slot) via dedicated HCI command. @@ -1198,7 +1247,7 @@ done: * safe to use g_ble_ll_conn_comp_ev */ static void -ble_ll_conn_hci_cancel_conn_complete_event(void) +ble_ll_conn_hci_cancel_conn_complete_event(void *user_data) { BLE_LL_ASSERT(g_ble_ll_conn_comp_ev); @@ -1216,7 +1265,7 @@ ble_ll_conn_hci_cancel_conn_complete_event(void) * @return int */ int -ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) +ble_ll_conn_create_cancel(void) { int rc; struct ble_ll_conn_sm *connsm; @@ -1236,7 +1285,7 @@ ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) ble_ll_scan_sm_stop(1); ble_ll_conn_end(connsm, BLE_ERR_UNK_CONN_ID); - *post_cmd_cb = ble_ll_conn_hci_cancel_conn_complete_event; + ble_ll_hci_post_cmd_cb_set(ble_ll_conn_hci_cancel_conn_complete_event, NULL); rc = BLE_ERR_SUCCESS; } else { diff --git a/nimble/controller/src/ble_ll_conn_priv.h b/nimble/controller/src/ble_ll_conn_priv.h index 023881d0f..a3e1cc4bb 100644 --- a/nimble/controller/src/ble_ll_conn_priv.h +++ b/nimble/controller/src/ble_ll_conn_priv.h @@ -204,7 +204,7 @@ int ble_ll_conn_hci_param_rr(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_conn_hci_param_nrr(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb); +int ble_ll_conn_create_cancel(void); void ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm); void ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status, uint8_t *evbuf, struct ble_ll_adv_sm *advsm); diff --git a/nimble/controller/src/ble_ll_hci.c b/nimble/controller/src/ble_ll_hci.c index 37ba94c61..0f92654b0 100644 --- a/nimble/controller/src/ble_ll_hci.c +++ b/nimble/controller/src/ble_ll_hci.c @@ -56,6 +56,9 @@ static uint64_t g_ble_ll_hci_event_mask2; static int16_t rx_path_pwr_compensation; static int16_t tx_path_pwr_compensation; +static ble_ll_hci_post_cmd_complete_cb hci_cmd_post_cb = NULL; +static void *hci_cmd_post_cb_user_data = NULL; + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) static enum { ADV_MODE_ANY, @@ -879,8 +882,7 @@ ble_ll_hci_le_set_host_chan_class(const uint8_t *cmdbuf, uint8_t len) */ static int ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, - uint8_t *rspbuf, uint8_t *rsplen, - ble_ll_hci_post_cmd_complete_cb *cb) + uint8_t *rspbuf, uint8_t *rsplen) { int rc; @@ -960,7 +962,7 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, break; case BLE_HCI_OCF_LE_CREATE_CONN_CANCEL: if (len == 0) { - rc = ble_ll_conn_create_cancel(cb); + rc = ble_ll_conn_create_cancel(); } break; #endif @@ -1187,7 +1189,7 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, break; case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC_CANCEL: if (len == 0) { - rc = ble_ll_sync_cancel(cb); + rc = ble_ll_sync_cancel(); } break; case BLE_HCI_OCF_LE_PERIODIC_ADV_TERM_SYNC: @@ -1736,6 +1738,15 @@ ble_ll_hci_cmd_fake_dual_mode(uint16_t opcode, uint8_t *cmdbuf, uint8_t len, } #endif + +void +ble_ll_hci_post_cmd_cb_set(ble_ll_hci_post_cmd_complete_cb cb, void *user_data) +{ + BLE_LL_ASSERT(hci_cmd_post_cb == NULL); + hci_cmd_post_cb = cb; + hci_cmd_post_cb_user_data = user_data; +} + /** * Called to process an HCI command from the host. * @@ -1750,7 +1761,6 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev) struct ble_hci_cmd *cmd; uint16_t opcode; uint16_t ocf; - ble_ll_hci_post_cmd_complete_cb post_cb = NULL; struct ble_hci_ev *hci_ev; struct ble_hci_ev_command_status *cmd_status; struct ble_hci_ev_command_complete *cmd_complete; @@ -1817,7 +1827,7 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev) rc = ble_ll_hci_status_params_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen); break; case BLE_HCI_OGF_LE: - rc = ble_ll_hci_le_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen, &post_cb); + rc = ble_ll_hci_le_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen); break; #if MYNEWT_VAL(BLE_LL_HCI_VS) case BLE_HCI_OGF_VENDOR: @@ -1875,8 +1885,11 @@ send_cc_cs: ble_ll_hci_event_send(hci_ev); /* Call post callback if set by command handler */ - if (post_cb) { - post_cb(); + if (hci_cmd_post_cb) { + hci_cmd_post_cb(hci_cmd_post_cb_user_data); + + hci_cmd_post_cb = NULL; + hci_cmd_post_cb_user_data = NULL; } BLE_LL_DEBUG_GPIO(HCI_CMD, 0); diff --git a/nimble/controller/src/ble_ll_sync.c b/nimble/controller/src/ble_ll_sync.c index 31791dce3..7016dfed0 100644 --- a/nimble/controller/src/ble_ll_sync.c +++ b/nimble/controller/src/ble_ll_sync.c @@ -1559,13 +1559,13 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len) } static void -ble_ll_sync_cancel_complete_event(void) +ble_ll_sync_cancel_complete_event(void *user_data) { ble_ll_sync_est_event_failed(BLE_ERR_OPERATION_CANCELLED); } int -ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) +ble_ll_sync_cancel(void) { struct ble_ll_sync_sm *sm; os_sr_t sr; @@ -1596,7 +1596,7 @@ ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) OS_EXIT_CRITICAL(sr); /* g_ble_ll_sync_create_comp_ev will be cleared by this callback */ - *post_cmd_cb = ble_ll_sync_cancel_complete_event; + ble_ll_hci_post_cmd_cb_set(ble_ll_sync_cancel_complete_event, NULL); return BLE_ERR_SUCCESS; }