From 3a0e8f86ed3d193cce5ee161c03d728bf74a7c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Rymanowski?= Date: Fri, 2 Jun 2017 11:15:13 +0200 Subject: [PATCH] nimble/gap: Add GAP API for extended connection For now we have separate function but maybe we could do it better. X-Original-Commit: a1ad55b988b7bea5426c1645a20a1055112a0999 --- nimble/host/include/host/ble_gap.h | 6 + nimble/host/src/ble_gap.c | 236 +++++++++++++++++++++++++++++ nimble/host/src/ble_hs_hci_priv.h | 3 + 3 files changed, 245 insertions(+) diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index f85183c68..c6b0037d7 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -587,6 +587,12 @@ int ble_gap_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, int32_t duration_ms, const struct ble_gap_conn_params *params, ble_gap_event_fn *cb, void *cb_arg); +int ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, + int32_t duration_ms, uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params, + ble_gap_event_fn *cb, void *cb_arg); int ble_gap_conn_cancel(void); int ble_gap_conn_active(void); int ble_gap_terminate(uint16_t conn_handle, uint8_t hci_reason); diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 60403855e..c0a97a94b 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -2613,6 +2613,242 @@ ble_gap_conn_create_tx(uint8_t own_addr_type, const ble_addr_t *peer_addr, return 0; } +#if MYNEWT_VAL(BLE_EXT_ADV) +static void +ble_gap_copy_params(struct hci_ext_conn_params *hcc_params, + const struct ble_gap_conn_params *gap_params) +{ + hcc_params->scan_itvl = gap_params->scan_itvl; + hcc_params->scan_window = gap_params->scan_window; + hcc_params->conn_itvl_max = gap_params->itvl_max; + hcc_params->conn_itvl_min = gap_params->itvl_min; + hcc_params->max_ce_len = gap_params->max_ce_len; + hcc_params->min_ce_len = gap_params->min_ce_len; + hcc_params->conn_latency = gap_params->latency; + hcc_params->supervision_timeout = gap_params->supervision_timeout; +} + +static int +ble_gap_ext_conn_create_tx(uint8_t own_addr_type, const ble_addr_t *peer_addr, + uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params) +{ + uint8_t buf[BLE_HCI_CMD_HDR_LEN + sizeof(struct hci_ext_create_conn)]; + struct hci_ext_create_conn hcc = {}; + int rc; + + if (peer_addr == NULL) { + /* Application wants to connect to any device in the white list. The + * peer address type and peer address fields are ignored by the + * controller; fill them with dummy values. + */ + hcc.filter_policy = BLE_HCI_CONN_FILT_USE_WL; + hcc.peer_addr_type = 0; + memset(hcc.peer_addr, 0, sizeof hcc.peer_addr); + } else { + hcc.filter_policy = BLE_HCI_CONN_FILT_NO_WL; + hcc.peer_addr_type = peer_addr->type;; + memcpy(hcc.peer_addr, peer_addr->val, sizeof hcc.peer_addr); + } + + hcc.own_addr_type = own_addr_type; + + hcc.init_phy_mask = phy_mask; + + if (phy_mask & BLE_GAP_LE_PHY_1M_MASK) { + /* XXX same structs */ + ble_gap_copy_params(&hcc.params[0], phy_1m_conn_params); + } + + if (phy_mask & BLE_GAP_LE_PHY_2M_MASK) { + /* XXX same structs */ + ble_gap_copy_params(&hcc.params[1], phy_2m_conn_params); + } + + if (phy_mask & BLE_GAP_LE_PHY_CODED_MASK) { + /* XXX same structs */ + ble_gap_copy_params(&hcc.params[2], phy_coded_conn_params); + } + + rc = ble_hs_hci_cmd_build_le_ext_create_conn(&hcc, buf, sizeof buf); + if (rc != 0) { + return BLE_HS_EUNKNOWN; + } + + rc = ble_hs_hci_cmd_tx_empty_ack(buf); + if (rc != 0) { + return rc; + } + + return 0; +} + +/** + * Initiates a connect procedure. + * + * @param own_addr_type The type of address the stack should use for + * itself during connection establishment. + * o BLE_OWN_ADDR_PUBLIC + * o BLE_OWN_ADDR_RANDOM + * o BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT + * o BLE_OWN_ADDR_RPA_RANDOM_DEFAULT + * @param peer_addr The address of the peer to connect to. + * If this parameter is NULL, the white list + * is used. + * @param duration_ms The duration of the discovery procedure. + * On expiration, the procedure ends and a + * BLE_GAP_EVENT_DISC_COMPLETE event is + * reported. Units are milliseconds. + * @param phy_mask Define on which PHYs connection attempt should + * be done + * @param phy_1m_conn_params Additional arguments specifying the particulars + * of the connect procedure. When + * BLE_GAP_LE_PHY_1M_MASK is set in phy_mask + * this parameter can be specify to null for + * default values. + * @param phy_2m_conn_params Additional arguments specifying the particulars + * of the connect procedure. When + * BLE_GAP_LE_PHY_2M_MASK is set in phy_mask + * this parameter can be specify to null for + * default values. + * @param phy_coded_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 be specify to null for + * default values. + * @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_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, + int32_t duration_ms, uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params, + ble_gap_event_fn *cb, void *cb_arg) +{ +#if !MYNEWT_VAL(BLE_ROLE_CENTRAL) + return BLE_HS_ENOTSUP; +#endif + + uint32_t duration_ticks; + int rc; + + STATS_INC(ble_gap_stats, initiate); + + ble_hs_lock(); + + if (ble_gap_conn_active()) { + rc = BLE_HS_EALREADY; + goto done; + } + + if (ble_gap_disc_active()) { + rc = BLE_HS_EBUSY; + goto done; + } + + if (!ble_hs_conn_can_alloc()) { + rc = BLE_HS_ENOMEM; + goto done; + } + + if (peer_addr && + peer_addr->type != BLE_ADDR_PUBLIC && + peer_addr->type != BLE_ADDR_RANDOM && + peer_addr->type != BLE_ADDR_PUBLIC_ID && + peer_addr->type != BLE_ADDR_RANDOM_ID) { + + rc = BLE_HS_EINVAL; + goto done; + } + + if ((phy_mask & BLE_GAP_LE_PHY_1M_MASK) && phy_1m_conn_params == NULL) { + phy_1m_conn_params = &ble_gap_conn_params_dflt; + } + + if ((phy_mask & BLE_GAP_LE_PHY_2M_MASK) && phy_2m_conn_params == NULL) { + phy_2m_conn_params = &ble_gap_conn_params_dflt; + } + + if ((phy_mask & BLE_GAP_LE_PHY_CODED_MASK) && phy_coded_conn_params == NULL) { + phy_coded_conn_params = &ble_gap_conn_params_dflt; + } + + if (duration_ms == 0) { + duration_ms = BLE_GAP_CONN_DUR_DFLT; + } + + if (duration_ms != BLE_HS_FOREVER) { + rc = os_time_ms_to_ticks(duration_ms, &duration_ticks); + if (rc != 0) { + /* Duration too great. */ + rc = BLE_HS_EINVAL; + goto done; + } + } + + /* Verify peer not already connected. */ + if (ble_hs_conn_find_by_addr(peer_addr) != NULL) { + rc = BLE_HS_EDONE; + goto done; + } + + /* XXX: Verify conn_params. */ + + rc = ble_hs_id_use_addr(own_addr_type); + if (rc != 0) { + goto done; + } + + ble_gap_master.cb = cb; + ble_gap_master.cb_arg = cb_arg; + ble_gap_master.conn.using_wl = peer_addr == NULL; + ble_gap_master.conn.our_addr_type = own_addr_type; + + ble_gap_master.op = BLE_GAP_OP_M_CONN; + + rc = ble_gap_ext_conn_create_tx(own_addr_type, peer_addr, phy_mask, + phy_1m_conn_params, phy_2m_conn_params, + phy_coded_conn_params); + if (rc != 0) { + ble_gap_master_reset_state(); + goto done; + } + + if (duration_ms != BLE_HS_FOREVER) { + ble_gap_master_set_timer(duration_ticks); + } + + rc = 0; + +done: + ble_hs_unlock(); + + if (rc != 0) { + STATS_INC(ble_gap_stats, initiate_fail); + } + return rc; +} +#endif + /** * Initiates a connect procedure. * diff --git a/nimble/host/src/ble_hs_hci_priv.h b/nimble/host/src/ble_hs_hci_priv.h index 2588c5fc9..afea977b0 100644 --- a/nimble/host/src/ble_hs_hci_priv.h +++ b/nimble/host/src/ble_hs_hci_priv.h @@ -215,6 +215,9 @@ int ble_hs_hci_cmd_build_le_set_phy(uint16_t conn_handle, uint8_t tx_phys_mask, uint8_t rx_phys_mask, uint16_t phy_opts, uint8_t *dst, int dst_len); +#if MYNEWT_VAL(BLE_EXT_ADV) +#endif + #ifdef __cplusplus } #endif