Skip to content

Commit

Permalink
[Linux] Add support for extended advertisement (#31668)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
arkq and restyled-commits authored Feb 6, 2024
1 parent 819a4f1 commit bd6c4ab
Show file tree
Hide file tree
Showing 16 changed files with 201 additions and 120 deletions.
27 changes: 27 additions & 0 deletions docs/guides/BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,33 @@ Complete the following steps:
1. Reboot your Raspberry Pi after installing `pi-bluetooth`.
#### Enable experimental Bluetooth support in BlueZ
The Matter application on Linux uses BlueZ to communicate with the Bluetooth
controller. The BlueZ version that comes with Ubuntu 22.04 does not support all
the features required by the Matter application by default. To enable these
features, you need to enable experimental Bluetooth support in BlueZ.
1. Edit the `bluetooth.service` unit by running the following command:
```sh
sudo systemctl edit bluetooth.service
```
1. Add the following content to the override file:
```ini
[Service]
ExecStart=
ExecStart=/usr/lib/bluetooth/bluetoothd -E
```
1. Restart the Bluetooth service by running the following command:
```sh
sudo systemctl restart bluetooth.service
```
#### Configuring wpa_supplicant for storing permanent changes
By default, wpa_supplicant is not allowed to update (overwrite) configuration.
Expand Down
4 changes: 2 additions & 2 deletions examples/lock-app/esp32/main/AppTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ void AppTask::FunctionHandler(AppEvent * aEvent)
}
else
{
// If the button was released before factory reset got initiated, start BLE advertissement in fast mode
// If the button was released before factory reset got initiated, start BLE advertisement in fast mode
if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_StartBleAdv)
{
sAppTask.CancelTimer();
Expand All @@ -336,7 +336,7 @@ void AppTask::FunctionHandler(AppEvent * aEvent)
}
else
{
ESP_LOGI(TAG, "Network is already provisioned, Ble advertissement not enabled");
ESP_LOGI(TAG, "Network is already provisioned, Ble advertisement not enabled");
}
}
else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset)
Expand Down
4 changes: 2 additions & 2 deletions examples/platform/silabs/BaseApplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ void BaseApplication::ButtonHandler(AppEvent * aEvent)
{
// The factory reset sequence was not initiated,
// Press and Release:
// - Open the commissioning window and start BLE advertissement in fast mode when not commissioned
// - Open the commissioning window and start BLE advertisement in fast mode when not commissioned
// - Output qr code in logs
// - Cycle LCD screen
CancelFunctionTimer();
Expand All @@ -477,7 +477,7 @@ void BaseApplication::ButtonHandler(AppEvent * aEvent)
}
else
{
SILABS_LOG("Network is already provisioned, Ble advertissement not enabled");
SILABS_LOG("Network is already provisioned, Ble advertisement not enabled");
#if CHIP_CONFIG_ENABLE_ICD_SERVER
// Temporarily claim network activity, until we implement a "user trigger" reason for ICD wakeups.
PlatformMgr().LockChipStack();
Expand Down
2 changes: 1 addition & 1 deletion src/app/server/Dnssd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ CHIP_ERROR DnssdServer::GenerateRotatingDeviceId(char rotatingDeviceIdHexBuffer[
void DnssdServer::OnICDModeChange()
{
// ICDMode changed, restart DNS-SD advertising, because SII and ICD key are affected by this change.
// StartServer will take care of setting the operational and commissionable advertissements
// StartServer will take care of setting the operational and commissionable advertisements
StartServer();
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib/dnssd/minimal_mdns/tests/TestAdvertiser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ CommissionAdvertisingParameters commissionableNodeParamsEnhancedAsICDLIT =
.SetTcpSupported(chip::Optional<bool>(true))
.SetICDOperatingAsLIT(chip::Optional<bool>(true))
.SetLocalMRPConfig(Optional<ReliableMessageProtocolConfig>::Value(3600000_ms32, 3600000_ms32, 65535_ms16));
// With ICD Operation as LIT, SII key will not be added to the advertissement
// With ICD Operation as LIT, SII key will not be added to the advertisement
QNamePart txtCommissionableNodeParamsEnhancedAsICDLITParts[] = { "D=22", "VP=555+897", "CM=2", "DT=70000",
"DN=testy-test", "PI=Pair me", "PH=3", "SAI=3600000",
"SAT=65535", "T=1", "ICD=1" };
Expand Down
2 changes: 1 addition & 1 deletion src/platform/Infineon/PSOC6/BLEManagerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ void BLEManagerImpl::DriveBLEState(void)
ChipLogProgress(DeviceLayer, "CHIPoBLE stop advertising");
wiced_bt_start_advertisements(BTM_BLE_ADVERT_OFF, BLE_ADDR_PUBLIC, NULL);

/* Delete the heap allocated during BLE Advertisment Stop */
/* Delete the heap allocated during BLE Advertisement Stop */
if (p_heap)
{
wiced_bt_delete_heap(p_heap);
Expand Down
112 changes: 77 additions & 35 deletions src/platform/Linux/BLEManagerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ namespace {

static constexpr System::Clock::Timeout kNewConnectionScanTimeout = System::Clock::Seconds16(20);
static constexpr System::Clock::Timeout kConnectTimeout = System::Clock::Seconds16(20);
static constexpr System::Clock::Timeout kFastAdvertiseTimeout =
System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME);
#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
// The CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS specifies the transition time
// starting from advertisement commencement. Since the extended advertisement timer is started after
// the fast-to-slow transition, we have to subtract the time spent in fast advertising.
static constexpr System::Clock::Timeout kSlowAdvertiseTimeout = System::Clock::Milliseconds32(
CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS - CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME);
static_assert(CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS >=
CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME,
"The extended advertising interval change time must be greater than the fast advertising interval change time");
#endif

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

OnChipBleConnectReceived = HandleIncomingBleConnection;

PlatformMgr().ScheduleWork(DriveBLEState, 0);
DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveBLEState(); });

exit:
return err;
Expand Down Expand Up @@ -119,7 +131,7 @@ CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val)
mFlags.Set(Flags::kAdvertisingEnabled, val);
}

PlatformMgr().ScheduleWork(DriveBLEState, 0);
DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveBLEState(); });

return err;
}
Expand All @@ -138,7 +150,7 @@ CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode)
return CHIP_ERROR_INVALID_ARGUMENT;
}
mFlags.Set(Flags::kAdvertisingRefreshNeeded);
PlatformMgr().ScheduleWork(DriveBLEState, 0);
DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveBLEState(); });
return CHIP_NO_ERROR;
}

Expand Down Expand Up @@ -186,14 +198,9 @@ uint16_t BLEManagerImpl::_NumConnections()

CHIP_ERROR BLEManagerImpl::ConfigureBle(uint32_t aAdapterId, bool aIsCentral)
{

mAdapterId = aAdapterId;
mIsCentral = aIsCentral;

mBLEAdvType = ChipAdvType::BLUEZ_ADV_TYPE_UNDIRECTED_CONNECTABLE_SCANNABLE;
mBLEAdvDurationMs = 2;
mpBLEAdvUUID = "0xFFF6";

mAdapterId = aAdapterId;
mIsCentral = aIsCentral;
mpBLEAdvUUID = "0xFFF6";
return CHIP_NO_ERROR;
}

Expand Down Expand Up @@ -278,17 +285,14 @@ void BLEManagerImpl::HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * apEv
case DeviceEventType::kPlatformLinuxBLEPeripheralAdvStartComplete:
VerifyOrExit(apEvent->Platform.BLEPeripheralAdvStartComplete.mIsSuccess, err = CHIP_ERROR_INCORRECT_STATE);
sInstance.mFlags.Clear(Flags::kControlOpInProgress).Clear(Flags::kAdvertisingRefreshNeeded);

if (!sInstance.mFlags.Has(Flags::kAdvertising))
{
sInstance.mFlags.Set(Flags::kAdvertising);
}

// Start a timer to make sure that the fast advertising is stopped after specified timeout.
SuccessOrExit(err = DeviceLayer::SystemLayer().StartTimer(kFastAdvertiseTimeout, HandleAdvertisingTimer, this));
sInstance.mFlags.Set(Flags::kAdvertising);
break;
case DeviceEventType::kPlatformLinuxBLEPeripheralAdvStopComplete:
VerifyOrExit(apEvent->Platform.BLEPeripheralAdvStopComplete.mIsSuccess, err = CHIP_ERROR_INCORRECT_STATE);

sInstance.mFlags.Clear(Flags::kControlOpInProgress).Clear(Flags::kAdvertisingRefreshNeeded);
DeviceLayer::SystemLayer().CancelTimer(HandleAdvertisingTimer, this);

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

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

// Start advertising. This is an asynchronous step. BLE manager will be notified of
// advertising start completion via a call to NotifyBLEPeripheralAdvStartComplete.
SuccessOrExit(err = mBLEAdvertisement.Start());
mFlags.Set(Flags::kControlOpInProgress);
ExitNow();
// Setup service data for advertising.
auto serviceDataFlags = BluezAdvertisement::kServiceDataNone;
#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
if (mFlags.Has(Flags::kExtAdvertisingEnabled))
serviceDataFlags |= BluezAdvertisement::kServiceDataExtendedAnnouncement;
#endif
SuccessOrExit(err = mBLEAdvertisement.SetupServiceData(serviceDataFlags));

// Set or update the advertising intervals.
SuccessOrExit(err = mBLEAdvertisement.SetIntervals(GetAdvertisingIntervals()));

if (!mFlags.Has(Flags::kAdvertising))
{
// Start advertising. This is an asynchronous step. BLE manager will be notified of
// advertising start completion via a call to NotifyBLEPeripheralAdvStartComplete.
SuccessOrExit(err = mBLEAdvertisement.Start());
mFlags.Set(Flags::kControlOpInProgress);
ExitNow();
}
}
}

Expand All @@ -627,11 +646,6 @@ void BLEManagerImpl::DriveBLEState()
}
}

void BLEManagerImpl::DriveBLEState(intptr_t arg)
{
sInstance.DriveBLEState();
}

void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId)
{
ChipLogProgress(Ble, "Got notification regarding chip connection closure");
Expand All @@ -641,6 +655,39 @@ void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId)
#endif
}

BluezAdvertisement::AdvertisingIntervals BLEManagerImpl::GetAdvertisingIntervals() const
{
if (mFlags.Has(Flags::kFastAdvertisingEnabled))
return { CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN, CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX };
#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
if (mFlags.Has(Flags::kExtAdvertisingEnabled))
return { CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MIN, CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MAX };
#endif
return { CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN, CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX };
}

void BLEManagerImpl::HandleAdvertisingTimer(chip::System::Layer *, void * appState)
{
auto * self = static_cast<BLEManagerImpl *>(appState);

if (self->mFlags.Has(Flags::kFastAdvertisingEnabled))
{
ChipLogDetail(DeviceLayer, "bleAdv Timeout : Start slow advertisement");
self->_SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising);
#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
self->mFlags.Clear(Flags::kExtAdvertisingEnabled);
DeviceLayer::SystemLayer().StartTimer(kSlowAdvertiseTimeout, HandleAdvertisingTimer, self);
}
else
{
ChipLogDetail(DeviceLayer, "bleAdv Timeout : Start extended advertisement");
self->mFlags.Set(Flags::kExtAdvertisingEnabled);
// This will trigger advertising intervals update in the DriveBLEState() function.
self->_SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising);
#endif
}
}

void BLEManagerImpl::InitiateScan(BleScanState scanType)
{
DriveBLEState();
Expand Down Expand Up @@ -695,18 +742,13 @@ void BLEManagerImpl::CleanScanConfig()
mBLEScanConfig.mBleScanState = BleScanState::kNotScanning;
}

void BLEManagerImpl::InitiateScan(intptr_t arg)
{
sInstance.InitiateScan(static_cast<BleScanState>(arg));
}

void BLEManagerImpl::NewConnection(BleLayer * bleLayer, void * appState, const SetupDiscriminator & connDiscriminator)
{
mBLEScanConfig.mDiscriminator = connDiscriminator;
mBLEScanConfig.mAppState = appState;

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

CHIP_ERROR BLEManagerImpl::CancelConnection()
Expand Down
12 changes: 6 additions & 6 deletions src/platform/Linux/BLEManagerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class BLEManagerImpl final : public BLEManager,
CHIP_ERROR CancelConnection() override;

// ===== Members that implement virtual methods on ChipDeviceScannerDelegate

void OnDeviceScanned(BluezDevice1 & device, const chip::Ble::ChipBLEDeviceIdentificationInfo & info) override;
void OnScanComplete() override;

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

// ===== Private members reserved for use by this class only.

enum class Flags : uint16_t
{
kAsyncInitCompleted = 0x0001, /**< One-time asynchronous initialization actions have been performed. */
Expand All @@ -164,6 +166,7 @@ class BLEManagerImpl final : public BLEManager,
kFastAdvertisingEnabled = 0x0080, /**< The application has enabled fast advertising. */
kUseCustomDeviceName = 0x0100, /**< The application has configured a custom BLE device name. */
kAdvertisingRefreshNeeded = 0x0200, /**< The advertising configuration/state in BLE layer needs to be updated. */
kExtAdvertisingEnabled = 0x0400, /**< The application has enabled CHIPoBLE extended advertising. */
};

enum
Expand All @@ -174,10 +177,9 @@ class BLEManagerImpl final : public BLEManager,
};

void DriveBLEState();
static void DriveBLEState(intptr_t arg);

BluezAdvertisement::AdvertisingIntervals GetAdvertisingIntervals() const;
static void HandleAdvertisingTimer(chip::System::Layer *, void * appState);
void InitiateScan(BleScanState scanType);
static void InitiateScan(intptr_t arg);
void CleanScanConfig();

CHIPoBLEServiceMode mServiceMode;
Expand All @@ -189,9 +191,7 @@ class BLEManagerImpl final : public BLEManager,
BluezEndpoint mEndpoint;

BluezAdvertisement mBLEAdvertisement;
ChipAdvType mBLEAdvType = ChipAdvType::BLUEZ_ADV_TYPE_UNDIRECTED_CONNECTABLE_SCANNABLE;
uint16_t mBLEAdvDurationMs = 20;
const char * mpBLEAdvUUID = nullptr;
const char * mpBLEAdvUUID = nullptr;

ChipDeviceScanner mDeviceScanner;
BLEScanConfig mBLEScanConfig;
Expand Down
Loading

0 comments on commit bd6c4ab

Please sign in to comment.