From 560d7773be2f543f8a73a6cf0c3bb807c2bc4dbc Mon Sep 17 00:00:00 2001 From: "Jens B." Date: Sat, 17 Feb 2024 19:10:46 +0100 Subject: [PATCH] extended advertising - support BLE_GAP_ADV_SET_DATA_SIZE_MAX - add setters for advertising parameters max_adv_evts, filter_policy, primary_phy and secondary_phy --- libraries/Bluefruit52Lib/library.properties | 4 +- .../Bluefruit52Lib/src/BLEAdvertising.cpp | 132 +++++++++++++++--- libraries/Bluefruit52Lib/src/BLEAdvertising.h | 19 ++- 3 files changed, 129 insertions(+), 26 deletions(-) diff --git a/libraries/Bluefruit52Lib/library.properties b/libraries/Bluefruit52Lib/library.properties index a68f583ee..85af1fcde 100644 --- a/libraries/Bluefruit52Lib/library.properties +++ b/libraries/Bluefruit52Lib/library.properties @@ -1,6 +1,6 @@ name=Adafruit Bluefruit nRF52 Libraries -version=0.21.0 -author=Adafruit +version=0.21.1 +author=JensB maintainer=Adafruit sentence=Arduino library for nRF52-based Adafruit Bluefruit LE modules paragraph=Arduino library for nRF52-based Adafruit Bluefruit LE modules diff --git a/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp b/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp index e44372337..b53e84124 100644 --- a/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp +++ b/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp @@ -41,13 +41,17 @@ *------------------------------------------------------------------*/ BLEAdvertisingData::BLEAdvertisingData(void) { - _count = 0; - arrclr(_data); + clearData(); +} + +void BLEAdvertisingData::setMaxLen(uint8_t max_len) +{ + _max_len = max_len; } bool BLEAdvertisingData::addData(uint8_t type, const void* data, uint8_t len) { - VERIFY( _count + len + 2 <= BLE_GAP_ADV_SET_DATA_SIZE_MAX ); + VERIFY( _count + len + 2 <= _max_len ); uint8_t* adv_data = &_data[_count]; @@ -183,7 +187,7 @@ bool BLEAdvertisingData::addName(void) uint8_t len = Bluefruit.getName(name, sizeof(name)); // not enough for full name, chop it - if (_count + len + 2 > BLE_GAP_ADV_SET_DATA_SIZE_MAX) + if (_count + len + 2 > _max_len) { type = BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME; len = BLE_GAP_ADV_SET_DATA_SIZE_MAX - (_count+2); @@ -231,7 +235,7 @@ uint8_t* BLEAdvertisingData::getData(void) bool BLEAdvertisingData::setData(uint8_t const * data, uint8_t count) { - VERIFY( data && (count <= BLE_GAP_ADV_SET_DATA_SIZE_MAX) ); + VERIFY( data && (count <= _max_len) ); memcpy(_data, data, count); _count = count; @@ -243,6 +247,7 @@ void BLEAdvertisingData::clearData(void) { _count = 0; arrclr(_data); + _max_len = BLE_GAP_ADV_SET_DATA_SIZE_MAX; } /*------------------------------------------------------------------*/ @@ -275,6 +280,14 @@ void BLEAdvertising::setFastTimeout(uint16_t sec) void BLEAdvertising::setType(uint8_t adv_type) { _type = adv_type; + if (isExtended()) + { + setMaxLen(BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED); + } + else + { + setMaxLen(BLE_GAP_ADV_SET_DATA_SIZE_MAX); + } } /** @@ -296,6 +309,22 @@ void BLEAdvertising::setIntervalMS(uint16_t fast, uint16_t slow) setInterval(MS1000TO625(fast), MS1000TO625(slow)); } +void BLEAdvertising::setMaxEvents(uint8_t maxEvents) +{ + _max_events = maxEvents; +} + +void BLEAdvertising::setFilter(uint8_t filter) +{ + _filter = filter; +} + +void BLEAdvertising::setPhy(uint8_t phy) +{ + _primary_phy = phy; + _secondary_phy = phy; +} + /** * Get current active interval * @return Either slow or fast interval in unit of 0.625 ms @@ -324,6 +353,42 @@ bool BLEAdvertising::isRunning(void) return _runnning; } +bool BLEAdvertising::isScannable(void) +{ + return _type == BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED + || _type == BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED + || _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED + || _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED; +} + +bool BLEAdvertising::isConnectable(void) +{ + return _type == BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED + || _type == BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE + || _type == BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED + || _type == BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED + || _type == BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED; +} + +bool BLEAdvertising::isDirected(void) +{ + return _type == BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE + || _type == BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED + || _type == BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED + || _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED + || _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED; +} + +bool BLEAdvertising::isExtended(void) +{ + return _type == BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED + || _type == BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED + || _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED + || _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED + || _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED + || _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED; +} + bool BLEAdvertising::setBeacon(BLEBeacon& beacon) { return beacon.start(*this); @@ -348,32 +413,41 @@ bool BLEAdvertising::_start(uint16_t interval, uint16_t timeout) .interval = interval , // advertising interval (in units of 0.625 ms) .duration = (uint16_t) (timeout*100) , // in 10-ms unit - .max_adv_evts = 0 , // TODO can be used for fast/slow mode - .channel_mask = { 0, 0, 0, 0, 0 } , // 40 channel, set 1 to disable - .filter_policy = BLE_GAP_ADV_FP_ANY , + .max_adv_evts = _max_events , // can be used for fast/slow mode + .channel_mask = { 0, 0, 0, 0, 0 } , // 40 channel, set 1 to disable, e.g. { 0, 0, 0, 0, 0xA0 } for not primary 37 and 38 + .filter_policy = _filter , - .primary_phy = BLE_GAP_PHY_AUTO , // 1 Mbps will be used - .secondary_phy = BLE_GAP_PHY_AUTO , // 1 Mbps will be used + .primary_phy = (isExtended() ? _primary_phy : (uint8_t)BLE_GAP_PHY_AUTO) , + .secondary_phy = _secondary_phy , // , .set_id, .scan_req_notification }; - switch(_type) { - case BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE: - case BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED: - case BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED: - case BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED: - case BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED: - adv_para.p_peer_addr = &_peer_addr; - break; - - default: break; - } - + if (isDirected()) { + adv_para.p_peer_addr = &_peer_addr; + } + // gap_adv long-live is required by SD v6 static ble_gap_adv_data_t gap_adv = { .adv_data = { .p_data = _data, .len = _count }, .scan_rsp_data = { .p_data = Bluefruit.ScanResponse.getData(), .len = Bluefruit.ScanResponse.count() } }; + + // no advertising data supported? + // https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.s140.api.v7.3.0/group___b_l_e___g_a_p___a_d_v___t_y_p_e_s.html + if ( _type == BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED + || _type == BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE + || _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED + || _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED ) + { + gap_adv.adv_data = { .p_data = nullptr, .len = 0 }; + } + + // no scan response data required? + if (!isScannable()) + { + gap_adv.scan_rsp_data = { .p_data = nullptr, .len = 0 }; + } + VERIFY_STATUS( sd_ble_gap_adv_set_configure(&_hdl, &gap_adv, &adv_para), false ); VERIFY_STATUS( sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, _hdl, Bluefruit.getTxPower() ), false ); VERIFY_STATUS( sd_ble_gap_adv_start(_hdl, CONN_CFG_PERIPHERAL), false ); @@ -473,9 +547,21 @@ void BLEAdvertising::_eventHandler(ble_evt_t* evt) if (_stop_cb) ada_callback(NULL, 0, _stop_cb); } } + }else + { + if (evt->evt.gap_evt.params.adv_set_terminated.reason == BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_LIMIT_REACHED) + { + _runnning = false; + + // Stop advertising + Bluefruit._stopConnLed(); // stop blinking + + // invoke stop callback + if (_stop_cb) ada_callback(NULL, 0, _stop_cb); + } } break; default: break; } -} \ No newline at end of file +} diff --git a/libraries/Bluefruit52Lib/src/BLEAdvertising.h b/libraries/Bluefruit52Lib/src/BLEAdvertising.h index 3a0c556ec..212c67202 100644 --- a/libraries/Bluefruit52Lib/src/BLEAdvertising.h +++ b/libraries/Bluefruit52Lib/src/BLEAdvertising.h @@ -72,12 +72,16 @@ class Advertisable class BLEAdvertisingData { protected: - uint8_t _data[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; + uint8_t _max_len = BLE_GAP_ADV_SET_DATA_SIZE_MAX; + uint8_t _data[BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED]; uint8_t _count; public: BLEAdvertisingData(void); + // @param max_len must be set before adding data, defaults to BLE_GAP_ADV_SET_DATA_SIZE_MAX + void setMaxLen(uint8_t max_len); + /*------------- Adv Data -------------*/ bool addData(uint8_t type, const void* data, uint8_t len); bool addFlags(uint8_t flags); @@ -120,6 +124,7 @@ class BLEAdvertising : public BLEAdvertisingData BLEAdvertising(void); + // must be set as first property after clear for extended advertising void setType(uint8_t adv_type); void setFastTimeout(uint16_t sec); @@ -129,6 +134,10 @@ class BLEAdvertising : public BLEAdvertisingData void setInterval (uint16_t fast, uint16_t slow); void setIntervalMS(uint16_t fast, uint16_t slow); + void setMaxEvents(uint8_t maxEvents); + void setFilter(uint8_t filter); + void setPhy(uint8_t phy); + uint16_t getInterval(void); bool setBeacon(BLEBeacon& beacon); @@ -138,6 +147,10 @@ class BLEAdvertising : public BLEAdvertisingData void setPeerAddress(const ble_gap_addr_t& peer_addr); bool isRunning(void); + bool isScannable(void); + bool isConnectable(void); + bool isDirected(void); + bool isExtended(void); void restartOnDisconnect(bool enable); bool start(uint16_t timeout = 0); @@ -153,6 +166,10 @@ class BLEAdvertising : public BLEAdvertisingData private: uint8_t _hdl; uint8_t _type; + uint8_t _max_events = 0; // initially time limited + uint8_t _filter = BLE_GAP_ADV_FP_ANY; + uint8_t _primary_phy = BLE_GAP_PHY_AUTO; + uint8_t _secondary_phy = BLE_GAP_PHY_AUTO; bool _start_if_disconnect; bool _runnning; ble_gap_addr_t _peer_addr; //! Target address for an ADV_DIRECT_IND advertisement