-
-
Save liuzhida33/281ab1a3e7ee6aca4aa837fb1ae55a43 to your computer and use it in GitHub Desktop.
Sample RxBluetoothKit implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
import CoreBluetooth | |
import RxSwift | |
import RxBluetoothKit | |
extension CBUUID { | |
var type: UUID { | |
return UUID(rawValue: uuidString)! | |
} | |
enum UUID: String { | |
case main = "3749FA00-4CED-524B-33D5-F00FD858C4F2" | |
case info = "3749FA01-4CED-524B-33D5-F00FD858C4F2" | |
case alert = "3749FA05-4CED-524B-33D5-F00FD858C4F2" | |
var cbuuid: CBUUID { return CBUUID(string: self.rawValue) } | |
} | |
static func common(_ type: UUID) -> CBUUID { | |
return type.cbuuid | |
} | |
} | |
extension ObservableType { | |
func unwrap() -> Observable<E> { | |
return flatMap { $0 == nil ? Observable.empty() : Observable.just($0!) } | |
} | |
} | |
extension ObservableType { | |
public func retryWithDelay(_ timeInterval: RxTimeInterval, maxAttempts: Int? = nil) | |
-> Observable<E> { | |
return retryWhen { (errors: Observable<Error>) in | |
return errors.flatMapWithIndex { (error, attempt) -> Observable<Int64> in | |
if let maxAttempts = maxAttempts, attempt >= maxAttempts - 1 { | |
return Observable.error(error) | |
} | |
return Observable<Int64>.timer(timeInterval, scheduler: MainScheduler.instance) | |
} | |
} | |
} | |
} | |
class Device { | |
let measure = PublishSubject<Data>() | |
let alert = PublishSubject<Data>() | |
private let disposeBag = DisposeBag() | |
init(name: String) { | |
let manager = BluetoothManager(queue: .main) | |
let queue = DispatchQueue(label: "fr.xdev.rxbluetoothkit.bluetooth") | |
let scheduler = SerialDispatchQueueScheduler(queue: queue, internalSerialQueueName: "") | |
let characteristics = manager.rx_state | |
.filter { $0 == .poweredOn } | |
.take(1) | |
.flatMap { _ in manager.scanForPeripherals(withServices: [.common(.main)]) } // scan | |
.filter { $0.peripheral.name == name } | |
.take(1) | |
.flatMap { $0.peripheral.connect() } | |
.flatMap { $0.discoverServices([.common(.main)]) } // extension on CBUUID to matching enum | |
.flatMap { Observable.from($0) } | |
.flatMap { $0.discoverCharacteristics([.common(.measure), .common(.protection)]) } // extension on CBUUID to matching enum | |
.flatMap { Observable.from($0) } | |
characteristics | |
.filter { $0.uuid.type == .measure } // extension on CBUUID to matching enum | |
.flatMap { $0.setNotificationAndMonitorUpdates() } | |
.map { $0.value } | |
.unwrap() // ignore nil value | |
.retryWithDelay(5) // !!!: retry and resubscribe to the full chain on error | |
.subscribe(onNext: { [unowned self] data in | |
self.measure.onNext(data!) | |
}) | |
.disposed(by: disposeBag) | |
characteristics | |
.filter { $0.uuid.type == .alert } // extension on CBUUID to matching enum | |
.flatMap { $0.setNotificationAndMonitorUpdates() } | |
.map { $0.value } | |
.unwrap() // ignore nil value | |
.retryWithDelay(5) // !!!: retry and resubscribe to the full chain on error | |
.subscribe(onNext: { [unowned self] data in | |
self.alert.onNext(data!) | |
}) | |
.disposed(by: disposeBag) | |
} | |
} | |
class ViewController: UIViewController { | |
let disposeBag = DisposeBag() | |
let device = Device(name: "Device-XXX") | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
device.measure | |
.subscribeOn(MainScheduler.instance) | |
.subscribe(onNext: { data in | |
print("measure:", [UInt8](data)) | |
}) | |
.disposed(by: disposeBag) | |
device.alert | |
.subscribeOn(MainScheduler.instance) | |
.subscribe(onNext: { data in | |
print("alert:", [UInt8](data)) | |
}) | |
.disposed(by: disposeBag) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment