@@ -374,9 +374,7 @@ Gap::Gap(
374374#endif // BLE_ROLE_OBSERVER
375375{
376376#if BLE_FEATURE_EXTENDED_ADVERTISING
377- _advertising_enable_queue.handle = ble::INVALID_ADVERTISING_HANDLE;
378- _advertising_enable_queue.next = nullptr ;
379- _advertising_enable_pending = false ;
377+ _advertising_enable_command_params.number_of_handles = 0 ;
380378#endif // BLE_FEATURE_EXTENDED_ADVERTISING
381379 _pal_gap.initialize ();
382380
@@ -1214,7 +1212,6 @@ ble_error_t Gap::reset()
12141212 /* Notify that the instance is about to shut down */
12151213// shutdownCallChain.call(this);
12161214 shutdownCallChain.clear ();
1217- _event_queue.clear ();
12181215
12191216 _event_handler = nullptr ;
12201217 _initiating = false ;
@@ -1240,16 +1237,9 @@ ble_error_t Gap::reset()
12401237 _pal_gap.clear_advertising_sets ();
12411238#if BLE_FEATURE_EXTENDED_ADVERTISING
12421239 /* reset pending advertising sets */
1243- AdvertisingEnableStackNode_t* next = _advertising_enable_queue.next ;
1244- _advertising_enable_queue.next = nullptr ;
1245- _advertising_enable_queue.handle = ble::INVALID_ADVERTISING_HANDLE;
1246- _advertising_enable_pending = false ;
1247- /* free any allocated nodes */
1248- while (next) {
1249- AdvertisingEnableStackNode_t* node_to_free = next;
1250- AdvertisingEnableStackNode_t* next = next->next ;
1251- delete node_to_free;
1252- }
1240+ _advertising_enable_command_params.number_of_handles = 0 ;
1241+ _process_enable_queue_pending = false ;
1242+ _process_disable_queue_pending = false ;
12531243 _existing_sets.clear ();
12541244#if BLE_FEATURE_PERIODIC_ADVERTISING
12551245 _active_periodic_sets.clear ();
@@ -2402,10 +2392,23 @@ ble_error_t Gap::startAdvertising(
24022392 _pal_gap.set_advertising_set_random_address (handle, *random_address);
24032393 }
24042394
2405- _event_queue.post ([this , handle, maxDuration, maxEvents] {
2406- queue_advertising_start (handle, maxDuration, maxEvents);
2407- process_enable_queue ();
2408- });
2395+ /* remember the parameters that will be enabled when the last command completes */
2396+ if (_advertising_enable_command_params.number_of_handles == BLE_GAP_HOST_MAX_OUTSTANDING_ADVERTISING_START_COMMANDS) {
2397+ return BLE_ERROR_NO_MEM;
2398+ }
2399+
2400+ const uint8_t i = _advertising_enable_command_params.number_of_handles ;
2401+ _advertising_enable_command_params.handles [i] = handle;
2402+ _advertising_enable_command_params.max_durations [i] = maxDuration;
2403+ _advertising_enable_command_params.max_events [i] = maxEvents;
2404+ _advertising_enable_command_params.number_of_handles ++;
2405+
2406+ /* we delay the processing to gather as many calls as we can in one go */
2407+ if (!_process_enable_queue_pending) {
2408+ _process_enable_queue_pending = _event_queue.post ([this ] {
2409+ process_enable_queue ();
2410+ });
2411+ }
24092412
24102413 } else
24112414#endif // BLE_FEATURE_EXTENDED_ADVERTISING
@@ -2448,90 +2451,51 @@ ble_error_t Gap::startAdvertising(
24482451#endif
24492452
24502453#if BLE_FEATURE_EXTENDED_ADVERTISING
2451- void Gap::queue_advertising_start (
2452- advertising_handle_t handle,
2453- adv_duration_t maxDuration,
2454- uint8_t maxEvents
2455- )
2456- {
2457- /* remember the parameters that will be enabled when the last command completes */
2458- if (_advertising_enable_queue.handle == ble::INVALID_ADVERTISING_HANDLE) {
2459- /* special case when there is only one pending */
2460- _advertising_enable_queue.handle = handle;
2461- _advertising_enable_queue.max_duration = maxDuration;
2462- _advertising_enable_queue.max_events = maxEvents;
2463- _advertising_enable_queue.next = nullptr ;
2464- } else {
2465- AdvertisingEnableStackNode_t** next = &_advertising_enable_queue.next ;
2466- /* move down the queue until we're over a nullptr */
2467- if (*next) {
2468- while ((*next)->next ) {
2469- next = &((*next)->next );
2470- }
2471- next = &(*next)->next ;
2472- }
2473- *next = new (std::nothrow) AdvertisingEnableStackNode_t ();
2474- if (!*next) {
2475- tr_error (" Out of memory creating pending advertising enable node for handle %d" , handle);
2476- return ;
2477- }
2478- (*next)->handle = handle;
2479- (*next)->max_duration = maxDuration;
2480- (*next)->max_events = maxEvents;
2481- (*next)->next = nullptr ;
2482- }
2483- }
2484-
24852454void Gap::process_enable_queue ()
24862455{
24872456 tr_info (" Evaluating pending advertising sets to be started" );
2488- if (_advertising_enable_pending) {
2457+ if (!_advertising_enable_command_params.number_of_handles ) {
2458+ /* no set pending to be enabled */
24892459 return ;
24902460 }
24912461
2492- if (_advertising_enable_queue.handle == ble::INVALID_ADVERTISING_HANDLE) {
2493- /* no set pending to be enabled*/
2494- return ;
2462+ for (size_t i = 0 ; i < BLE_GAP_MAX_ADVERTISING_SETS; ++i) {
2463+ if (_pending_sets.get (i)) {
2464+ /* we have to wait until nothing is pending */
2465+ return ;
2466+ }
24952467 }
24962468
24972469 ble_error_t error = _pal_gap.extended_advertising_enable (
24982470 /* enable */ true ,
2499- /* number of advertising sets */ 1 ,
2500- &_advertising_enable_queue. handle ,
2501- _advertising_enable_queue. max_duration . storage () ,
2502- &_advertising_enable_queue .max_events
2471+ _advertising_enable_command_params. number_of_handles ,
2472+ _advertising_enable_command_params. handles ,
2473+ ( uint16_t *)&_advertising_enable_command_params. max_durations ,
2474+ _advertising_enable_command_params .max_events
25032475 );
25042476
25052477 if (error) {
25062478 tr_error (" Failed to start advertising set with error: %s" , to_string (error));
25072479 if (_event_handler) {
2508- _event_handler-> onAdvertisingCommandFailed (
2509- AdvertisingCommandFailedEvent (
2510- _advertising_enable_queue. handle ,
2511- error
2512- )
2513- );
2480+ for ( size_t i = 0 ; i < _advertising_enable_command_params. number_of_handles ; ++i) {
2481+ _pending_sets. clear (_advertising_enable_command_params. handles [i]);
2482+ _event_handler-> onAdvertisingStart (
2483+ AdvertisingStartEvent (_advertising_enable_command_params. handles [i], error)
2484+ );
2485+ }
25142486 }
25152487 } else {
2516- _advertising_enable_pending = true ;
2517- if (_advertising_enable_queue.max_duration .value () || _advertising_enable_queue.max_events ) {
2518- _interruptible_sets.clear (_advertising_enable_queue.handle );
2519- } else {
2520- _interruptible_sets.set (_advertising_enable_queue.handle );
2488+ for (size_t i = 0 ; i < _advertising_enable_command_params.number_of_handles ; ++i) {
2489+ if (_advertising_enable_command_params.max_durations [i].value () || _advertising_enable_command_params.max_events [i]) {
2490+ _interruptible_sets.clear (_advertising_enable_command_params.handles [i]);
2491+ } else {
2492+ _interruptible_sets.set (_advertising_enable_command_params.handles [i]);
2493+ }
25212494 }
25222495 }
25232496
2524- /* if there's anything else waiting, queue it up, otherwise mark the head node handle as invalid */
2525- if (_advertising_enable_queue.next ) {
2526- AdvertisingEnableStackNode_t* next = _advertising_enable_queue.next ;
2527- _advertising_enable_queue.handle = next->handle ;
2528- _advertising_enable_queue.max_duration = next->max_duration ;
2529- _advertising_enable_queue.max_events = next->max_events ;
2530- _advertising_enable_queue.next = next->next ;
2531- delete next;
2532- } else {
2533- _advertising_enable_queue.handle = ble::INVALID_ADVERTISING_HANDLE;
2534- }
2497+ _advertising_enable_command_params.number_of_handles = 0 ;
2498+ _process_enable_queue_pending = false ;
25352499}
25362500#endif // BLE_FEATURE_EXTENDED_ADVERTISING
25372501
@@ -2564,22 +2528,15 @@ ble_error_t Gap::stopAdvertising(advertising_handle_t handle)
25642528
25652529#if BLE_FEATURE_EXTENDED_ADVERTISING
25662530 if (is_extended_advertising_available ()) {
2567- _event_queue.post ([this , handle] {
2568- /* if any already pending to stop delay the command execution */
2569- bool delay = false ;
2570- for (size_t i = 0 ; i < BLE_GAP_MAX_ADVERTISING_SETS; ++i) {
2571- if (_pending_stop_sets.get (i)) {
2572- delay = true ;
2573- break ;
2574- }
2575- }
2576- _pending_stop_sets.set (handle);
2577- if (!delay) {
2578- process_stop ();
2579- }
2580- });
2531+ _pending_stop_sets.set (handle);
2532+ /* delay execution of command to accumulate multiple sets */
2533+ if (!_process_disable_queue_pending) {
2534+ _process_disable_queue_pending = _event_queue.post ([this ] {
2535+ process_disable_queue ();
2536+ });
2537+ }
25812538
2582- return BLE_ERROR_NONE;
2539+ status = BLE_ERROR_NONE;
25832540
25842541 } else
25852542#endif // BLE_FEATURE_EXTENDED_ADVERTISING
@@ -2604,31 +2561,44 @@ ble_error_t Gap::stopAdvertising(advertising_handle_t handle)
26042561}
26052562
26062563#if BLE_FEATURE_EXTENDED_ADVERTISING
2607- void Gap::process_stop ()
2564+ void Gap::process_disable_queue ()
26082565{
2566+ advertising_handle_t sets[BLE_GAP_MAX_ADVERTISING_SETS];
2567+ uint8_t number_of_handles = 0 ;
26092568 // refresh for address for all connectable advertising sets
26102569 for (size_t i = 0 ; i < BLE_GAP_MAX_ADVERTISING_SETS; ++i) {
26112570 if (_pending_stop_sets.get (i)) {
2612- ble_error_t status = _pal_gap.extended_advertising_enable (
2613- /* enable */ false ,
2614- /* number of advertising sets */ 1 ,
2615- (advertising_handle_t *)&i,
2616- nullptr ,
2617- nullptr
2618- );
2619- if (status) {
2620- _event_handler->onAdvertisingCommandFailed (
2621- AdvertisingCommandFailedEvent (
2622- (advertising_handle_t )i,
2571+ sets[number_of_handles] = i;
2572+ number_of_handles++;
2573+ _pending_stop_sets.clear (i);
2574+ }
2575+ }
2576+
2577+ if (number_of_handles) {
2578+ ble_error_t status = _pal_gap.extended_advertising_enable (
2579+ /* enable */ false ,
2580+ number_of_handles,
2581+ (advertising_handle_t *)&sets,
2582+ nullptr ,
2583+ nullptr
2584+ );
2585+ if (status) {
2586+ for (size_t i = 0 ; i < number_of_handles; ++i) {
2587+ _event_handler->onAdvertisingEnd (
2588+ AdvertisingEndEvent (
2589+ (advertising_handle_t )sets[i],
2590+ 0 /* connection*/ ,
2591+ 0 /* completed_events*/ ,
2592+ false /* connected*/ ,
26232593 status
26242594 )
26252595 );
26262596 tr_error (" Could not stop advertising set %u, error: %s" , i, to_string (status));
26272597 }
2628- break ;
26292598 }
26302599 }
26312600
2601+ _process_disable_queue_pending = false ;
26322602}
26332603#endif // BLE_FEATURE_EXTENDED_ADVERTISING
26342604
@@ -3459,11 +3429,6 @@ void Gap::on_advertising_set_started(const mbed::Span<const uint8_t>& handles)
34593429{
34603430 tr_info (" Advertising set started - handles=%s" , mbed_trace_array (handles.data (), handles.size ()));
34613431
3462- _event_queue.post ([this ] {
3463- _advertising_enable_pending = false ;
3464- process_enable_queue ();
3465- });
3466-
34673432 for (const auto &handle : handles) {
34683433 _active_sets.set (handle);
34693434 _pending_sets.clear (handle);
@@ -3475,6 +3440,13 @@ void Gap::on_advertising_set_started(const mbed::Span<const uint8_t>& handles)
34753440 );
34763441 }
34773442 }
3443+
3444+ /* delay processing to minimise churn (if multiple events are pending that would trigger it) */
3445+ if (!_process_enable_queue_pending) {
3446+ _process_enable_queue_pending = _event_queue.post ([this ] {
3447+ process_enable_queue ();
3448+ });
3449+ }
34783450}
34793451
34803452void Gap::on_advertising_set_terminated (
@@ -3504,10 +3476,12 @@ void Gap::on_advertising_set_terminated(
35043476 return ;
35053477 }
35063478
3507- _event_queue.post ([this , advertising_handle] {
3508- _pending_stop_sets.clear (advertising_handle);
3509- process_stop ();
3510- });
3479+ /* postpone as other events may still be pending */
3480+ if (!_process_disable_queue_pending) {
3481+ _process_disable_queue_pending = _event_queue.post ([this ] {
3482+ process_disable_queue ();
3483+ });
3484+ }
35113485
35123486 if (!_event_handler) {
35133487 return ;
0 commit comments