Skip to content

Commit d999e62

Browse files
authored
Merge pull request #813 from jnsbyr/feature/extended-advertising
improve support for extended advertising and add missing setters for advertising parameters
2 parents a0aad47 + 5b3721f commit d999e62

3 files changed

Lines changed: 206 additions & 38 deletions

File tree

libraries/Bluefruit52Lib/library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=Adafruit Bluefruit nRF52 Libraries
2-
version=0.21.0
2+
version=0.22.0
33
author=Adafruit
44
maintainer=Adafruit <info@adafruit.com>
55
sentence=Arduino library for nRF52-based Adafruit Bluefruit LE modules

libraries/Bluefruit52Lib/src/BLEAdvertising.cpp

Lines changed: 177 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,51 @@
4040
/* BLEAdvertisingData shared between ADV and ScanResponse
4141
*------------------------------------------------------------------*/
4242
BLEAdvertisingData::BLEAdvertisingData(void)
43+
: _data(NULL), _max_len(0), _count(0)
4344
{
44-
_count = 0;
45-
arrclr(_data);
45+
setMaxLen(BLE_GAP_ADV_SET_DATA_SIZE_MAX);
46+
}
47+
48+
BLEAdvertisingData::~BLEAdvertisingData(void)
49+
{
50+
if (_data) rtos_free(_data);
51+
}
52+
53+
void BLEAdvertisingData::setMaxLen(uint8_t max_len)
54+
{
55+
if (_data && max_len == _max_len) return;
56+
57+
uint8_t* old_data = _data;
58+
uint8_t old_count = _count;
59+
60+
if (old_count)
61+
{
62+
// stop advertising before re-allocate adv buffer
63+
if (Bluefruit.Advertising.isRunning()) Bluefruit.Advertising.stop();
64+
}
65+
66+
_data = (uint8_t*) rtos_malloc(max_len);
67+
if (_data)
68+
{
69+
// Preserve previously added bytes across resize; truncate if shrinking.
70+
uint8_t keep = (old_count <= max_len) ? old_count : max_len;
71+
if (old_data && keep) memcpy(_data, old_data, keep);
72+
if (keep < max_len) memset(_data + keep, 0, max_len - keep);
73+
_max_len = max_len;
74+
_count = keep;
75+
}
76+
else
77+
{
78+
_max_len = 0;
79+
_count = 0;
80+
}
81+
82+
if (old_data) rtos_free(old_data);
4683
}
4784

4885
bool BLEAdvertisingData::addData(uint8_t type, const void* data, uint8_t len)
4986
{
50-
VERIFY( _count + len + 2 <= BLE_GAP_ADV_SET_DATA_SIZE_MAX );
87+
VERIFY( _count + len + 2 <= _max_len );
5188

5289
uint8_t* adv_data = &_data[_count];
5390

@@ -177,19 +214,34 @@ bool BLEAdvertisingData::addService(BLEClientService& service)
177214
*/
178215
bool BLEAdvertisingData::addName(void)
179216
{
180-
char name[BLE_GAP_ADV_SET_DATA_SIZE_MAX+1];
181-
182-
uint8_t type = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
183-
uint8_t len = Bluefruit.getName(name, sizeof(name));
184-
185-
// not enough for full name, chop it
186-
if (_count + len + 2 > BLE_GAP_ADV_SET_DATA_SIZE_MAX)
187-
{
217+
// Need room for at least [len][type][1 char]
218+
VERIFY(_count + 2 < _max_len);
219+
uint8_t* adv_slot = &_data[_count];
220+
const uint8_t remaining = _max_len - _count - 2;
221+
222+
// Try writing the name directly into _data. If it fits, sd returns NRF_SUCCESS
223+
// with name_len = bytes copied. If it doesn't fit, sd returns NRF_ERROR_DATA_SIZE
224+
// without copying and sets name_len to the full device name length.
225+
uint16_t name_len = remaining;
226+
uint32_t err = sd_ble_gap_device_name_get(adv_slot + 2, &name_len);
227+
228+
uint8_t type;
229+
uint8_t len;
230+
if (err == NRF_SUCCESS) {
231+
type = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
232+
len = (uint8_t) name_len;
233+
} else {
234+
// Truncate: fetch full name into a temp buffer, then copy what fits.
235+
uint8_t buftmp[name_len];
236+
VERIFY_STATUS(sd_ble_gap_device_name_get(buftmp, &name_len), false);
237+
memcpy(adv_slot + 2, buftmp, remaining);
188238
type = BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME;
189-
len = BLE_GAP_ADV_SET_DATA_SIZE_MAX - (_count+2);
239+
len = remaining;
190240
}
191241

192-
VERIFY( addData(type, name, len) );
242+
adv_slot[0] = len + 1;
243+
adv_slot[1] = type;
244+
_count += 2 + len;
193245

194246
return type == BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
195247
}
@@ -231,7 +283,7 @@ uint8_t* BLEAdvertisingData::getData(void)
231283

232284
bool BLEAdvertisingData::setData(uint8_t const * data, uint8_t count)
233285
{
234-
VERIFY( data && (count <= BLE_GAP_ADV_SET_DATA_SIZE_MAX) );
286+
VERIFY( data && (count <= _max_len) );
235287

236288
memcpy(_data, data, count);
237289
_count = count;
@@ -242,7 +294,7 @@ bool BLEAdvertisingData::setData(uint8_t const * data, uint8_t count)
242294
void BLEAdvertisingData::clearData(void)
243295
{
244296
_count = 0;
245-
arrclr(_data);
297+
if (_data) memset(_data, 0, _max_len);
246298
}
247299

248300
/*------------------------------------------------------------------*/
@@ -275,6 +327,16 @@ void BLEAdvertising::setFastTimeout(uint16_t sec)
275327
void BLEAdvertising::setType(uint8_t adv_type)
276328
{
277329
_type = adv_type;
330+
if (isExtended())
331+
{
332+
// Connectable extended PDUs are capped at 238 bytes; other extended PDUs at 255.
333+
setMaxLen(isConnectable() ? BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED
334+
: BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED);
335+
}
336+
else
337+
{
338+
setMaxLen(BLE_GAP_ADV_SET_DATA_SIZE_MAX);
339+
}
278340
}
279341

280342
/**
@@ -296,6 +358,22 @@ void BLEAdvertising::setIntervalMS(uint16_t fast, uint16_t slow)
296358
setInterval(MS1000TO625(fast), MS1000TO625(slow));
297359
}
298360

361+
void BLEAdvertising::setMaxEvents(uint8_t maxEvents)
362+
{
363+
_max_events = maxEvents;
364+
}
365+
366+
void BLEAdvertising::setFilter(uint8_t filter)
367+
{
368+
_filter = filter;
369+
}
370+
371+
void BLEAdvertising::setPhy(uint8_t phy)
372+
{
373+
_primary_phy = phy;
374+
_secondary_phy = phy;
375+
}
376+
299377
/**
300378
* Get current active interval
301379
* @return Either slow or fast interval in unit of 0.625 ms
@@ -324,6 +402,42 @@ bool BLEAdvertising::isRunning(void)
324402
return _running;
325403
}
326404

405+
bool BLEAdvertising::isScannable(void)
406+
{
407+
return _type == BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED
408+
|| _type == BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED
409+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED
410+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED;
411+
}
412+
413+
bool BLEAdvertising::isConnectable(void)
414+
{
415+
return _type == BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED
416+
|| _type == BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE
417+
|| _type == BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED
418+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED
419+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED;
420+
}
421+
422+
bool BLEAdvertising::isDirected(void)
423+
{
424+
return _type == BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE
425+
|| _type == BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED
426+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED
427+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED
428+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED;
429+
}
430+
431+
bool BLEAdvertising::isExtended(void)
432+
{
433+
return _type == BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED
434+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED
435+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED
436+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED
437+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED
438+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED;
439+
}
440+
327441
bool BLEAdvertising::setBeacon(BLEBeacon& beacon)
328442
{
329443
return beacon.start(*this);
@@ -347,25 +461,17 @@ bool BLEAdvertising::_start(uint16_t interval, uint16_t timeout) {
347461
.interval = interval , // advertising interval (in units of 0.625 ms)
348462
.duration = (uint16_t) (timeout*100) , // in 10-ms unit
349463

350-
.max_adv_evts = 0 , // TODO can be used for fast/slow mode
351-
.channel_mask = { 0, 0, 0, 0, 0 } , // 40 channel, set 1 to disable
352-
.filter_policy = BLE_GAP_ADV_FP_ANY ,
464+
.max_adv_evts = _max_events , // can be used for fast/slow mode
465+
.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
466+
.filter_policy = _filter ,
353467

354-
.primary_phy = BLE_GAP_PHY_AUTO , // 1 Mbps will be used
355-
.secondary_phy = BLE_GAP_PHY_AUTO , // 1 Mbps will be used
468+
.primary_phy = (isExtended() ? _primary_phy : (uint8_t)BLE_GAP_PHY_AUTO) ,
469+
.secondary_phy = _secondary_phy ,
356470
// , .set_id, .scan_req_notification
357471
};
358472

359-
switch(_type) {
360-
case BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE:
361-
case BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED:
362-
case BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED:
363-
case BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED:
364-
case BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED:
365-
adv_para.p_peer_addr = &_peer_addr;
366-
break;
367-
368-
default: break;
473+
if (isDirected()) {
474+
adv_para.p_peer_addr = &_peer_addr;
369475
}
370476

371477
// stop first if current running since we may change advertising data/params
@@ -375,10 +481,34 @@ bool BLEAdvertising::_start(uint16_t interval, uint16_t timeout) {
375481

376482
// gap_adv long-live is required by SD v6
377483
static ble_gap_adv_data_t gap_adv;
378-
gap_adv.adv_data.p_data = _data;
379-
gap_adv.adv_data.len = _count;
380-
gap_adv.scan_rsp_data.p_data = Bluefruit.ScanResponse.getData();
381-
gap_adv.scan_rsp_data.len = Bluefruit.ScanResponse.count();
484+
485+
// no advertising data supported?
486+
// 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
487+
if ( _type == BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED
488+
|| _type == BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE
489+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED
490+
|| _type == BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED )
491+
{
492+
gap_adv.adv_data.p_data = nullptr;
493+
gap_adv.adv_data.len = 0;
494+
}
495+
else
496+
{
497+
gap_adv.adv_data.p_data = _data;
498+
gap_adv.adv_data.len = _count;
499+
}
500+
501+
// no scan response data required?
502+
if (!isScannable())
503+
{
504+
gap_adv.scan_rsp_data.p_data = nullptr;
505+
gap_adv.scan_rsp_data.len = 0;
506+
}
507+
else
508+
{
509+
gap_adv.scan_rsp_data.p_data = Bluefruit.ScanResponse.getData();
510+
gap_adv.scan_rsp_data.len = Bluefruit.ScanResponse.count();
511+
}
382512

383513
VERIFY_STATUS( sd_ble_gap_adv_set_configure(&_hdl, &gap_adv, &adv_para), false );
384514
VERIFY_STATUS( sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, _hdl, Bluefruit.getTxPower() ), false );
@@ -479,9 +609,21 @@ void BLEAdvertising::_eventHandler(ble_evt_t* evt)
479609
if (_stop_cb) ada_callback(NULL, 0, _stop_cb);
480610
}
481611
}
612+
}else
613+
{
614+
if (evt->evt.gap_evt.params.adv_set_terminated.reason == BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_LIMIT_REACHED)
615+
{
616+
_running = false;
617+
618+
// Stop advertising
619+
Bluefruit._stopConnLed(); // stop blinking
620+
621+
// invoke stop callback
622+
if (_stop_cb) ada_callback(NULL, 0, _stop_cb);
623+
}
482624
}
483625
break;
484626

485627
default: break;
486628
}
487-
}
629+
}

libraries/Bluefruit52Lib/src/BLEAdvertising.h

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,23 @@ class Advertisable
7272
class BLEAdvertisingData
7373
{
7474
protected:
75-
uint8_t _data[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
76-
uint8_t _count;
75+
uint8_t* _data;
76+
uint8_t _max_len;
77+
uint8_t _count;
7778

7879
public:
7980
BLEAdvertisingData(void);
81+
~BLEAdvertisingData(void);
82+
83+
// Class owns a heap buffer; disable copy to prevent shallow-copy / double-free.
84+
BLEAdvertisingData(const BLEAdvertisingData&) = delete;
85+
BLEAdvertisingData& operator=(const BLEAdvertisingData&) = delete;
86+
87+
// Resize the internal buffer (heap-allocated). Defaults to BLE_GAP_ADV_SET_DATA_SIZE_MAX (31).
88+
// For extended advertising use BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED (238)
89+
// or BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED (255).
90+
// Reallocates the buffer; any previously added data is discarded.
91+
void setMaxLen(uint8_t max_len);
8092

8193
/*------------- Adv Data -------------*/
8294
bool addData(uint8_t type, const void* data, uint8_t len);
@@ -120,6 +132,8 @@ class BLEAdvertising : public BLEAdvertisingData
120132

121133
BLEAdvertising(void);
122134

135+
// Sets the advertising type and resizes the internal buffer accordingly
136+
// (extended types -> larger buffer, legacy types -> 31-byte buffer).
123137
void setType(uint8_t adv_type);
124138
void setFastTimeout(uint16_t sec);
125139

@@ -129,6 +143,10 @@ class BLEAdvertising : public BLEAdvertisingData
129143
void setInterval (uint16_t fast, uint16_t slow);
130144
void setIntervalMS(uint16_t fast, uint16_t slow);
131145

146+
void setMaxEvents(uint8_t maxEvents);
147+
void setFilter(uint8_t filter);
148+
void setPhy(uint8_t phy);
149+
132150
uint16_t getInterval(void);
133151

134152
bool setBeacon(BLEBeacon& beacon);
@@ -138,6 +156,10 @@ class BLEAdvertising : public BLEAdvertisingData
138156
void setPeerAddress(const ble_gap_addr_t& peer_addr);
139157

140158
bool isRunning(void);
159+
bool isScannable(void);
160+
bool isConnectable(void);
161+
bool isDirected(void);
162+
bool isExtended(void);
141163

142164
void restartOnDisconnect(bool enable);
143165
bool start(uint16_t timeout = 0);
@@ -153,6 +175,10 @@ class BLEAdvertising : public BLEAdvertisingData
153175
private:
154176
uint8_t _hdl;
155177
uint8_t _type;
178+
uint8_t _max_events = 0; // initially time limited
179+
uint8_t _filter = BLE_GAP_ADV_FP_ANY;
180+
uint8_t _primary_phy = BLE_GAP_PHY_AUTO;
181+
uint8_t _secondary_phy = BLE_GAP_PHY_AUTO;
156182
bool _start_if_disconnect;
157183
bool _running;
158184
ble_gap_addr_t _peer_addr; //! Target address for an ADV_DIRECT_IND advertisement

0 commit comments

Comments
 (0)