Skip to content

Commit bd6c4ab

Browse files
[Linux] Add support for extended advertisement (project-chip#31668)
* Use ScheduleLambda() instead of ScheduleWork * Set min/max advertisement interval * Matter BLE advertisement type shall be peripheral * Allow intervals to be set after initialization * Keep BlueZ default for adv slicing duration * Allow to update intervals on the fly - fast/slow * Transition to slow advertising after timeout * Fix advertisement typos in all places in the codebase * Do not specify advertisement timeout in BlueZ * Add support for extended advertisement * Post review changes - add manual how to enable experimental features in BlueZ * Restyled by prettier-markdown * Assert that extended adv interval is >= fast adv interval * Cancel HandleAdvertisingTimer timer in case of error --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent 819a4f1 commit bd6c4ab

File tree

16 files changed

+201
-120
lines changed

16 files changed

+201
-120
lines changed

docs/guides/BUILDING.md

+27
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,33 @@ Complete the following steps:
9494
9595
1. Reboot your Raspberry Pi after installing `pi-bluetooth`.
9696
97+
#### Enable experimental Bluetooth support in BlueZ
98+
99+
The Matter application on Linux uses BlueZ to communicate with the Bluetooth
100+
controller. The BlueZ version that comes with Ubuntu 22.04 does not support all
101+
the features required by the Matter application by default. To enable these
102+
features, you need to enable experimental Bluetooth support in BlueZ.
103+
104+
1. Edit the `bluetooth.service` unit by running the following command:
105+
106+
```sh
107+
sudo systemctl edit bluetooth.service
108+
```
109+
110+
1. Add the following content to the override file:
111+
112+
```ini
113+
[Service]
114+
ExecStart=
115+
ExecStart=/usr/lib/bluetooth/bluetoothd -E
116+
```
117+
118+
1. Restart the Bluetooth service by running the following command:
119+
120+
```sh
121+
sudo systemctl restart bluetooth.service
122+
```
123+
97124
#### Configuring wpa_supplicant for storing permanent changes
98125
99126
By default, wpa_supplicant is not allowed to update (overwrite) configuration.

examples/lock-app/esp32/main/AppTask.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ void AppTask::FunctionHandler(AppEvent * aEvent)
322322
}
323323
else
324324
{
325-
// If the button was released before factory reset got initiated, start BLE advertissement in fast mode
325+
// If the button was released before factory reset got initiated, start BLE advertisement in fast mode
326326
if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_StartBleAdv)
327327
{
328328
sAppTask.CancelTimer();
@@ -336,7 +336,7 @@ void AppTask::FunctionHandler(AppEvent * aEvent)
336336
}
337337
else
338338
{
339-
ESP_LOGI(TAG, "Network is already provisioned, Ble advertissement not enabled");
339+
ESP_LOGI(TAG, "Network is already provisioned, Ble advertisement not enabled");
340340
}
341341
}
342342
else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset)

examples/platform/silabs/BaseApplication.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ void BaseApplication::ButtonHandler(AppEvent * aEvent)
453453
{
454454
// The factory reset sequence was not initiated,
455455
// Press and Release:
456-
// - Open the commissioning window and start BLE advertissement in fast mode when not commissioned
456+
// - Open the commissioning window and start BLE advertisement in fast mode when not commissioned
457457
// - Output qr code in logs
458458
// - Cycle LCD screen
459459
CancelFunctionTimer();
@@ -477,7 +477,7 @@ void BaseApplication::ButtonHandler(AppEvent * aEvent)
477477
}
478478
else
479479
{
480-
SILABS_LOG("Network is already provisioned, Ble advertissement not enabled");
480+
SILABS_LOG("Network is already provisioned, Ble advertisement not enabled");
481481
#if CHIP_CONFIG_ENABLE_ICD_SERVER
482482
// Temporarily claim network activity, until we implement a "user trigger" reason for ICD wakeups.
483483
PlatformMgr().LockChipStack();

src/app/server/Dnssd.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ CHIP_ERROR DnssdServer::GenerateRotatingDeviceId(char rotatingDeviceIdHexBuffer[
496496
void DnssdServer::OnICDModeChange()
497497
{
498498
// ICDMode changed, restart DNS-SD advertising, because SII and ICD key are affected by this change.
499-
// StartServer will take care of setting the operational and commissionable advertissements
499+
// StartServer will take care of setting the operational and commissionable advertisements
500500
StartServer();
501501
}
502502

src/lib/dnssd/minimal_mdns/tests/TestAdvertiser.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ CommissionAdvertisingParameters commissionableNodeParamsEnhancedAsICDLIT =
210210
.SetTcpSupported(chip::Optional<bool>(true))
211211
.SetICDOperatingAsLIT(chip::Optional<bool>(true))
212212
.SetLocalMRPConfig(Optional<ReliableMessageProtocolConfig>::Value(3600000_ms32, 3600000_ms32, 65535_ms16));
213-
// With ICD Operation as LIT, SII key will not be added to the advertissement
213+
// With ICD Operation as LIT, SII key will not be added to the advertisement
214214
QNamePart txtCommissionableNodeParamsEnhancedAsICDLITParts[] = { "D=22", "VP=555+897", "CM=2", "DT=70000",
215215
"DN=testy-test", "PI=Pair me", "PH=3", "SAI=3600000",
216216
"SAT=65535", "T=1", "ICD=1" };

src/platform/Infineon/PSOC6/BLEManagerImpl.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ void BLEManagerImpl::DriveBLEState(void)
426426
ChipLogProgress(DeviceLayer, "CHIPoBLE stop advertising");
427427
wiced_bt_start_advertisements(BTM_BLE_ADVERT_OFF, BLE_ADDR_PUBLIC, NULL);
428428

429-
/* Delete the heap allocated during BLE Advertisment Stop */
429+
/* Delete the heap allocated during BLE Advertisement Stop */
430430
if (p_heap)
431431
{
432432
wiced_bt_delete_heap(p_heap);

src/platform/Linux/BLEManagerImpl.cpp

+77-35
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ namespace {
5454

5555
static constexpr System::Clock::Timeout kNewConnectionScanTimeout = System::Clock::Seconds16(20);
5656
static constexpr System::Clock::Timeout kConnectTimeout = System::Clock::Seconds16(20);
57+
static constexpr System::Clock::Timeout kFastAdvertiseTimeout =
58+
System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME);
59+
#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
60+
// The CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS specifies the transition time
61+
// starting from advertisement commencement. Since the extended advertisement timer is started after
62+
// the fast-to-slow transition, we have to subtract the time spent in fast advertising.
63+
static constexpr System::Clock::Timeout kSlowAdvertiseTimeout = System::Clock::Milliseconds32(
64+
CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS - CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME);
65+
static_assert(CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS >=
66+
CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME,
67+
"The extended advertising interval change time must be greater than the fast advertising interval change time");
68+
#endif
5769

5870
const ChipBleUUID ChipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
5971
0x9D, 0x11 } };
@@ -91,7 +103,7 @@ CHIP_ERROR BLEManagerImpl::_Init()
91103

92104
OnChipBleConnectReceived = HandleIncomingBleConnection;
93105

94-
PlatformMgr().ScheduleWork(DriveBLEState, 0);
106+
DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveBLEState(); });
95107

96108
exit:
97109
return err;
@@ -119,7 +131,7 @@ CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val)
119131
mFlags.Set(Flags::kAdvertisingEnabled, val);
120132
}
121133

122-
PlatformMgr().ScheduleWork(DriveBLEState, 0);
134+
DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveBLEState(); });
123135

124136
return err;
125137
}
@@ -138,7 +150,7 @@ CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode)
138150
return CHIP_ERROR_INVALID_ARGUMENT;
139151
}
140152
mFlags.Set(Flags::kAdvertisingRefreshNeeded);
141-
PlatformMgr().ScheduleWork(DriveBLEState, 0);
153+
DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveBLEState(); });
142154
return CHIP_NO_ERROR;
143155
}
144156

@@ -186,14 +198,9 @@ uint16_t BLEManagerImpl::_NumConnections()
186198

187199
CHIP_ERROR BLEManagerImpl::ConfigureBle(uint32_t aAdapterId, bool aIsCentral)
188200
{
189-
190-
mAdapterId = aAdapterId;
191-
mIsCentral = aIsCentral;
192-
193-
mBLEAdvType = ChipAdvType::BLUEZ_ADV_TYPE_UNDIRECTED_CONNECTABLE_SCANNABLE;
194-
mBLEAdvDurationMs = 2;
195-
mpBLEAdvUUID = "0xFFF6";
196-
201+
mAdapterId = aAdapterId;
202+
mIsCentral = aIsCentral;
203+
mpBLEAdvUUID = "0xFFF6";
197204
return CHIP_NO_ERROR;
198205
}
199206

@@ -278,17 +285,14 @@ void BLEManagerImpl::HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * apEv
278285
case DeviceEventType::kPlatformLinuxBLEPeripheralAdvStartComplete:
279286
VerifyOrExit(apEvent->Platform.BLEPeripheralAdvStartComplete.mIsSuccess, err = CHIP_ERROR_INCORRECT_STATE);
280287
sInstance.mFlags.Clear(Flags::kControlOpInProgress).Clear(Flags::kAdvertisingRefreshNeeded);
281-
282-
if (!sInstance.mFlags.Has(Flags::kAdvertising))
283-
{
284-
sInstance.mFlags.Set(Flags::kAdvertising);
285-
}
286-
288+
// Start a timer to make sure that the fast advertising is stopped after specified timeout.
289+
SuccessOrExit(err = DeviceLayer::SystemLayer().StartTimer(kFastAdvertiseTimeout, HandleAdvertisingTimer, this));
290+
sInstance.mFlags.Set(Flags::kAdvertising);
287291
break;
288292
case DeviceEventType::kPlatformLinuxBLEPeripheralAdvStopComplete:
289293
VerifyOrExit(apEvent->Platform.BLEPeripheralAdvStopComplete.mIsSuccess, err = CHIP_ERROR_INCORRECT_STATE);
290-
291294
sInstance.mFlags.Clear(Flags::kControlOpInProgress).Clear(Flags::kAdvertisingRefreshNeeded);
295+
DeviceLayer::SystemLayer().CancelTimer(HandleAdvertisingTimer, this);
292296

293297
// Transition to the not Advertising state...
294298
if (sInstance.mFlags.Has(Flags::kAdvertising))
@@ -311,6 +315,7 @@ void BLEManagerImpl::HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * apEv
311315
{
312316
ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err));
313317
mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
318+
DeviceLayer::SystemLayer().CancelTimer(HandleAdvertisingTimer, this);
314319
sInstance.mFlags.Clear(Flags::kControlOpInProgress);
315320
}
316321

@@ -595,15 +600,29 @@ void BLEManagerImpl::DriveBLEState()
595600
// Configure advertising data if it hasn't been done yet.
596601
if (!mFlags.Has(Flags::kAdvertisingConfigured))
597602
{
598-
SuccessOrExit(err = mBLEAdvertisement.Init(mEndpoint, mBLEAdvType, mpBLEAdvUUID, mBLEAdvDurationMs, mDeviceName));
603+
SuccessOrExit(err = mBLEAdvertisement.Init(mEndpoint, mpBLEAdvUUID, mDeviceName));
599604
mFlags.Set(Flags::kAdvertisingConfigured);
600605
}
601606

602-
// Start advertising. This is an asynchronous step. BLE manager will be notified of
603-
// advertising start completion via a call to NotifyBLEPeripheralAdvStartComplete.
604-
SuccessOrExit(err = mBLEAdvertisement.Start());
605-
mFlags.Set(Flags::kControlOpInProgress);
606-
ExitNow();
607+
// Setup service data for advertising.
608+
auto serviceDataFlags = BluezAdvertisement::kServiceDataNone;
609+
#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
610+
if (mFlags.Has(Flags::kExtAdvertisingEnabled))
611+
serviceDataFlags |= BluezAdvertisement::kServiceDataExtendedAnnouncement;
612+
#endif
613+
SuccessOrExit(err = mBLEAdvertisement.SetupServiceData(serviceDataFlags));
614+
615+
// Set or update the advertising intervals.
616+
SuccessOrExit(err = mBLEAdvertisement.SetIntervals(GetAdvertisingIntervals()));
617+
618+
if (!mFlags.Has(Flags::kAdvertising))
619+
{
620+
// Start advertising. This is an asynchronous step. BLE manager will be notified of
621+
// advertising start completion via a call to NotifyBLEPeripheralAdvStartComplete.
622+
SuccessOrExit(err = mBLEAdvertisement.Start());
623+
mFlags.Set(Flags::kControlOpInProgress);
624+
ExitNow();
625+
}
607626
}
608627
}
609628

@@ -627,11 +646,6 @@ void BLEManagerImpl::DriveBLEState()
627646
}
628647
}
629648

630-
void BLEManagerImpl::DriveBLEState(intptr_t arg)
631-
{
632-
sInstance.DriveBLEState();
633-
}
634-
635649
void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId)
636650
{
637651
ChipLogProgress(Ble, "Got notification regarding chip connection closure");
@@ -641,6 +655,39 @@ void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId)
641655
#endif
642656
}
643657

658+
BluezAdvertisement::AdvertisingIntervals BLEManagerImpl::GetAdvertisingIntervals() const
659+
{
660+
if (mFlags.Has(Flags::kFastAdvertisingEnabled))
661+
return { CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN, CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX };
662+
#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
663+
if (mFlags.Has(Flags::kExtAdvertisingEnabled))
664+
return { CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MIN, CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MAX };
665+
#endif
666+
return { CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN, CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX };
667+
}
668+
669+
void BLEManagerImpl::HandleAdvertisingTimer(chip::System::Layer *, void * appState)
670+
{
671+
auto * self = static_cast<BLEManagerImpl *>(appState);
672+
673+
if (self->mFlags.Has(Flags::kFastAdvertisingEnabled))
674+
{
675+
ChipLogDetail(DeviceLayer, "bleAdv Timeout : Start slow advertisement");
676+
self->_SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising);
677+
#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
678+
self->mFlags.Clear(Flags::kExtAdvertisingEnabled);
679+
DeviceLayer::SystemLayer().StartTimer(kSlowAdvertiseTimeout, HandleAdvertisingTimer, self);
680+
}
681+
else
682+
{
683+
ChipLogDetail(DeviceLayer, "bleAdv Timeout : Start extended advertisement");
684+
self->mFlags.Set(Flags::kExtAdvertisingEnabled);
685+
// This will trigger advertising intervals update in the DriveBLEState() function.
686+
self->_SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising);
687+
#endif
688+
}
689+
}
690+
644691
void BLEManagerImpl::InitiateScan(BleScanState scanType)
645692
{
646693
DriveBLEState();
@@ -695,18 +742,13 @@ void BLEManagerImpl::CleanScanConfig()
695742
mBLEScanConfig.mBleScanState = BleScanState::kNotScanning;
696743
}
697744

698-
void BLEManagerImpl::InitiateScan(intptr_t arg)
699-
{
700-
sInstance.InitiateScan(static_cast<BleScanState>(arg));
701-
}
702-
703745
void BLEManagerImpl::NewConnection(BleLayer * bleLayer, void * appState, const SetupDiscriminator & connDiscriminator)
704746
{
705747
mBLEScanConfig.mDiscriminator = connDiscriminator;
706748
mBLEScanConfig.mAppState = appState;
707749

708750
// Scan initiation performed async, to ensure that the BLE subsystem is initialized.
709-
PlatformMgr().ScheduleWork(InitiateScan, static_cast<intptr_t>(BleScanState::kScanForDiscriminator));
751+
DeviceLayer::SystemLayer().ScheduleLambda([this] { InitiateScan(BleScanState::kScanForDiscriminator); });
710752
}
711753

712754
CHIP_ERROR BLEManagerImpl::CancelConnection()

src/platform/Linux/BLEManagerImpl.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ class BLEManagerImpl final : public BLEManager,
141141
CHIP_ERROR CancelConnection() override;
142142

143143
// ===== Members that implement virtual methods on ChipDeviceScannerDelegate
144+
144145
void OnDeviceScanned(BluezDevice1 & device, const chip::Ble::ChipBLEDeviceIdentificationInfo & info) override;
145146
void OnScanComplete() override;
146147

@@ -152,6 +153,7 @@ class BLEManagerImpl final : public BLEManager,
152153
static BLEManagerImpl sInstance;
153154

154155
// ===== Private members reserved for use by this class only.
156+
155157
enum class Flags : uint16_t
156158
{
157159
kAsyncInitCompleted = 0x0001, /**< One-time asynchronous initialization actions have been performed. */
@@ -164,6 +166,7 @@ class BLEManagerImpl final : public BLEManager,
164166
kFastAdvertisingEnabled = 0x0080, /**< The application has enabled fast advertising. */
165167
kUseCustomDeviceName = 0x0100, /**< The application has configured a custom BLE device name. */
166168
kAdvertisingRefreshNeeded = 0x0200, /**< The advertising configuration/state in BLE layer needs to be updated. */
169+
kExtAdvertisingEnabled = 0x0400, /**< The application has enabled CHIPoBLE extended advertising. */
167170
};
168171

169172
enum
@@ -174,10 +177,9 @@ class BLEManagerImpl final : public BLEManager,
174177
};
175178

176179
void DriveBLEState();
177-
static void DriveBLEState(intptr_t arg);
178-
180+
BluezAdvertisement::AdvertisingIntervals GetAdvertisingIntervals() const;
181+
static void HandleAdvertisingTimer(chip::System::Layer *, void * appState);
179182
void InitiateScan(BleScanState scanType);
180-
static void InitiateScan(intptr_t arg);
181183
void CleanScanConfig();
182184

183185
CHIPoBLEServiceMode mServiceMode;
@@ -189,9 +191,7 @@ class BLEManagerImpl final : public BLEManager,
189191
BluezEndpoint mEndpoint;
190192

191193
BluezAdvertisement mBLEAdvertisement;
192-
ChipAdvType mBLEAdvType = ChipAdvType::BLUEZ_ADV_TYPE_UNDIRECTED_CONNECTABLE_SCANNABLE;
193-
uint16_t mBLEAdvDurationMs = 20;
194-
const char * mpBLEAdvUUID = nullptr;
194+
const char * mpBLEAdvUUID = nullptr;
195195

196196
ChipDeviceScanner mDeviceScanner;
197197
BLEScanConfig mBLEScanConfig;

0 commit comments

Comments
 (0)