Created
March 26, 2021 18:05
-
-
Save michael-martinez/9f129a8bd45193c647b4692f555d13ca to your computer and use it in GitHub Desktop.
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
// MARK: Reading Values | |
private var receiveDetectionEventsTimer: Timer? = nil | |
func receiveDetectionEvents() { | |
let charUuid = wifiUuid | |
print("STEP 1: READING CHARACTERISTIC \(charUuid)...") | |
if manager == nil { | |
manager = CentralManager(options: [CBCentralManagerOptionRestoreIdentifierKey : "CentralMangerKey" as NSString]) | |
} | |
guard let manager = manager else { | |
delegate?.readFailure(error: "Erreur Bluetooth") | |
return | |
} | |
let stateChangeFuture = manager.whenStateChanges() | |
/// Handles state changes and returns a scan future if the bluetooth is powered on | |
let scanFuture = stateChangeFuture.flatMap { state -> FutureStream<Peripheral> in | |
switch state { | |
case .poweredOn: | |
/// Scans for peripherals which have our service | |
print("STEP 2: SCANNING FOR SERVICE \(self.serviceUUID)...") | |
return manager.startScanning(forServiceUUIDs: [self.serviceUUID]) | |
case .poweredOff: | |
throw AppError.poweredOff | |
case .unauthorized, .unsupported: | |
throw AppError.invalidState | |
case .resetting: | |
throw AppError.resetting | |
case .unknown: | |
throw AppError.unknown | |
} | |
} | |
scanFuture.onFailure { error in | |
guard let appError = error as? AppError else { | |
return | |
} | |
switch appError { | |
case .invalidState: | |
break | |
case .resetting: | |
manager.reset() | |
case .poweredOff: | |
break | |
case .unknown: | |
break | |
default: | |
break; | |
} | |
} | |
/// Connects to the first scanned peripheral | |
let connectionFuture = scanFuture.flatMap { p -> FutureStream<Void> in | |
/// Stops the scan when we find the first peripheral | |
manager.stopScanning() | |
self.peripheral = p | |
guard let peripheral = self.peripheral else { | |
throw AppError.unknown | |
} | |
/// Connects to the peripheral to trigger connected mode | |
print("STEP 3: CONNECTING TO PERIPHERAL...") | |
return peripheral.connect(connectionTimeout: 10, capacity: 5) | |
} | |
/// Discovers our service so we can read its characteristics | |
let discoveryFuture = connectionFuture.flatMap { _ -> Future<Void> in | |
guard let peripheral = self.peripheral else { | |
throw AppError.unknown | |
} | |
print("STEP 4: DISCOVERING SERVICES...") | |
return peripheral.discoverServices([self.serviceUUID]) | |
}.flatMap { _ -> Future<Void> in | |
guard let discoveredPeripheral = self.peripheral else { | |
throw AppError.unknown | |
} | |
guard let service = discoveredPeripheral.services(withUUID: self.serviceUUID)?.first else { | |
throw AppError.serviceNotFound | |
} | |
self.peripheral = discoveredPeripheral | |
/// Discovers the specific characteristic | |
print("STEP 5: DISCOVERING CHARACTERISTICS...") | |
return service.discoverCharacteristics([charUuid]) | |
} | |
/// Checks if characteristic is correctly discovered; Registers for notifications with dataFuture variable | |
let dataFuture = discoveryFuture.flatMap { _ -> Future<Void> in | |
print("STEP 5a") | |
guard let discoveredPeripheral = self.peripheral else { | |
throw AppError.unknown | |
} | |
print("STEP 5b") | |
guard let dataCharacteristic1 = discoveredPeripheral.services(withUUID: self.serviceUUID)?.first?.characteristics(withUUID: charUuid)?.first else { | |
throw AppError.dataCharactertisticNotFound | |
} | |
print("STEP 5c") | |
self.dataCharWifi = dataCharacteristic1 | |
self.receiveDetectionEventsTimer?.invalidate() | |
self.receiveDetectionEventsTimer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { timer in | |
print("Step POLLING") | |
self.readData() | |
} | |
/// Asks the characteristic to start notifying when the value is changed | |
print("STEP 5d") | |
return dataCharacteristic1.startNotifying() | |
}.flatMap { _ -> FutureStream<Data?> in | |
print("STEP 6") | |
guard let discoveredPeripheral = self.peripheral else { | |
throw AppError.unknown | |
} | |
guard let characteristic = discoveredPeripheral.services(withUUID: self.serviceUUID)?.first?.characteristics(withUUID: charUuid)?.first else { | |
throw AppError.dataCharactertisticNotFound | |
} | |
/// Registers to receive notification when characteristic value changes; returns future to handle notification | |
return characteristic.receiveNotificationUpdates(capacity: 10) | |
} | |
/// onSuccess called every time the characteristic value changes | |
dataFuture.onSuccess { data in | |
print("STEP 6: called every time the characteristic value changes") | |
DispatchQueue.main.async { | |
self.delegate?.readSuccess(characteristicType: .wifi, data: data) | |
} | |
} | |
dataFuture.onFailure { error in | |
print("Step RCK: FAILURE \(error)") | |
switch error { | |
case PeripheralError.disconnected, PeripheralError.connectionTimeout: | |
self.receiveDetectionEventsTimer?.invalidate() | |
self.receiveDetectionEventsTimer = nil | |
self.peripheral?.terminate() | |
self.delegate?.readFailure(error: "Erreur : \(error)") | |
/*DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 10) { | |
self.peripheral?.reconnect() | |
}*/ | |
case AppError.serviceNotFound: | |
break | |
case AppError.dataCharactertisticNotFound: | |
break | |
default: | |
break | |
} | |
} | |
} | |
private func readData() { | |
var readFuture: Future<Void>? | |
readFuture = self.dataCharWifi?.read(timeout: TimeInterval.infinity) | |
readFuture?.onSuccess { (_) in | |
DispatchQueue.main.async { | |
if let data = self.dataCharWifi?.dataValue { | |
do { | |
let wifiData = try Com_Org_Protocol_WifiSettings.init(serializedData: data) | |
self.delegate?.readSuccess(characteristicType: characteristicType, data: wifiData) | |
} catch { | |
self.delegate?.readFailure(error: "Erreur de désérialisation des données pour le wifi") | |
} | |
} else { | |
self.delegate?.readFailure(error: "Erreur de désérialisation des données pour le wifi") | |
} | |
} | |
} | |
readFuture?.onFailure { (e) in | |
print("STEP: onFailure TWO") | |
self.delegate?.readFailure(error: "Erreur : \(e.localizedDescription)") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment