troystribling / BlueCap

iOS Bluetooth LE framework
MIT License
715 stars 115 forks source link

BLE Central Manager doesn't timeout scan after successful connection #85

Open romansavrulin opened 5 years ago

romansavrulin commented 5 years ago

Bluecap from Carthage, version 0.7.0.

The following simple code

let discoveryFuture = manager.startScanning(forServiceUUIDs: [CBUUID(string:uuid)], timeout:5.0).flatMap { peripheral -> FutureStream<Void> in
                log.info("scanFuture: Found peripheral UUID: \(peripheral.identifier.uuidString). Trying to connect")
                self.manager.stopScanning()
                self.peripheral = peripheral

                return peripheral.connect(connectionTimeout: 5, capacity: 5)
            }

will successfully timeout scan for not available service for the first time. But if I will scan for the service that is available and connect to the device, the second scan attempt for unavailable service will never timeout.

Is it a Bluecap or Core Bluetooth issue?

troystribling commented 5 years ago

That is the way it is implemented. You can stop the scan anytime after you connect.

romansavrulin commented 5 years ago

@troystribling But the scan is stopped right after discovery. Why the second scan attempt doesn't employ timeout?

romansavrulin commented 5 years ago

@troystribling Quick follow-up sequence

  1. disable the peripheral you are trying to discover
  2. start scanning for it with timeout
  3. you will get timeout as expected
  4. enable the peripheral you are trying to discover
  5. start scanning for it with timeout
  6. you will successfully connect and stop scanning in the future
  7. disconnect
  8. disable the peripheral you are trying to discover
  9. start scanning for it with timeout
  10. you won't get timeout for that discovery attempt

Am I missing something?

troystribling commented 5 years ago

Did not follow. That sounds like a bug. Start looking here. https://github.com/troystribling/BlueCap/blob/master/BlueCapKit/Central/CentralManager.swift#L212. The code is not that complicated. I do not have the time available now to look into this but will be will ing to accept a PR.

romansavrulin commented 5 years ago

@troystribling Ok, thank you. Will dive into this, once we will be working on new maintenance release of our App

romansavrulin commented 5 years ago

Quick try to fix the timeout inside the library wasn't successful, so I've worked-around this by the following code

 func startDiscovery(uuid:String){

     scanTimeoutTimer = Timer.scheduledTimer(withTimeInterval: 10.0, repeats: false) { _ in
            log.info("Scan timeout has passed")
            if self.manager.isScanning {
                self.manager.stopScanning()
                //trigger timeout event here
            }
            self.scanTimeoutTimer?.invalidate()
        }

        let discoveryFuture = manager.startScanning(forServiceUUIDs: [CBUUID(string:uuid)]).flatMap { peripheral -> FutureStream<Void> in
                log.info("scanFuture: Found peripheral UUID: \(peripheral.identifier.uuidString). Trying to connect")
                self.manager.stopScanning()
                self.scanTimeoutTimer?.invalidate()
                return peripheral.connect(connectionTimeout: 10, capacity: 1)
            }
}