Skip to content

Commit 8ec7cfd

Browse files
start and stop adv sets in batches
1 parent 0670470 commit 8ec7cfd

File tree

2 files changed

+105
-134
lines changed

2 files changed

+105
-134
lines changed

connectivity/FEATURE_BLE/source/generic/GapImpl.cpp

Lines changed: 93 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
24852454
void 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

34803452
void 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;

connectivity/FEATURE_BLE/source/generic/GapImpl.h

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -563,14 +563,8 @@ class Gap :
563563

564564
#if BLE_ROLE_BROADCASTER
565565
#if BLE_FEATURE_EXTENDED_ADVERTISING
566-
void queue_advertising_start(
567-
advertising_handle_t handle,
568-
adv_duration_t maxDuration,
569-
uint8_t maxEvents
570-
);
571-
572566
void process_enable_queue();
573-
void process_stop();
567+
void process_disable_queue();
574568
#endif // BLE_FEATURE_EXTENDED_ADVERTISING
575569

576570
ble_error_t setAdvertisingData(
@@ -1006,16 +1000,19 @@ class Gap :
10061000
BitArray<BLE_GAP_MAX_ADVERTISING_SETS> _adv_started_from_refresh;
10071001

10081002
#if BLE_FEATURE_EXTENDED_ADVERTISING
1009-
struct AdvertisingEnableStackNode_t {
1010-
adv_duration_t max_duration;
1011-
advertising_handle_t handle;
1012-
uint8_t max_events;
1013-
AdvertisingEnableStackNode_t* next;
1003+
#if BLE_GAP_HOST_MAX_OUTSTANDING_ADVERTISING_START_COMMANDS < 1 || BLE_GAP_HOST_MAX_OUTSTANDING_ADVERTISING_START_COMMANDS > BLE_GAP_MAX_ADVERTISING_SETS
1004+
#error "BLE_GAP_HOST_MAX_OUTSTANDING_ADVERTISING_START_COMMANDS must be at least 1 and not bigget than BLE_GAP_MAX_ADVERTISING_SETS"
1005+
#endif
1006+
struct AdvertisingEnableCommandParams_t {
1007+
adv_duration_t max_durations[BLE_GAP_HOST_MAX_OUTSTANDING_ADVERTISING_START_COMMANDS];
1008+
advertising_handle_t handles[BLE_GAP_HOST_MAX_OUTSTANDING_ADVERTISING_START_COMMANDS];
1009+
uint8_t max_events[BLE_GAP_HOST_MAX_OUTSTANDING_ADVERTISING_START_COMMANDS];
1010+
uint8_t number_of_handles;
10141011
};
10151012

1016-
/* to simplify code and avoid allocation unless multiple requests issued we keep one node as member */
1017-
AdvertisingEnableStackNode_t _advertising_enable_queue;
1018-
bool _advertising_enable_pending;
1013+
AdvertisingEnableCommandParams_t _advertising_enable_command_params;
1014+
bool _process_enable_queue_pending = false;
1015+
bool _process_disable_queue_pending = false;
10191016
#endif // BLE_FEATURE_EXTENDED_ADVERTISING
10201017

10211018
bool _user_manage_connection_parameter_requests;

0 commit comments

Comments
 (0)