4040/* BLEAdvertisingData shared between ADV and ScanResponse
4141 *------------------------------------------------------------------*/
4242BLEAdvertisingData::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
4885bool 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 */
178215bool 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
232284bool 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)
242294void 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)
275327void 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+
327441bool 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+ }
0 commit comments