Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

samples: matter: Added BT recovery mechanism to Matter Bridge. #12066

Merged
merged 1 commit into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions applications/matter_bridge/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ target_sources(app PRIVATE
${COMMON_ROOT}/src/bridge/bridge_manager.cpp
${COMMON_ROOT}/src/bridge/bridged_device.cpp
${COMMON_ROOT}/src/bridge/bridge_storage_manager.cpp
${COMMON_ROOT}/src/bridge/bridged_device_data_provider.cpp
src/zap-generated/IMClusterCommandHandler.cpp
src/zap-generated/callback-stub.cpp
${COMMON_ROOT}/src/led_widget.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ void BleOnOffLightDataProvider::NotifyUpdateState(chip::ClusterId clusterId, chi
size_t dataSize)
{
if (mUpdateAttributeCallback) {
mUpdateAttributeCallback(*this, Clusters::OnOff::Id, Clusters::OnOff::Attributes::OnOff::Id, data,
dataSize);
mUpdateAttributeCallback(*this, clusterId, attributeId, data, dataSize);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,28 +112,37 @@ CHIP_ERROR OnOffLightDevice::HandleWrite(ClusterId clusterId, AttributeId attrib
CHIP_ERROR OnOffLightDevice::HandleAttributeChange(chip::ClusterId clusterId, chip::AttributeId attributeId, void *data,
size_t dataSize)
{
if (clusterId != Clusters::OnOff::Id || !data) {
if (!data) {
return CHIP_ERROR_INVALID_ARGUMENT;
}

CHIP_ERROR err;
switch (clusterId) {
case Clusters::BridgedDeviceBasicInformation::Id:
markaj-nordic marked this conversation as resolved.
Show resolved Hide resolved
HandleWriteDeviceBasicInformation(clusterId, attributeId, data, dataSize);
return CHIP_NO_ERROR;
case Clusters::OnOff::Id: {
switch (attributeId) {
case Clusters::OnOff::Attributes::OnOff::Id: {
CHIP_ERROR err;

switch (attributeId) {
case Clusters::OnOff::Attributes::OnOff::Id: {
bool value;
bool value;

err = CopyAttribute(data, dataSize, &value, sizeof(value));
err = CopyAttribute(data, dataSize, &value, sizeof(value));

if (err != CHIP_NO_ERROR) {
return err;
}
if (err != CHIP_NO_ERROR) {
return err;
}

SetOnOff(value);
break;
SetOnOff(value);
break;
}
default:
return CHIP_ERROR_INVALID_ARGUMENT;
}
}
default:
return CHIP_ERROR_INVALID_ARGUMENT;
}

return err;
return CHIP_ERROR_INVALID_ARGUMENT;
}
12 changes: 12 additions & 0 deletions samples/matter/common/src/bridge/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,15 @@ config BRIDGE_MAX_DYNAMIC_ENDPOINTS_NUMBER
config BRIDGE_MAX_BRIDGED_DEVICES_NUMBER
int "Maximum number of physical non-Matter devices supported by the Bridge"
default 16

if BRIDGED_DEVICE_BT

config BRIDGE_BT_RECOVERY_INTERVAL_MS
ArekBalysNordic marked this conversation as resolved.
Show resolved Hide resolved
int "Time (in ms) between recovery attempts when the BLE connection to the bridged device is lost"
default 1000
markaj-nordic marked this conversation as resolved.
Show resolved Hide resolved

config BRIDGE_BT_RECOVERY_SCAN_TIMEOUT_MS
int "Time (in ms) within which the Bridge will try to re-establish a connection to the lost BT LE device"
default 2000

endif
4 changes: 2 additions & 2 deletions samples/matter/common/src/bridge/ble_bridged_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ struct BLEBridgedDevice {
bool discoverySucceeded, void *context);

bt_addr_le_t mAddr;
DeviceConnectedCallback mConnectedCallback;
void *mConnectedCallbackContext;
DeviceConnectedCallback mFirstConnectionCallback;
void *mFirstConnectionCallbackContext;
bt_uuid *mServiceUuid;
bt_conn *mConn;
BLEBridgedDeviceProvider *mProvider;
Expand Down
160 changes: 141 additions & 19 deletions samples/matter/common/src/bridge/ble_connectivity_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ void BLEConnectivityManager::ConnectionHandler(bt_conn *conn, uint8_t conn_err)

/* Find the created device instance based on address. */
for (int i = 0; i < Instance().mCreatedDevicesCounter; i++) {
if (memcmp(&Instance().mCreatedDevices[i].mAddr, addr,
sizeof(Instance().mCreatedDevices[i].mAddr)) == 0) {
if (memcmp(&Instance().mCreatedDevices[i].mAddr, addr, sizeof(Instance().mCreatedDevices[i].mAddr)) ==
0) {
device = &Instance().mCreatedDevices[i];
break;
}
Expand All @@ -79,10 +79,15 @@ void BLEConnectivityManager::ConnectionHandler(bt_conn *conn, uint8_t conn_err)
return;
}

LOG_INF("Connected: %s", str_addr);

/* TODO: Add security validation. */

if (conn_err && Instance().mRecovery.mRecoveryInProgress) {
Instance().mRecovery.PutDevice(device);
markaj-nordic marked this conversation as resolved.
Show resolved Hide resolved
return;
}

LOG_INF("Connected: %s", str_addr);

/* Start GATT discovery for the device's service UUID. */
err = bt_gatt_dm_start(conn, device->mServiceUuid, &discovery_cb, device);
if (err) {
Expand All @@ -94,19 +99,35 @@ void BLEConnectivityManager::ConnectionHandler(bt_conn *conn, uint8_t conn_err)

void BLEConnectivityManager::DisconnectionHandler(bt_conn *conn, uint8_t reason)
{
char addr[BT_ADDR_LE_STR_LEN];
/* Verify whether the device should be recovered */
BLEBridgedDevice *device = Instance().FindBLEBridgedDevice(conn);

bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
if (device) {
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

LOG_INF("Disconnected: %s (reason %u)", addr, reason);
LOG_INF("Disconnected: %s (reason %u)", addr, reason);

/* TODO: Implement connection re-establishment procedure. */
if (device->mConn) {
bt_conn_unref(device->mConn);
device->mConn = nullptr;
}

if (reason == BT_HCI_ERR_CONN_TIMEOUT) {
markaj-nordic marked this conversation as resolved.
Show resolved Hide resolved
Instance().mRecovery.NotifyLostDevice(device);
if (device->mProvider) {
VerifyOrReturn(CHIP_NO_ERROR == device->mProvider->NotifyReachableStatusChange(false),
LOG_WRN("The device has not been notified about the status change."));
}
}

/* TODO Add removing a device when disconnection has been invoked by the user */
}
}

void BLEConnectivityManager::DiscoveryCompletedHandler(bt_gatt_dm *dm, void *context)
{
LOG_INF("The GATT discovery completed");

BLEBridgedDevice *device = reinterpret_cast<BLEBridgedDevice *>(context);
bool discoveryResult = false;
const bt_gatt_dm_attr *gatt_service_attr = bt_gatt_dm_service_get(dm);
Expand All @@ -120,7 +141,22 @@ void BLEConnectivityManager::DiscoveryCompletedHandler(bt_gatt_dm *dm, void *con
discoveryResult = true;
exit:

device->mConnectedCallback(device, dm, discoveryResult, device->mConnectedCallbackContext);
if (!Instance().mRecovery.mRecoveryInProgress) {
device->mFirstConnectionCallback(device, dm, discoveryResult, device->mFirstConnectionCallbackContext);
}

if (device->mProvider) {
VerifyOrReturn(CHIP_NO_ERROR == device->mProvider->NotifyReachableStatusChange(true),
LOG_WRN("The device has not been notified about the status change."));
}

Instance().mRecovery.mRecoveryInProgress = false;

if (Instance().mRecovery.IsNeeded()) {
Instance().mRecovery.StartTimer();
}

bt_gatt_dm_data_release(dm);
}

void BLEConnectivityManager::DiscoveryNotFound(bt_conn *conn, void *context)
Expand All @@ -129,7 +165,7 @@ void BLEConnectivityManager::DiscoveryNotFound(bt_conn *conn, void *context)

BLEBridgedDevice *device = reinterpret_cast<BLEBridgedDevice *>(context);

device->mConnectedCallback(device, nullptr, false, device->mConnectedCallbackContext);
device->mFirstConnectionCallback(device, nullptr, false, device->mFirstConnectionCallbackContext);
}

void BLEConnectivityManager::DiscoveryError(bt_conn *conn, int err, void *context)
Expand All @@ -138,7 +174,7 @@ void BLEConnectivityManager::DiscoveryError(bt_conn *conn, int err, void *contex

BLEBridgedDevice *device = reinterpret_cast<BLEBridgedDevice *>(context);

device->mConnectedCallback(device, nullptr, false, device->mConnectedCallbackContext);
device->mFirstConnectionCallback(device, nullptr, false, device->mFirstConnectionCallbackContext);
}

CHIP_ERROR BLEConnectivityManager::Init(bt_uuid **serviceUuids, uint8_t serviceUuidsCount)
Expand Down Expand Up @@ -180,7 +216,7 @@ CHIP_ERROR BLEConnectivityManager::Init(bt_uuid **serviceUuids, uint8_t serviceU
return CHIP_NO_ERROR;
}

CHIP_ERROR BLEConnectivityManager::Scan(ScanDoneCallback callback, void *context)
CHIP_ERROR BLEConnectivityManager::Scan(ScanDoneCallback callback, void *context, uint32_t scanTimeoutMs)
{
if (mScanActive) {
LOG_ERR("Scan is already in progress");
Expand All @@ -201,12 +237,43 @@ CHIP_ERROR BLEConnectivityManager::Scan(ScanDoneCallback callback, void *context
return System::MapErrorZephyr(err);
}

k_timer_start(&mScanTimer, K_MSEC(kScanTimeoutMs), K_NO_WAIT);
k_timer_start(&mScanTimer, K_MSEC(scanTimeoutMs), K_NO_WAIT);
mScanActive = true;

return CHIP_NO_ERROR;
}

void BLEConnectivityManager::ReScanCallback(ScannedDevice *devices, uint8_t count, void *context)
{
LOG_DBG("Lost devices no. %d", Instance().mRecovery.GetCurrentAmount());
LOG_DBG("Found devices no. %d", Instance().mScannedDevicesCounter);

if (Instance().mScannedDevicesCounter != 0 && !Instance().mRecovery.mRecoveryInProgress) {
BLEBridgedDevice *deviceLost = Instance().mRecovery.GetDevice();
if (deviceLost) {
for (uint8_t idx = 0; idx < Instance().mScannedDevicesCounter; idx++) {
auto &deviceScanned = Instance().mScannedDevices[idx];
if (memcmp(&deviceScanned.mAddr, &deviceLost->mAddr, sizeof(deviceLost->mAddr)) == 0) {
LOG_DBG("Found the lost device");

Instance().mRecovery.mIndexToRecover = idx;
Instance().mRecovery.mCurrentDevice = deviceLost;
Instance().mRecovery.mRecoveryInProgress = true;

DeviceLayer::PlatformMgr().ScheduleWork(
[](intptr_t context) { Instance().Reconnect(); }, 0);
break;
}
}
if (!Instance().mRecovery.mRecoveryInProgress) {
Instance().mRecovery.NotifyLostDevice(deviceLost);
}
}
} else if (Instance().mRecovery.IsNeeded()) {
Instance().mRecovery.StartTimer();
}
}

CHIP_ERROR BLEConnectivityManager::StopScan()
{
if (!mScanActive) {
Expand All @@ -232,9 +299,25 @@ void BLEConnectivityManager::ScanTimeoutCallback(k_timer *timer)
void BLEConnectivityManager::ScanTimeoutHandle(intptr_t context)
{
Instance().StopScan();
Instance().mScanDoneCallback(Instance().mScannedDevices,
Instance().mScannedDevicesCounter,
Instance().mScanDoneCallbackContext);
Instance().mScanDoneCallback(Instance().mScannedDevices, Instance().mScannedDevicesCounter,
Instance().mScanDoneCallbackContext);
}

CHIP_ERROR BLEConnectivityManager::Reconnect()
{
StopScan();

bt_conn *conn;

int err = bt_conn_le_create(&mScannedDevices[Instance().mRecovery.mIndexToRecover].mAddr, create_param,
&mScannedDevices[Instance().mRecovery.mIndexToRecover].mConnParam, &conn);

if (err) {
LOG_ERR("Creating reconnection failed (err %d)", err);
return System::MapErrorZephyr(err);
}

return CHIP_NO_ERROR;
}

CHIP_ERROR BLEConnectivityManager::Connect(uint8_t index, BLEBridgedDevice::DeviceConnectedCallback callback,
Expand Down Expand Up @@ -267,8 +350,8 @@ CHIP_ERROR BLEConnectivityManager::Connect(uint8_t index, BLEBridgedDevice::Devi
}

mCreatedDevices[mCreatedDevicesCounter].mAddr = mScannedDevices[index].mAddr;
mCreatedDevices[mCreatedDevicesCounter].mConnectedCallback = callback;
mCreatedDevices[mCreatedDevicesCounter].mConnectedCallbackContext = context;
mCreatedDevices[mCreatedDevicesCounter].mFirstConnectionCallback = callback;
mCreatedDevices[mCreatedDevicesCounter].mFirstConnectionCallbackContext = context;
mCreatedDevices[mCreatedDevicesCounter].mServiceUuid = serviceUuid;
mCreatedDevicesCounter++;

Expand All @@ -295,3 +378,42 @@ BLEBridgedDevice *BLEConnectivityManager::FindBLEBridgedDevice(bt_conn *conn)

return nullptr;
}

BLEConnectivityManager::Recovery::Recovery()
{
ring_buf_init(&mRingBuf, sizeof(mDevicesToRecover), reinterpret_cast<uint8_t *>(mDevicesToRecover));
k_timer_init(&mRecoveryTimer, TimerTimeoutCallback, nullptr);
k_timer_user_data_set(&mRecoveryTimer, this);
}

void BLEConnectivityManager::Recovery::NotifyLostDevice(BLEBridgedDevice *device)
{
if (device) {
PutDevice(device);
StartTimer();
}
}

void BLEConnectivityManager::Recovery::TimerTimeoutCallback(k_timer *timer)
{
LOG_DBG("Re-scanning BLE connections...");
DeviceLayer::PlatformMgr().ScheduleWork(
[](intptr_t) { Instance().Scan(ReScanCallback, nullptr, kRecoveryScanTimeoutMs); }, 0);
}

BLEBridgedDevice *BLEConnectivityManager::Recovery::GetDevice()
{
uint32_t deviceAddr;
int ret = ring_buf_get(&mRingBuf, reinterpret_cast<uint8_t *>(&deviceAddr), sizeof(deviceAddr));
if (ret == sizeof(deviceAddr)) {
return reinterpret_cast<BLEBridgedDevice *>(deviceAddr);
}

return nullptr;
}

bool BLEConnectivityManager::Recovery::PutDevice(BLEBridgedDevice *device)
{
int ret = ring_buf_put(&mRingBuf, reinterpret_cast<uint8_t *>(&device), sizeof(device));
return ret == sizeof(device);
}
Loading
Loading