add APIs for multiple connect

This commit is contained in:
Shen Weilong
2024-02-20 12:22:49 +05:30
committed by Abhinav Kudnar
parent 3a1db72f83
commit d714e24fb7
2 changed files with 265 additions and 1 deletions
+85
View File
@@ -1141,6 +1141,53 @@ struct ble_gap_event {
};
};
#if MYNEWT_VAL(OPTIMIZE_MULTI_CONN)
/** @brief multiple Connection parameters */
struct ble_gap_multi_conn_params {
/** The type of address the stack should use for itself. */
uint8_t own_addr_type;
#if MYNEWT_VAL(BLE_EXT_ADV)
/** Define on which PHYs connection attempt should be done */
uint8_t phy_mask;
#endif // MYNEWT_VAL(BLE_EXT_ADV)
/** The address of the peer to connect to. */
const ble_addr_t *peer_addr;
/** The duration of the discovery procedure. */
int32_t duration_ms;
/**
* Additional arguments specifying the particulars of the connect procedure. When extended
* adv is disabled or BLE_GAP_LE_PHY_1M_MASK is set in phy_mask this parameter can't be
* specified to null.
*/
const struct ble_gap_conn_params *phy_1m_conn_params;
#if MYNEWT_VAL(BLE_EXT_ADV)
/**
* Additional arguments specifying the particulars of the connect procedure. When
* BLE_GAP_LE_PHY_2M_MASK is set in phy_mask this parameter can't be specified to null.
*/
const struct ble_gap_conn_params *phy_2m_conn_params;
/**
* Additional arguments specifying the particulars of the connect procedure. When
* BLE_GAP_LE_PHY_CODED_MASK is set in phy_mask this parameter can't be specified to null.
*/
const struct ble_gap_conn_params *phy_coded_conn_params;
#endif // MYNEWT_VAL(BLE_EXT_ADV)
/**
* The minimum length occupied by this connection in scheduler. 0 means disable the
* optimization for this connection.
*/
uint32_t scheduling_len_us;
};
#endif // MYNEWT_VAL(OPTIMIZE_MULTI_CONN)
typedef int ble_gap_event_fn(struct ble_gap_event *event, void *arg);
typedef int ble_gap_conn_foreach_handle_fn(uint16_t conn_handle, void *arg);
@@ -1937,6 +1984,44 @@ int ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr,
const struct ble_gap_conn_params *phy_coded_conn_params,
ble_gap_event_fn *cb, void *cb_arg);
#if MYNEWT_VAL(OPTIMIZE_MULTI_CONN)
/**
* @brief Enable the optimization of multiple connections.
*
* @param enable Enable or disable the optimization.
* @param common_factor The greatest common factor of all intervals in 0.625ms units.
* @return 0 on success;
*
*/
int ble_gap_common_factor_set(bool enable, uint32_t common_factor);
/**
* Initiates an extended connect procedure with optimization.
*
* @param multi_conn_params Additional arguments specifying the particulars
* of the connect procedure.
* @param cb The callback to associate with this connect
* procedure. When the connect procedure
* completes, the result is reported through
* this callback. If the connect procedure
* succeeds, the connection inherits this
* callback as its event-reporting mechanism.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success;
* BLE_HS_EALREADY if a connection attempt is
* already in progress;
* BLE_HS_EBUSY if initiating a connection is not
* possible because scanning is in progress;
* BLE_HS_EDONE if the specified peer is already
* connected;
* Other nonzero on error.
*/
int ble_gap_multi_connect(struct ble_gap_multi_conn_params *multi_conn_params,
ble_gap_event_fn *cb, void *cb_arg);
#endif
/**
* Aborts a connect procedure in progress.
*
+180 -1
View File
@@ -235,6 +235,17 @@ static os_membuf_t ble_gap_update_entry_mem[
static struct os_mempool ble_gap_update_entry_pool;
static struct ble_gap_update_entry_list ble_gap_update_entries;
#if MYNEWT_VAL(OPTIMIZE_MULTI_CONN)
struct ble_gap_multi_conn_state
{
bool enabled;
bool scheduling_len_set;
uint32_t common_factor;
};
static struct ble_gap_multi_conn_state ble_gap_multi_conn;
#endif
static void ble_gap_update_entry_free(struct ble_gap_update_entry *entry);
#if NIMBLE_BLE_CONNECT
@@ -5337,6 +5348,15 @@ ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr,
STATS_INC(ble_gap_stats, initiate);
#if MYNEWT_VAL(OPTIMIZE_MULTI_CONN)
/* If the optimization is enabled, we disallow to invoke this API directly.
* See @ble_gap_multi_connect()
*/
if (ble_gap_multi_conn.enabled && !ble_gap_multi_conn.scheduling_len_set) {
return BLE_HS_EINVAL;
}
#endif // MYNEWT_VAL(OPTIMIZE_MULTI_CONN)
ble_hs_lock();
if (ble_gap_conn_active()) {
@@ -5466,6 +5486,15 @@ ble_gap_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr,
STATS_INC(ble_gap_stats, initiate);
#if MYNEWT_VAL(OPTIMIZE_MULTI_CONN)
/* If the optimization is enabled, we disallow to invoke this API directly.
* See @ble_gap_multi_connect()
*/
if (ble_gap_multi_conn.enabled && !ble_gap_multi_conn.scheduling_len_set) {
return BLE_HS_EINVAL;
}
#endif // MYNEWT_VAL(OPTIMIZE_MULTI_CONN)
ble_hs_lock();
if (ble_gap_conn_active()) {
@@ -5593,9 +5622,155 @@ done:
#else
return BLE_HS_ENOTSUP;
#endif
}
#if MYNEWT_VAL(OPTIMIZE_MULTI_CONN)
static bool
ble_gap_interval_is_integer_multiple(uint32_t min_itvl, uint32_t max_itvl)
{
if (max_itvl < ble_gap_multi_conn.common_factor) {
return false;
}
max_itvl = max_itvl - (max_itvl % ble_gap_multi_conn.common_factor);
if (max_itvl >= min_itvl) {
return true;
}
return false;
}
int
ble_gap_common_factor_set(bool enable, uint32_t common_factor)
{
int rc;
uint8_t vs_cmd[5];
if (!ble_hs_is_enabled()) {
return BLE_HS_EDISABLED;
}
if (enable) {
vs_cmd[0] = common_factor & 0xfful;
vs_cmd[1] = (common_factor >> 8) & 0xfful;
vs_cmd[2] = (common_factor >> 16) & 0xfful;
vs_cmd[3] = (common_factor >> 24) & 0xfful;
vs_cmd[4] = 1;
} else {
memset(vs_cmd, 0, sizeof(vs_cmd));
}
rc = ble_hs_hci_send_vs_cmd(0x10f, (const void *)vs_cmd, sizeof(vs_cmd), NULL, 0);
if (rc == 0) {
if (enable) {
ble_gap_multi_conn.enabled = true;
ble_gap_multi_conn.common_factor = common_factor;
} else {
ble_gap_multi_conn.enabled = false;
ble_gap_multi_conn.common_factor = 0;
}
}
return rc;
}
#if MYNEWT_VAL(BLE_ROLE_CENTRAL)
int
ble_gap_multi_connect(struct ble_gap_multi_conn_params *multi_conn_params,
ble_gap_event_fn *cb, void *cb_arg)
{
int rc;
uint8_t vs_cmd[5];
uint32_t scheduling_len_us;
const struct ble_gap_conn_params *conn_params;
#if MYNEWT_VAL(BLE_EXT_ADV)
uint8_t phy_mask;
#endif // MYNEWT_VAL(BLE_EXT_ADV)
if (!ble_hs_is_enabled()) {
return BLE_HS_EDISABLED;
}
if (!ble_gap_multi_conn.enabled || (multi_conn_params == NULL)) {
return BLE_HS_EINVAL;
}
#if MYNEWT_VAL(BLE_EXT_ADV)
phy_mask = multi_conn_params->phy_mask;
if (phy_mask == 0) {
return BLE_HS_EINVAL;
}
#endif // MYNEWT_VAL(BLE_EXT_ADV)
scheduling_len_us = multi_conn_params->scheduling_len_us;
/* `scheduling_len_us == 0` is allowed. It indicates that the optimization for this connection
* is disabled. The connection interval must be an integer multiple of `common factor`. Note
* that the unit of the connection interval is 1.25ms, while the common factor's unit is 0.625ms.
*/
if (scheduling_len_us != 0) {
#if MYNEWT_VAL(BLE_EXT_ADV)
if (phy_mask & BLE_GAP_LE_PHY_1M_MASK) {
conn_params = multi_conn_params->phy_1m_conn_params;
if ((conn_params == NULL) ||
!ble_gap_interval_is_integer_multiple(conn_params->itvl_min << 1,
conn_params->itvl_max << 1)) {
return BLE_HS_EINVAL;
}
}
if (phy_mask & BLE_GAP_LE_PHY_2M_MASK) {
conn_params = multi_conn_params->phy_2m_conn_params;
if ((conn_params == NULL) ||
!ble_gap_interval_is_integer_multiple(conn_params->itvl_min << 1,
conn_params->itvl_max << 1)) {
return BLE_HS_EINVAL;
}
}
if (phy_mask & BLE_GAP_LE_PHY_CODED_MASK) {
conn_params = multi_conn_params->phy_coded_conn_params;
if ((conn_params == NULL) ||
!ble_gap_interval_is_integer_multiple(conn_params->itvl_min << 1,
conn_params->itvl_max << 1)) {
return BLE_HS_EINVAL;
}
}
#else
conn_params = multi_conn_params->phy_1m_conn_params;
if ((conn_params == NULL) ||
!ble_gap_interval_is_integer_multiple(conn_params->itvl_min << 1,
conn_params->itvl_max << 1)) {
return BLE_HS_EINVAL;
}
#endif // MYNEWT_VAL(BLE_EXT_ADV)
}
vs_cmd[0] = 0;
vs_cmd[1] = scheduling_len_us & 0xfful;
vs_cmd[2] = (scheduling_len_us >> 8) & 0xfful;
vs_cmd[3] = (scheduling_len_us >> 16) & 0xfful;
vs_cmd[4] = (scheduling_len_us >> 24) & 0xfful;
rc = ble_hs_hci_send_vs_cmd(0x110, (const void *)vs_cmd, sizeof(vs_cmd), NULL, 0);
if (rc != 0) {
return rc;
}
ble_gap_multi_conn.scheduling_len_set = true;
#if MYNEWT_VAL(BLE_EXT_ADV)
rc = ble_gap_ext_connect(multi_conn_params->own_addr_type, multi_conn_params->peer_addr,
multi_conn_params->duration_ms, multi_conn_params->phy_mask,
multi_conn_params->phy_1m_conn_params,
multi_conn_params->phy_2m_conn_params,
multi_conn_params->phy_coded_conn_params, cb, cb_arg);
#else
rc = ble_gap_ext_connect(multi_conn_params->own_addr_type, multi_conn_params->peer_addr,
multi_conn_params->duration_ms, multi_conn_params->phy_1m_conn_params,
cb, cb_arg);
#endif // MYNEWT_VAL(BLE_EXT_ADV)
ble_gap_multi_conn.scheduling_len_set = false;
return rc;
}
#endif // MYNEWT_VAL(BLE_ROLE_CENTRAL)
#endif
int
ble_gap_conn_active(void)
{
@@ -6777,6 +6952,10 @@ ble_gap_init(void)
memset(&ble_gap_master, 0, sizeof(ble_gap_master));
memset(ble_gap_slave, 0, sizeof(ble_gap_slave));
#if MYNEWT_VAL(OPTIMIZE_MULTI_CONN)
memset(&ble_gap_multi_conn, 0, sizeof(ble_gap_multi_conn));
#endif
#if MYNEWT_VAL(BLE_PERIODIC_ADV)
memset(&ble_gap_sync, 0, sizeof(ble_gap_sync));
#endif