diff --git a/examples/chip-tool/commands/common/DeviceScanner.cpp b/examples/chip-tool/commands/common/DeviceScanner.cpp index af3accbbc03b4e..f5c1e39fda7d9d 100644 --- a/examples/chip-tool/commands/common/DeviceScanner.cpp +++ b/examples/chip-tool/commands/common/DeviceScanner.cpp @@ -72,7 +72,7 @@ void DeviceScanner::OnNodeDiscovered(const DiscoveredNodeData & nodeData) } #if CHIP_TOOL_DEVICE_SCANNER_USE_BLE -void DeviceScanner::OnBleScanResult(BLE_CONNECTION_OBJECT connObj, const ChipBLEDeviceIdentificationInfo & info) +void DeviceScanner::OnBleScanAdd(BLE_CONNECTION_OBJECT connObj, const ChipBLEDeviceIdentificationInfo & info) { auto discriminator = info.GetDeviceDiscriminator(); auto vendorId = static_cast(info.GetVendorId()); @@ -85,6 +85,8 @@ void DeviceScanner::OnBleScanResult(BLE_CONNECTION_OBJECT connObj, const ChipBLE DeviceScannerResult result = { params, vendorId, productId, discriminator }; mDiscoveredResults.push_back(result); } + +void DeviceScanner::OnBleScanRemove(BLE_CONNECTION_OBJECT connObj) {} #endif // CHIP_TOOL_DEVICE_SCANNER_USE_BLE CHIP_ERROR DeviceScanner::Get(uint16_t index, RendezvousParameters & params) diff --git a/examples/chip-tool/commands/common/DeviceScanner.h b/examples/chip-tool/commands/common/DeviceScanner.h index 62479a36edba0f..57dd6affc8ef46 100644 --- a/examples/chip-tool/commands/common/DeviceScanner.h +++ b/examples/chip-tool/commands/common/DeviceScanner.h @@ -59,7 +59,8 @@ class DeviceScanner : public chip::Dnssd::CommissioningResolveDelegate #if CHIP_TOOL_DEVICE_SCANNER_USE_BLE /////////// BleScannerDelegate Interface ///////// - void OnBleScanResult(BLE_CONNECTION_OBJECT connObj, const chip::Ble::ChipBLEDeviceIdentificationInfo & info) override; + void OnBleScanAdd(BLE_CONNECTION_OBJECT connObj, const chip::Ble::ChipBLEDeviceIdentificationInfo & info) override; + void OnBleScanRemove(BLE_CONNECTION_OBJECT connObj) override; #endif // CHIP_TOOL_DEVICE_SCANNER_USE_BLE private: diff --git a/src/platform/Darwin/BleConnectionDelegateImpl.mm b/src/platform/Darwin/BleConnectionDelegateImpl.mm index ab8242ea649060..5afd14fcb89199 100644 --- a/src/platform/Darwin/BleConnectionDelegateImpl.mm +++ b/src/platform/Darwin/BleConnectionDelegateImpl.mm @@ -42,6 +42,8 @@ constexpr uint64_t kScanningWithDiscriminatorTimeoutInSeconds = 60; constexpr uint64_t kScanningWithoutDelegateTimeoutInSeconds = 120; +constexpr uint64_t kCachePeripheralTimeoutInSeconds + = static_cast(CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX / 1000.0 * 8.0 * 0.625); constexpr const char * kBleWorkQueueName = "org.csa-iot.matter.framework.ble.workqueue"; typedef NS_ENUM(uint8_t, BleConnectionMode) { @@ -60,7 +62,7 @@ @interface BleConnection : NSObject * cachedPeripherals; @property (unsafe_unretained, nonatomic) bool found; @property (unsafe_unretained, nonatomic) chip::SetupDiscriminator deviceDiscriminator; @property (unsafe_unretained, nonatomic) void * appState; @@ -81,6 +83,9 @@ - (void)updateWithPeripheral:(CBPeripheral *)peripheral; - (BOOL)isScanningWithoutDelegate; - (BOOL)isScanning; - (BOOL)isConnecting; +- (void)addPeripheralToCache:(CBPeripheral *)peripheral data:(NSData *)data; +- (void)removePeripheralFromCache:(CBPeripheral *)peripheral; +- (void)removePeripheralsFromCache; @end @@ -379,18 +384,7 @@ - (void)centralManager:(CBCentralManager *)central } if (![self isConnecting]) { - if ([_cachedPeripherals objectForKey:peripheral] == nil) { - ChipLogProgress(Ble, "Storing device %p with discriminator: %d", peripheral, discriminator); - if (_scannerDelegate) { - dispatch_async(_chipWorkQueue, ^{ - ChipBLEDeviceIdentificationInfo info; - memcpy(&info, bytes, sizeof(info)); - _scannerDelegate->OnBleScanResult((__bridge void *) peripheral, info); - }); - } - } - - _cachedPeripherals[peripheral] = serviceData; + [self addPeripheralToCache:peripheral data:serviceData]; } } @@ -542,9 +536,9 @@ - (void)start - (void)stop { [self stopScanning]; - _scannerDelegate = nil; - [_cachedPeripherals removeAllObjects]; + [self removePeripheralsFromCache]; _cachedPeripherals = nil; + _scannerDelegate = nil; if (!_centralManager || !_peripheral) { return; @@ -597,17 +591,16 @@ - (void)connect:(CBPeripheral *)peripheral - (void)updateWithDelegate:(chip::DeviceLayer::BleScannerDelegate *)delegate { - [_cachedPeripherals removeAllObjects]; _scannerDelegate = delegate; _currentMode = (delegate == nullptr) ? kScanningWithoutDelegate : kScanning; if (_currentMode == kScanning) { for (CBPeripheral * cachedPeripheral in _cachedPeripherals) { - NSData * serviceData = _cachedPeripherals[cachedPeripheral]; + NSData * serviceData = _cachedPeripherals[cachedPeripheral][@"data"]; dispatch_async(_chipWorkQueue, ^{ ChipBLEDeviceIdentificationInfo info; memcpy(&info, [serviceData bytes], sizeof(info)); - _scannerDelegate->OnBleScanResult((__bridge void *) cachedPeripheral, info); + _scannerDelegate->OnBleScanAdd((__bridge void *) cachedPeripheral, info); }); } } @@ -623,7 +616,7 @@ - (void)updateWithDiscriminator:(const chip::SetupDiscriminator &)deviceDiscrimi CBPeripheral * peripheral = nil; for (CBPeripheral * cachedPeripheral in _cachedPeripherals) { - NSData * serviceData = _cachedPeripherals[cachedPeripheral]; + NSData * serviceData = _cachedPeripherals[cachedPeripheral][@"data"]; ChipBLEDeviceIdentificationInfo info; memcpy(&info, [serviceData bytes], sizeof(info)); @@ -633,6 +626,8 @@ - (void)updateWithDiscriminator:(const chip::SetupDiscriminator &)deviceDiscrimi } } + [self removePeripheralsFromCache]; + if (peripheral) { ChipLogProgress(Ble, "Connecting to cached device: %p", peripheral); [self connect:peripheral]; @@ -652,6 +647,62 @@ - (void)updateWithPeripheral:(CBPeripheral *)peripheral [self stopScanning]; } +- (void)addPeripheralToCache:(CBPeripheral *)peripheral data:(NSData *)data +{ + dispatch_source_t timeoutTimer; + + if ([_cachedPeripherals objectForKey:peripheral]) { + timeoutTimer = _cachedPeripherals[peripheral][@"timer"]; + } else { + auto delegate = _scannerDelegate; + if (delegate) { + dispatch_async(_chipWorkQueue, ^{ + ChipBLEDeviceIdentificationInfo info; + auto bytes = (const uint8_t *) [data bytes]; + memcpy(&info, bytes, sizeof(info)); + delegate->OnBleScanAdd((__bridge void *) peripheral, info); + }); + } + + timeoutTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _workQueue); + dispatch_source_set_event_handler(timeoutTimer, ^{ + [self removePeripheralFromCache:peripheral]; + }); + dispatch_resume(timeoutTimer); + } + + auto timeout = static_cast(kCachePeripheralTimeoutInSeconds * NSEC_PER_SEC); + dispatch_source_set_timer(timeoutTimer, dispatch_walltime(nullptr, timeout), DISPATCH_TIME_FOREVER, 5 * NSEC_PER_SEC); + + _cachedPeripherals[peripheral] = @{ + @"data" : data, + @"timer" : timeoutTimer, + }; +} + +- (void)removePeripheralFromCache:(CBPeripheral *)peripheral +{ + auto entry = [_cachedPeripherals objectForKey:peripheral]; + if (entry) { + dispatch_source_cancel(entry[@"timer"]); + [_cachedPeripherals removeObjectForKey:peripheral]; + + auto delegate = _scannerDelegate; + if (delegate) { + dispatch_async(_chipWorkQueue, ^{ + delegate->OnBleScanRemove((__bridge void *) peripheral); + }); + } + } +} + +- (void)removePeripheralsFromCache +{ + for (CBPeripheral * peripheral in _cachedPeripherals) { + [self removePeripheralFromCache:peripheral]; + } +} + /** * private static method to copy service and characteristic UUIDs from CBCharacteristic to a pair of ChipBleUUID objects. * this is used in calls into Chip layer to decouple it from CoreBluetooth diff --git a/src/platform/Darwin/BleScannerDelegate.h b/src/platform/Darwin/BleScannerDelegate.h index bfb0c389179648..7759abbb4ba87c 100644 --- a/src/platform/Darwin/BleScannerDelegate.h +++ b/src/platform/Darwin/BleScannerDelegate.h @@ -30,7 +30,10 @@ class DLL_EXPORT BleScannerDelegate virtual ~BleScannerDelegate() {} // Called when a scan result is available. - virtual void OnBleScanResult(BLE_CONNECTION_OBJECT connObj, const Ble::ChipBLEDeviceIdentificationInfo & info) = 0; + virtual void OnBleScanAdd(BLE_CONNECTION_OBJECT connObj, const Ble::ChipBLEDeviceIdentificationInfo & info) = 0; + + // Called when a scan result is not available anymore. + virtual void OnBleScanRemove(BLE_CONNECTION_OBJECT connObj) = 0; }; } // namespace DeviceLayer