From 2a0da8450c0a1290dd79f1e89c3bab1f563829f9 Mon Sep 17 00:00:00 2001 From: Arkadiusz Balys Date: Thu, 17 Aug 2023 18:08:42 +0200 Subject: [PATCH] samples: matter: Added BT recovery mechanism to Matter Bridge. After lost the connection between the Matter Bridge and the Bluetooth LE bridged device the recovery mechanism is started and the Bridge tries to scan and re-connect the lost device. Multiple BT LE devices can be lost asynchronously and then the Bridge device will scan and try to connect to each of them one by one. Added notify mechanism to inform the Matter layer that rhe bridge device loses/returns the Bluetooth LE connection to the Bridged device. Signed-off-by: Arkadiusz Balys Added scan timeout --- applications/matter_bridge/CMakeLists.txt | 1 + .../ble_onoff_light_data_provider.cpp | 3 +- .../src/bridged_device_types/onoff_light.cpp | 33 ++-- samples/matter/common/src/bridge/Kconfig | 12 ++ .../common/src/bridge/ble_bridged_device.h | 4 +- .../src/bridge/ble_connectivity_manager.cpp | 160 +++++++++++++++--- .../src/bridge/ble_connectivity_manager.h | 58 +++++-- .../common/src/bridge/bridged_device.cpp | 17 +- .../matter/common/src/bridge/bridged_device.h | 5 + .../bridge/bridged_device_data_provider.cpp | 40 +++++ .../src/bridge/bridged_device_data_provider.h | 8 + 11 files changed, 292 insertions(+), 49 deletions(-) create mode 100644 samples/matter/common/src/bridge/bridged_device_data_provider.cpp diff --git a/applications/matter_bridge/CMakeLists.txt b/applications/matter_bridge/CMakeLists.txt index 1b92824d75a9..f374bb7b8031 100644 --- a/applications/matter_bridge/CMakeLists.txt +++ b/applications/matter_bridge/CMakeLists.txt @@ -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 diff --git a/applications/matter_bridge/src/bridged_device_types/ble_onoff_light_data_provider.cpp b/applications/matter_bridge/src/bridged_device_types/ble_onoff_light_data_provider.cpp index d574fe1903c1..a51e9268896e 100644 --- a/applications/matter_bridge/src/bridged_device_types/ble_onoff_light_data_provider.cpp +++ b/applications/matter_bridge/src/bridged_device_types/ble_onoff_light_data_provider.cpp @@ -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); } } diff --git a/applications/matter_bridge/src/bridged_device_types/onoff_light.cpp b/applications/matter_bridge/src/bridged_device_types/onoff_light.cpp index d02a34ce3e7d..c03f1cc36ace 100644 --- a/applications/matter_bridge/src/bridged_device_types/onoff_light.cpp +++ b/applications/matter_bridge/src/bridged_device_types/onoff_light.cpp @@ -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: + 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; } diff --git a/samples/matter/common/src/bridge/Kconfig b/samples/matter/common/src/bridge/Kconfig index 78c4ab4fe969..c1ac68088b18 100644 --- a/samples/matter/common/src/bridge/Kconfig +++ b/samples/matter/common/src/bridge/Kconfig @@ -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 + int "Time (in ms) between recovery attempts when the BLE connection to the bridged device is lost" + default 1000 + +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 diff --git a/samples/matter/common/src/bridge/ble_bridged_device.h b/samples/matter/common/src/bridge/ble_bridged_device.h index 0f3e56bfd5ef..d02543f8a37c 100644 --- a/samples/matter/common/src/bridge/ble_bridged_device.h +++ b/samples/matter/common/src/bridge/ble_bridged_device.h @@ -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; diff --git a/samples/matter/common/src/bridge/ble_connectivity_manager.cpp b/samples/matter/common/src/bridge/ble_connectivity_manager.cpp index fdab1f7da1f8..3a1bb95fb3eb 100644 --- a/samples/matter/common/src/bridge/ble_connectivity_manager.cpp +++ b/samples/matter/common/src/bridge/ble_connectivity_manager.cpp @@ -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; } @@ -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); + 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) { @@ -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) { + 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(context); bool discoveryResult = false; const bt_gatt_dm_attr *gatt_service_attr = bt_gatt_dm_service_get(dm); @@ -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) @@ -129,7 +165,7 @@ void BLEConnectivityManager::DiscoveryNotFound(bt_conn *conn, void *context) BLEBridgedDevice *device = reinterpret_cast(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) @@ -138,7 +174,7 @@ void BLEConnectivityManager::DiscoveryError(bt_conn *conn, int err, void *contex BLEBridgedDevice *device = reinterpret_cast(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) @@ -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"); @@ -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) { @@ -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, @@ -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++; @@ -295,3 +378,42 @@ BLEBridgedDevice *BLEConnectivityManager::FindBLEBridgedDevice(bt_conn *conn) return nullptr; } + +BLEConnectivityManager::Recovery::Recovery() +{ + ring_buf_init(&mRingBuf, sizeof(mDevicesToRecover), reinterpret_cast(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(&deviceAddr), sizeof(deviceAddr)); + if (ret == sizeof(deviceAddr)) { + return reinterpret_cast(deviceAddr); + } + + return nullptr; +} + +bool BLEConnectivityManager::Recovery::PutDevice(BLEBridgedDevice *device) +{ + int ret = ring_buf_put(&mRingBuf, reinterpret_cast(&device), sizeof(device)); + return ret == sizeof(device); +} diff --git a/samples/matter/common/src/bridge/ble_connectivity_manager.h b/samples/matter/common/src/bridge/ble_connectivity_manager.h index 550d64abd3a0..4cd47a05e207 100644 --- a/samples/matter/common/src/bridge/ble_connectivity_manager.h +++ b/samples/matter/common/src/bridge/ble_connectivity_manager.h @@ -14,8 +14,45 @@ #include #include #include +#include class BLEConnectivityManager { +public: + static constexpr uint16_t kScanTimeoutMs = 10000; + static constexpr uint16_t kMaxScannedDevices = 16; + /* One BT connection is reserved for the Matter service purposes. */ + static constexpr uint16_t kMaxCreatedDevices = CONFIG_BT_MAX_CONN - 1; + static constexpr uint8_t kMaxServiceUuids = CONFIG_BT_SCAN_UUID_CNT; + +private: + class Recovery { + friend class BLEConnectivityManager; + constexpr static auto kRecoveryIntervalMs = CONFIG_BRIDGE_BT_RECOVERY_INTERVAL_MS; + constexpr static auto kRecoveryScanTimeoutMs = CONFIG_BRIDGE_BT_RECOVERY_SCAN_TIMEOUT_MS; + + public: + Recovery(); + ~Recovery() { CancelTimer(); } + void NotifyLostDevice(BLEBridgedDevice *device); + + private: + BLEBridgedDevice *GetDevice(); + bool PutDevice(BLEBridgedDevice *device); + bool IsNeeded() { return !ring_buf_is_empty(&mRingBuf); } + void StartTimer() { k_timer_start(&mRecoveryTimer, K_MSEC(kRecoveryIntervalMs), K_NO_WAIT); } + void CancelTimer() { k_timer_stop(&mRecoveryTimer); } + size_t GetCurrentAmount() { return ring_buf_size_get(&mRingBuf) / sizeof(BLEBridgedDevice *); } + + static void TimerTimeoutCallback(k_timer *timer); + + BLEBridgedDevice *mDevicesToRecover[BLEConnectivityManager::kMaxCreatedDevices]; + BLEBridgedDevice *mCurrentDevice = nullptr; + bool mRecoveryInProgress = false; + ring_buf mRingBuf; + uint8_t mIndexToRecover; + k_timer mRecoveryTimer; + }; + public: struct ScannedDevice { bt_addr_le_t mAddr; @@ -24,17 +61,12 @@ class BLEConnectivityManager { using ScanDoneCallback = void (*)(ScannedDevice *devices, uint8_t count, void *context); - static constexpr uint16_t kScanTimeoutMs = 10000; - static constexpr uint16_t kMaxScannedDevices = 16; - /* One BT connection is reserved for the Matter service purposes. */ - static constexpr uint16_t kMaxCreatedDevices = CONFIG_BT_MAX_CONN - 1; - static constexpr uint8_t kMaxServiceUuids = CONFIG_BT_SCAN_UUID_CNT; - CHIP_ERROR Init(bt_uuid **serviceUuids, uint8_t serviceUuidsCount); - CHIP_ERROR Scan(ScanDoneCallback callback, void *context); + CHIP_ERROR Scan(ScanDoneCallback callback, void *context, uint32_t scanTimeoutMs = kScanTimeoutMs); CHIP_ERROR StopScan(); CHIP_ERROR Connect(uint8_t index, BLEBridgedDevice::DeviceConnectedCallback callback, void *context, bt_uuid *serviceUuid); + CHIP_ERROR Reconnect(); BLEBridgedDevice *FindBLEBridgedDevice(bt_conn *conn); static void FilterMatch(bt_scan_device_info *device_info, bt_scan_filter_match *filter_match, bool connectable); @@ -46,11 +78,12 @@ class BLEConnectivityManager { static void DiscoveryNotFound(bt_conn *conn, void *context); static void DiscoveryError(bt_conn *conn, int err, void *context); - static BLEConnectivityManager & Instance() - { - static BLEConnectivityManager sInstance; - return sInstance; - } + static BLEConnectivityManager &Instance() + { + static BLEConnectivityManager sInstance; + return sInstance; + } + static void ReScanCallback(ScannedDevice *devices, uint8_t count, void *context); private: bool mScanActive; @@ -63,4 +96,5 @@ class BLEConnectivityManager { uint8_t mServicesUuidCount; ScanDoneCallback mScanDoneCallback; void *mScanDoneCallbackContext; + Recovery mRecovery; }; diff --git a/samples/matter/common/src/bridge/bridged_device.cpp b/samples/matter/common/src/bridge/bridged_device.cpp index 7bab12ba28e5..7a20cc6d10b0 100644 --- a/samples/matter/common/src/bridge/bridged_device.cpp +++ b/samples/matter/common/src/bridge/bridged_device.cpp @@ -10,8 +10,7 @@ using namespace ::chip; using namespace ::chip::app; -CHIP_ERROR BridgedDevice::CopyAttribute(void *attribute, size_t attributeSize, void *buffer, - uint16_t maxBufferSize) +CHIP_ERROR BridgedDevice::CopyAttribute(void *attribute, size_t attributeSize, void *buffer, uint16_t maxBufferSize) { if (maxBufferSize < attributeSize) { return CHIP_ERROR_INVALID_ARGUMENT; @@ -22,6 +21,20 @@ CHIP_ERROR BridgedDevice::CopyAttribute(void *attribute, size_t attributeSize, v return CHIP_NO_ERROR; } +CHIP_ERROR BridgedDevice::HandleWriteDeviceBasicInformation(chip::ClusterId clusterId, chip::AttributeId attributeId, + void *data, size_t dataSize) +{ + switch (attributeId) { + case Clusters::BridgedDeviceBasicInformation::Attributes::Reachable::Id: + if (data && dataSize == sizeof(bool)) { + SetIsReachable(*reinterpret_cast(data)); + return CHIP_NO_ERROR; + } + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } +} + CHIP_ERROR BridgedDevice::HandleReadBridgedDeviceBasicInformation(AttributeId attributeId, uint8_t *buffer, uint16_t maxReadLength) { diff --git a/samples/matter/common/src/bridge/bridged_device.h b/samples/matter/common/src/bridge/bridged_device.h index 4cafd4813734..0fcee5c26cf2 100644 --- a/samples/matter/common/src/bridge/bridged_device.h +++ b/samples/matter/common/src/bridge/bridged_device.h @@ -67,12 +67,15 @@ class BridgedDevice { virtual CHIP_ERROR HandleAttributeChange(chip::ClusterId clusterId, chip::AttributeId attributeId, void *data, size_t dataSize) = 0; CHIP_ERROR CopyAttribute(void *attribute, size_t attributeSize, void *buffer, uint16_t maxBufferSize); + CHIP_ERROR HandleWriteDeviceBasicInformation(chip::ClusterId clusterId, chip::AttributeId attributeId, + void *data, size_t dataSize); CHIP_ERROR HandleReadBridgedDeviceBasicInformation(chip::AttributeId attributeId, uint8_t *buffer, uint16_t maxReadLength); CHIP_ERROR HandleReadDescriptor(chip::AttributeId attributeId, uint8_t *buffer, uint16_t maxReadLength); bool GetIsReachable() const { return mIsReachable; } const char *GetNodeLabel() const { return mNodeLabel; } + void SetIsReachable(bool isReachable) { mIsReachable = isReachable; } uint16_t GetBridgedDeviceBasicInformationClusterRevision() { return kBridgedDeviceBasicInformationClusterRevision; @@ -81,6 +84,8 @@ class BridgedDevice { uint16_t GetDescriptorClusterRevision() { return kDescriptorClusterRevision; } uint32_t GetDescriptorFeatureMap() { return kDescrtiptorFeatureMap; } + static void NotifyAttributeChange(intptr_t context); + EmberAfEndpointType *mEp; const EmberAfDeviceType *mDeviceTypeList; size_t mDeviceTypeListSize; diff --git a/samples/matter/common/src/bridge/bridged_device_data_provider.cpp b/samples/matter/common/src/bridge/bridged_device_data_provider.cpp new file mode 100644 index 000000000000..3cef34f51b91 --- /dev/null +++ b/samples/matter/common/src/bridge/bridged_device_data_provider.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "bridged_device_data_provider.h" + +#include + +LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); + +CHIP_ERROR BridgedDeviceDataProvider::NotifyReachableStatusChange(bool isReachable) +{ + auto reachableContext = chip::Platform::New(); + if (!reachableContext) { + return CHIP_ERROR_NO_MEMORY; + } + + reachableContext->mIsReachable = isReachable; + reachableContext->mProvider = this; + + CHIP_ERROR err = chip::DeviceLayer::PlatformMgr().ScheduleWork( + [](intptr_t context) { + auto ctx = reinterpret_cast(context); + ctx->mProvider->NotifyUpdateState( + chip::app::Clusters::BridgedDeviceBasicInformation::Id, + chip::app::Clusters::BridgedDeviceBasicInformation::Attributes::Reachable::Id, + &ctx->mIsReachable, sizeof(ctx->mIsReachable)); + chip::Platform::Delete(ctx); + }, + reinterpret_cast(reachableContext)); + + if (CHIP_NO_ERROR != err) { + chip::Platform::Delete(reachableContext); + return err; + } + + return CHIP_NO_ERROR; +} diff --git a/samples/matter/common/src/bridge/bridged_device_data_provider.h b/samples/matter/common/src/bridge/bridged_device_data_provider.h index ed25375939a7..238e7bf1354f 100644 --- a/samples/matter/common/src/bridge/bridged_device_data_provider.h +++ b/samples/matter/common/src/bridge/bridged_device_data_provider.h @@ -21,6 +21,14 @@ class BridgedDeviceDataProvider { size_t dataSize) = 0; virtual CHIP_ERROR UpdateState(chip::ClusterId clusterId, chip::AttributeId attributeId, uint8_t *buffer) = 0; + CHIP_ERROR NotifyReachableStatusChange(bool isReachable); + protected: UpdateAttributeCallback mUpdateAttributeCallback; + +private: + struct ReachableContext { + bool mIsReachable; + BridgedDeviceDataProvider *mProvider; + }; };