Skip to content

Commit ab123d3

Browse files
advertising start queued up waiting for completion
1 parent 7279ae2 commit ab123d3

File tree

4 files changed

+250
-29
lines changed

4 files changed

+250
-29
lines changed

connectivity/FEATURE_BLE/include/ble/Gap.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,18 @@ class Gap {
341341
{
342342
}
343343

344+
/**
345+
* Called when an asynchronous advertising command fails.
346+
*
347+
* @param event Advertising command failed event.
348+
*
349+
* @see startAdvertising()
350+
* @see stopAdvertising()
351+
*/
352+
virtual void onAdvertisingCommandFailed(const AdvertisingCommandFailedEvent &event)
353+
{
354+
}
355+
344356
/**
345357
* Called when a scanner receives an advertising or a scan response packet.
346358
*
@@ -747,7 +759,9 @@ class Gap {
747759
* @param handle Advertising set handle.
748760
* @param maxDuration Max duration for advertising (in units of 10ms) - 0 means no limit.
749761
* @param maxEvents Max number of events produced during advertising - 0 means no limit.
750-
* @return BLE_ERROR_NONE on success.
762+
* @return BLE_ERROR_NONE on success. This does not guarantee the set has started if
763+
* extended advertising is enabled. Register an event handler and wait for onAdvertisingStart
764+
* event. An (unlikely) failed start will emit an onAdvertisingCommandFailed instead.
751765
*
752766
* @see EventHandler::onAdvertisingStart when the advertising starts.
753767
* @see EventHandler::onScanRequestReceived when a scan request is received.
@@ -765,7 +779,9 @@ class Gap {
765779
* which will not be affected.
766780
*
767781
* @param handle Advertising set handle.
768-
* @return BLE_ERROR_NONE on success.
782+
* @return BLE_ERROR_NONE on success. For extented advertising this does not guarantee
783+
* the set is stopped if. Register an event handler and wait for onAdvertisingEnd event.
784+
* An (unlikely) failed stop will emit an onAdvertisingCommandFailed instead.
769785
*/
770786
ble_error_t stopAdvertising(advertising_handle_t handle);
771787

connectivity/FEATURE_BLE/include/ble/gap/Events.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,44 @@ struct AdvertisingStartEvent {
604604
advertising_handle_t advHandle;
605605
};
606606

607+
/**
608+
* Event produced when an async advertising command fails.
609+
*
610+
* @see ble::Gap::EventHandler::onAdvertisingCommandFailed().
611+
*/
612+
struct AdvertisingCommandFailedEvent {
613+
#if !defined(DOXYGEN_ONLY)
614+
/** Create an extended advertising command failed event.
615+
*
616+
* @param advHandle Advertising set handle.
617+
* @param status Error code.
618+
*/
619+
AdvertisingCommandFailedEvent(
620+
advertising_handle_t advHandle,
621+
ble_error_t status
622+
) :
623+
advHandle(advHandle),
624+
status(status)
625+
{
626+
}
627+
628+
#endif
629+
/** Get advertising handle. */
630+
advertising_handle_t getAdvHandle() const
631+
{
632+
return advHandle;
633+
}
634+
635+
/** Error code that caused the event. */
636+
uint8_t getStatus() const
637+
{
638+
return status;
639+
}
640+
private:
641+
advertising_handle_t advHandle;
642+
ble_error_t status;
643+
};
644+
607645
/**
608646
* Event produced when advertising ends.
609647
*

connectivity/FEATURE_BLE/source/generic/GapImpl.cpp

Lines changed: 168 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,11 @@ Gap::Gap(
373373
, _scan_parameters_set(false)
374374
#endif // BLE_ROLE_OBSERVER
375375
{
376+
#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;
380+
#endif //BLE_FEATURE_EXTENDED_ADVERTISING
376381
_pal_gap.initialize();
377382

378383
_pal_gap.when_gap_event_received(
@@ -1214,6 +1219,21 @@ ble_error_t Gap::reset()
12141219
_initiating = false;
12151220
set_scan_state(ScanState::idle);
12161221
_scan_requested = false;
1222+
1223+
#if BLE_FEATURE_EXTENDED_ADVERTISING
1224+
/* reset pending advertising sets */
1225+
AdvertisingEnableStackNode_t* next = _advertising_enable_queue.next;
1226+
_advertising_enable_queue.next = nullptr;
1227+
_advertising_enable_queue.handle = ble::INVALID_ADVERTISING_HANDLE;
1228+
_advertising_enable_pending = false;
1229+
/* free any allocated nodes */
1230+
while (next) {
1231+
AdvertisingEnableStackNode_t* node_to_free = next;
1232+
AdvertisingEnableStackNode_t* next = next->next;
1233+
delete node_to_free;
1234+
}
1235+
#endif // BLE_FEATURE_EXTENDED_ADVERTISING
1236+
12171237
#if BLE_FEATURE_PRIVACY
12181238
_privacy_initialization_pending = false;
12191239
#if BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
@@ -1268,6 +1288,7 @@ ble_error_t Gap::reset()
12681288
#endif // BLE_FEATURE_EXTENDED_ADVERTISING
12691289

12701290
_active_sets.clear();
1291+
_pending_stop_sets.clear();
12711292
_pending_sets.clear();
12721293
_address_refresh_sets.clear();
12731294
_interruptible_sets.clear();
@@ -2413,23 +2434,10 @@ ble_error_t Gap::startAdvertising(
24132434
_pal_gap.set_advertising_set_random_address(handle, *random_address);
24142435
}
24152436

2416-
error = _pal_gap.extended_advertising_enable(
2417-
/* enable */ true,
2418-
/* number of advertising sets */ 1,
2419-
&handle,
2420-
maxDuration.storage(),
2421-
&maxEvents
2422-
);
2423-
2424-
if (error) {
2425-
return error;
2426-
}
2427-
2428-
if (maxDuration.value() || maxEvents) {
2429-
_interruptible_sets.clear(handle);
2430-
} else {
2431-
_interruptible_sets.set(handle);
2432-
}
2437+
_event_queue.post([this, handle, maxDuration, maxEvents] {
2438+
start_advertising_enable(handle, maxDuration, maxEvents);
2439+
evaluate_advertising_enable_queue();
2440+
});
24332441

24342442
} else
24352443
#endif // BLE_FEATURE_EXTENDED_ADVERTISING
@@ -2469,6 +2477,93 @@ ble_error_t Gap::startAdvertising(
24692477
}
24702478
#endif
24712479

2480+
#if BLE_FEATURE_EXTENDED_ADVERTISING
2481+
void Gap::start_advertising_enable(
2482+
advertising_handle_t handle,
2483+
adv_duration_t maxDuration,
2484+
uint8_t maxEvents
2485+
)
2486+
{
2487+
/* remember the parameters that will be enabled when the last command completes */
2488+
if (_advertising_enable_queue.handle == ble::INVALID_ADVERTISING_HANDLE) {
2489+
/* special case when there is only one pending */
2490+
_advertising_enable_queue.handle = handle;
2491+
_advertising_enable_queue.max_duration = maxDuration;
2492+
_advertising_enable_queue.max_events = maxEvents;
2493+
_advertising_enable_queue.next = nullptr;
2494+
} else {
2495+
AdvertisingEnableStackNode_t** next = &_advertising_enable_queue.next;
2496+
/* move down the queue until we're over a nullptr */
2497+
if (*next) {
2498+
while ((*next)->next) {
2499+
next = &((*next)->next);
2500+
}
2501+
next = &(*next)->next;
2502+
}
2503+
*next = new AdvertisingEnableStackNode_t();
2504+
if (!*next) {
2505+
tr_error("Out of memory creating pending advertising enable node for handle %d", handle);
2506+
return;
2507+
}
2508+
(*next)->handle = handle;
2509+
(*next)->max_duration = maxDuration;
2510+
(*next)->max_events = maxEvents;
2511+
(*next)->next = nullptr;
2512+
}
2513+
}
2514+
2515+
void Gap::evaluate_advertising_enable_queue()
2516+
{
2517+
tr_info("Evaluating pending advertising sets to be started");
2518+
if (_advertising_enable_pending) {
2519+
return;
2520+
}
2521+
2522+
if (_advertising_enable_queue.handle == ble::INVALID_ADVERTISING_HANDLE) {
2523+
/* no set pending to be enabled*/
2524+
return;
2525+
}
2526+
2527+
ble_error_t error = _pal_gap.extended_advertising_enable(
2528+
/* enable */ true,
2529+
/* number of advertising sets */ 1,
2530+
&_advertising_enable_queue.handle,
2531+
_advertising_enable_queue.max_duration.storage(),
2532+
&_advertising_enable_queue.max_events
2533+
);
2534+
2535+
if (error) {
2536+
tr_error("Failed to start advertising set with error: %s", to_string(error));
2537+
if (_event_handler) {
2538+
_event_handler->onAdvertisingCommandFailed(
2539+
AdvertisingCommandFailedEvent(
2540+
_advertising_enable_queue.handle,
2541+
error
2542+
)
2543+
);
2544+
}
2545+
} else {
2546+
_advertising_enable_pending = true;
2547+
if (_advertising_enable_queue.max_duration.value() || _advertising_enable_queue.max_events) {
2548+
_interruptible_sets.clear(_advertising_enable_queue.handle);
2549+
} else {
2550+
_interruptible_sets.set(_advertising_enable_queue.handle);
2551+
}
2552+
}
2553+
2554+
/* if there's anything else waiting, queue it up, otherwise mark the head node handle as invalid */
2555+
if (_advertising_enable_queue.next) {
2556+
AdvertisingEnableStackNode_t* next = _advertising_enable_queue.next;
2557+
_advertising_enable_queue.handle = next->handle;
2558+
_advertising_enable_queue.max_duration = next->max_duration;
2559+
_advertising_enable_queue.max_events = next->max_events;
2560+
_advertising_enable_queue.next = next->next;
2561+
delete next;
2562+
} else {
2563+
_advertising_enable_queue.handle = ble::INVALID_ADVERTISING_HANDLE;
2564+
}
2565+
}
2566+
#endif //BLE_FEATURE_EXTENDED_ADVERTISING
24722567

24732568
#if BLE_ROLE_BROADCASTER
24742569
ble_error_t Gap::stopAdvertising(advertising_handle_t handle)
@@ -2499,17 +2594,23 @@ ble_error_t Gap::stopAdvertising(advertising_handle_t handle)
24992594

25002595
#if BLE_FEATURE_EXTENDED_ADVERTISING
25012596
if (is_extended_advertising_available()) {
2502-
status = _pal_gap.extended_advertising_enable(
2503-
/*enable ? */ false,
2504-
/* number of advertising sets */ 1,
2505-
&handle,
2506-
nullptr,
2507-
nullptr
2508-
);
2597+
_event_queue.post([this, handle] {
2598+
/* if any already pending to stop delay the command execution */
2599+
bool delay = false;
2600+
for (size_t i = 0; i < BLE_GAP_MAX_ADVERTISING_SETS; ++i) {
2601+
if (_pending_stop_sets.get(i)) {
2602+
delay = true;
2603+
break;
2604+
}
2605+
}
2606+
_pending_stop_sets.set(handle);
2607+
if (!delay) {
2608+
evaluate_advertising_stop();
2609+
}
2610+
});
2611+
2612+
return BLE_ERROR_NONE;
25092613

2510-
if (status) {
2511-
return status;
2512-
}
25132614
} else
25142615
#endif // BLE_FEATURE_EXTENDED_ADVERTISING
25152616
{
@@ -2531,6 +2632,36 @@ ble_error_t Gap::stopAdvertising(advertising_handle_t handle)
25312632

25322633
return status;
25332634
}
2635+
2636+
#if BLE_FEATURE_EXTENDED_ADVERTISING
2637+
void Gap::evaluate_advertising_stop()
2638+
{
2639+
// refresh for address for all connectable advertising sets
2640+
for (size_t i = 0; i < BLE_GAP_MAX_ADVERTISING_SETS; ++i) {
2641+
if (_pending_stop_sets.get(i)) {
2642+
ble_error_t status = _pal_gap.extended_advertising_enable(
2643+
/* enable */ false,
2644+
/* number of advertising sets */ 1,
2645+
(advertising_handle_t*)&i,
2646+
nullptr,
2647+
nullptr
2648+
);
2649+
if (status) {
2650+
_event_handler->onAdvertisingCommandFailed(
2651+
AdvertisingCommandFailedEvent(
2652+
(advertising_handle_t)i,
2653+
status
2654+
)
2655+
);
2656+
tr_error("Could not stop advertising set %u, error: %s", i, to_string(status));
2657+
}
2658+
break;
2659+
}
2660+
}
2661+
2662+
}
2663+
#endif // BLE_FEATURE_EXTENDED_ADVERTISING
2664+
25342665
#endif
25352666

25362667

@@ -3354,6 +3485,11 @@ void Gap::on_advertising_set_started(const mbed::Span<const uint8_t>& handles)
33543485
{
33553486
tr_info("Advertising set started - handles=%s", mbed_trace_array(handles.data(), handles.size()));
33563487

3488+
_event_queue.post([this] {
3489+
_advertising_enable_pending = false;
3490+
evaluate_advertising_enable_queue();
3491+
});
3492+
33573493
for (const auto &handle : handles) {
33583494
_active_sets.set(handle);
33593495
_pending_sets.clear(handle);
@@ -3394,6 +3530,11 @@ void Gap::on_advertising_set_terminated(
33943530
return;
33953531
}
33963532

3533+
_event_queue.post([this, advertising_handle] {
3534+
_pending_stop_sets.clear(advertising_handle);
3535+
evaluate_advertising_stop();
3536+
});
3537+
33973538
if (!_event_handler) {
33983539
return;
33993540
}

connectivity/FEATURE_BLE/source/generic/GapImpl.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,17 @@ class Gap :
562562
~Gap();
563563

564564
#if BLE_ROLE_BROADCASTER
565+
#if BLE_FEATURE_EXTENDED_ADVERTISING
566+
void start_advertising_enable(
567+
advertising_handle_t handle,
568+
adv_duration_t maxDuration,
569+
uint8_t maxEvents
570+
);
571+
572+
void evaluate_advertising_enable_queue();
573+
void evaluate_advertising_stop();
574+
#endif // BLE_FEATURE_EXTENDED_ADVERTISING
575+
565576
ble_error_t setAdvertisingData(
566577
advertising_handle_t handle,
567578
Span<const uint8_t> payload,
@@ -980,6 +991,9 @@ class Gap :
980991
};
981992

982993
BitArray<BLE_GAP_MAX_ADVERTISING_SETS> _existing_sets;
994+
#if BLE_FEATURE_EXTENDED_ADVERTISING
995+
BitArray<BLE_GAP_MAX_ADVERTISING_SETS> _pending_stop_sets;
996+
#endif // BLE_FEATURE_EXTENDED_ADVERTISING
983997
BitArray<BLE_GAP_MAX_ADVERTISING_SETS> _active_sets;
984998
BitArray<BLE_GAP_MAX_ADVERTISING_SETS> _active_periodic_sets;
985999
BitArray<BLE_GAP_MAX_ADVERTISING_SETS> _connectable_payload_size_exceeded;
@@ -989,6 +1003,18 @@ class Gap :
9891003
BitArray<BLE_GAP_MAX_ADVERTISING_SETS> _interruptible_sets;
9901004
BitArray<BLE_GAP_MAX_ADVERTISING_SETS> _adv_started_from_refresh;
9911005

1006+
#if BLE_FEATURE_EXTENDED_ADVERTISING
1007+
struct AdvertisingEnableStackNode_t {
1008+
adv_duration_t max_duration;
1009+
advertising_handle_t handle;
1010+
uint8_t max_events;
1011+
AdvertisingEnableStackNode_t* next;
1012+
};
1013+
1014+
/* to simplify code and avoid allocation unless multiple requests issued we keep one node as member */
1015+
AdvertisingEnableStackNode_t _advertising_enable_queue;
1016+
bool _advertising_enable_pending;
1017+
#endif // BLE_FEATURE_EXTENDED_ADVERTISING
9921018

9931019
bool _user_manage_connection_parameter_requests;
9941020
#if BLE_ROLE_OBSERVER

0 commit comments

Comments
 (0)