Skip to content
Open
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
10 changes: 5 additions & 5 deletions Sources/SwiftBluetooth/CentralManager/CentralManager+async.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import CoreBluetooth

public extension CentralManager {
@available(iOS 13, macOS 10.15, watchOS 6.0, tvOS 13.0, *)
func waitUntilReady() async throws {
func waitUntilReady(timeout: TimeInterval = Double.infinity) async throws {
try await withCheckedThrowingContinuation { cont in
self.waitUntilReady { result in
self.waitUntilReady(timeout: timeout) { result in
cont.resume(with: result)
}
}
Expand Down Expand Up @@ -44,13 +44,13 @@ public extension CentralManager {

// This method doesn't need to be marked async, but it prevents a signature collision
@available(iOS 13, macOS 10.15, watchOS 6.0, tvOS 13.0, *)
func scanForPeripherals(withServices services: [CBUUID]? = nil, timeout: TimeInterval? = nil, options: [String: Any]? = nil) async -> AsyncStream<Peripheral> {
func scanForPeripherals(withServices services: [CBUUID]? = nil, timeout: TimeInterval? = nil, options: [String: Any]? = nil) async -> AsyncStream<PeripheralScanResult> {
.init { cont in
var timer: Timer?
let subscription = eventSubscriptions.queue { event, done in
switch event {
case .discovered(let peripheral, _, _):
cont.yield(peripheral)
case .discovered(let peripheral, let advData, let rssi):
cont.yield(PeripheralScanResult(peripheral: peripheral, advertisementData: advData, rssi: rssi))
case .stopScan:
done()
cont.finish()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import Foundation
import CoreBluetooth

public struct PeripheralScanResult {
public let peripheral: Peripheral
public let advertisementData: [String: Any]
public let rssi: NSNumber
}

public extension CentralManager {
func waitUntilReady(completionHandler: @escaping (Result<Void, Error>) -> Void) {
func waitUntilReady(timeout: TimeInterval = Double.infinity, completionHandler: @escaping (Result<Void, Error>) -> Void) {
eventQueue.async { [self] in
guard state != .poweredOn else {
completionHandler(.success(Void()))
Expand All @@ -18,8 +24,9 @@ public extension CentralManager {
completionHandler(.failure(CentralError.unavailable))
return
}

eventSubscriptions.queue { event, done in

var timer: Timer?
let task = eventSubscriptions.queue { event, done in
guard case .stateUpdated(let state) = event else { return }

switch state {
Expand All @@ -32,9 +39,19 @@ public extension CentralManager {
default:
return
}


timer?.invalidate()
done()
}

if timeout != .infinity {
let timeoutTimer = Timer(fire: Date() + timeout, interval: 0, repeats: false) { _ in
task.cancel()
completionHandler(.failure(CentralError.poweredOff))
}
timer = timeoutTimer
RunLoop.main.add(timeoutTimer, forMode: .default)
}
}
}

Expand Down Expand Up @@ -78,13 +95,13 @@ public extension CentralManager {
}
}

func scanForPeripherals(withServices services: [CBUUID]? = nil, timeout: TimeInterval? = nil, options: [String: Any]? = nil, onPeripheralFound: @escaping (Peripheral) -> Void) -> CancellableTask {
func scanForPeripherals(withServices services: [CBUUID]? = nil, timeout: TimeInterval? = nil, options: [String: Any]? = nil, onPeripheralFound: @escaping (PeripheralScanResult) -> Void) -> CancellableTask {
eventQueue.sync {
var timer: Timer?
let subscription = eventSubscriptions.queue { event, done in
switch event {
case .discovered(let peripheral, _, _):
onPeripheralFound(peripheral)
case .discovered(let peripheral, let advData, let rssi):
onPeripheralFound(PeripheralScanResult(peripheral: peripheral, advertisementData: advData, rssi: rssi))
case .stopScan:
done()
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ public enum CentralError: Error {
case unknown
case unauthorized
case unavailable
case poweredOff
}