diff --git a/nimble/controller/include/controller/ble_ll.h b/nimble/controller/include/controller/ble_ll.h index 9bf3bcaaa..051a8c840 100644 --- a/nimble/controller/include/controller/ble_ll.h +++ b/nimble/controller/include/controller/ble_ll.h @@ -203,6 +203,7 @@ extern STATS_SECT_DECL(ble_ll_stats) ble_ll_stats; /* LL timing */ #define BLE_LL_IFS (150) /* usecs */ +#define BLE_LL_MAFS (300) /* usecs */ /* * BLE LL device address. Note that element 0 of the array is the LSB and @@ -270,6 +271,34 @@ struct ble_dev_addr #define BLE_ADV_PDU_TYPE_AUX_SCAN_REQ BLE_ADV_PDU_TYPE_SCAN_REQ #define BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP (8) +#define BLE_ADV_PDU_TYPE_AUX_SCAN_REQ BLE_ADV_PDU_TYPE_SCAN_REQ +#define BLE_ADV_PDU_TYPE_AUX_CONNECT_REQ BLE_ADV_PDU_TYPE_CONNECT_REQ +#define BLE_ADV_PDU_TYPE_ADV_EXT_IND (7) +#define BLE_ADV_PDU_TYPE_AUX_ADV_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND +#define BLE_ADV_PDU_TYPE_AUX_SCAN_RSP BLE_ADV_PDU_TYPE_ADV_EXT_IND +#define BLE_ADV_PDU_TYPE_AUX_SYNC_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND +#define BLE_ADV_PDU_TYPE_AUX_CHAIN_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND +#define BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP (8) + +#define BLE_LL_EXT_ADV_ADVA_BIT (0) +#define BLE_LL_EXT_ADV_TARGETA_BIT (1) +#define BLE_LL_EXT_ADV_RFU_BIT (2) +#define BLE_LL_EXT_ADV_DATA_INFO_BIT (3) +#define BLE_LL_EXT_ADV_AUX_PTR_BIT (4) +#define BLE_LL_EXT_ADV_SYNC_INFO_BIT (5) +#define BLE_LL_EXT_ADV_TX_POWER_BIT (6) + +#define BLE_LL_EXT_ADV_ADVA_SIZE (6) +#define BLE_LL_EXT_ADV_TARGETA_SIZE (6) +#define BLE_LL_EXT_ADV_DATA_INFO_SIZE (2) +#define BLE_LL_EXT_ADV_AUX_PTR_SIZE (3) +#define BLE_LL_EXT_ADV_SYNC_INFO_SIZE (18) +#define BLE_LL_EXT_ADV_TX_POWER_SIZE (1) + +#define BLE_LL_EXT_ADV_MODE_NON_CONN (0x00) +#define BLE_LL_EXT_ADV_MODE_CONN (0x01) +#define BLE_LL_EXT_ADV_MODE_SCAN (0x02) + /* If Channel Selection Algorithm #2 is supported */ #define BLE_ADV_PDU_HDR_CHSEL (0x20) diff --git a/nimble/controller/include/controller/ble_ll_adv.h b/nimble/controller/include/controller/ble_ll_adv.h index 635c62ea7..259006a7a 100644 --- a/nimble/controller/include/controller/ble_ll_adv.h +++ b/nimble/controller/include/controller/ble_ll_adv.h @@ -113,25 +113,22 @@ int ble_ll_adv_start_req(uint8_t adv_chanmask, uint8_t adv_type, uint8_t *init_addr, uint16_t adv_itvl, void *handle); /* Start or stop advertising */ -int ble_ll_adv_set_enable(uint8_t *cmd, uint8_t instance); +int ble_ll_adv_set_enable(uint8_t instance, uint8_t enable, uint16_t duration, + uint8_t event); /* Set advertising data */ -int ble_ll_adv_set_adv_data(uint8_t *cmd, uint8_t instance); +int ble_ll_adv_set_adv_data(uint8_t *cmd, uint8_t instance, uint8_t operation); /* Set scan response data */ -int ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t instance); +int ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t instance, + uint8_t operation); /* Set advertising parameters */ -int ble_ll_adv_set_adv_params(uint8_t *cmd, uint8_t instance, int is_multi); +int ble_ll_adv_set_adv_params(uint8_t *cmd); /* Read advertising channel power */ int ble_ll_adv_read_txpwr(uint8_t *rspbuf, uint8_t *rsplen); -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) -int ble_ll_adv_multi_adv_cmd(uint8_t *cmd, uint8_t cmdlen, uint8_t *rspbuf, - uint8_t *rsplen); -#endif - /*---- API used by BLE LL ----*/ /* Send the connection complete event */ void ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm, @@ -165,9 +162,6 @@ void ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, /* Boolean function denoting whether or not the whitelist can be changed */ int ble_ll_adv_can_chg_whitelist(void); -/* Called when an advertising event has been scheduled */ -void ble_ll_adv_scheduled(struct ble_ll_adv_sm *, uint32_t sch_start); - /* * Called when an advertising event has been removed from the scheduler * without being run. @@ -180,6 +174,14 @@ void ble_ll_adv_halt(struct ble_ll_adv_sm *advsm); /* Called to determine if advertising is enabled */ uint8_t ble_ll_adv_enabled(void); +int ble_ll_adv_set_random_addr(uint8_t *addr, uint8_t instance); +int ble_ll_adv_remove(uint8_t instance); +int ble_ll_adv_clear_all(void); +int ble_ll_adv_ext_set_param(uint8_t *cmdbuf, uint8_t *rspbuf, uint8_t *rsplen); +int ble_ll_adv_ext_set_adv_data(uint8_t *cmdbuf, uint8_t cmdlen); +int ble_ll_adv_ext_set_scan_rsp(uint8_t *cmdbuf, uint8_t cmdlen); +int ble_ll_adv_ext_set_enable(uint8_t *cmdbuf, uint8_t len); + #ifdef __cplusplus } #endif diff --git a/nimble/controller/include/controller/ble_ll_ctrl.h b/nimble/controller/include/controller/ble_ll_ctrl.h index 14d570925..3a9a8c7b7 100644 --- a/nimble/controller/include/controller/ble_ll_ctrl.h +++ b/nimble/controller/include/controller/ble_ll_ctrl.h @@ -270,6 +270,10 @@ int ble_ll_hci_ev_ltk_req(struct ble_ll_conn_sm *connsm); int ble_ll_hci_ev_hw_err(uint8_t hw_err); void ble_ll_hci_ev_databuf_overflow(void); void ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm); +void ble_ll_hci_ev_send_scan_req_recv(uint8_t adv_handle, const uint8_t *peer, + uint8_t peer_addr_type); +void ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle, + uint16_t conn_handle, uint8_t events); int ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status); void ble_ll_calc_session_key(struct ble_ll_conn_sm *connsm); void ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm); diff --git a/nimble/controller/include/controller/ble_ll_sched.h b/nimble/controller/include/controller/ble_ll_sched.h index 4aade28a7..4b9cb14d0 100644 --- a/nimble/controller/include/controller/ble_ll_sched.h +++ b/nimble/controller/include/controller/ble_ll_sched.h @@ -111,8 +111,11 @@ int ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, /* Schedule a new slave connection */ int ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm); +struct ble_ll_adv_sm; +typedef void ble_ll_sched_adv_new_cb(struct ble_ll_adv_sm *advsm, uint32_t sch_start); + /* Schedule a new advertising event */ -int ble_ll_sched_adv_new(struct ble_ll_sched_item *sch); +int ble_ll_sched_adv_new(struct ble_ll_sched_item *sch, ble_ll_sched_adv_new_cb cb); /* Reschedule an advertising event */ int ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start, diff --git a/nimble/controller/include/controller/ble_phy.h b/nimble/controller/include/controller/ble_phy.h index 734f9e940..e5267e4d5 100644 --- a/nimble/controller/include/controller/ble_phy.h +++ b/nimble/controller/include/controller/ble_phy.h @@ -121,6 +121,9 @@ int ble_phy_rssi_get(void); /* Set the transmit power */ int ble_phy_txpwr_set(int dbm); +/* Get highest allowed power from range */ +int ble_phy_txpower_round(int dbm); + /* Get the transmit power */ int ble_phy_txpwr_get(void); diff --git a/nimble/controller/src/ble_ll_adv.c b/nimble/controller/src/ble_ll_adv.c index 980ca5459..506e0ea74 100644 --- a/nimble/controller/src/ble_ll_adv.c +++ b/nimble/controller/src/ble_ll_adv.c @@ -27,7 +27,6 @@ #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" -#include "nimble/hci_vendor.h" #include "nimble/ble_hci_trans.h" #include "controller/ble_phy.h" #include "controller/ble_hw.h" @@ -73,7 +72,6 @@ struct ble_ll_adv_sm { uint8_t adv_enabled; uint8_t adv_instance; - uint8_t adv_type; uint8_t adv_len; uint8_t adv_chanmask; uint8_t adv_filter_policy; @@ -83,10 +81,9 @@ struct ble_ll_adv_sm uint8_t scan_rsp_len; uint8_t adv_pdu_len; int8_t adv_rpa_index; - uint8_t adv_directed; /* note: can be 1 bit */ - uint8_t adv_txadd; /* note: can be 1 bit */ - uint8_t adv_rxadd; /* note: can be 1 bit */ + uint8_t flags; int8_t adv_txpwr; + uint16_t props; uint16_t adv_itvl_min; uint16_t adv_itvl_max; uint32_t adv_itvl_usecs; @@ -103,16 +100,32 @@ struct ble_ll_adv_sm uint8_t *conn_comp_ev; struct os_event adv_txdone_ev; struct ble_ll_sched_item adv_sch; -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + uint32_t adv_secondary_start_time; + struct ble_ll_sched_item adv_secondary_sch; + uint16_t duration; /* TODO */ + uint16_t adi; + uint8_t adv_secondary_chan; uint8_t adv_random_addr[BLE_DEV_ADDR_LEN]; + uint8_t events_max; + uint8_t events; + uint8_t pri_phy; + uint8_t sec_phy; #endif }; +#define BLE_LL_ADV_SM_FLAG_TX_ADD 0x01 +#define BLE_LL_ADV_SM_FLAG_RX_ADD 0x02 +#define BLE_LL_ADV_SM_FLAG_SCAN_REQ_NOTIF 0x04 +#define BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD 0x08 +#define BLE_LL_ADV_SM_FLAG_SECONDARY 0x10 + /* The advertising state machine global object */ struct ble_ll_adv_sm g_ble_ll_adv_sm[BLE_LL_ADV_INSTANCES]; struct ble_ll_adv_sm *g_ble_ll_cur_adv_sm; static void ble_ll_adv_done(struct ble_ll_adv_sm *advsm); +static void ble_ll_adv_sm_init(struct ble_ll_adv_sm *advsm); #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1) /** @@ -143,16 +156,16 @@ ble_ll_adv_chk_rpa_timeout(struct ble_ll_adv_sm *advsm) ble_ll_resolv_gen_rpa(advsm->peer_addr, advsm->peer_addr_type, advsm->adva, 1); - if (advsm->adv_directed) { + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { ble_ll_resolv_gen_rpa(advsm->peer_addr, advsm->peer_addr_type, advsm->initiator_addr, 0); if (ble_ll_is_rpa(advsm->initiator_addr, 1)) { - advsm->adv_rxadd = 1; + advsm->flags |= BLE_LL_ADV_SM_FLAG_RX_ADD; } else { if (advsm->own_addr_type & 1) { - advsm->adv_rxadd = 1; + advsm->flags |= BLE_LL_ADV_SM_FLAG_RX_ADD; } else { - advsm->adv_rxadd = 0; + advsm->flags &= ~BLE_LL_ADV_SM_FLAG_RX_ADD; } } } @@ -160,12 +173,12 @@ ble_ll_adv_chk_rpa_timeout(struct ble_ll_adv_sm *advsm) /* May have to reset txadd bit */ if (ble_ll_is_rpa(advsm->adva, 1)) { - advsm->adv_txadd = 1; + advsm->flags |= BLE_LL_ADV_SM_FLAG_TX_ADD; } else { if (advsm->own_addr_type & 1) { - advsm->adv_txadd = 1; + advsm->flags |= BLE_LL_ADV_SM_FLAG_TX_ADD; } else { - advsm->adv_txadd = 0; + advsm->flags &= ~BLE_LL_ADV_SM_FLAG_TX_ADD; } } } @@ -223,12 +236,12 @@ ble_ll_adv_final_chan(struct ble_ll_adv_sm *advsm) } /** - * Create the advertising PDU + * Create the advertising legacy PDU * * @param advsm Pointer to advertisement state machine */ static void -ble_ll_adv_pdu_make(struct ble_ll_adv_sm *advsm, struct os_mbuf *m) +ble_ll_adv_legacy_pdu_make(struct ble_ll_adv_sm *advsm, struct os_mbuf *m) { uint8_t adv_data_len; uint8_t *dptr; @@ -239,45 +252,29 @@ ble_ll_adv_pdu_make(struct ble_ll_adv_sm *advsm, struct os_mbuf *m) adv_data_len = advsm->adv_len; pdulen = BLE_DEV_ADDR_LEN + adv_data_len; - /* Must be an advertising type! */ - switch (advsm->adv_type) { - case BLE_HCI_ADV_TYPE_ADV_IND: - pdu_type = BLE_ADV_PDU_TYPE_ADV_IND; - -#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1) - pdu_type |= BLE_ADV_PDU_HDR_CHSEL; -#endif - break; - - case BLE_HCI_ADV_TYPE_ADV_NONCONN_IND: - pdu_type = BLE_ADV_PDU_TYPE_ADV_NONCONN_IND; - break; - - case BLE_HCI_ADV_TYPE_ADV_SCAN_IND: - pdu_type = BLE_ADV_PDU_TYPE_ADV_SCAN_IND; - break; - - case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD: - case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD: + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { pdu_type = BLE_ADV_PDU_TYPE_ADV_DIRECT_IND; #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1) pdu_type |= BLE_ADV_PDU_HDR_CHSEL; #endif - adv_data_len = 0; - pdulen = BLE_ADV_DIRECT_IND_LEN; - if (advsm->adv_rxadd) { + if (advsm->flags & BLE_LL_ADV_SM_FLAG_RX_ADD) { pdu_type |= BLE_ADV_PDU_HDR_RXADD_RAND; } - break; - /* Set these to avoid compiler warnings */ - default: - pdulen = 0; - pdu_type = 0; - adv_data_len = 0xFF; - break; + adv_data_len = 0; + pdulen = BLE_ADV_DIRECT_IND_LEN; + } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { + pdu_type = BLE_ADV_PDU_TYPE_ADV_IND; + +#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1) + pdu_type |= BLE_ADV_PDU_HDR_CHSEL; +#endif + } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) { + pdu_type = BLE_ADV_PDU_TYPE_ADV_SCAN_IND; + } else { + pdu_type = BLE_ADV_PDU_TYPE_ADV_NONCONN_IND; } /* An invalid advertising data length indicates a memory overwrite */ @@ -287,7 +284,7 @@ ble_ll_adv_pdu_make(struct ble_ll_adv_sm *advsm, struct os_mbuf *m) advsm->adv_pdu_len = pdulen + BLE_LL_PDU_HDR_LEN; /* Set TxAdd to random if needed. */ - if (advsm->adv_txadd) { + if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND; } @@ -300,7 +297,7 @@ ble_ll_adv_pdu_make(struct ble_ll_adv_sm *advsm, struct os_mbuf *m) dptr += BLE_DEV_ADDR_LEN; /* For ADV_DIRECT_IND add inita */ - if (advsm->adv_directed) { + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { memcpy(dptr, advsm->initiator_addr, BLE_DEV_ADDR_LEN); } @@ -310,13 +307,213 @@ ble_ll_adv_pdu_make(struct ble_ll_adv_sm *advsm, struct os_mbuf *m) } } -/** - * Create a scan response PDU +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +/* TODO this shouldn't be needed + * + * PDU could be constructed before scheduling and held in mbuf until + * transmission * - * @param advsm */ +static uint8_t +ble_ll_adv_secondary_pdu_len(struct ble_ll_adv_sm *advsm) +{ + uint8_t pdulen; + + pdulen = 2 + BLE_LL_PDU_HDR_LEN + BLE_LL_EXT_ADV_DATA_INFO_SIZE; + + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) && + advsm->adv_len) { + pdulen += advsm->adv_len; + } + + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR) { + pdulen += BLE_LL_EXT_ADV_TX_POWER_SIZE; + } + + if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) || + (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE)) { + pdulen += BLE_LL_EXT_ADV_TARGETA_SIZE; + } + + return pdulen; +} + +/** + * Create the advertising PDU + */ +static void +ble_ll_adv_pdu_make(struct ble_ll_adv_sm *advsm, struct os_mbuf *m) +{ + uint8_t *dptr; + uint8_t pdulen; + uint8_t pdu_type; + + bool adva = false; + bool targeta = false; + bool adi = false; + bool aux_ptr = false; + bool tx_power = false; + bool adv_data = false; + uint8_t adv_mode; + uint8_t ext_hdr_len; + uint8_t ext_hdr_flags; + uint32_t offset; + + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + return ble_ll_adv_legacy_pdu_make(advsm, m); + } + + pdulen = 1; /* ext hdr len + AdvMode */ + + ext_hdr_len = 0; + + /* TODO for now always add flags */ + ext_hdr_len += 1; + ext_hdr_flags = 0; + + + if (advsm->flags & BLE_LL_ADV_SM_FLAG_SECONDARY) { + pdu_type = BLE_ADV_PDU_TYPE_AUX_ADV_IND; + + adi = true; + adva = true; + + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) && + advsm->adv_len) { + adv_data = true; + } + + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR) { + tx_power = true; + } + + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { + targeta = true; + } + + } else { + /* only ADV_EXT_IND goes on primary advertising channels */ + pdu_type = BLE_ADV_PDU_TYPE_ADV_EXT_IND; + + /* TODO in some cases we could avoid auxiliary packet */ + aux_ptr = true; + adi = true; + } + + adv_mode = 0; + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { + adv_mode |= BLE_LL_EXT_ADV_MODE_CONN; + } + + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) { + adv_mode |= BLE_LL_EXT_ADV_MODE_SCAN; + } + + if (adva) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_ADVA_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_ADVA_SIZE; + } + + if (targeta) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_TARGETA_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_TARGETA_SIZE; + } + + if (adi) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + } + + if (aux_ptr) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_AUX_PTR_SIZE; + } + + if (tx_power) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; + } + + /* TODO ACAD */ + + if (adv_data) { + pdulen += advsm->adv_len; + } + + /* Set TxAdd to random if needed. */ + if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { + pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND; + } + + pdulen += ext_hdr_len; + + /* Set the PDU length in the state machine (includes header) */ + advsm->adv_pdu_len = pdulen + BLE_LL_PDU_HDR_LEN; + + ble_ll_mbuf_init(m, pdulen, pdu_type); + + /* Construct advertisement */ + dptr = m->om_data; + + /* ext hdr len and adv mode */ + dptr[0] = ext_hdr_len | (adv_mode << 6); + dptr += 1; + + /* ext hdr flags */ + dptr[0] = ext_hdr_flags; + dptr += 1; + + if (adva) { + memcpy(dptr, advsm->adva, BLE_LL_EXT_ADV_ADVA_SIZE); + dptr += BLE_LL_EXT_ADV_ADVA_SIZE; + } + + if (targeta) { + memcpy(dptr, advsm->initiator_addr, BLE_LL_EXT_ADV_TARGETA_SIZE); + dptr += BLE_LL_EXT_ADV_TARGETA_SIZE; + } + + if (adi) { + dptr[0] = advsm->adi & 0x00ff; + dptr[1] = advsm->adi >> 8; + dptr += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + } + + if (aux_ptr) { + offset = advsm->adv_secondary_start_time - os_cputime_get32() + 1; + + /* in usecs */ + offset = os_cputime_ticks_to_usecs(offset); + + dptr[0] = advsm->adv_secondary_chan; + + if (offset > 245700) { + dptr[0] |= 0x80; + offset = offset / 300; + } else { + offset = offset / 30; + } + + dptr[1] = (offset & 0x000000ff); + dptr[2] = ((offset >> 8) & 0x0000001f) | (advsm->sec_phy - 1) << 5; //TODO; + + dptr += BLE_LL_EXT_ADV_AUX_PTR_SIZE; + } + + if (tx_power) { + dptr[0] = advsm->adv_txpwr; + dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE; + } + + if (adv_data) { + memcpy(dptr, advsm->adv_data, advsm->adv_len); + dptr += advsm->adv_len; + } +} +#endif + static struct os_mbuf * -ble_ll_adv_scan_rsp_pdu_make(struct ble_ll_adv_sm *advsm) +ble_ll_adv_scan_rsp_legacy_pdu_make(struct ble_ll_adv_sm *advsm) { uint8_t scan_rsp_len; uint8_t *dptr; @@ -338,7 +535,7 @@ ble_ll_adv_scan_rsp_pdu_make(struct ble_ll_adv_sm *advsm) /* Set BLE transmit header */ pdulen = BLE_DEV_ADDR_LEN + scan_rsp_len; hdr = BLE_ADV_PDU_TYPE_SCAN_RSP; - if (advsm->adv_txadd) { + if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { hdr |= BLE_ADV_PDU_HDR_TXADD_RAND; } @@ -362,6 +559,147 @@ ble_ll_adv_scan_rsp_pdu_make(struct ble_ll_adv_sm *advsm) return m; } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +/** + * Create a scan response PDU + * + * @param advsm + */ +static struct os_mbuf * +ble_ll_adv_scan_rsp_pdu_make(struct ble_ll_adv_sm *advsm) +{ + uint8_t *dptr; + uint8_t pdulen; + uint8_t ext_hdr_len; + uint8_t ext_hdr_flags; + uint8_t hdr; + struct os_mbuf *m; + + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + return ble_ll_adv_scan_rsp_legacy_pdu_make(advsm); + } + + /* ext hdr len + SCAN_RSP */ + pdulen = 1 + advsm->scan_rsp_len; + + /* flags, adva and optional TX power */ + ext_hdr_len = 1 + BLE_LL_EXT_ADV_ADVA_SIZE; + ext_hdr_flags = (1 << BLE_LL_EXT_ADV_ADVA_BIT); + + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR) { + ext_hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; + ext_hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; + } + + pdulen += ext_hdr_len; + + /* Obtain scan response buffer */ + m = os_msys_get_pkthdr(pdulen, sizeof(struct ble_mbuf_hdr)); + if (!m) { + return NULL; + } + + /* Set BLE transmit header */ + hdr = BLE_ADV_PDU_TYPE_AUX_SCAN_RSP; + if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { + hdr |= BLE_ADV_PDU_HDR_TXADD_RAND; + } + + ble_ll_mbuf_init(m, pdulen, hdr); + + /* Construct scan response */ + dptr = m->om_data; + + /* ext hdr len and adv mode (00b) */ + dptr[0] = ext_hdr_len; + dptr += 1; + + /* ext hdr flags */ + dptr[0] = ext_hdr_flags; + dptr += 1; + + /* + * The adva in this packet will be the same one that was being advertised + * and is based on the peer identity address in the set advertising + * parameters. If a different peer sends us a scan request (for some reason) + * we will reply with an adva that was not generated based on the local irk + * of the peer sending the scan request. + */ + memcpy(dptr, advsm->adva, BLE_LL_EXT_ADV_ADVA_SIZE); + dptr += BLE_LL_EXT_ADV_ADVA_SIZE; + + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR) { + dptr[0] = advsm->adv_txpwr; + dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE; + } + + memcpy(dptr, advsm->scan_rsp_data, advsm->scan_rsp_len); + dptr += advsm->scan_rsp_len; + + return m; +} + +/** + * Create a AUX connect response PDU + * + * @param advsm + */ +static struct os_mbuf * +ble_ll_adv_aux_conn_rsp_pdu_make(struct ble_ll_adv_sm *advsm, uint8_t *peer, + uint8_t rxadd) +{ + uint8_t *dptr; + uint8_t pdulen; + uint8_t ext_hdr_len; + uint8_t ext_hdr_flags; + uint8_t hdr; + struct os_mbuf *m; + + /* ext hdr len */ + pdulen = 1; + + /* flags,AdvA and TargetA */ + ext_hdr_len = 1 + BLE_LL_EXT_ADV_ADVA_SIZE + BLE_LL_EXT_ADV_TARGETA_SIZE; + ext_hdr_flags = (1 << BLE_LL_EXT_ADV_ADVA_BIT); + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_TARGETA_BIT); + + pdulen += ext_hdr_len; + + /* Obtain scan response buffer */ + m = os_msys_get_pkthdr(pdulen, sizeof(struct ble_mbuf_hdr)); + if (!m) { + return NULL; + } + + /* Set BLE transmit header */ + hdr = BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP | rxadd; + if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { + hdr |= BLE_ADV_PDU_HDR_TXADD_MASK; + } + + ble_ll_mbuf_init(m, pdulen, hdr); + + /* Construct connect response */ + dptr = m->om_data; + + /* ext hdr len and adv mode (00b) */ + dptr[0] = ext_hdr_len; + dptr += 1; + + /* ext hdr flags */ + dptr[0] = ext_hdr_flags; + dptr += 1; + + memcpy(dptr, advsm->adva, BLE_LL_EXT_ADV_ADVA_SIZE); + dptr += BLE_LL_EXT_ADV_ADVA_SIZE; + + memcpy(dptr, peer, BLE_LL_EXT_ADV_TARGETA_SIZE); + dptr += BLE_LL_EXT_ADV_ADVA_SIZE; + + return m; +} +#endif + /** * Called to indicate the advertising event is over. * @@ -460,12 +798,13 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch) #endif /* Set phy mode based on type of advertisement */ - if (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) { - end_trans = BLE_PHY_TRANSITION_NONE; - ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm); - } else { + if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) || + (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { end_trans = BLE_PHY_TRANSITION_TX_RX; ble_phy_set_txend_cb(NULL, NULL); + } else { + end_trans = BLE_PHY_TRANSITION_NONE; + ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm); } /* Get an advertising mbuf (packet header) */ @@ -476,10 +815,22 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch) goto adv_tx_done; } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + advsm->flags &= ~BLE_LL_ADV_SM_FLAG_SECONDARY; ble_ll_adv_pdu_make(advsm, adv_pdu); +#if (BLE_LL_BT5_PHY_SUPPORTED == 1) + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + ble_phy_mode_set(BLE_PHY_MODE_1M, BLE_PHY_MODE_1M); + } else { + ble_phy_mode_set(advsm->pri_phy, advsm->pri_phy); + } +#endif +#else + ble_ll_adv_legacy_pdu_make(advsm, adv_pdu); #if (BLE_LL_BT5_PHY_SUPPORTED == 1) ble_phy_mode_set(BLE_PHY_MODE_1M, BLE_PHY_MODE_1M); +#endif #endif /* Transmit advertisement */ @@ -521,18 +872,20 @@ ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm) sch->sched_type = BLE_LL_SCHED_TYPE_ADV; /* Set end time to maximum time this schedule item may take */ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + max_usecs = ble_ll_pdu_tx_time_get(advsm->adv_pdu_len, BLE_PHY_MODE_1M); + } else { + max_usecs = ble_ll_pdu_tx_time_get(advsm->adv_pdu_len, advsm->pri_phy); + } +#else max_usecs = ble_ll_pdu_tx_time_get(advsm->adv_pdu_len, BLE_PHY_MODE_1M); - switch (advsm->adv_type) { - case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD: - case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD: +#endif + + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { max_usecs += BLE_LL_SCHED_DIRECT_ADV_MAX_USECS; - break; - case BLE_HCI_ADV_TYPE_ADV_IND: - case BLE_HCI_ADV_TYPE_ADV_SCAN_IND: + } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { max_usecs += BLE_LL_SCHED_ADV_MAX_USECS; - break; - default: - break; } /* @@ -547,6 +900,143 @@ ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm) os_cputime_usecs_to_ticks(max_usecs); } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +static int +ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item *sch) +{ + int rc; + uint8_t end_trans; + uint32_t txstart; + struct ble_ll_adv_sm *advsm; + struct os_mbuf *adv_pdu; + + /* Get the state machine for the event */ + advsm = (struct ble_ll_adv_sm *)sch->cb_arg; + + /* Set the current advertiser */ + g_ble_ll_cur_adv_sm = advsm; + + /* Set the power */ + ble_phy_txpwr_set(advsm->adv_txpwr); + + /* Set channel */ + rc = ble_phy_setchan(advsm->adv_secondary_chan, BLE_ACCESS_ADDR_ADV, + BLE_LL_CRCINIT_ADV); + assert(rc == 0); + + /* Set transmit start time. */ + txstart = sch->start_time + g_ble_ll_sched_offset_ticks; + rc = ble_phy_tx_set_start_time(txstart, sch->remainder); + if (rc) { + STATS_INC(ble_ll_stats, adv_late_starts); + goto adv_tx_done; + } + +#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1) + /* XXX: automatically do this in the phy based on channel? */ + ble_phy_encrypt_disable(); +#endif + +#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1) + advsm->adv_rpa_index = -1; + if (ble_ll_resolv_enabled()) { + ble_phy_resolv_list_enable(); + } else { + ble_phy_resolv_list_disable(); + } +#endif + + /* Set phy mode based on type of advertisement */ + if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) || + (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { + end_trans = BLE_PHY_TRANSITION_TX_RX; + ble_phy_set_txend_cb(NULL, NULL); + } else { + end_trans = BLE_PHY_TRANSITION_NONE; + ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm); + } + + /* Get an advertising mbuf (packet header) */ + adv_pdu = os_msys_get_pkthdr(BLE_ADV_MAX_PKT_LEN, + sizeof(struct ble_mbuf_hdr)); + if (!adv_pdu) { + ble_phy_disable(); + goto adv_tx_done; + } + + advsm->flags |= BLE_LL_ADV_SM_FLAG_SECONDARY; + ble_ll_adv_pdu_make(advsm, adv_pdu); + +#if (BLE_LL_BT5_PHY_SUPPORTED == 1) + ble_phy_mode_set(advsm->sec_phy, advsm->sec_phy); +#endif + + /* Transmit advertisement */ + rc = ble_phy_tx(adv_pdu, end_trans); + os_mbuf_free_chain(adv_pdu); + if (rc) { + goto adv_tx_done; + } + + /* Enable/disable whitelisting based on filter policy */ + if (advsm->adv_filter_policy != BLE_HCI_ADV_FILT_NONE) { + ble_ll_whitelist_enable(); + } else { + ble_ll_whitelist_disable(); + } + + /* Set link layer state to advertising */ + ble_ll_state_set(BLE_LL_STATE_ADV); + + /* Count # of adv. sent */ + STATS_INC(ble_ll_stats, adv_txg); + + return BLE_LL_SCHED_STATE_RUNNING; + +adv_tx_done: + ble_ll_adv_tx_done(advsm); + return BLE_LL_SCHED_STATE_DONE; +} + +static void +ble_ll_adv_secondary_set_sched(struct ble_ll_adv_sm *advsm) +{ + uint32_t max_usecs; + struct ble_ll_sched_item *sch; + + sch = &advsm->adv_secondary_sch; + sch->cb_arg = advsm; + sch->sched_cb = ble_ll_adv_secondary_tx_start_cb; + sch->sched_type = BLE_LL_SCHED_TYPE_ADV; + + /* TODO we could use CSA2 for this + * (will be needed for periodic advertising anyway) + */ + advsm->adv_secondary_chan = rand() % BLE_PHY_NUM_DATA_CHANS; + + /* Set end time to maximum time this schedule item may take */ + max_usecs = ble_ll_pdu_tx_time_get(ble_ll_adv_secondary_pdu_len(advsm), + advsm->sec_phy); + + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { + max_usecs += BLE_LL_SCHED_DIRECT_ADV_MAX_USECS; + } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { + max_usecs += BLE_LL_SCHED_ADV_MAX_USECS; + } + + /* + * XXX: For now, just schedule some additional time so we insure we have + * enough time to do everything we want. + */ + max_usecs += XCVR_PROC_DELAY_USECS; + + sch->start_time = advsm->adv_secondary_start_time - g_ble_ll_sched_offset_ticks; + sch->remainder = 0; + sch->end_time = advsm->adv_secondary_start_time + + os_cputime_usecs_to_ticks(max_usecs); +} +#endif + /** * Called when advertising need to be halted. This normally should not be called * and is only called when a scheduled item executes but advertising is still @@ -571,36 +1061,24 @@ ble_ll_adv_halt(struct ble_ll_adv_sm *advsm) * @return int */ int -ble_ll_adv_set_adv_params(uint8_t *cmd, uint8_t instance, int is_multi) +ble_ll_adv_set_adv_params(uint8_t *cmd) { uint8_t adv_type; uint8_t adv_filter_policy; uint8_t adv_chanmask; uint8_t own_addr_type; uint8_t peer_addr_type; - uint8_t offset; uint16_t adv_itvl_min; uint16_t adv_itvl_max; uint16_t min_itvl; struct ble_ll_adv_sm *advsm; + uint16_t props; - /* If already enabled, we return an error */ - if (instance >= BLE_LL_ADV_INSTANCES) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - advsm = &g_ble_ll_adv_sm[instance]; + advsm = &g_ble_ll_adv_sm[0]; if (advsm->adv_enabled) { return BLE_ERR_CMD_DISALLOWED; } - /* Add offset if this is a multi-advertising command */ - if (is_multi) { - offset = 6; - } else { - offset = 0; - } - /* Make sure intervals are OK (along with advertising type */ adv_itvl_min = get_le16(cmd); adv_itvl_max = get_le16(cmd + 2); @@ -610,36 +1088,42 @@ ble_ll_adv_set_adv_params(uint8_t *cmd, uint8_t instance, int is_multi) * Get the filter policy now since we will ignore it if we are doing * directed advertising */ - adv_filter_policy = cmd[14 + offset]; + adv_filter_policy = cmd[14]; /* Assume min interval based on low duty cycle/indirect advertising */ min_itvl = BLE_LL_ADV_ITVL_MIN; - advsm->adv_directed = 0; switch (adv_type) { - /* Fall through intentional */ case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD: + adv_filter_policy = BLE_HCI_ADV_FILT_NONE; + memcpy(advsm->peer_addr, cmd + 7, BLE_DEV_ADDR_LEN); + /* Ignore min/max interval */ min_itvl = 0; adv_itvl_min = 0; adv_itvl_max = 0; + props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_HD_DIR ; + break; case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD: adv_filter_policy = BLE_HCI_ADV_FILT_NONE; - advsm->adv_directed = 1; memcpy(advsm->peer_addr, cmd + 7, BLE_DEV_ADDR_LEN); + + props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_LD_DIR ; break; case BLE_HCI_ADV_TYPE_ADV_IND: - /* Nothing to do */ + props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND; break; case BLE_HCI_ADV_TYPE_ADV_NONCONN_IND: + min_itvl = 0; + props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_NONCONN; + break; case BLE_HCI_ADV_TYPE_ADV_SCAN_IND: min_itvl = 0; + props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_SCAN; break; default: - /* This will cause an invalid parameter error */ - min_itvl = 0xFFFF; - break; + return BLE_ERR_INV_HCI_CMD_PARMS; } /* Make sure interval minimum is valid for the advertising type */ @@ -651,44 +1135,19 @@ ble_ll_adv_set_adv_params(uint8_t *cmd, uint8_t instance, int is_multi) /* Check own and peer address type */ own_addr_type = cmd[5]; - peer_addr_type = cmd[6 + offset]; + peer_addr_type = cmd[6]; if ((own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) || (peer_addr_type > BLE_HCI_ADV_PEER_ADDR_MAX)) { return BLE_ERR_INV_HCI_CMD_PARMS; } - /* Deal with multi-advertising command specific*/ -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) - if (is_multi) { - /* Get and check advertising power */ - advsm->adv_txpwr = cmd[22]; - if (advsm->adv_txpwr > 20) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Get own address if it is there. */ - if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } else { - if (own_addr_type == BLE_HCI_ADV_OWN_ADDR_RANDOM) { - /* Use this random address if set in own address */ - if (ble_ll_is_valid_random_addr(cmd + 6)) { - memcpy(advsm->adv_random_addr, cmd + 6, BLE_DEV_ADDR_LEN); - } - } - } - } else { - advsm->adv_txpwr = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); - } -#else advsm->adv_txpwr = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); -#endif #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1) if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { /* Copy peer address */ - memcpy(advsm->peer_addr, cmd + 7 + offset, BLE_DEV_ADDR_LEN); + memcpy(advsm->peer_addr, cmd + 7, BLE_DEV_ADDR_LEN); /* Reset RPA timer so we generate a new RPA */ advsm->adv_rpa_timer = os_time_get(); @@ -701,7 +1160,7 @@ ble_ll_adv_set_adv_params(uint8_t *cmd, uint8_t instance, int is_multi) #endif /* There are only three adv channels, so check for any outside the range */ - adv_chanmask = cmd[13 + offset]; + adv_chanmask = cmd[13]; if (((adv_chanmask & 0xF8) != 0) || (adv_chanmask == 0)) { return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -718,7 +1177,7 @@ ble_ll_adv_set_adv_params(uint8_t *cmd, uint8_t instance, int is_multi) advsm->adv_chanmask = adv_chanmask; advsm->adv_itvl_min = adv_itvl_min; advsm->adv_itvl_max = adv_itvl_max; - advsm->adv_type = adv_type; + advsm->props = props; return 0; } @@ -739,9 +1198,15 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm) /* Remove any scheduled advertising items */ ble_ll_sched_rmv_elem(&advsm->adv_sch); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) { + ble_ll_sched_rmv_elem(&advsm->adv_secondary_sch); + } +#endif + /* Set to standby if we are no longer advertising */ OS_ENTER_CRITICAL(sr); -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (g_ble_ll_cur_adv_sm == advsm) { ble_phy_disable(); ble_ll_wfr_disable(); @@ -779,6 +1244,50 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm) } } +static void +ble_ll_adv_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start) +{ + /* The event start time is when we start transmission of the adv PDU */ + advsm->adv_event_start_time = sch_start + g_ble_ll_sched_offset_ticks; + advsm->adv_pdu_start_time = advsm->adv_event_start_time; + + /* + * Set the time at which we must end directed, high-duty cycle advertising. + * Does not matter that we calculate this value if we are not doing high + * duty cycle advertising. + */ + advsm->adv_dir_hd_end_time = advsm->adv_event_start_time + + os_cputime_usecs_to_ticks(BLE_LL_ADV_STATE_HD_MAX * 1000); +} + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +static void +ble_ll_set_adv_secondary_start_time(struct ble_ll_adv_sm *advsm) +{ + static const uint8_t bits[8] = {0, 1, 1, 2, 1, 2, 2, 3}; + struct ble_ll_sched_item *sched = &advsm->adv_sch; + uint32_t ext_duration; + uint8_t chans; + + assert(advsm->adv_chanmask <= BLE_HCI_ADV_CHANMASK_DEF); + + chans = bits[advsm->adv_chanmask]; + + ext_duration = (int32_t)(sched->end_time - sched->start_time); + ext_duration += os_cputime_usecs_to_ticks(BLE_LL_IFS) * (chans -1); + + advsm->adv_secondary_start_time = advsm->adv_event_start_time + + ext_duration + + os_cputime_usecs_to_ticks(BLE_LL_MAFS); +} + +static void +ble_ll_adv_secondary_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start) +{ + advsm->adv_secondary_start_time = sch_start; +} +#endif + /** * Start the advertising state machine. This is called when the host sends * the "enable advertising" command and is not called again while in the @@ -797,17 +1306,16 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) uint8_t *addr; uint8_t *evbuf; - /* - * This is not in the specification. I will reject the command with a - * command disallowed error if no random address has been sent by the - * host. All the parameter errors refer to the command - * parameter (which in this case is just enable or disable) so that - * is why I chose command disallowed. - */ + /* only clear flags that are not set from HCI */ + advsm->flags &= ~BLE_LL_ADV_SM_FLAG_TX_ADD; + advsm->flags &= ~BLE_LL_ADV_SM_FLAG_RX_ADD; + advsm->flags &= ~BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD; + advsm->flags &= ~BLE_LL_ADV_SM_FLAG_SECONDARY; + if (advsm->own_addr_type == BLE_HCI_ADV_OWN_ADDR_RANDOM) { -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (!ble_ll_is_valid_random_addr(advsm->adv_random_addr)) { - return BLE_ERR_CMD_DISALLOWED; + return BLE_ERR_INV_HCI_CMD_PARMS; } #else if (!ble_ll_is_valid_random_addr(g_random_addr)) { @@ -820,10 +1328,7 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) * Get an event with which to send the connection complete event if * this is connectable */ - switch (advsm->adv_type) { - case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD: - case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD: - case BLE_HCI_ADV_TYPE_ADV_IND: + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { /* We expect this to be NULL but if not we wont allocate one... */ if (advsm->conn_comp_ev == NULL) { evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); @@ -832,31 +1337,25 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) } advsm->conn_comp_ev = evbuf; } - break; - default: - break; } /* Set advertising address */ if ((advsm->own_addr_type & 1) == 0) { addr = g_dev_addr; - advsm->adv_txadd = 0; } else { -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) addr = advsm->adv_random_addr; #else addr = g_random_addr; #endif - advsm->adv_txadd = 1; + advsm->flags |= BLE_LL_ADV_SM_FLAG_TX_ADD; } memcpy(advsm->adva, addr, BLE_DEV_ADDR_LEN); - if (advsm->adv_directed) { + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { memcpy(advsm->initiator_addr, advsm->peer_addr, BLE_DEV_ADDR_LEN); if (advsm->peer_addr_type & 1) { - advsm->adv_rxadd = 1; - } else { - advsm->adv_rxadd = 0; + advsm->flags |= BLE_LL_ADV_SM_FLAG_RX_ADD; } } @@ -869,7 +1368,7 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) advsm->adv_enabled = 1; /* Determine the advertising interval we will use */ - if (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) { + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { /* Set it to max. allowed for high duty cycle advertising */ advsm->adv_itvl_usecs = BLE_LL_ADV_PDU_ITVL_HD_MS_MAX; } else { @@ -899,28 +1398,20 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) * times to the earliest possible start/end. */ ble_ll_adv_set_sched(advsm); - ble_ll_sched_adv_new(&advsm->adv_sch); + ble_ll_sched_adv_new(&advsm->adv_sch, ble_ll_adv_scheduled); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) { + ble_ll_set_adv_secondary_start_time(advsm); + ble_ll_adv_secondary_set_sched(advsm); + ble_ll_sched_adv_new(&advsm->adv_secondary_sch, + ble_ll_adv_secondary_scheduled); + } +#endif return BLE_ERR_SUCCESS; } -void -ble_ll_adv_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start) -{ - /* The event start time is when we start transmission of the adv PDU */ - advsm->adv_event_start_time = sch_start + g_ble_ll_sched_offset_ticks; - - advsm->adv_pdu_start_time = advsm->adv_event_start_time; - - /* - * Set the time at which we must end directed, high-duty cycle advertising. - * Does not matter that we calculate this value if we are not doing high - * duty cycle advertising. - */ - advsm->adv_dir_hd_end_time = advsm->adv_event_start_time + - os_cputime_usecs_to_ticks(BLE_LL_ADV_STATE_HD_MAX * 1000); -} - /** * Called when the LE HCI command read advertising channel tx power command * has been received. Returns the current advertising transmit power. @@ -947,10 +1438,10 @@ ble_ll_adv_read_txpwr(uint8_t *rspbuf, uint8_t *rsplen) * @return int */ int -ble_ll_adv_set_enable(uint8_t *cmd, uint8_t instance) +ble_ll_adv_set_enable(uint8_t instance, uint8_t enable, uint16_t duration, + uint8_t events) { int rc; - uint8_t enable; struct ble_ll_adv_sm *advsm; if (instance >= BLE_LL_ADV_INSTANCES) { @@ -960,8 +1451,13 @@ ble_ll_adv_set_enable(uint8_t *cmd, uint8_t instance) advsm = &g_ble_ll_adv_sm[instance]; rc = BLE_ERR_SUCCESS; - enable = cmd[0]; if (enable == 1) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + advsm->duration = duration; + advsm->events_max = events; + advsm->events = 0; +#endif + /* If already enabled, do nothing */ if (!advsm->adv_enabled) { /* Start the advertising state machine */ @@ -985,25 +1481,85 @@ ble_ll_adv_set_enable(uint8_t *cmd, uint8_t instance) * @return int */ int -ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t instance) +ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t instance, uint8_t operation) { uint8_t datalen; + uint8_t off = 0; struct ble_ll_adv_sm *advsm; - /* Check for valid scan response data length */ - datalen = cmd[0]; - if (datalen > BLE_SCAN_RSP_DATA_MAX_LEN) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - if (instance >= BLE_LL_ADV_INSTANCES) { return BLE_ERR_INV_HCI_CMD_PARMS; } - /* Copy the new data into the advertising structure. */ advsm = &g_ble_ll_adv_sm[instance]; - advsm->scan_rsp_len = datalen; - memcpy(advsm->scan_rsp_data, cmd + 1, datalen); + datalen = cmd[0]; + + /* check if type of advertising support scan rsp */ + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + switch (operation) { + case BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_COMPLETE: + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + if (datalen > BLE_ADV_DATA_MAX_LEN) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + } + + break; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_LAST: + /* TODO mark scan rsp as complete? */ + /* fall through */ + case BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_INT: + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (advsm->adv_enabled) { + return BLE_ERR_CMD_DISALLOWED; + } + + if (!datalen) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + off = advsm->scan_rsp_len; + break; + case BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_FIRST: + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (advsm->adv_enabled) { + return BLE_ERR_CMD_DISALLOWED; + } + + if (!datalen) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + break; +#endif + default: + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* Check for valid advertising data length */ + if (datalen + off > BLE_SCAN_RSP_DATA_MAX_LEN) { + advsm->scan_rsp_len = 0; + return BLE_ERR_MEM_CAPACITY; + } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + /* DID shall be updated when host provides new scan response data */ + advsm->adi = (advsm->adi & 0xf000) | (rand() & 0x0fff); +#endif + + /* Copy the new data into the advertising structure. */ + advsm->scan_rsp_len = datalen + off; + memcpy(advsm->scan_rsp_data + off, cmd + 1, datalen); return BLE_ERR_SUCCESS; } @@ -1018,30 +1574,401 @@ ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t instance) * @return int 0: success; BLE_ERR_INV_HCI_CMD_PARMS otherwise. */ int -ble_ll_adv_set_adv_data(uint8_t *cmd, uint8_t instance) +ble_ll_adv_set_adv_data(uint8_t *cmd, uint8_t instance, uint8_t operation) { uint8_t datalen; + uint8_t off = 0; struct ble_ll_adv_sm *advsm; - /* Check for valid advertising data length */ - datalen = cmd[0]; - if (datalen > BLE_ADV_DATA_MAX_LEN) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - if (instance >= BLE_LL_ADV_INSTANCES) { return BLE_ERR_INV_HCI_CMD_PARMS; } - /* Copy the new data into the advertising structure. */ advsm = &g_ble_ll_adv_sm[instance]; - advsm->adv_len = datalen; - memcpy(advsm->adv_data, cmd + 1, datalen); + datalen = cmd[0]; + + /* check if type of advertising support adv data */ + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + } else { + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + } + + switch (operation) { + case BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_COMPLETE: + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + if (datalen > BLE_ADV_DATA_MAX_LEN) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + } + + break; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_UNCHANGED: + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (!advsm->adv_enabled || !advsm->adv_len || datalen) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* update DID only */ + advsm->adi = (advsm->adi & 0xf000) | (rand() & 0x0fff); + return BLE_ERR_SUCCESS; + case BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_LAST: + /* TODO mark adv data as complete? */ + /* fall through */ + case BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_INT: + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (!datalen) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (advsm->adv_enabled) { + return BLE_ERR_CMD_DISALLOWED; + } + + off = advsm->adv_len; + break; + case BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_FIRST: + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (advsm->adv_enabled) { + return BLE_ERR_CMD_DISALLOWED; + } + + if (!datalen) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + break; +#endif + default: + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* Check for valid advertising data length */ + if (datalen + off > BLE_ADV_DATA_MAX_LEN) { + advsm->adv_len = 0; + return BLE_ERR_MEM_CAPACITY; + } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + /* DID shall be updated when host provides new advertising data */ + advsm->adi = (advsm->adi & 0xf000) | (rand() & 0x0fff); +#endif + + /* Copy the new data into the advertising structure. */ + advsm->adv_len = datalen + off; + memcpy(advsm->adv_data + off, cmd + 1, datalen); + + return BLE_ERR_SUCCESS; +} + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +int +ble_ll_adv_ext_set_param(uint8_t *cmdbuf, uint8_t *rspbuf, uint8_t *rsplen) +{ + uint8_t adv_filter_policy; + uint8_t adv_chanmask; + uint8_t own_addr_type; + uint8_t peer_addr_type; + uint32_t adv_itvl_min; + uint32_t adv_itvl_max; + uint16_t min_itvl = 0; + uint16_t props; + struct ble_ll_adv_sm *advsm; + uint8_t pri_phy; + uint8_t sec_phy; + uint8_t sid; + uint8_t scan_req_notif; + int8_t tx_power; + + if (cmdbuf[0] >= BLE_LL_ADV_INSTANCES) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + advsm = &g_ble_ll_adv_sm[cmdbuf[0]]; + if (advsm->adv_enabled) { + return BLE_ERR_CMD_DISALLOWED; + } + + props = get_le16(&cmdbuf[1]); + + adv_itvl_min = cmdbuf[5] << 16 | cmdbuf[4] << 8 | cmdbuf[3]; + adv_itvl_max = cmdbuf[8] << 16 | cmdbuf[7] << 8 | cmdbuf[6]; + + if (props & ~BLE_HCI_LE_SET_EXT_ADV_PROP_MASK) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + if (advsm->adv_len > BLE_ADV_DATA_MAX_LEN || + advsm->scan_rsp_len > BLE_SCAN_RSP_DATA_MAX_LEN) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* if legacy bit is set possible values are limited */ + switch (props) { + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND: + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_LD_DIR: + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_HD_DIR: + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_SCAN: + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_NONCONN: + break; + default: + return BLE_ERR_INV_HCI_CMD_PARMS; + } + } else { + /* HD directed advertising allowed only on legacy PDUs */ + if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* if ext advertising PDUs are used then it shall not be both + * connectable and scanable + */ + if ((props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) && + (props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + } + + if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { + min_itvl = BLE_LL_ADV_ITVL_MIN; + } + + if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { + if (advsm->adv_len || advsm->scan_rsp_len) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* Ignore min/max interval */ + min_itvl = 0; + adv_itvl_min = 0; + adv_itvl_max = 0; + } + + /* Make sure interval minimum is valid for the advertising type + * TODO for now limit those to values from legacy advertising + */ + if ((adv_itvl_min > adv_itvl_max) || (adv_itvl_min < min_itvl) || + (adv_itvl_min > BLE_HCI_ADV_ITVL_MAX) || + (adv_itvl_max > BLE_HCI_ADV_ITVL_MAX)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* There are only three adv channels, so check for any outside the range */ + adv_chanmask = cmdbuf[9]; + if (((adv_chanmask & 0xF8) != 0) || (adv_chanmask == 0)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* Check own and peer address type */ + own_addr_type = cmdbuf[10]; + peer_addr_type = cmdbuf[11]; + + if ((own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) || + (peer_addr_type > BLE_HCI_ADV_PEER_ADDR_MAX)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + +#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1) + if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { + /* Reset RPA timer so we generate a new RPA */ + advsm->adv_rpa_timer = os_time_get(); + } +#else + /* If we dont support privacy some address types wont work */ + if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { + return BLE_ERR_UNSUPPORTED; + } +#endif + + adv_filter_policy = cmdbuf[18]; + /* Check filter policy (valid only for undirected */ + if (!(props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) && + adv_filter_policy > BLE_HCI_ADV_FILT_MAX) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + pri_phy = cmdbuf[20]; + if (pri_phy != BLE_HCI_LE_PHY_1M && pri_phy != BLE_HCI_LE_PHY_CODED) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + sec_phy = cmdbuf[22]; + if (pri_phy != BLE_HCI_LE_PHY_1M && pri_phy != BLE_HCI_LE_PHY_2M && + pri_phy != BLE_HCI_LE_PHY_CODED) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + sid = cmdbuf[23]; + if (sid > 0x0f) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + scan_req_notif = cmdbuf[24]; + if (scan_req_notif > 0x01) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { + memcpy(advsm->peer_addr, &cmdbuf[12], BLE_DEV_ADDR_LEN); + } + + tx_power = (int8_t) rspbuf[21]; + if (tx_power == 127) { + /* no preference */ + advsm->adv_txpwr = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); + } else { + advsm->adv_txpwr = ble_phy_txpower_round(tx_power); + } + + advsm->own_addr_type = own_addr_type; + advsm->peer_addr_type = peer_addr_type; + advsm->adv_filter_policy = adv_filter_policy; + advsm->adv_chanmask = adv_chanmask; + advsm->adv_itvl_min = adv_itvl_min; + advsm->adv_itvl_max = adv_itvl_max; + advsm->pri_phy = pri_phy; + advsm->sec_phy = sec_phy; + /* Update SID only */ + advsm->adi = (advsm->adi & 0x0fff) | ((sid << 12)); + + advsm->props = props; + + if (scan_req_notif) { + advsm->flags |= BLE_LL_ADV_SM_FLAG_SCAN_REQ_NOTIF; + } else { + advsm->flags &= ~BLE_LL_ADV_SM_FLAG_SCAN_REQ_NOTIF; + } + + rspbuf[0] = advsm->adv_txpwr; + *rsplen = 1; + + return 0; +} + +int +ble_ll_adv_ext_set_adv_data(uint8_t *cmdbuf, uint8_t cmdlen) +{ + /* check if length is correct */ + if (cmdlen < 4) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* TODO fragment preference ignored for now */ + + return ble_ll_adv_set_adv_data(cmdbuf + 3, cmdbuf[0], cmdbuf[1]); +} + +int +ble_ll_adv_ext_set_scan_rsp(uint8_t *cmdbuf, uint8_t cmdlen) +{ + /* check if length is correct */ + if (cmdlen < 4) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* TODO fragment preference ignored for now */ + + return ble_ll_adv_set_scan_rsp_data(cmdbuf + 3, cmdbuf[0], cmdbuf[1]); +} + +struct ext_adv_set { + uint8_t handle; + uint16_t duration; + uint8_t events; +} __attribute__((packed)); + +/** + * HCI LE extended advertising enable command + * + * @param cmd Pointer to command data + * @param len Command data length + * + * @return int BLE error code + */ +int +ble_ll_adv_ext_set_enable(uint8_t *cmd, uint8_t len) +{ + struct ext_adv_set* set; + uint8_t enable; + uint8_t sets; + int i, j, rc; + + if (len < 2) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + enable = cmd[0]; + sets = cmd[1]; + cmd += 2; + + /* check if length is correct */ + if (len != 2 + (sets * sizeof (*set))) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (sets > BLE_LL_ADV_INSTANCES) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (sets == 0) { + if (enable) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* disable all instances */ + for (i = 0; i < BLE_LL_ADV_INSTANCES; i++) { + ble_ll_adv_set_enable(i, 0, 0, 0); + } + + return BLE_ERR_SUCCESS; + } + + set = (void *) cmd; + /* validate instances */ + for (i = 0; i < sets; i++) { + if (set->handle > BLE_LL_ADV_INSTANCES) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* validate duplicated sets */ + for (j = 1; j < sets - i; j++) { + if (set->handle == set[j].handle) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + } + + set++; + } + + set = (void *) cmd; + for (i = 0; i < sets; i++) { + rc = ble_ll_adv_set_enable(set->handle, enable, le16toh(set->duration), + set->events); + if (rc) { + return rc; + } + + set++; + } return BLE_ERR_SUCCESS; } -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) int ble_ll_adv_set_random_addr(uint8_t *addr, uint8_t instance) { @@ -1050,72 +1977,76 @@ ble_ll_adv_set_random_addr(uint8_t *addr, uint8_t instance) if (instance >= BLE_LL_ADV_INSTANCES) { return BLE_ERR_INV_HCI_CMD_PARMS; } + advsm = &g_ble_ll_adv_sm[instance]; + + /* + * Reject if connectable advertising is on + * Core Spec Vol. 2 Part E 7.8.52 + */ + if (advsm->adv_enabled && + (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE)) { + return BLE_ERR_CMD_DISALLOWED; + } + memcpy(advsm->adv_random_addr, addr, BLE_DEV_ADDR_LEN); return BLE_ERR_SUCCESS; } /** - * Process the multi-advertising command + * HCI LE extended advertising remove command * - * NOTE: the command length was already checked to make sure it is non-zero. + * @param instance Advertising instance to be removed * - * @param cmdbuf Pointer to command buffer - * @param cmdlen The length of the command data - * @param rspbuf Pointer to response buffer - * @param rsplen Pointer to response length - * - * @return int + * @return int BLE error code */ int -ble_ll_adv_multi_adv_cmd(uint8_t *cmdbuf, uint8_t cmdlen, uint8_t *rspbuf, - uint8_t *rsplen) +ble_ll_adv_remove(uint8_t instance) { - int rc; - uint8_t subcmd; + struct ble_ll_adv_sm *advsm; - /* NOTE: the command length includes the sub command byte */ - rc = BLE_ERR_INV_HCI_CMD_PARMS; - subcmd = cmdbuf[0]; - ++cmdbuf; - switch (subcmd) { - case BLE_HCI_MULTI_ADV_PARAMS: - if (cmdlen == BLE_HCI_MULTI_ADV_PARAMS_LEN) { - rc = ble_ll_adv_set_adv_params(cmdbuf, cmdbuf[21], 1); - } - break; - case BLE_HCI_MULTI_ADV_DATA: - if (cmdlen == BLE_HCI_MULTI_ADV_DATA_LEN) { - rc = ble_ll_adv_set_adv_data(cmdbuf, cmdbuf[32]); - } - break; - case BLE_HCI_MULTI_ADV_SCAN_RSP_DATA: - if (cmdlen == BLE_HCI_MULTI_ADV_SCAN_RSP_DATA_LEN) { - rc = ble_ll_adv_set_scan_rsp_data(cmdbuf, cmdbuf[32]); - } - break; - case BLE_HCI_MULTI_ADV_SET_RAND_ADDR: - if (cmdlen == BLE_HCI_MULTI_ADV_SET_RAND_ADDR_LEN) { - rc = ble_ll_adv_set_random_addr(cmdbuf, cmdbuf[6]); - } - break; - case BLE_HCI_MULTI_ADV_ENABLE: - if (cmdlen == BLE_HCI_MULTI_ADV_ENABLE_LEN) { - rc = ble_ll_adv_set_enable(cmdbuf, cmdbuf[1]); - } - break; - default: - rc = BLE_ERR_UNKNOWN_HCI_CMD; - break; + /* TODO + * Should we allow any value for instance ID? + */ + + if (instance >= BLE_LL_ADV_INSTANCES) { + return BLE_ERR_INV_HCI_CMD_PARMS; } - rspbuf[0] = subcmd; - *rsplen = 1; + advsm = &g_ble_ll_adv_sm[instance]; - return rc; + if (advsm->adv_enabled) { + return BLE_ERR_CMD_DISALLOWED; + } + + ble_ll_adv_sm_init(advsm); + + return BLE_ERR_SUCCESS; +} + +/** + * HCI LE extended advertising clear command + * + * @return int BLE error code + */ +int +ble_ll_adv_clear_all(void) +{ + int i; + + for (i = 0; i < BLE_LL_ADV_INSTANCES; i++) { + if (g_ble_ll_adv_sm[i].adv_enabled) { + return BLE_ERR_CMD_DISALLOWED; + } + } + + ble_ll_adv_reset(); + + return BLE_ERR_SUCCESS; } #endif + /** * Called when the LL receives a scan request or connection request * @@ -1140,7 +2071,7 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) uint8_t *peer; struct ble_mbuf_hdr *ble_hdr; struct ble_ll_adv_sm *advsm; - struct os_mbuf *scan_rsp; + struct os_mbuf *rsp; /* See if adva in the request (scan or connect) matches what we sent */ advsm = g_ble_ll_cur_adv_sm; @@ -1200,18 +2131,58 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) /* Setup to transmit the scan response if appropriate */ rc = -1; + if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) { - scan_rsp = ble_ll_adv_scan_rsp_pdu_make(advsm); - if (scan_rsp) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (advsm->flags & BLE_LL_ADV_SM_FLAG_SCAN_REQ_NOTIF) { + ble_ll_hci_ev_send_scan_req_recv(advsm->adv_instance, peer, + peer_addr_type); + } + + rsp = ble_ll_adv_scan_rsp_pdu_make(advsm); +#else + rsp = ble_ll_adv_scan_rsp_legacy_pdu_make(advsm); +#endif + if (rsp) { /* XXX TODO: assume we do not need to change phy mode */ ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm); - rc = ble_phy_tx(scan_rsp, BLE_PHY_TRANSITION_NONE); + rc = ble_phy_tx(rsp, BLE_PHY_TRANSITION_NONE); if (!rc) { ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_SCAN_RSP_TXD; STATS_INC(ble_ll_stats, scan_rsp_txg); } - os_mbuf_free_chain(scan_rsp); + os_mbuf_free_chain(rsp); } + } else if (pdu_type == BLE_ADV_PDU_TYPE_AUX_CONNECT_REQ) { + /* + * Only accept connect requests from the desired address if we + * are doing directed advertising + */ + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { + if (memcmp(advsm->peer_addr, peer, BLE_DEV_ADDR_LEN)) { + return -1; + } + } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + return -1; + } + + /* use remote address used over the air */ + rsp = ble_ll_adv_aux_conn_rsp_pdu_make(advsm, + rxbuf + BLE_LL_PDU_HDR_LEN, + rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK); + if (rsp) { + ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm); + rc = ble_phy_tx(rsp, BLE_PHY_TRANSITION_NONE); + if (!rc) { + advsm->flags |= BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD; + //STATS_INC(ble_ll_stats, scan_rsp_txg); TODO + } + os_mbuf_free_chain(rsp); + } +#endif } return rc; @@ -1239,6 +2210,13 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr, uint8_t *inita; uint8_t *ident_addr; + /* Don't create connection if AUX_CONNECT_RSP was not send */ + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) { + if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD)) { + return 0; + } + } + /* Check filter policy. */ valid = 0; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) @@ -1258,8 +2236,7 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr, * Only accept connect requests from the desired address if we * are doing directed advertising */ - if ((advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) || - (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD)) { + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { ident_addr = inita; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) @@ -1296,9 +2273,13 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr, #endif /* Try to start slave connection. If successful, stop advertising */ - valid = ble_ll_conn_slave_start(rxbuf, addr_type, hdr); + valid = ble_ll_conn_slave_start(rxbuf, addr_type, hdr, + !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)); if (valid) { - ble_ll_adv_sm_stop(advsm); + /* stop advertising only if not transmitting connection response */ + if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD)) { + ble_ll_adv_sm_stop(advsm); + } } } @@ -1330,7 +2311,7 @@ int ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok) { int rc; -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) struct ble_mbuf_hdr *rxhdr; #endif @@ -1338,7 +2319,7 @@ ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok) if (rxpdu == NULL) { ble_ll_adv_tx_done(g_ble_ll_cur_adv_sm); } else { -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) rxhdr = BLE_MBUF_HDR_PTR(rxpdu); rxhdr->rxinfo.advsm = g_ble_ll_cur_adv_sm; #endif @@ -1382,7 +2363,7 @@ ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr) int adv_event_over; struct ble_ll_adv_sm *advsm; -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) advsm = (struct ble_ll_adv_sm *)hdr->rxinfo.advsm; #else advsm = &g_ble_ll_adv_sm[0]; @@ -1449,16 +2430,13 @@ ble_ll_adv_rx_isr_start(uint8_t pdu_type) advsm = g_ble_ll_cur_adv_sm; if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) { /* Only accept scan requests if we are indirect adv or scan adv */ - if ((advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_SCAN_IND) || - (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_IND)) { + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) { rc = 1; } } else { /* Only accept connect requests if connectable advertising event */ if (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_REQ) { - if ((advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) || - (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD) || - (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_IND)) { + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { rc = 0; } } @@ -1475,6 +2453,47 @@ ble_ll_adv_rx_isr_start(uint8_t pdu_type) return rc; } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +static void +ble_ll_adv_secondary_done(struct ble_ll_adv_sm *advsm) +{ + int rc; + + ble_ll_sched_rmv_elem(&advsm->adv_secondary_sch); + os_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + + /* Check if we need to resume scanning */ + ble_ll_scan_chk_resume(); + + if (advsm->events_max && (advsm->events >= advsm->events_max)) { + ble_ll_hci_ev_send_adv_set_terminated(BLE_RR_LIMIT_REACHED, + advsm->adv_instance, 0, + advsm->events); + /* Disable advertising */ + advsm->adv_enabled = 0; + ble_ll_scan_chk_resume(); + return; + } + + ble_ll_set_adv_secondary_start_time(advsm); + ble_ll_adv_secondary_set_sched(advsm); + + /* + * In the unlikely event we cant reschedule this, just post a done + * event and we will reschedule the next advertising event + * + * TODO should we give scheduler more flexibility with delay? + */ + /* Reschedule advertising event */ + rc = ble_ll_sched_adv_reschedule(&advsm->adv_secondary_sch, + &advsm->adv_secondary_start_time, + os_cputime_usecs_to_ticks(0)); + if (rc) { + os_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + } +} +#endif + /** * Called when an advertising event is over. * @@ -1497,8 +2516,22 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) assert(advsm->adv_enabled); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + /* stop advertising this was due to transmitting connection response */ + if (advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD) { + ble_ll_adv_sm_stop(advsm); + return; + } + + if (advsm->flags & BLE_LL_ADV_SM_FLAG_SECONDARY) { + ble_ll_adv_secondary_done(advsm); + return; + } +#endif + /* Remove the element from the schedule if it is still there. */ ble_ll_sched_rmv_elem(&advsm->adv_sch); + os_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); /* @@ -1509,6 +2542,12 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) final_adv_chan = ble_ll_adv_final_chan(advsm); if (advsm->adv_chan == final_adv_chan) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (advsm->events_max) { + advsm->events++; + } +#endif + /* Check if we need to resume scanning */ ble_ll_scan_chk_resume(); @@ -1525,11 +2564,11 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) * add the random advDelay as the scheduling code will do that. */ itvl = advsm->adv_itvl_usecs; - if (advsm->adv_type != BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) { + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { + max_delay_ticks = 0; + } else { max_delay_ticks = os_cputime_usecs_to_ticks(BLE_LL_ADV_DELAY_MS_MAX * 1000); - } else { - max_delay_ticks = 0; } tick_itvl = os_cputime_usecs_to_ticks(itvl); advsm->adv_event_start_time += tick_itvl; @@ -1579,7 +2618,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) * Stop high duty cycle directed advertising if we have been doing * it for more than 1.28 seconds */ - if (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) { + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { if (advsm->adv_pdu_start_time >= advsm->adv_dir_hd_end_time) { /* Disable advertising */ advsm->adv_enabled = 0; @@ -1591,6 +2630,25 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) } } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (advsm->events_max && (advsm->events >= advsm->events_max)) { + /* Legacy PDUs need to be stop here, for ext adv it will be stopped when + * AUX is done. + */ + if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { + ble_ll_hci_ev_send_adv_set_terminated(BLE_RR_LIMIT_REACHED, + advsm->adv_instance, 0, + advsm->events); + + /* Disable advertising */ + advsm->adv_enabled = 0; + ble_ll_scan_chk_resume(); + } + + return; + } +#endif + /* We need to regenerate our RPA's if we have passed timeout */ #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1) ble_ll_adv_chk_rpa_timeout(advsm); @@ -1638,10 +2696,8 @@ ble_ll_adv_event_done(struct os_event *ev) int ble_ll_adv_can_chg_whitelist(void) { - int rc; struct ble_ll_adv_sm *advsm; - -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) + int rc; int i; rc = 1; @@ -1653,15 +2709,6 @@ ble_ll_adv_can_chg_whitelist(void) break; } } -#else - advsm = &g_ble_ll_adv_sm[0]; - if (advsm->adv_enabled && - (advsm->adv_filter_policy != BLE_HCI_ADV_FILT_NONE)) { - rc = 0; - } else { - rc = 1; - } -#endif return rc; } @@ -1678,18 +2725,8 @@ ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm, uint8_t *evbuf; struct ble_ll_adv_sm *advsm; -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) advsm = (struct ble_ll_adv_sm *)rxhdr->rxinfo.advsm; - evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (evbuf) { - evbuf[0] = BLE_HCI_EVCODE_LE_META; - evbuf[1] = 5; /* Length of event, including sub-event code */ - evbuf[2] = BLE_HCI_LE_SUBEV_ADV_STATE_CHG; - evbuf[3] = advsm->adv_instance; - evbuf[4] = 0x00; /* status code */ - put_le16(evbuf + 5, connsm->conn_handle); - ble_ll_hci_event_send(evbuf); - } #else advsm = &g_ble_ll_adv_sm[0]; #endif @@ -1700,6 +2737,11 @@ ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm, ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, evbuf, advsm); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + ble_ll_hci_ev_send_adv_set_terminated(0, advsm->adv_instance, + connsm->conn_handle, advsm->events); +#endif + #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1) ble_ll_hci_ev_le_csa(connsm); #endif @@ -1780,6 +2822,23 @@ ble_ll_adv_enabled(void) return g_ble_ll_adv_sm[0].adv_enabled; } +static void +ble_ll_adv_sm_init(struct ble_ll_adv_sm *advsm) +{ + uint8_t i = advsm->adv_instance; + + memset(advsm, 0, sizeof(struct ble_ll_adv_sm)); + + advsm->adv_instance = i; + advsm->adv_itvl_min = BLE_HCI_ADV_ITVL_DEF; + advsm->adv_itvl_max = BLE_HCI_ADV_ITVL_DEF; + advsm->adv_chanmask = BLE_HCI_ADV_CHANMASK_DEF; + + /* Initialize advertising tx done event */ + advsm->adv_txdone_ev.ev_cb = ble_ll_adv_event_done; + advsm->adv_txdone_ev.ev_arg = advsm; +} + /** * Initialize the advertising functionality of a BLE device. This should * be called once on initialization @@ -1788,22 +2847,11 @@ void ble_ll_adv_init(void) { int i; - struct ble_ll_adv_sm *advsm; /* Set default advertising parameters */ for (i = 0; i < BLE_LL_ADV_INSTANCES; ++i) { - advsm = &g_ble_ll_adv_sm[i]; - - memset(advsm, 0, sizeof(struct ble_ll_adv_sm)); - - advsm->adv_instance = i; - advsm->adv_itvl_min = BLE_HCI_ADV_ITVL_DEF; - advsm->adv_itvl_max = BLE_HCI_ADV_ITVL_DEF; - advsm->adv_chanmask = BLE_HCI_ADV_CHANMASK_DEF; - - /* Initialize advertising tx done event */ - advsm->adv_txdone_ev.ev_cb = ble_ll_adv_event_done; - advsm->adv_txdone_ev.ev_arg = advsm; + g_ble_ll_adv_sm[i].adv_instance = i; + ble_ll_adv_sm_init(&g_ble_ll_adv_sm[i]); } } diff --git a/nimble/controller/src/ble_ll_conn.c b/nimble/controller/src/ble_ll_conn.c index 67a8f209a..e9e010492 100644 --- a/nimble/controller/src/ble_ll_conn.c +++ b/nimble/controller/src/ble_ll_conn.c @@ -2291,9 +2291,24 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) connsm->last_anchor_point = rxhdr->beg_cputime; usecs = rxhdr->rem_usecs + 1250 + - (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS) + - ble_ll_pdu_tx_time_get(BLE_CONNECT_REQ_LEN, - connsm->phy_data.tx_phy_mode); + (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS) + + ble_ll_pdu_tx_time_get(BLE_CONNECT_REQ_LEN, + connsm->phy_data.rx_phy_mode); + + if (rxhdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) { + switch (rxhdr->rxinfo.phy) { + case BLE_PHY_1M: + usecs += 1250; + break; + case BLE_PHY_CODED: + usecs += 2500; + break; + case BLE_PHY_2M: + default: + assert(0); + break; + } + } /* Anchor point is cputime. */ endtime = os_cputime_usecs_to_ticks(usecs); @@ -3714,7 +3729,8 @@ ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, uint8_t *chanmap) * @return 0: connection not started; 1 connecton started */ int -ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr) +ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr, + bool force_csa2) { int rc; uint32_t temp; @@ -3804,7 +3820,9 @@ ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr) /* Start the connection state machine */ connsm->conn_role = BLE_LL_CONN_ROLE_SLAVE; ble_ll_conn_sm_new(connsm); - ble_ll_conn_set_csa(connsm, rxbuf[0] & BLE_ADV_PDU_HDR_CHSEL_MASK); + + ble_ll_conn_set_csa(connsm, + force_csa2 || (rxbuf[0] & BLE_ADV_PDU_HDR_CHSEL_MASK)); /* Set initial schedule callback */ connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb; diff --git a/nimble/controller/src/ble_ll_conn_priv.h b/nimble/controller/src/ble_ll_conn_priv.h index 1e169fc67..60f7aa273 100644 --- a/nimble/controller/src/ble_ll_conn_priv.h +++ b/nimble/controller/src/ble_ll_conn_priv.h @@ -112,7 +112,7 @@ void ble_ll_conn_datalen_update(struct ble_ll_conn_sm *connsm, /* Advertising interface */ int ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, - struct ble_mbuf_hdr *rxhdr); + struct ble_mbuf_hdr *rxhdr, bool force_csa2); /* Link Layer interface */ void ble_ll_conn_module_init(void); diff --git a/nimble/controller/src/ble_ll_hci.c b/nimble/controller/src/ble_ll_hci.c index 625647496..fa41ca6b2 100644 --- a/nimble/controller/src/ble_ll_hci.c +++ b/nimble/controller/src/ble_ll_hci.c @@ -24,7 +24,6 @@ #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" -#include "nimble/hci_vendor.h" #include "nimble/ble_hci_trans.h" #include "controller/ble_hw.h" #include "controller/ble_ll_adv.h" @@ -582,8 +581,25 @@ ble_ll_hci_le_cmd_send_cmd_status(uint16_t ocf) return rc; } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +/** HCI LE read maximum advertising data length command. Returns the controllers +* max supported advertising data length; +* +* @param rspbuf Pointer to response buffer +* @param rsplen Length of response buffer +* +* @return int BLE error code +*/ +static int +ble_ll_adv_rd_max_adv_data_len(uint8_t *rspbuf, uint8_t *rsplen) +{ + put_le16(rspbuf, BLE_ADV_DATA_MAX_LEN); + *rsplen = BLE_HCI_RD_MAX_ADV_DATA_LEN; + return BLE_ERR_SUCCESS; +} + /** - * Returns the vendor specific capabilities + * HCI LE read number of supported advertising sets * * @param rspbuf Pointer to response buffer * @param rsplen Length of response buffer @@ -591,78 +607,21 @@ ble_ll_hci_le_cmd_send_cmd_status(uint16_t ocf) * @return int BLE error code */ static int -ble_ll_hci_vendor_caps(uint8_t *rspbuf, uint8_t *rsplen) +ble_ll_adv_rd_sup_adv_sets(uint8_t *rspbuf, uint8_t *rsplen) { - /* Clear all bytes */ - memset(rspbuf, 0, 14); - - /* Fill out the ones we support */ rspbuf[0] = BLE_LL_ADV_INSTANCES; - rspbuf[9] = 0x60; - *rsplen = 14; + *rsplen = BLE_HCI_RD_NR_SUP_ADV_SETS; return BLE_ERR_SUCCESS; } -/** - * Process a vendor command sent from the host to the controller. The HCI - * command has a 3 byte command header followed by data. The header is: - * -> opcode (2 bytes) - * -> Length of parameters (1 byte; does include command header bytes). - * - * @param cmdbuf Pointer to command buffer. Points to start of command header. - * @param ocf Opcode command field. - * @param *rsplen Pointer to length of response - * - * @return int This function returns a BLE error code. If a command status - * event should be returned as opposed to command complete, - * 256 gets added to the return value. - */ static int -ble_ll_hci_vendor_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, uint8_t *rsplen) +ble_ll_ext_adv_set_remove(uint8_t *cmd) { - int rc; - uint8_t cmdlen; - uint8_t *rspbuf; - - /* Assume error; if all pass rc gets set to 0 */ - rc = BLE_ERR_INV_HCI_CMD_PARMS; - - /* Get length from command */ - cmdlen = cmdbuf[sizeof(uint16_t)]; - - /* - * The command response pointer points into the same buffer as the - * command data itself. That is fine, as each command reads all the data - * before crafting a response. - */ - rspbuf = cmdbuf + BLE_HCI_EVENT_CMD_COMPLETE_MIN_LEN; - - /* Move past HCI command header */ - cmdbuf += BLE_HCI_CMD_HDR_LEN; - - switch (ocf) { - case BLE_HCI_OCF_VENDOR_CAPS: - if (cmdlen == 0) { - ble_ll_hci_vendor_caps(rspbuf, rsplen); - rc = BLE_ERR_SUCCESS; - } - break; -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) - case BLE_HCI_OCF_MULTI_ADV: - if (cmdlen > 0) { - rc = ble_ll_adv_multi_adv_cmd(cmdbuf, cmdlen, rspbuf, rsplen); - } - break; -#endif - default: - rc = BLE_ERR_UNKNOWN_HCI_CMD; - break; - } - - /* XXX: for now, all vendor commands return a command complete */ - return rc; + return ble_ll_adv_remove(cmd[0]); } +#endif + /** * Process a LE command sent from the host to the controller. The HCI command * has a 3 byte command header followed by data. The header is: @@ -721,19 +680,21 @@ ble_ll_hci_le_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, uint8_t *rsplen) rc = ble_ll_set_random_addr(cmdbuf); break; case BLE_HCI_OCF_LE_SET_ADV_PARAMS: - rc = ble_ll_adv_set_adv_params(cmdbuf, 0, 0); + rc = ble_ll_adv_set_adv_params(cmdbuf); break; case BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR: rc = ble_ll_adv_read_txpwr(rspbuf, rsplen); break; case BLE_HCI_OCF_LE_SET_ADV_DATA: - rc = ble_ll_adv_set_adv_data(cmdbuf, 0); + rc = ble_ll_adv_set_adv_data(cmdbuf, 0, + BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_COMPLETE); break; case BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA: - rc = ble_ll_adv_set_scan_rsp_data(cmdbuf, 0); + rc = ble_ll_adv_set_scan_rsp_data(cmdbuf, 0, + BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_COMPLETE); break; case BLE_HCI_OCF_LE_SET_ADV_ENABLE: - rc = ble_ll_adv_set_enable(cmdbuf, 0); + rc = ble_ll_adv_set_enable(cmdbuf[0], 0, 0, 0); break; case BLE_HCI_OCF_LE_SET_SCAN_ENABLE: rc = ble_ll_scan_set_enable(cmdbuf, 0); @@ -852,6 +813,35 @@ ble_ll_hci_le_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, uint8_t *rsplen) case BLE_HCI_OCF_LE_RD_MAX_DATA_LEN: rc = ble_ll_hci_le_rd_max_data_len(rspbuf, rsplen); break; +#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) == 1) + case BLE_HCI_OCF_LE_SET_ADV_SET_RND_ADDR: + rc = ble_ll_adv_set_random_addr(cmdbuf + 1, cmdbuf[0]); + break; + case BLE_HCI_OCF_LE_SET_EXT_ADV_PARAM: + rc = ble_ll_adv_ext_set_param(cmdbuf, rspbuf, rsplen); + break; + case BLE_HCI_OCF_LE_SET_EXT_ADV_DATA: + rc = ble_ll_adv_ext_set_adv_data(cmdbuf, cmdlen); + break; + case BLE_HCI_OCF_LE_SET_EXT_SCAN_RSP_DATA: + rc = ble_ll_adv_ext_set_scan_rsp(cmdbuf, cmdlen); + break; + case BLE_HCI_OCF_LE_SET_EXT_ADV_ENABLE: + rc = ble_ll_adv_ext_set_enable(cmdbuf, len); + break; + case BLE_HCI_OCF_LE_RD_MAX_ADV_DATA_LEN: + rc = ble_ll_adv_rd_max_adv_data_len(rspbuf, rsplen); + break; + case BLE_HCI_OCF_LE_RD_NUM_OF_ADV_SETS: + rc = ble_ll_adv_rd_sup_adv_sets(rspbuf, rsplen); + break; + case BLE_HCI_OCF_LE_REMOVE_ADV_SET: + rc = ble_ll_ext_adv_set_remove(cmdbuf); + break; + case BLE_HCI_OCF_LE_CLEAR_ADV_SETS: + rc = ble_ll_adv_clear_all(); + break; +#endif #if (BLE_LL_BT5_PHY_SUPPORTED == 1) case BLE_HCI_OCF_LE_RD_PHY: rc = ble_ll_conn_hci_le_rd_phy(cmdbuf, rspbuf, rsplen); @@ -1122,9 +1112,6 @@ ble_ll_hci_cmd_proc(struct os_event *ev) case BLE_HCI_OGF_LE: rc = ble_ll_hci_le_cmd_proc(cmdbuf, ocf, &rsplen); break; - case BLE_HCI_OGF_VENDOR: - rc = ble_ll_hci_vendor_cmd_proc(cmdbuf, ocf, &rsplen); - break; default: /* XXX: Need to support other OGF. For now, return unsupported */ rc = BLE_ERR_UNKNOWN_HCI_CMD; diff --git a/nimble/controller/src/ble_ll_hci_ev.c b/nimble/controller/src/ble_ll_hci_ev.c index bd7b8ad2a..70ba68f9c 100644 --- a/nimble/controller/src/ble_ll_hci_ev.c +++ b/nimble/controller/src/ble_ll_hci_ev.c @@ -293,6 +293,59 @@ ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm) } #endif +/** + * Sends the LE Scan Request Received event + * + */ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +void +ble_ll_hci_ev_send_scan_req_recv(uint8_t adv_handle, const uint8_t *peer, + uint8_t peer_addr_type) +{ + uint8_t *evbuf; + + if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD)) { + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + if (evbuf) { + evbuf[0] = BLE_HCI_EVCODE_LE_META; + evbuf[1] = BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD_LEN; + evbuf[2] = BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD; + evbuf[3] = adv_handle; + evbuf[4] = peer_addr_type; + memcpy(&evbuf[5], peer, BLE_DEV_ADDR_LEN); + ble_ll_hci_event_send(evbuf); + } + } +} +#endif + +/** + * Sends the LE Advertising Set Terminated event + * + */ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +void +ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle, + uint16_t conn_handle, uint8_t events) +{ + uint8_t *evbuf; + + if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED)) { + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + if (evbuf) { + evbuf[0] = BLE_HCI_EVCODE_LE_META; + evbuf[1] = BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED_LEN; + evbuf[2] = BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED; + evbuf[3] = status; + evbuf[4] = adv_handle; + put_le16(evbuf + 5, conn_handle); + evbuf[7] = events; + ble_ll_hci_event_send(evbuf); + } + } +} +#endif + /** * Send a PHY update complete event * diff --git a/nimble/controller/src/ble_ll_sched.c b/nimble/controller/src/ble_ll_sched.c index 0b7d78dcb..2ffb1cec5 100644 --- a/nimble/controller/src/ble_ll_sched.c +++ b/nimble/controller/src/ble_ll_sched.c @@ -595,7 +595,7 @@ ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm) } int -ble_ll_sched_adv_new(struct ble_ll_sched_item *sch) +ble_ll_sched_adv_new(struct ble_ll_sched_item *sch, ble_ll_sched_adv_new_cb cb) { int rc; os_sr_t sr; @@ -646,7 +646,9 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch) sch = TAILQ_FIRST(&g_ble_ll_sched_q); } - ble_ll_adv_scheduled((struct ble_ll_adv_sm *)orig->cb_arg, adv_start); + if (cb) { + cb((struct ble_ll_adv_sm *)orig->cb_arg, adv_start); + } #ifdef BLE_XCVR_RFCLK if (orig == sch) { diff --git a/nimble/drivers/native/src/ble_phy.c b/nimble/drivers/native/src/ble_phy.c index a8fd9f54d..6a39346c7 100644 --- a/nimble/drivers/native/src/ble_phy.c +++ b/nimble/drivers/native/src/ble_phy.c @@ -497,6 +497,29 @@ ble_phy_txpwr_set(int dbm) return 0; } +/** + * ble phy txpwr round + * + * Get the rounded transmit output power (in dBm). + * + * @param dbm Power output in dBm. + * + * @return int Rounded power in dBm + */ +int ble_phy_txpower_round(int dbm) +{ + /* "Rail" power level if outside supported range */ + if (dbm > BLE_XCVR_TX_PWR_MAX_DBM) { + dbm = BLE_XCVR_TX_PWR_MAX_DBM; + } else { + if (dbm < BLE_XCVR_TX_PWR_MIN_DBM) { + dbm = BLE_XCVR_TX_PWR_MIN_DBM; + } + } + + return dbm; +} + /** * ble phy txpwr get * diff --git a/nimble/drivers/nrf51/src/ble_phy.c b/nimble/drivers/nrf51/src/ble_phy.c index 84d61d6a1..b74e7831b 100644 --- a/nimble/drivers/nrf51/src/ble_phy.c +++ b/nimble/drivers/nrf51/src/ble_phy.c @@ -1212,6 +1212,29 @@ ble_phy_txpwr_set(int dbm) return 0; } +/** + * ble phy txpwr round + * + * Get the rounded transmit output power (in dBm). + * + * @param dbm Power output in dBm. + * + * @return int Rounded power in dBm + */ +int ble_phy_txpower_round(int dbm) +{ + /* "Rail" power level if outside supported range */ + if (dbm > NRF_TX_PWR_MAX_DBM) { + dbm = NRF_TX_PWR_MAX_DBM; + } else { + if (dbm < NRF_TX_PWR_MIN_DBM) { + dbm = NRF_TX_PWR_MIN_DBM; + } + } + + return dbm; +} + /** * ble phy txpwr get * diff --git a/nimble/drivers/nrf52/src/ble_phy.c b/nimble/drivers/nrf52/src/ble_phy.c index 81becf955..f14831448 100644 --- a/nimble/drivers/nrf52/src/ble_phy.c +++ b/nimble/drivers/nrf52/src/ble_phy.c @@ -1294,6 +1294,29 @@ ble_phy_txpwr_set(int dbm) return 0; } +/** + * ble phy txpwr round + * + * Get the rounded transmit output power (in dBm). + * + * @param dbm Power output in dBm. + * + * @return int Rounded power in dBm + */ +int ble_phy_txpower_round(int dbm) +{ + /* "Rail" power level if outside supported range */ + if (dbm > NRF_TX_PWR_MAX_DBM) { + dbm = NRF_TX_PWR_MAX_DBM; + } else { + if (dbm < NRF_TX_PWR_MIN_DBM) { + dbm = NRF_TX_PWR_MIN_DBM; + } + } + + return dbm; +} + /** * ble phy set access addr * diff --git a/nimble/include/nimble/ble.h b/nimble/include/nimble/ble.h index 69ac3a384..d8e019942 100644 --- a/nimble/include/nimble/ble.h +++ b/nimble/include/nimble/ble.h @@ -67,10 +67,9 @@ struct ble_mbuf_hdr_rxinfo uint8_t handle; int8_t rssi; int8_t phy; -#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT) - void *advsm; /* advertising state machine */ -#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + /* TODO this could be just one user-data pointer */ + void *advsm; /* advertising state machine */ void *aux_data; #endif }; @@ -208,6 +207,9 @@ enum ble_error_codes BLE_ERR_CONN_ESTABLISHMENT = 62, BLE_ERR_MAC_CONN_FAIL = 63, BLE_ERR_COARSE_CLK_ADJ = 64, + BLE_ERR_TYPE0_SUBMAP_NDEF = 65, + BLE_ERR_UNK_ADV_INDENT = 66, + BLE_RR_LIMIT_REACHED = 67, BLE_ERR_MAX = 255 }; diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h index 4686c51fe..9b5712eb4 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -467,12 +467,35 @@ extern "C" { /* --- LE set extended advertising parameters (OCF 0x0036) */ #define BLE_HCI_LE_SET_EXT_ADV_PARAM_LEN (25) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE (0x0001) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE (0x0002) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED (0x0004) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED (0x0008) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY (0x0010) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV (0x0020) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR (0x0040) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_MASK (0x7F) + +#define BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND (0x0013) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_LD_DIR (0x0015) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_HD_DIR (0x001d) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_SCAN (0x0012) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_NONCONN (0x0010) /* --- LE set extended advertising data (OCF 0x0037) */ #define BLE_HCI_LE_SET_EXT_ADV_DATA_LEN BLE_HCI_VARIABLE_LEN +#define BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_INT (0) +#define BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_FIRST (1) +#define BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_LAST (2) +#define BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_COMPLETE (3) +#define BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_UNCHANGED (4) /* --- LE set extended scan response data (OCF 0x0038) */ #define BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_LEN BLE_HCI_VARIABLE_LEN +#define BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_INT (0) +#define BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_FIRST (1) +#define BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_LAST (2) +#define BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_COMPLETE (3) /* --- LE set extended advertising enable (OCF 0x0039) */ #define BLE_HCI_LE_SET_EXT_ADV_ENABLE_LEN BLE_HCI_VARIABLE_LEN @@ -480,6 +503,12 @@ extern "C" { /* --- LE remove advertising set (OCF 0x003C) */ #define BLE_HCI_LE_REMOVE_ADV_SET_LEN (1) +/* --- LE read maximum advertising data length (OCF 0x003A) */ +#define BLE_HCI_RD_MAX_ADV_DATA_LEN (2) + +/* --- LE read number of supported advertising sets (OCF 0x003B) */ +#define BLE_HCI_RD_NR_SUP_ADV_SETS (1) + /* --- LE set periodic advertising parameters (OCF 0x003E) */ #define BLE_HCI_LE_SET_PER_ADV_PARAMS_LEN (7) @@ -706,6 +735,12 @@ extern "C" { /* LE PHY update complete event (sub event 0x0C) */ #define BLE_HCI_LE_PHY_UPD_LEN (6) +/* LE Advertising Set Terminated Event (sub event 0x12) */ +#define BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED_LEN (6) + +/* LE Scan Request Received event (sub event 0x13) */ +#define BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD_LEN (9) + /* LE Channel Selection Algorithm event (sub event 0x14) */ #define BLE_HCI_LE_SUBEV_CHAN_SEL_ALG_LEN (4) diff --git a/nimble/include/nimble/hci_vendor.h b/nimble/include/nimble/hci_vendor.h deleted file mode 100644 index 2ef3190c3..000000000 --- a/nimble/include/nimble/hci_vendor.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_HCI_VENDOR_ -#define H_BLE_HCI_VENDOR_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Here is a list of the vendor specific OCFs */ -#define BLE_HCI_OCF_VENDOR_CAPS (0x153) -#define BLE_HCI_OCF_MULTI_ADV (0x154) - -/* Multi-advertiser sub-commands */ -#define BLE_HCI_MULTI_ADV_PARAMS (0x01) -#define BLE_HCI_MULTI_ADV_DATA (0x02) -#define BLE_HCI_MULTI_ADV_SCAN_RSP_DATA (0x03) -#define BLE_HCI_MULTI_ADV_SET_RAND_ADDR (0x04) -#define BLE_HCI_MULTI_ADV_ENABLE (0x05) - -/* Command lengths. Includes sub-command opcode */ -#define BLE_HCI_MULTI_ADV_PARAMS_LEN (24) -#define BLE_HCI_MULTI_ADV_DATA_LEN (34) -#define BLE_HCI_MULTI_ADV_SCAN_RSP_DATA_LEN (34) -#define BLE_HCI_MULTI_ADV_SET_RAND_ADDR_LEN (8) -#define BLE_HCI_MULTI_ADV_ENABLE_LEN (3) - -/* Vendor specific events (LE meta events) */ -#define BLE_HCI_LE_SUBEV_ADV_STATE_CHG (0x55) - -/* Data structures associated with vendor specific commands */ -struct hci_vendor_capabilities -{ - uint8_t max_advt_instances; - uint8_t offloaded_resolution_of_priv_addr; - uint16_t total_scan_results_bytes; - uint8_t max_irk_list_sz; - uint8_t filtering_support; - uint8_t max_filters; - uint8_t activity_energy_info_support; - uint16_t version_supported; - uint16_t total_adv_tracked; - uint8_t extended_scan_support; - uint8_t debug_logging_supported; -}; - -/* NOTE: these are not in command order */ -struct hci_multi_adv_params -{ - uint8_t adv_type; - uint8_t adv_channel_map; - uint8_t own_addr_type; - uint8_t peer_addr_type; - uint8_t adv_filter_policy; - int8_t adv_tx_pwr; /* -70 to +20 */ - uint8_t adv_instance; - uint16_t adv_itvl_min; - uint16_t adv_itvl_max; - uint8_t peer_addr[BLE_DEV_ADDR_LEN]; - uint8_t own_addr[BLE_DEV_ADDR_LEN]; -}; - -/* - * NOTE: structures are not defined for the following sub commands. - * The format of these commands is: - * - * Multi-adv Set Advertising Data: - * - Advertising data length (1) - * - Advertising data (31) - * - Advertising Instance (1) - * - * Multi-adv Set Scan Response Data: - * - Scan response data length (1) - * - Scan response data (31) - * - Advertising Instance (1) - * - * Multi-adv Set Random Address: - * - Random Address (6) - * - Advertising Instance (1) - * - * Multi-adv Set Advertising Enable: - * - Random Address (6) - * - Advertising Instance (1) - * - * All of these commands generate a Command Complete with this format: - * - Status (1) - * - Multi-adv opcode (1) - */ - - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_HCI_VENDOR_ */ diff --git a/nimble/syscfg.yml b/nimble/syscfg.yml index 8675b65d2..4d379571b 100644 --- a/nimble/syscfg.yml +++ b/nimble/syscfg.yml @@ -41,9 +41,6 @@ syscfg.defs: Enables the BLE whitelist for controlling who to connect to or accept a connection from. (0/1) value: 1 - BLE_MULTI_ADV_SUPPORT: - description: 'Support for multi-advertisers' - value: 0 BLE_MULTI_ADV_INSTANCES: description: > This is the number of multi-advertising instances. This is NOT the