diff --git a/.vscode/settings.json b/.vscode/settings.json index 9d2857f..3e5a36d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,18 +1,31 @@ { "cSpell.words": [ + "BTLE", + "bytevc", "connnection", "DSIMPLEBLE", + "hresult", + "hstring", + "HWND", "Inspectable", + "LPARAM", + "LRESULT", "microtask", "modalias", + "navideck", "NSUUID", + "NTDDI", "pairable", "rssi", "simpleble", "unawaited", + "UNIVERSALBLE", "Unpair", + "Unpairing", "unwatch", - "uuidstr" + "uuidstr", + "winrt", + "WPARAM" ], "cmake.configureOnOpen": false, "files.associations": { diff --git a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt index 877506c..0def244 100644 --- a/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt +++ b/android/src/main/kotlin/com/navideck/universal_ble/UniversalBle.g.kt @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v13.0.0), do not edit directly. +// Autogenerated from Pigeon (v16.0.5), do not edit directly. // See also: https://pub.dev/packages/pigeon package com.navideck.universal_ble @@ -31,6 +31,9 @@ private fun wrapError(exception: Throwable): List { } } +private fun createConnectionError(channelName: String): FlutterError { + return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "")} + /** * Error class for passing custom error details to Flutter via a thrown PlatformException. * @property code The error code. @@ -525,73 +528,83 @@ class UniversalBleCallbackChannel(private val binaryMessenger: BinaryMessenger) UniversalBleCallbackChannelCodec } } - fun onAvailabilityChanged(stateArg: Long, callback: (Result) -> Unit) { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged", codec) + fun onAvailabilityChanged(stateArg: Long, callback: (Result) -> Unit) +{ + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) channel.send(listOf(stateArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))); + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { - callback(Result.success(Unit)); + callback(Result.success(Unit)) } } else { - callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", ""))); + callback(Result.failure(createConnectionError(channelName))) } } } - fun onPairStateChange(deviceIdArg: String, isPairedArg: Boolean, errorArg: String?, callback: (Result) -> Unit) { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange", codec) + fun onPairStateChange(deviceIdArg: String, isPairedArg: Boolean, errorArg: String?, callback: (Result) -> Unit) +{ + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) channel.send(listOf(deviceIdArg, isPairedArg, errorArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))); + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { - callback(Result.success(Unit)); + callback(Result.success(Unit)) } } else { - callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", ""))); + callback(Result.failure(createConnectionError(channelName))) } } } - fun onScanResult(resultArg: UniversalBleScanResult, callback: (Result) -> Unit) { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult", codec) + fun onScanResult(resultArg: UniversalBleScanResult, callback: (Result) -> Unit) +{ + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) channel.send(listOf(resultArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))); + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { - callback(Result.success(Unit)); + callback(Result.success(Unit)) } } else { - callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", ""))); + callback(Result.failure(createConnectionError(channelName))) } } } - fun onValueChanged(deviceIdArg: String, characteristicIdArg: String, valueArg: ByteArray, callback: (Result) -> Unit) { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged", codec) + fun onValueChanged(deviceIdArg: String, characteristicIdArg: String, valueArg: ByteArray, callback: (Result) -> Unit) +{ + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) channel.send(listOf(deviceIdArg, characteristicIdArg, valueArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))); + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { - callback(Result.success(Unit)); + callback(Result.success(Unit)) } } else { - callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", ""))); + callback(Result.failure(createConnectionError(channelName))) } } } - fun onConnectionChanged(deviceIdArg: String, stateArg: Long, callback: (Result) -> Unit) { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged", codec) + fun onConnectionChanged(deviceIdArg: String, stateArg: Long, callback: (Result) -> Unit) +{ + val channelName = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) channel.send(listOf(deviceIdArg, stateArg)) { if (it is List<*>) { if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))); + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) } else { - callback(Result.success(Unit)); + callback(Result.success(Unit)) } } else { - callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", ""))); + callback(Result.failure(createConnectionError(channelName))) } } } diff --git a/darwin/Classes/UniversalBle.g.swift b/darwin/Classes/UniversalBle.g.swift index e005102..b1a7151 100644 --- a/darwin/Classes/UniversalBle.g.swift +++ b/darwin/Classes/UniversalBle.g.swift @@ -1,18 +1,15 @@ -// Autogenerated from Pigeon (v13.0.0), do not edit directly. +// Autogenerated from Pigeon (v16.0.5), do not edit directly. // See also: https://pub.dev/packages/pigeon import Foundation -#if os(iOS) -import Flutter -#elseif os(macOS) -import FlutterMacOS -#else -#error("Unsupported platform.") -#endif -private func isNullish(_ value: Any?) -> Bool { - return value is NSNull || value == nil -} +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#else + #error("Unsupported platform.") +#endif private func wrapResult(_ result: Any?) -> [Any?] { return [result] @@ -23,16 +20,24 @@ private func wrapError(_ error: Any) -> [Any?] { return [ flutterError.code, flutterError.message, - flutterError.details + flutterError.details, ] } return [ "\(error)", "\(type(of: error))", - "Stacktrace: \(Thread.callStackSymbols)" + "Stacktrace: \(Thread.callStackSymbols)", ] } +private func createConnectionError(withChannelName channelName: String) -> FlutterError { + return FlutterError(code: "channel-error", message: "Unable to establish connection on channel: '\(channelName)'.", details: "") +} + +private func isNullish(_ value: Any?) -> Bool { + return value is NSNull || value == nil +} + private func nilOrValue(_ value: Any?) -> T? { if value is NSNull { return nil } return value as! T? @@ -123,14 +128,14 @@ struct UniversalBleCharacteristic { private class UniversalBlePlatformChannelCodecReader: FlutterStandardReader { override func readValue(ofType type: UInt8) -> Any? { switch type { - case 128: - return UniversalBleCharacteristic.fromList(self.readValue() as! [Any?]) - case 129: - return UniversalBleScanResult.fromList(self.readValue() as! [Any?]) - case 130: - return UniversalBleService.fromList(self.readValue() as! [Any?]) - default: - return super.readValue(ofType: type) + case 128: + return UniversalBleCharacteristic.fromList(self.readValue() as! [Any?]) + case 129: + return UniversalBleScanResult.fromList(self.readValue() as! [Any?]) + case 130: + return UniversalBleService.fromList(self.readValue() as! [Any?]) + default: + return super.readValue(ofType: type) } } } @@ -196,12 +201,12 @@ class UniversalBlePlatformChannelSetup { let getBluetoothAvailabilityStateChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState", binaryMessenger: binaryMessenger, codec: codec) if let api = api { getBluetoothAvailabilityStateChannel.setMessageHandler { _, reply in - api.getBluetoothAvailabilityState() { result in + api.getBluetoothAvailabilityState { result in switch result { - case .success(let res): - reply(wrapResult(res)) - case .failure(let error): - reply(wrapError(error)) + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) } } } @@ -211,12 +216,12 @@ class UniversalBlePlatformChannelSetup { let enableBluetoothChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth", binaryMessenger: binaryMessenger, codec: codec) if let api = api { enableBluetoothChannel.setMessageHandler { _, reply in - api.enableBluetooth() { result in + api.enableBluetooth { result in switch result { - case .success(let res): - reply(wrapResult(res)) - case .failure(let error): - reply(wrapError(error)) + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) } } } @@ -304,10 +309,10 @@ class UniversalBlePlatformChannelSetup { let deviceIdArg = args[0] as! String api.discoverServices(deviceId: deviceIdArg) { result in switch result { - case .success(let res): - reply(wrapResult(res)) - case .failure(let error): - reply(wrapError(error)) + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) } } } @@ -323,10 +328,10 @@ class UniversalBlePlatformChannelSetup { let characteristicArg = args[2] as! String api.readValue(deviceId: deviceIdArg, service: serviceArg, characteristic: characteristicArg) { result in switch result { - case .success(let res): - reply(wrapResult(res)) - case .failure(let error): - reply(wrapError(error)) + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) } } } @@ -341,10 +346,10 @@ class UniversalBlePlatformChannelSetup { let expectedMtuArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) api.requestMtu(deviceId: deviceIdArg, expectedMtu: expectedMtuArg) { result in switch result { - case .success(let res): - reply(wrapResult(res)) - case .failure(let error): - reply(wrapError(error)) + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) } } } @@ -362,10 +367,10 @@ class UniversalBlePlatformChannelSetup { let bleOutputPropertyArg = args[4] is Int64 ? args[4] as! Int64 : Int64(args[4] as! Int32) api.writeValue(deviceId: deviceIdArg, service: serviceArg, characteristic: characteristicArg, value: valueArg, bleOutputProperty: bleOutputPropertyArg) { result in switch result { - case .success: - reply(wrapResult(nil)) - case .failure(let error): - reply(wrapError(error)) + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) } } } @@ -379,10 +384,10 @@ class UniversalBlePlatformChannelSetup { let deviceIdArg = args[0] as! String api.isPaired(deviceId: deviceIdArg) { result in switch result { - case .success(let res): - reply(wrapResult(res)) - case .failure(let error): - reply(wrapError(error)) + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) } } } @@ -426,10 +431,10 @@ class UniversalBlePlatformChannelSetup { let withServicesArg = args[0] as! [String] api.getConnectedDevices(withServices: withServicesArg) { result in switch result { - case .success(let res): - reply(wrapResult(res)) - case .failure(let error): - reply(wrapError(error)) + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) } } } @@ -441,10 +446,10 @@ class UniversalBlePlatformChannelSetup { private class UniversalBleCallbackChannelCodecReader: FlutterStandardReader { override func readValue(ofType type: UInt8) -> Any? { switch type { - case 128: - return UniversalBleScanResult.fromList(self.readValue() as! [Any?]) - default: - return super.readValue(ofType: type) + case 128: + return UniversalBleScanResult.fromList(self.readValue() as! [Any?]) + default: + return super.readValue(ofType: type) } } } @@ -478,48 +483,108 @@ class UniversalBleCallbackChannelCodec: FlutterStandardMessageCodec { /// /// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift. protocol UniversalBleCallbackChannelProtocol { - func onAvailabilityChanged(state stateArg: Int64, completion: @escaping (Result) -> Void) - func onPairStateChange(deviceId deviceIdArg: String, isPaired isPairedArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) - func onScanResult(result resultArg: UniversalBleScanResult, completion: @escaping (Result) -> Void) - func onValueChanged(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, value valueArg: FlutterStandardTypedData, completion: @escaping (Result) -> Void) - func onConnectionChanged(deviceId deviceIdArg: String, state stateArg: Int64, completion: @escaping (Result) -> Void) + func onAvailabilityChanged(state stateArg: Int64, completion: @escaping (Result) -> Void) + func onPairStateChange(deviceId deviceIdArg: String, isPaired isPairedArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) + func onScanResult(result resultArg: UniversalBleScanResult, completion: @escaping (Result) -> Void) + func onValueChanged(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, value valueArg: FlutterStandardTypedData, completion: @escaping (Result) -> Void) + func onConnectionChanged(deviceId deviceIdArg: String, state stateArg: Int64, completion: @escaping (Result) -> Void) } class UniversalBleCallbackChannel: UniversalBleCallbackChannelProtocol { private let binaryMessenger: FlutterBinaryMessenger - init(binaryMessenger: FlutterBinaryMessenger){ + init(binaryMessenger: FlutterBinaryMessenger) { self.binaryMessenger = binaryMessenger } var codec: FlutterStandardMessageCodec { return UniversalBleCallbackChannelCodec.shared } - func onAvailabilityChanged(state stateArg: Int64, completion: @escaping (Result) -> Void) { - let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged", binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([stateArg] as [Any?]) { _ in - completion(.success(Void())) + func onAvailabilityChanged(state stateArg: Int64, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([stateArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(FlutterError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } } } - func onPairStateChange(deviceId deviceIdArg: String, isPaired isPairedArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) { - let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange", binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([deviceIdArg, isPairedArg, errorArg] as [Any?]) { _ in - completion(.success(Void())) + func onPairStateChange(deviceId deviceIdArg: String, isPaired isPairedArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, isPairedArg, errorArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(FlutterError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } } } - func onScanResult(result resultArg: UniversalBleScanResult, completion: @escaping (Result) -> Void) { - let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult", binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([resultArg] as [Any?]) { _ in - completion(.success(Void())) + func onScanResult(result resultArg: UniversalBleScanResult, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([resultArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(FlutterError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } } } - func onValueChanged(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, value valueArg: FlutterStandardTypedData, completion: @escaping (Result) -> Void) { - let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged", binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([deviceIdArg, characteristicIdArg, valueArg] as [Any?]) { _ in - completion(.success(Void())) + func onValueChanged(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, value valueArg: FlutterStandardTypedData, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, characteristicIdArg, valueArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(FlutterError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } } } - func onConnectionChanged(deviceId deviceIdArg: String, state stateArg: Int64, completion: @escaping (Result) -> Void) { - let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged", binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([deviceIdArg, stateArg] as [Any?]) { _ in - completion(.success(Void())) + func onConnectionChanged(deviceId deviceIdArg: String, state stateArg: Int64, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([deviceIdArg, stateArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(FlutterError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } } } } diff --git a/example/pubspec.lock b/example/pubspec.lock index 2489f2a..5499614 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -386,7 +386,7 @@ packages: path: ".." relative: true source: path - version: "0.8.3" + version: "0.8.4" vector_math: dependency: transitive description: diff --git a/lib/src/universal_ble_pigeon/universal_ble.g.dart b/lib/src/universal_ble_pigeon/universal_ble.g.dart index c72a268..1891d79 100644 --- a/lib/src/universal_ble_pigeon/universal_ble.g.dart +++ b/lib/src/universal_ble_pigeon/universal_ble.g.dart @@ -1,12 +1,20 @@ -// Autogenerated from Pigeon (v13.0.0), do not edit directly. +// Autogenerated from Pigeon (v16.0.5), do not edit directly. // See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers import 'dart:async'; import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; import 'package:flutter/services.dart'; + +PlatformException _createConnectionError(String channelName) { + return PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); +} + List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { if (empty) { return []; @@ -154,81 +162,81 @@ class UniversalBlePlatformChannel { /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. UniversalBlePlatformChannel({BinaryMessenger? binaryMessenger}) - : _binaryMessenger = binaryMessenger; - final BinaryMessenger? _binaryMessenger; + : __pigeon_binaryMessenger = binaryMessenger; + final BinaryMessenger? __pigeon_binaryMessenger; - static const MessageCodec codec = _UniversalBlePlatformChannelCodec(); + static const MessageCodec pigeonChannelCodec = _UniversalBlePlatformChannelCodec(); Future getBluetoothAvailabilityState() async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; - if (replyList == null) { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getBluetoothAvailabilityState'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send(null) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { + } else if (__pigeon_replyList[0] == null) { throw PlatformException( code: 'null-error', message: 'Host platform returned null value for non-null return value.', ); } else { - return (replyList[0] as int?)!; + return (__pigeon_replyList[0] as int?)!; } } Future enableBluetooth() async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; - if (replyList == null) { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.enableBluetooth'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send(null) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { + } else if (__pigeon_replyList[0] == null) { throw PlatformException( code: 'null-error', message: 'Host platform returned null value for non-null return value.', ); } else { - return (replyList[0] as bool?)!; + return (__pigeon_replyList[0] as bool?)!; } } Future startScan() async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; - if (replyList == null) { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.startScan'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send(null) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); } else { return; @@ -236,291 +244,291 @@ class UniversalBlePlatformChannel { } Future stopScan() async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send(null) as List?; - if (replyList == null) { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.stopScan'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send(null) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); } else { return; } } - Future connect(String arg_deviceId) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_deviceId]) as List?; - if (replyList == null) { + Future connect(String deviceId) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.connect'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([deviceId]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); } else { return; } } - Future disconnect(String arg_deviceId) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_deviceId]) as List?; - if (replyList == null) { + Future disconnect(String deviceId) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.disconnect'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([deviceId]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); } else { return; } } - Future setNotifiable(String arg_deviceId, String arg_service, String arg_characteristic, int arg_bleInputProperty) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_deviceId, arg_service, arg_characteristic, arg_bleInputProperty]) as List?; - if (replyList == null) { + Future setNotifiable(String deviceId, String service, String characteristic, int bleInputProperty) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setNotifiable'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([deviceId, service, characteristic, bleInputProperty]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); } else { return; } } - Future> discoverServices(String arg_deviceId) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_deviceId]) as List?; - if (replyList == null) { + Future> discoverServices(String deviceId) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.discoverServices'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([deviceId]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { + } else if (__pigeon_replyList[0] == null) { throw PlatformException( code: 'null-error', message: 'Host platform returned null value for non-null return value.', ); } else { - return (replyList[0] as List?)!.cast(); + return (__pigeon_replyList[0] as List?)!.cast(); } } - Future readValue(String arg_deviceId, String arg_service, String arg_characteristic) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_deviceId, arg_service, arg_characteristic]) as List?; - if (replyList == null) { + Future readValue(String deviceId, String service, String characteristic) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readValue'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([deviceId, service, characteristic]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { + } else if (__pigeon_replyList[0] == null) { throw PlatformException( code: 'null-error', message: 'Host platform returned null value for non-null return value.', ); } else { - return (replyList[0] as Uint8List?)!; + return (__pigeon_replyList[0] as Uint8List?)!; } } - Future requestMtu(String arg_deviceId, int arg_expectedMtu) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_deviceId, arg_expectedMtu]) as List?; - if (replyList == null) { + Future requestMtu(String deviceId, int expectedMtu) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.requestMtu'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([deviceId, expectedMtu]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { + } else if (__pigeon_replyList[0] == null) { throw PlatformException( code: 'null-error', message: 'Host platform returned null value for non-null return value.', ); } else { - return (replyList[0] as int?)!; + return (__pigeon_replyList[0] as int?)!; } } - Future writeValue(String arg_deviceId, String arg_service, String arg_characteristic, Uint8List arg_value, int arg_bleOutputProperty) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_deviceId, arg_service, arg_characteristic, arg_value, arg_bleOutputProperty]) as List?; - if (replyList == null) { + Future writeValue(String deviceId, String service, String characteristic, Uint8List value, int bleOutputProperty) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.writeValue'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([deviceId, service, characteristic, value, bleOutputProperty]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); } else { return; } } - Future isPaired(String arg_deviceId) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_deviceId]) as List?; - if (replyList == null) { + Future isPaired(String deviceId) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.isPaired'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([deviceId]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { + } else if (__pigeon_replyList[0] == null) { throw PlatformException( code: 'null-error', message: 'Host platform returned null value for non-null return value.', ); } else { - return (replyList[0] as bool?)!; + return (__pigeon_replyList[0] as bool?)!; } } - Future pair(String arg_deviceId) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_deviceId]) as List?; - if (replyList == null) { + Future pair(String deviceId) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.pair'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([deviceId]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); } else { return; } } - Future unPair(String arg_deviceId) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_deviceId]) as List?; - if (replyList == null) { + Future unPair(String deviceId) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.unPair'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([deviceId]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); } else { return; } } - Future> getConnectedDevices(List arg_withServices) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectedDevices', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = - await channel.send([arg_withServices]) as List?; - if (replyList == null) { + Future> getConnectedDevices(List withServices) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.getConnectedDevices'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([withServices]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else if (replyList[0] == null) { + } else if (__pigeon_replyList[0] == null) { throw PlatformException( code: 'null-error', message: 'Host platform returned null value for non-null return value.', ); } else { - return (replyList[0] as List?)!.cast(); + return (__pigeon_replyList[0] as List?)!.cast(); } } } @@ -550,7 +558,7 @@ class _UniversalBleCallbackChannelCodec extends StandardMessageCodec { /// Native -> Flutter abstract class UniversalBleCallbackChannel { - static const MessageCodec codec = _UniversalBleCallbackChannelCodec(); + static const MessageCodec pigeonChannelCodec = _UniversalBleCallbackChannelCodec(); void onAvailabilityChanged(int state); @@ -564,13 +572,13 @@ abstract class UniversalBleCallbackChannel { static void setup(UniversalBleCallbackChannel? api, {BinaryMessenger? binaryMessenger}) { { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged', codec, + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - channel.setMessageHandler(null); + __pigeon_channel.setMessageHandler(null); } else { - channel.setMessageHandler((Object? message) async { + __pigeon_channel.setMessageHandler((Object? message) async { assert(message != null, 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged was null.'); final List args = (message as List?)!; @@ -589,13 +597,13 @@ abstract class UniversalBleCallbackChannel { } } { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange', codec, + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - channel.setMessageHandler(null); + __pigeon_channel.setMessageHandler(null); } else { - channel.setMessageHandler((Object? message) async { + __pigeon_channel.setMessageHandler((Object? message) async { assert(message != null, 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange was null.'); final List args = (message as List?)!; @@ -618,13 +626,13 @@ abstract class UniversalBleCallbackChannel { } } { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult', codec, + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - channel.setMessageHandler(null); + __pigeon_channel.setMessageHandler(null); } else { - channel.setMessageHandler((Object? message) async { + __pigeon_channel.setMessageHandler((Object? message) async { assert(message != null, 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult was null.'); final List args = (message as List?)!; @@ -643,13 +651,13 @@ abstract class UniversalBleCallbackChannel { } } { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged', codec, + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - channel.setMessageHandler(null); + __pigeon_channel.setMessageHandler(null); } else { - channel.setMessageHandler((Object? message) async { + __pigeon_channel.setMessageHandler((Object? message) async { assert(message != null, 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged was null.'); final List args = (message as List?)!; @@ -674,13 +682,13 @@ abstract class UniversalBleCallbackChannel { } } { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged', codec, + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + 'dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - channel.setMessageHandler(null); + __pigeon_channel.setMessageHandler(null); } else { - channel.setMessageHandler((Object? message) async { + __pigeon_channel.setMessageHandler((Object? message) async { assert(message != null, 'Argument for dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged was null.'); final List args = (message as List?)!; diff --git a/pigeon/universal_ble.dart b/pigeon/universal_ble.dart index 731a253..6abee3d 100644 --- a/pigeon/universal_ble.dart +++ b/pigeon/universal_ble.dart @@ -12,8 +12,8 @@ import 'package:pigeon/pigeon.dart'; kotlinOptions: KotlinOptions(package: 'com.navideck.universal_ble'), swiftOptions: SwiftOptions(), cppOptions: CppOptions(namespace: 'universal_ble'), - cppHeaderOut: 'windows/UniversalBle.g.h', - cppSourceOut: 'windows/UniversalBle.g.cpp', + cppHeaderOut: 'windows/src/generated/universal_ble.g.h', + cppSourceOut: 'windows/src/generated/universal_ble.g.cpp', debugGenerators: true, ), ) diff --git a/pubspec.yaml b/pubspec.yaml index b934e8f..8bde286 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,7 +12,7 @@ platforms: macos: web: windows: - + environment: sdk: ">=3.1.3 <4.0.0" flutter: ">=3.3.0" @@ -30,7 +30,7 @@ dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 - pigeon: ^13.0.0 + pigeon: ^16.0.5 flutter: plugin: @@ -46,5 +46,3 @@ flutter: sharedDarwinSource: true windows: pluginClass: UniversalBlePluginCApi - - diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index 3979c5b..f78fba8 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -6,7 +6,7 @@ include(FetchContent) set(CPPWINRT_VERSION "2.0.220418.1") set(PLUGIN_NAME "universal_ble_plugin") -################ NuGet intall begin ################ +# ############### NuGet intall begin ################ FetchContent_Declare(nuget URL "https://dist.nuget.org/win-x86-commandline/v6.0.0/nuget.exe" URL_HASH SHA256=04eb6c4fe4213907e2773e1be1bbbd730e9a655a3c9c58387ce8d4a714a5b9e1 @@ -14,31 +14,33 @@ FetchContent_Declare(nuget ) find_program(NUGET nuget) -if (NOT NUGET) - message("Nuget.exe not found, trying to download or use cached version.") - FetchContent_MakeAvailable(nuget) - set(NUGET ${nuget_SOURCE_DIR}/nuget.exe) + +if(NOT NUGET) + message("Nuget.exe not found, trying to download or use cached version.") + FetchContent_MakeAvailable(nuget) + set(NUGET ${nuget_SOURCE_DIR}/nuget.exe) endif() execute_process(COMMAND - ${NUGET} install "Microsoft.Windows.CppWinRT" -Version ${CPPWINRT_VERSION} -OutputDirectory packages - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE ret) -if (NOT ret EQUAL 0) - message(FATAL_ERROR "Failed to install nuget package Microsoft.Windows.CppWinRT.${CPPWINRT_VERSION}") + ${NUGET} install "Microsoft.Windows.CppWinRT" -Version ${CPPWINRT_VERSION} -OutputDirectory packages + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE ret) + +if(NOT ret EQUAL 0) + message(FATAL_ERROR "Failed to install nuget package Microsoft.Windows.CppWinRT.${CPPWINRT_VERSION}") endif() -################ NuGet install end ################ - - +# ############### NuGet install end ################ list(APPEND PLUGIN_SOURCES - "universal_ble_plugin.cpp" - "universal_ble_plugin.h" - "universal_enum.h" - "Utils.cpp" - "Utils.h" - "UniversalBle.g.cpp" - "UniversalBle.g.h" + "src/universal_ble_plugin.cpp" + "src/universal_ble_plugin.h" + "src/helper/universal_enum.h" + "src/helper/universal_ble_base.h" + "src/helper/utils.cpp" + "src/helper/utils.h" + "src/ui_thread_handler.hpp" + "src/generated/universal_ble.g.cpp" + "src/generated/universal_ble.g.h" ) add_library(${PLUGIN_NAME} SHARED @@ -47,11 +49,9 @@ add_library(${PLUGIN_NAME} SHARED ${PLUGIN_SOURCES} ) - apply_standard_settings(${PLUGIN_NAME}) - -################ NuGet import begin ################ +# ############### NuGet import begin ################ set_target_properties(${PLUGIN_NAME} PROPERTIES VS_PROJECT_IMPORT ${CMAKE_BINARY_DIR}/packages/Microsoft.Windows.CppWinRT.${CPPWINRT_VERSION}/build/native/Microsoft.Windows.CppWinRT.props ) @@ -59,8 +59,8 @@ set_target_properties(${PLUGIN_NAME} PROPERTIES VS_PROJECT_IMPORT target_link_libraries(${PLUGIN_NAME} PRIVATE ${CMAKE_BINARY_DIR}/packages/Microsoft.Windows.CppWinRT.${CPPWINRT_VERSION}/build/native/Microsoft.Windows.CppWinRT.targets ) -################ NuGet import end ################ +# ############### NuGet import end ################ set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) @@ -69,7 +69,6 @@ target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) - set(universal_ble_bundled_libraries "" PARENT_SCOPE diff --git a/windows/UniversalBle.g.cpp b/windows/src/generated/universal_ble.g.cpp similarity index 92% rename from windows/UniversalBle.g.cpp rename to windows/src/generated/universal_ble.g.cpp index 4eae7b1..84f04eb 100644 --- a/windows/UniversalBle.g.cpp +++ b/windows/src/generated/universal_ble.g.cpp @@ -1,9 +1,9 @@ -// Autogenerated from Pigeon (v13.0.0), do not edit directly. +// Autogenerated from Pigeon (v16.0.5), do not edit directly. // See also: https://pub.dev/packages/pigeon #undef _HAS_EXCEPTIONS -#include "UniversalBle.g.h" +#include "universal_ble.g.h" #include #include @@ -21,6 +21,13 @@ using flutter::EncodableList; using flutter::EncodableMap; using flutter::EncodableValue; +FlutterError CreateConnectionError(const std::string channel_name) { + return FlutterError( + "channel-error", + "Unable to establish connection on channel: '" + channel_name + "'.", + EncodableValue("")); +} + // UniversalBleScanResult UniversalBleScanResult::UniversalBleScanResult(const std::string& device_id) @@ -811,22 +818,23 @@ void UniversalBleCallbackChannel::OnAvailabilityChanged( int64_t state_arg, std::function&& on_success, std::function&& on_error) { - auto channel = std::make_unique>(binary_messenger_, "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged", &GetCodec()); + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onAvailabilityChanged"; + auto channel = std::make_unique>(binary_messenger_, channel_name, &GetCodec()); EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ EncodableValue(state_arg), }); - channel->Send(encoded_api_arguments, [on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + channel->Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); const auto& encodable_return_value = *response; const auto* list_return_value = std::get_if(&encodable_return_value); if (list_return_value) { if (list_return_value->size() > 1) { - on_error(FlutterError( std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); } else { on_success(); } } else { - on_error(FlutterError("channel-error", "Unable to establish connection on channel.", EncodableValue(""))); + on_error(CreateConnectionError(channel_name)); } }); } @@ -837,24 +845,25 @@ void UniversalBleCallbackChannel::OnPairStateChange( const std::string* error_arg, std::function&& on_success, std::function&& on_error) { - auto channel = std::make_unique>(binary_messenger_, "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange", &GetCodec()); + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onPairStateChange"; + auto channel = std::make_unique>(binary_messenger_, channel_name, &GetCodec()); EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ EncodableValue(device_id_arg), EncodableValue(is_paired_arg), error_arg ? EncodableValue(*error_arg) : EncodableValue(), }); - channel->Send(encoded_api_arguments, [on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + channel->Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); const auto& encodable_return_value = *response; const auto* list_return_value = std::get_if(&encodable_return_value); if (list_return_value) { if (list_return_value->size() > 1) { - on_error(FlutterError( std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); } else { on_success(); } } else { - on_error(FlutterError("channel-error", "Unable to establish connection on channel.", EncodableValue(""))); + on_error(CreateConnectionError(channel_name)); } }); } @@ -863,22 +872,23 @@ void UniversalBleCallbackChannel::OnScanResult( const UniversalBleScanResult& result_arg, std::function&& on_success, std::function&& on_error) { - auto channel = std::make_unique>(binary_messenger_, "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult", &GetCodec()); + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onScanResult"; + auto channel = std::make_unique>(binary_messenger_, channel_name, &GetCodec()); EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ CustomEncodableValue(result_arg), }); - channel->Send(encoded_api_arguments, [on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + channel->Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); const auto& encodable_return_value = *response; const auto* list_return_value = std::get_if(&encodable_return_value); if (list_return_value) { if (list_return_value->size() > 1) { - on_error(FlutterError( std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); } else { on_success(); } } else { - on_error(FlutterError("channel-error", "Unable to establish connection on channel.", EncodableValue(""))); + on_error(CreateConnectionError(channel_name)); } }); } @@ -889,24 +899,25 @@ void UniversalBleCallbackChannel::OnValueChanged( const std::vector& value_arg, std::function&& on_success, std::function&& on_error) { - auto channel = std::make_unique>(binary_messenger_, "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged", &GetCodec()); + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onValueChanged"; + auto channel = std::make_unique>(binary_messenger_, channel_name, &GetCodec()); EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ EncodableValue(device_id_arg), EncodableValue(characteristic_id_arg), EncodableValue(value_arg), }); - channel->Send(encoded_api_arguments, [on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + channel->Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); const auto& encodable_return_value = *response; const auto* list_return_value = std::get_if(&encodable_return_value); if (list_return_value) { if (list_return_value->size() > 1) { - on_error(FlutterError( std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); } else { on_success(); } } else { - on_error(FlutterError("channel-error", "Unable to establish connection on channel.", EncodableValue(""))); + on_error(CreateConnectionError(channel_name)); } }); } @@ -916,23 +927,24 @@ void UniversalBleCallbackChannel::OnConnectionChanged( int64_t state_arg, std::function&& on_success, std::function&& on_error) { - auto channel = std::make_unique>(binary_messenger_, "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged", &GetCodec()); + const std::string channel_name = "dev.flutter.pigeon.universal_ble.UniversalBleCallbackChannel.onConnectionChanged"; + auto channel = std::make_unique>(binary_messenger_, channel_name, &GetCodec()); EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ EncodableValue(device_id_arg), EncodableValue(state_arg), }); - channel->Send(encoded_api_arguments, [on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { + channel->Send(encoded_api_arguments, [channel_name, on_success = std::move(on_success), on_error = std::move(on_error)](const uint8_t* reply, size_t reply_size) { std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); const auto& encodable_return_value = *response; const auto* list_return_value = std::get_if(&encodable_return_value); if (list_return_value) { if (list_return_value->size() > 1) { - on_error(FlutterError( std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); + on_error(FlutterError(std::get(list_return_value->at(0)), std::get(list_return_value->at(1)), list_return_value->at(2))); } else { on_success(); } } else { - on_error(FlutterError("channel-error", "Unable to establish connection on channel.", EncodableValue(""))); + on_error(CreateConnectionError(channel_name)); } }); } diff --git a/windows/UniversalBle.g.h b/windows/src/generated/universal_ble.g.h similarity index 98% rename from windows/UniversalBle.g.h rename to windows/src/generated/universal_ble.g.h index b2fef5f..1d4b0cc 100644 --- a/windows/UniversalBle.g.h +++ b/windows/src/generated/universal_ble.g.h @@ -1,8 +1,8 @@ -// Autogenerated from Pigeon (v13.0.0), do not edit directly. +// Autogenerated from Pigeon (v16.0.5), do not edit directly. // See also: https://pub.dev/packages/pigeon -#ifndef PIGEON_UNIVERSALBLE_G_H_ -#define PIGEON_UNIVERSALBLE_G_H_ +#ifndef PIGEON_UNIVERSAL_BLE_G_H_ +#define PIGEON_UNIVERSAL_BLE_G_H_ #include #include #include @@ -308,4 +308,4 @@ class UniversalBleCallbackChannel { }; } // namespace universal_ble -#endif // PIGEON_UNIVERSALBLE_G_H_ +#endif // PIGEON_UNIVERSAL_BLE_G_H_ diff --git a/windows/src/helper/universal_ble_base.h b/windows/src/helper/universal_ble_base.h new file mode 100644 index 0000000..196761e --- /dev/null +++ b/windows/src/helper/universal_ble_base.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace universal_ble +{ + using namespace winrt; + using namespace winrt::Windows; + using namespace winrt::Windows::Devices; + using namespace winrt::Windows::Foundation; + using namespace winrt::Windows::Foundation::Collections; + using namespace winrt::Windows::Storage::Streams; + using namespace winrt::Windows::Devices::Radios; + using namespace winrt::Windows::Devices::Bluetooth; + using namespace winrt::Windows::Devices::Bluetooth::Advertisement; + using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile; + using namespace Windows::Devices::Enumeration; +} \ No newline at end of file diff --git a/windows/universal_enum.h b/windows/src/helper/universal_enum.h similarity index 100% rename from windows/universal_enum.h rename to windows/src/helper/universal_enum.h diff --git a/windows/Utils.cpp b/windows/src/helper/utils.cpp similarity index 88% rename from windows/Utils.cpp rename to windows/src/helper/utils.cpp index da72b84..2611234 100644 --- a/windows/Utils.cpp +++ b/windows/src/helper/utils.cpp @@ -9,11 +9,10 @@ #if WDK_NTDDI_VERSION < NTDDI_WIN10_VB #error "Windows SDK version before 10.0.19041.0 is not supported" #elif WDK_NTDDI_VERSION == NTDDI_WIN10_VB -// For Windows SDK version before 10.0.19041.0, remap functions to post-10.0.19041.0 versions #define WINRT_IMPL_CoGetApartmentType WINRT_CoGetApartmentType #endif -#define MAC_ADDRESS_STR_LENGTH (size_t)17 // Two chars per byte, 5 chars for colon +#define MAC_ADDRESS_STR_LENGTH (size_t)17 namespace universal_ble { @@ -29,7 +28,6 @@ namespace universal_ble uint64_t _str_to_mac_address(std::string mac_str) { - // TODO: Validate input - Expected Format: XX:XX:XX:XX:XX:XX uint64_t mac_address_number = 0; uint8_t *mac_ptr = (uint8_t *)&mac_address_number; sscanf_s(mac_str.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &mac_ptr[5], &mac_ptr[4], &mac_ptr[3], @@ -39,7 +37,6 @@ namespace universal_ble winrt::guid uuid_to_guid(const std::string &uuid) { - // TODO: Add proper cleanup / validation std::stringstream helper; for (int i = 0; i < uuid.length(); i++) { @@ -63,23 +60,18 @@ namespace universal_ble std::string guid_to_uuid(const winrt::guid &guid) { std::stringstream helper; - // TODO: It might be cleaner to use snprintf instead of string streams. - for (uint32_t i = 0; i < 4; i++) { - // * NOTE: We're performing a byte swap! helper << std::hex << std::setw(2) << std::setfill('0') << (int)((uint8_t *)&guid.Data1)[3 - i]; } helper << '-'; for (uint32_t i = 0; i < 2; i++) { - // * NOTE: We're performing a byte swap! helper << std::hex << std::setw(2) << std::setfill('0') << (int)((uint8_t *)&guid.Data2)[1 - i]; } helper << '-'; for (uint32_t i = 0; i < 2; i++) { - // * NOTE: We're performing a byte swap! helper << std::hex << std::setw(2) << std::setfill('0') << (int)((uint8_t *)&guid.Data3)[1 - i]; } helper << '-'; diff --git a/windows/Utils.h b/windows/src/helper/utils.h similarity index 52% rename from windows/Utils.h rename to windows/src/helper/utils.h index a5c588e..0a32d10 100644 --- a/windows/Utils.h +++ b/windows/src/helper/utils.h @@ -7,10 +7,7 @@ #include "winrt/Windows.Foundation.h" #include "winrt/Windows.Storage.Streams.h" #include "winrt/base.h" -#include "UniversalBle.g.h" - -using namespace winrt::Windows; -using namespace winrt::Windows::Storage::Streams; +#include "universal_ble_base.h" constexpr uint32_t TEN_SECONDS_IN_MSECS = 10000; @@ -29,34 +26,8 @@ namespace universal_ble std::string to_uuidstr(winrt::guid guid); - /// Structs for passing data between background to ui thread - struct ConnectionStateStruct - { - std::string deviceId; - int64_t connectionState; - ConnectionStateStruct(std::string deviceId, int64_t connectionState) - : deviceId(deviceId), connectionState(connectionState) {} - }; - struct PairStateStruct - { - std::string deviceId; - bool isPaired; - std::string errorMessage; - PairStateStruct(std::string deviceId, bool isPaired, std::string errorMessage) - : deviceId(deviceId), isPaired(isPaired), errorMessage(errorMessage) {} - }; - - struct ValueChangeStruct - { - std::string deviceId; - std::string characteristicId; - std::vector value; - ValueChangeStruct(std::string deviceId, std::string characteristicId, std::vector value) - : deviceId(deviceId), characteristicId(characteristicId), value(value) {} - }; - - /// To call async functions synchronously + /// To call async functions synchronously template static auto async_get(async_t const &async) { diff --git a/windows/src/ui_thread_handler.hpp b/windows/src/ui_thread_handler.hpp new file mode 100644 index 0000000..9f8a327 --- /dev/null +++ b/windows/src/ui_thread_handler.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include + +#include + +#include +#include +#include +#include + +class UniversalBleUiThreadHandler +{ +public: + explicit UniversalBleUiThreadHandler(flutter::PluginRegistrarWindows *registrar) + : registrar_(registrar) + { + windowProcId_ = registrar_->RegisterTopLevelWindowProcDelegate( + [this](HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) + { + return HandleWindowMessage(hwnd, message, wparam, lparam); + }); + } + + ~UniversalBleUiThreadHandler() + { + registrar_->UnregisterTopLevelWindowProcDelegate(windowProcId_); + } + + UniversalBleUiThreadHandler(const UniversalBleUiThreadHandler &) = delete; + UniversalBleUiThreadHandler &operator=(const UniversalBleUiThreadHandler &) = delete; + + void Post(std::function &&func) + { + std::lock_guard lock(mutex_); + queuedFuncs_.emplace_back(std::move(func)); + Notify(); + } + +private: + static const UINT kWmCallQueuedFunctions = WM_APP + 0x1d7; + + void Notify() + { + if (hwnd_ != 0) + { + PostMessage(hwnd_, kWmCallQueuedFunctions, 0, reinterpret_cast(this)); + } + } + + std::optional HandleWindowMessage( + HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) + { + if (hwnd_ == 0) + { + hwnd_ = hwnd; + Notify(); // Make sure queued functions are processed + } + if (message == kWmCallQueuedFunctions && lparam == reinterpret_cast(this)) + { + std::list> queuedFuncs; + { + std::lock_guard lock(mutex_); + std::swap(queuedFuncs_, queuedFuncs); + } + for (auto &func : queuedFuncs) + { + func(); + } + } + return std::nullopt; + } + + flutter::PluginRegistrarWindows *registrar_; + int windowProcId_ = 0; + HWND hwnd_ = 0; + std::list> queuedFuncs_; + std::mutex mutex_; +}; \ No newline at end of file diff --git a/windows/universal_ble_plugin.cpp b/windows/src/universal_ble_plugin.cpp similarity index 70% rename from windows/universal_ble_plugin.cpp rename to windows/src/universal_ble_plugin.cpp index 17eb51c..71556b5 100644 --- a/windows/universal_ble_plugin.cpp +++ b/windows/src/universal_ble_plugin.cpp @@ -9,16 +9,11 @@ #include #include #include -#include "UniversalBle.g.h" -#include "Utils.h" -#include "universal_enum.h" #include -#define WM_AVAILABILITY_CHANGE WM_USER + 101 -#define WM_PAIR_CHANGE WM_USER + 102 -#define WM_SCAN_RESULT WM_USER + 103 -#define WM_VALUE_CHANGE WM_USER + 104 -#define WM_CONNECTION_CHANGE WM_USER + 105 +#include "helper/utils.h" +#include "helper/universal_enum.h" +#include "generated/universal_ble.g.h" namespace universal_ble { @@ -27,8 +22,15 @@ namespace universal_ble using universal_ble::UniversalBlePlatformChannel; using universal_ble::UniversalBleScanResult; + const auto isConnectableKey = L"System.Devices.Aep.Bluetooth.Le.IsConnectable"; + const auto isConnectedKey = L"System.Devices.Aep.IsConnected"; + const auto isPairedKey = L"System.Devices.Aep.IsPaired"; + const auto isPresentKey = L"System.Devices.Aep.IsPresent"; + const auto deviceAddressKey = L"System.Devices.Aep.DeviceAddress"; + const auto signalStrengthKey = L"System.Devices.Aep.SignalStrength"; + std::unique_ptr callbackChannel; - std::map characteristicsTokens{}; + std::unordered_map characteristicsTokens{}; // TODO: Remove the map and store the token inside the characteristic object object union uint16_t_union { @@ -44,81 +46,14 @@ namespace universal_ble registrar->AddPlugin(std::move(plugin)); } - UniversalBlePlugin::UniversalBlePlugin(flutter::PluginRegistrarWindows *registrar) : registrar_(registrar) + UniversalBlePlugin::UniversalBlePlugin(flutter::PluginRegistrarWindows *registrar) + : uiThreadHandler_(registrar) { - if (window_proc_delegate_id_ == -1) - { - window_proc_delegate_id_ = registrar_->RegisterTopLevelWindowProcDelegate( - std::bind( - &UniversalBlePlugin::WindowProcDelegate, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3, std::placeholders::_4) - - ); - } InitializeAsync(); } UniversalBlePlugin::~UniversalBlePlugin() { - if (window_proc_delegate_id_ != -1) - { - registrar_->UnregisterTopLevelWindowProcDelegate( - static_cast(window_proc_delegate_id_)); - } - } - - HWND UniversalBlePlugin::GetWindow() - { - return ::GetAncestor(registrar_->GetView()->GetNativeWindow(), GA_ROOT); - } - - /// Background Messages Handler - std::optional UniversalBlePlugin::WindowProcDelegate(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) - { - switch (message) - { - case WM_SCAN_RESULT: - { - UniversalBleScanResult *scanResult = reinterpret_cast(wp); - callbackChannel->OnScanResult(*scanResult, SuccessCallback, ErrorCallback); - delete scanResult; - return 0; - } - case WM_AVAILABILITY_CHANGE: - { - callbackChannel->OnAvailabilityChanged(static_cast(wp), SuccessCallback, ErrorCallback); - return 0; - } - case WM_CONNECTION_CHANGE: - { - ConnectionStateStruct *connectionStateStruct = reinterpret_cast(wp); - callbackChannel->OnConnectionChanged(connectionStateStruct->deviceId, connectionStateStruct->connectionState, SuccessCallback, ErrorCallback); - delete connectionStateStruct; - return 0; - } - case WM_VALUE_CHANGE: - { - ValueChangeStruct *valueChangeStruct = reinterpret_cast(wp); - callbackChannel->OnValueChanged(valueChangeStruct->deviceId, valueChangeStruct->characteristicId, valueChangeStruct->value, SuccessCallback, ErrorCallback); - delete valueChangeStruct; - return 0; - } - case WM_PAIR_CHANGE: - { - PairStateStruct *pairStateStruct = reinterpret_cast(wp); - callbackChannel->OnPairStateChange(pairStateStruct->deviceId, pairStateStruct->isPaired, &pairStateStruct->errorMessage, SuccessCallback, ErrorCallback); - delete pairStateStruct; - return 0; - } - } - return std::nullopt; - } - - void UniversalBlePlugin::PostConnectionUpdate(uint64_t bluetoothAddress, ConnectionState connectionState) - { - ConnectionStateStruct *connectionStateStruct = new ConnectionStateStruct(_mac_address_to_str(bluetoothAddress), static_cast(connectionState)); - ::PostMessage(GetWindow(), WM_CONNECTION_CHANGE, reinterpret_cast(connectionStateStruct), 0); } // UniversalBlePlatformChannel implementation. @@ -163,9 +98,16 @@ namespace universal_ble if (!bluetoothLEWatcher) { bluetoothLEWatcher = BluetoothLEAdvertisementWatcher(); + bluetoothLEWatcher.ScanningMode(BluetoothLEScanningMode::Active); bluetoothLEWatcherReceivedToken = bluetoothLEWatcher.Received({this, &UniversalBlePlugin::BluetoothLEWatcher_Received}); } bluetoothLEWatcher.Start(); + setupDeviceWatcher(); + DeviceWatcherStatus status = deviceWatcher.Status(); + if (status != DeviceWatcherStatus::Started) + deviceWatcher.Start(); + else + return FlutterError("Already scanning"); return std::nullopt; } else @@ -176,6 +118,7 @@ namespace universal_ble std::optional UniversalBlePlugin::StopScan() { + if (bluetoothRadio && bluetoothRadio.State() == RadioState::On) { if (bluetoothLEWatcher) @@ -184,6 +127,7 @@ namespace universal_ble bluetoothLEWatcher.Received(bluetoothLEWatcherReceivedToken); } bluetoothLEWatcher = nullptr; + disposeDeviceWatcher(); return std::nullopt; } else @@ -194,12 +138,6 @@ namespace universal_ble std::optional UniversalBlePlugin::Connect(const std::string &device_id) { - auto isConnectable = deviceConnectableStatus[_str_to_mac_address(device_id)]; - if (isConnectable == false) - { - return FlutterError("Device is not connectable"); - } - ConnectAsync(_str_to_mac_address(device_id)); return std::nullopt; }; @@ -208,7 +146,10 @@ namespace universal_ble { auto deviceAddress = _str_to_mac_address(device_id); CleanConnection(deviceAddress); - PostConnectionUpdate(deviceAddress, ConnectionState::disconnected); + // TODO: send disconnect event only after disconnect is complete + uiThreadHandler_.Post([deviceAddress] + { callbackChannel->OnConnectionChanged(_mac_address_to_str(deviceAddress), static_cast(ConnectionState::disconnected), SuccessCallback, ErrorCallback); }); + return std::nullopt; }; @@ -233,6 +174,7 @@ namespace universal_ble } catch (...) { + std::cout << "DiscoverServicesLog: Unknown error" << std::endl; return result(FlutterError("Unknown error")); } } @@ -249,7 +191,7 @@ namespace universal_ble if (it == connectedDevices.end()) return FlutterError("IllegalArgument", "Unknown devicesId:" + device_id); auto bluetoothAgent = *it->second; - gatt_characteristic_t &gatt_characteristic_holder = bluetoothAgent._fetch_characteristic(service, characteristic); + GattCharacteristicObject &gatt_characteristic_holder = bluetoothAgent._fetch_characteristic(service, characteristic); GattCharacteristic gattCharacteristic = gatt_characteristic_holder.obj; auto descriptorValue = GattClientCharacteristicConfigurationDescriptorValue::None; auto properties = gattCharacteristic.CharacteristicProperties(); @@ -280,6 +222,7 @@ namespace universal_ble } catch (...) { + std::cout << "SetNotifiableLog: Unknown error" << std::endl; return FlutterError("Unknown error"); } }; @@ -299,7 +242,7 @@ namespace universal_ble return; } auto bluetoothAgent = *it->second; - gatt_characteristic_t &gatt_characteristic_holder = bluetoothAgent._fetch_characteristic(service, characteristic); + GattCharacteristicObject &gatt_characteristic_holder = bluetoothAgent._fetch_characteristic(service, characteristic); GattCharacteristic gattCharacteristic = gatt_characteristic_holder.obj; auto properties = gattCharacteristic.CharacteristicProperties(); if ((properties & GattCharacteristicProperties::Read) == GattCharacteristicProperties::None) @@ -336,6 +279,7 @@ namespace universal_ble } catch (...) { + std::cout << "ReadValueLog: Unknown error" << std::endl; return result(FlutterError("Unknown error")); } } @@ -357,7 +301,7 @@ namespace universal_ble return; } auto bluetoothAgent = *it->second; - gatt_characteristic_t &gatt_characteristic_holder = bluetoothAgent._fetch_characteristic(service, characteristic); + GattCharacteristicObject &gatt_characteristic_holder = bluetoothAgent._fetch_characteristic(service, characteristic); GattCharacteristic gattCharacteristic = gatt_characteristic_holder.obj; auto properties = gattCharacteristic.CharacteristicProperties(); auto writeOption = GattWriteOption::WriteWithResponse; @@ -407,6 +351,7 @@ namespace universal_ble } catch (...) { + std::cout << "WriteValue: Unknown error" << std::endl; result(FlutterError("Unknown error")); } } @@ -449,13 +394,14 @@ namespace universal_ble try { auto device = async_get(BluetoothLEDevice::FromBluetoothAddressAsync(_str_to_mac_address(device_id))); + std::cout << "PairLog: Device to be paired was found" << std::endl; auto deviceInformation = device.DeviceInformation(); bool isPaired = deviceInformation.Pairing().IsPaired(); if (isPaired) - return FlutterError("Device is already paired"); + return FlutterError("PairLog: Device is already paired"); bool canPair = deviceInformation.Pairing().CanPair(); if (!canPair) - return FlutterError("Device is not pairable"); + return FlutterError("PairLog: Device is not pairable"); auto customPairing = deviceInformation.Pairing().Custom(); winrt::event_token token = customPairing.PairingRequested([this](const Enumeration::DeviceInformationCustomPairing &sender, const Enumeration::DevicePairingRequestedEventArgs &eventArgs) @@ -466,18 +412,21 @@ namespace universal_ble eventArgs.Accept(); }); // DevicePairingKinds => None, ConfirmOnly, DisplayPin, ProvidePin, ConfirmPinMatch, ProvidePasswordCredential // DevicePairingProtectionLevel => Default, None, Encryption, EncryptionAndAuthentication + std::cout << "PairLog: Trying to pair" << std::endl; auto async_c = customPairing.PairAsync( Enumeration::DevicePairingKinds::ConfirmOnly, Enumeration::DevicePairingProtectionLevel::None); async_c.Completed([this, customPairing, token, device_id](IAsyncOperation const &sender, AsyncStatus const args) { auto result = sender.GetResults(); + std::cout << "PairLog: Received pairing status" << std::endl; customPairing.PairingRequested(token); auto isPaired = result.Status() == Enumeration::DevicePairingResultStatus::Paired; - // Post to main thread - PairStateStruct *pairStateStruct = new PairStateStruct(device_id, isPaired, parsePairingFailError(result)); - ::PostMessage(GetWindow(), WM_PAIR_CHANGE, reinterpret_cast(pairStateStruct), 0); }); + // Post to main thread + std::string errorStr = parsePairingFailError(result); + uiThreadHandler_.Post([device_id, isPaired, errorStr] + { callbackChannel->OnPairStateChange(device_id, isPaired, &errorStr, SuccessCallback, ErrorCallback); }); }); return std::nullopt; } catch (const FlutterError &err) @@ -528,6 +477,31 @@ namespace universal_ble } /// Helper Methods + + std::vector parseManufacturerDataHead(BluetoothLEAdvertisement advertisement, std::string deviceId) + { + try + { + if (advertisement.ManufacturerData().Size() == 0) + { + return std::vector(); + } + auto manufacturerData = advertisement.ManufacturerData().GetAt(0); + // FIXME Compat with REG_DWORD_BIG_ENDIAN + uint8_t *prefix = uint16_t_union{manufacturerData.CompanyId()}.bytes; + auto result = std::vector{prefix, prefix + sizeof(uint16_t_union)}; + + auto data = to_bytevc(manufacturerData.Data()); + result.insert(result.end(), data.begin(), data.end()); + return result; + } + catch (...) + { + std::cout << "Error in parsing manufacturer data: " << deviceId << std::endl; + return std::vector(); + } + } + winrt::fire_and_forget UniversalBlePlugin::InitializeAsync() { auto bluetoothAdapter = co_await BluetoothAdapter::GetDefaultAsync(); @@ -538,6 +512,209 @@ namespace universal_ble } } + // Send device to callback channel + // if device is already discovered in deviceWatcher then merge the scan result + void UniversalBlePlugin::pushUniversalScanResult(UniversalBleScanResult scanResult) + { + auto it = scanResults.find(scanResult.device_id()); + if (it != scanResults.end()) + { + UniversalBleScanResult &existingScanResult = it->second; + bool shouldUpdate = false; + if ((scanResult.name() == nullptr || scanResult.name()->empty()) && (existingScanResult.name() != nullptr && !existingScanResult.name()->empty())) + { + scanResult.set_name(*existingScanResult.name()); + shouldUpdate = true; + } + if (scanResult.is_paired() == nullptr && existingScanResult.is_paired() != nullptr) + { + scanResult.set_is_paired(existingScanResult.is_paired()); + shouldUpdate = true; + } + if (scanResult.manufacturer_data_head() == nullptr && existingScanResult.manufacturer_data_head() != nullptr) + { + scanResult.set_manufacturer_data_head(existingScanResult.manufacturer_data_head()); + shouldUpdate = true; + } + + // if nothing to update then return + if (!shouldUpdate) + return; + + // update the existing scan result + existingScanResult = scanResult; + } + else + { + // if not present, insert the new scan result + scanResults.insert(std::make_pair(scanResult.device_id(), scanResult)); + } + + uiThreadHandler_.Post([scanResult] + { callbackChannel->OnScanResult(scanResult, SuccessCallback, ErrorCallback); }); + } + + void UniversalBlePlugin::setupDeviceWatcher() + { + if (deviceWatcher != nullptr) + return; + + deviceWatcher = DeviceInformation::CreateWatcher( + L"(System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\")", + { + deviceAddressKey, + isConnectedKey, + isPairedKey, + isPresentKey, + isConnectableKey, + signalStrengthKey, + }, + DeviceInformationKind::AssociationEndpoint); + + /// Device Added from DeviceWatcher + deviceWatcherAddedToken = deviceWatcher.Added([this](DeviceWatcher sender, DeviceInformation deviceInfo) + { + std::string deviceId = winrt::to_string(deviceInfo.Id()); + deviceWatcherDevices.insert_or_assign(deviceId, deviceInfo); + onDeviceInfoReceived(deviceInfo); + // On Device Added + }); + + // Update only if device is already discovered in deviceWatcher.Added + deviceWatcherUpdatedToken = deviceWatcher.Updated([this](DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate) + { + std::string deviceId = winrt::to_string(deviceInfoUpdate.Id()); + auto it = deviceWatcherDevices.find(deviceId); + if (it != deviceWatcherDevices.end()) + { + it->second.Update(deviceInfoUpdate); + onDeviceInfoReceived(it->second); + } + // On Device Updated + }); + + deviceWatcherRemovedToken = deviceWatcher.Removed([this](DeviceWatcher sender, DeviceInformationUpdate args) + { + std::string deviceId = winrt::to_string(args.Id()); + deviceWatcherDevices.erase(deviceId); + // On Device Removed + }); + } + + void UniversalBlePlugin::disposeDeviceWatcher() + { + if (deviceWatcher != nullptr) + { + if (deviceWatcher.Status() == DeviceWatcherStatus::Started) + deviceWatcher.Stop(); + deviceWatcher.Added(deviceWatcherAddedToken); + deviceWatcher.Updated(deviceWatcherUpdatedToken); + deviceWatcher.Removed(deviceWatcherRemovedToken); + deviceWatcher = nullptr; + // Dispose tokens + deviceWatcherDevices.clear(); + } + } + + void UniversalBlePlugin::onDeviceInfoReceived(DeviceInformation deviceInfo) + { + auto properties = deviceInfo.Properties(); + + // Avoid devices if not connectable or if deviceAddressKey is not present + if (!(properties.HasKey(isConnectableKey) && (properties.Lookup(isConnectableKey).as()).GetBoolean()) || !properties.HasKey(deviceAddressKey)) + return; + + auto bluetoothAddressPropertyValue = properties.Lookup(deviceAddressKey).as(); + std::string deviceAddress = winrt::to_string(bluetoothAddressPropertyValue.GetString()); + + // Update device info if already discovered in advertisementWatcher + if (scanResults.count(deviceAddress) > 0) + { + bool isPaired = deviceInfo.Pairing().IsPaired(); + if (properties.HasKey(isPairedKey)) + { + auto isPairedPropertyValue = properties.Lookup(isPairedKey).as(); + isPaired = isPairedPropertyValue.GetBoolean(); + } + + UniversalBleScanResult universalScanResult(deviceAddress); + universalScanResult.set_is_paired(isPaired); + + if (!deviceInfo.Name().empty()) + universalScanResult.set_name(winrt::to_string(deviceInfo.Name())); + + if (properties.HasKey(signalStrengthKey)) + { + auto rssiPropertyValue = properties.Lookup(signalStrengthKey).as(); + int16_t rssi = rssiPropertyValue.GetInt16(); + universalScanResult.set_rssi(rssi); + } + pushUniversalScanResult(universalScanResult); + } + } + + /// Advertisement received from advertisementWatcher + void UniversalBlePlugin::BluetoothLEWatcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args) + { + try + { + // Avoid devices if they are not connectable + if (!args.IsConnectable()) + return; + + auto deviceId = _mac_address_to_str(args.BluetoothAddress()); + auto universalScanResult = UniversalBleScanResult(deviceId); + std::string name = winrt::to_string(args.Advertisement().LocalName()); + + // Use CompleteName from dataType if localName is empty + if (name.empty()) + { + auto dataSection = args.Advertisement().DataSections(); + for (auto &&data : dataSection) + { + auto dataBytes = to_bytevc(data.Data()); + if (data.DataType() == 0x09) + { + name = std::string(dataBytes.begin(), dataBytes.end()); + break; + } + } + } + + if (!name.empty()) + universalScanResult.set_name(name); + + auto manufacturerData = parseManufacturerDataHead(args.Advertisement(), deviceId); + universalScanResult.set_manufacturer_data_head(manufacturerData); + universalScanResult.set_rssi(args.RawSignalStrengthInDBm()); + + // check if this device already discovered in deviceWatcher + auto it = deviceWatcherDevices.find(deviceId); + if (it != deviceWatcherDevices.end()) + { + auto &deviceInfo = it->second; + auto properties = deviceInfo.Properties(); + + // Update Paired Status + bool isPaired = deviceInfo.Pairing().IsPaired(); + if (properties.HasKey(isPairedKey)) + isPaired = (properties.Lookup(isPairedKey).as()).GetBoolean(); + universalScanResult.set_is_paired(isPaired); + + // Update Name + if (name.empty() && !deviceInfo.Name().empty()) + universalScanResult.set_name(winrt::to_string(deviceInfo.Name())); + } + + // Cache connectable status + pushUniversalScanResult(universalScanResult); + } + catch (...) + { + std::cout << "ScanResultErrorInParsing" << std::endl; + } + } + AvailabilityState UniversalBlePlugin::getAvailabilityStateFromRadio(RadioState radioState) { auto state = [=]() -> AvailabilityState @@ -575,56 +752,12 @@ namespace universal_ble } oldRadioState = radioState; auto state = getAvailabilityStateFromRadio(radioState); - ::PostMessage(GetWindow(), WM_AVAILABILITY_CHANGE, static_cast(state), 0); + + uiThreadHandler_.Post([state] + { callbackChannel->OnAvailabilityChanged(static_cast(state), SuccessCallback, ErrorCallback); }); } - std::vector parseManufacturerDataHead(BluetoothLEAdvertisement advertisement, std::string deviceId) - { - try - { - if (advertisement.ManufacturerData().Size() == 0) - { - return std::vector(); - } - auto manufacturerData = advertisement.ManufacturerData().GetAt(0); - // FIXME Compat with REG_DWORD_BIG_ENDIAN - uint8_t *prefix = uint16_t_union{manufacturerData.CompanyId()}.bytes; - auto result = std::vector{prefix, prefix + sizeof(uint16_t_union)}; - - auto data = to_bytevc(manufacturerData.Data()); - result.insert(result.end(), data.begin(), data.end()); - return result; - } - catch (...) - { - std::cout << "Error in parsing manufacturer data: " << deviceId << std::endl; - return std::vector(); - } - } - - void UniversalBlePlugin::BluetoothLEWatcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args) - { - try - { - auto deviceId = _mac_address_to_str(args.BluetoothAddress()); - auto universalScanResult = new UniversalBleScanResult(deviceId); - hstring localName = args.Advertisement().LocalName(); - if (!localName.empty()) - universalScanResult->set_name(winrt::to_string(localName)); - - universalScanResult->set_manufacturer_data_head(parseManufacturerDataHead(args.Advertisement(), deviceId)); - universalScanResult->set_rssi(args.RawSignalStrengthInDBm()); - // Cache connectable status - deviceConnectableStatus[_str_to_mac_address(deviceId)] = args.IsConnectable(); - ::PostMessage(GetWindow(), WM_SCAN_RESULT, reinterpret_cast(universalScanResult), 0); - } - catch (...) - { - std::cout << "ScanResultErrorInParsing" << std::endl; - } - } - - std::string GattCommunicationStatusToString(GattCommunicationStatus status) + std::string UniversalBlePlugin::GattCommunicationStatusToString(GattCommunicationStatus status) { switch (status) { @@ -643,19 +776,32 @@ namespace universal_ble winrt::fire_and_forget UniversalBlePlugin::ConnectAsync(uint64_t bluetoothAddress) { - auto device = co_await BluetoothLEDevice::FromBluetoothAddressAsync(bluetoothAddress); - auto servicesResult = co_await device.GetGattServicesAsync((BluetoothCacheMode::Uncached)); - if (servicesResult.Status() != GattCommunicationStatus::Success) + BluetoothLEDevice device = co_await BluetoothLEDevice::FromBluetoothAddressAsync(bluetoothAddress); + std::cout << "ConnectionLog: Device found" << std::endl; + if (!device) { - PostConnectionUpdate(bluetoothAddress, ConnectionState::disconnected); + std::cout << "ConnectionLog: ConnectionFailed: Failed to get device" << std::endl; + uiThreadHandler_.Post([bluetoothAddress] + { callbackChannel->OnConnectionChanged(_mac_address_to_str(bluetoothAddress), static_cast(ConnectionState::disconnected), SuccessCallback, ErrorCallback); }); + co_return; } + auto servicesResult = co_await device.GetGattServicesAsync((BluetoothCacheMode::Uncached)); + auto status = servicesResult.Status(); + if (status != GattCommunicationStatus::Success) + { + std::cout << "ConnectionFailed: Failed to get services: " << GattCommunicationStatusToString(status) << std::endl; + uiThreadHandler_.Post([bluetoothAddress] + { callbackChannel->OnConnectionChanged(_mac_address_to_str(bluetoothAddress), static_cast(ConnectionState::disconnected), SuccessCallback, ErrorCallback); }); - std::map gatt_map_; + co_return; + } + std::cout << "ConnectionLog: Services discovered" << std::endl; + std::unordered_map gatt_map_; auto gatt_services = servicesResult.Services(); for (GattDeviceService &&service : gatt_services) { - gatt_service_t gatt_service; + GattServiceObject gatt_service; gatt_service.obj = service; std::string service_uuid = guid_to_uuid(service.Uuid()); auto characteristics_result = co_await service.GetCharacteristicsAsync(BluetoothCacheMode::Uncached); @@ -669,19 +815,21 @@ namespace universal_ble auto gatt_characteristics = characteristics_result.Characteristics(); for (GattCharacteristic &&characteristic : gatt_characteristics) { - gatt_characteristic_t gatt_characteristic; + GattCharacteristicObject gatt_characteristic; gatt_characteristic.obj = characteristic; std::string characteristic_uuid = guid_to_uuid(characteristic.Uuid()); - gatt_service.characteristics.emplace(characteristic_uuid, std::move(gatt_characteristic)); + gatt_service.characteristics.insert_or_assign(characteristic_uuid, std::move(gatt_characteristic)); } - gatt_map_.emplace(service_uuid, std::move(gatt_service)); + gatt_map_.insert_or_assign(service_uuid, std::move(gatt_service)); } - auto connnectionStatusChangedToken = device.ConnectionStatusChanged({this, &UniversalBlePlugin::BluetoothLEDevice_ConnectionStatusChanged}); + winrt::event_token connnectionStatusChangedToken = device.ConnectionStatusChanged({this, &UniversalBlePlugin::BluetoothLEDevice_ConnectionStatusChanged}); auto deviceAgent = std::make_unique(device, connnectionStatusChangedToken, gatt_map_); auto pair = std::make_pair(bluetoothAddress, std::move(deviceAgent)); connectedDevices.insert(std::move(pair)); - PostConnectionUpdate(bluetoothAddress, ConnectionState::connected); + std::cout << "ConnectionLog: Connected" << std::endl; + uiThreadHandler_.Post([bluetoothAddress] + { callbackChannel->OnConnectionChanged(_mac_address_to_str(bluetoothAddress), static_cast(ConnectionState::connected), SuccessCallback, ErrorCallback); }); } void UniversalBlePlugin::BluetoothLEDevice_ConnectionStatusChanged(BluetoothLEDevice sender, IInspectable args) @@ -689,7 +837,9 @@ namespace universal_ble if (sender.ConnectionStatus() == BluetoothConnectionStatus::Disconnected) { CleanConnection(sender.BluetoothAddress()); - PostConnectionUpdate(sender.BluetoothAddress(), ConnectionState::disconnected); + auto bluetoothAddress = sender.BluetoothAddress(); + uiThreadHandler_.Post([bluetoothAddress] + { callbackChannel->OnConnectionChanged(_mac_address_to_str(bluetoothAddress), static_cast(ConnectionState::disconnected), SuccessCallback, ErrorCallback); }); } } @@ -706,9 +856,11 @@ namespace universal_ble auto &service = servicePair.second; for (auto &characteristicPair : service.characteristics) { - gatt_characteristic_t &characteristic = characteristicPair.second; + GattCharacteristicObject &characteristic = characteristicPair.second; auto gattCharacteristic = characteristic.obj; - auto uniqTokenKey = to_uuidstr(gattCharacteristic.Uuid()) + _mac_address_to_str(gattCharacteristic.Service().Device().BluetoothAddress()); + std::stringstream uniqTokenKeyStream; + uniqTokenKeyStream << to_uuidstr(gattCharacteristic.Uuid()) << _mac_address_to_str(gattCharacteristic.Service().Device().BluetoothAddress()); + std::string uniqTokenKey = uniqTokenKeyStream.str(); if (characteristicsTokens.count(uniqTokenKey) != 0) { characteristic.obj.ValueChanged(characteristicsTokens[uniqTokenKey]); @@ -758,12 +910,13 @@ namespace universal_ble universalScanResult.set_name(winrt::to_string(deviceInfo.Name())); universalScanResult.set_is_paired(deviceInfo.Pairing().IsPaired()); results.push_back(flutter::CustomEncodableValue(universalScanResult)); - deviceConnectableStatus[_str_to_mac_address(deviceId)] = true; + // deviceConnectableStatus[_str_to_mac_address(deviceId)] = true; } result(results); } catch (...) { + std::cout << "Unknown error GetConnectedDevicesAsync" << std::endl; result(FlutterError("Unknown error")); } } @@ -840,7 +993,7 @@ namespace universal_ble catch (...) { result(FlutterError("DiscoverServiceError: Unknown error")); - std::cerr << "DiscoverServiceError: Unknown error" << '\n'; + std::cout << "DiscoverServiceError: Unknown error" << '\n'; } } @@ -864,7 +1017,7 @@ namespace universal_ble winrt::fire_and_forget UniversalBlePlugin::SetNotifiableAsync(BluetoothDeviceAgent &bluetoothDeviceAgent, const std::string &service, const std::string &characteristic, GattClientCharacteristicConfigurationDescriptorValue descriptorValue) { - gatt_characteristic_t &gatt_characteristic_holder = bluetoothDeviceAgent._fetch_characteristic(service, characteristic); + GattCharacteristicObject &gatt_characteristic_holder = bluetoothDeviceAgent._fetch_characteristic(service, characteristic); GattCharacteristic gattCharacteristic = gatt_characteristic_holder.obj; auto uuid = to_uuidstr(gattCharacteristic.Uuid()); @@ -898,7 +1051,9 @@ namespace universal_ble } // create uniqKey with uuid and deviceId // TODO: store token key in gatt_characteristic_t struct instead of using map - auto uniqTokenKey = uuid + _mac_address_to_str(gattCharacteristic.Service().Device().BluetoothAddress()); + std::stringstream uniqTokenKeyStream; + uniqTokenKeyStream << uuid << _mac_address_to_str(gattCharacteristic.Service().Device().BluetoothAddress()); + auto uniqTokenKey = uniqTokenKeyStream.str(); // Register/UnRegister handler for the ValueChanged event. if (descriptorValue == GattClientCharacteristicConfigurationDescriptorValue::None) @@ -927,8 +1082,8 @@ namespace universal_ble { auto uuid = to_uuidstr(sender.Uuid()); auto bytes = to_bytevc(args.CharacteristicValue()); - ValueChangeStruct *valueChangeStruct = new ValueChangeStruct(_mac_address_to_str(sender.Service().Device().BluetoothAddress()), uuid, bytes); - ::PostMessage(GetWindow(), WM_VALUE_CHANGE, reinterpret_cast(valueChangeStruct), 0); + uiThreadHandler_.Post([sender, uuid, bytes] + { callbackChannel->OnValueChanged(_mac_address_to_str(sender.Service().Device().BluetoothAddress()), uuid, bytes, SuccessCallback, ErrorCallback); }); } std::string UniversalBlePlugin::parsePairingFailError(Enumeration::DevicePairingResult result) diff --git a/windows/universal_ble_plugin.h b/windows/src/universal_ble_plugin.h similarity index 79% rename from windows/universal_ble_plugin.h rename to windows/src/universal_ble_plugin.h index a083033..37a1515 100644 --- a/windows/universal_ble_plugin.h +++ b/windows/src/universal_ble_plugin.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -15,42 +16,32 @@ #include #include -#include "Utils.h" -#include "UniversalBle.g.h" -#include "universal_enum.h" +#include "helper/utils.h" +#include "helper/universal_enum.h" +#include "helper/universal_ble_base.h" +#include "generated/universal_ble.g.h" +#include "ui_thread_handler.hpp" namespace universal_ble { - using namespace winrt; - using namespace winrt::Windows::Devices; - using namespace winrt::Windows::Foundation; - using namespace winrt::Windows::Foundation::Collections; - using namespace winrt::Windows::Storage::Streams; - using namespace winrt::Windows::Devices::Radios; - using namespace winrt::Windows::Devices::Bluetooth; - using namespace winrt::Windows::Devices::Bluetooth::Advertisement; - using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile; - using namespace Windows::Devices::Enumeration; - - struct gatt_characteristic_t + struct GattCharacteristicObject { GattCharacteristic obj = nullptr; - // winrt::event_token value_changed_token; }; - struct gatt_service_t + struct GattServiceObject { GattDeviceService obj = nullptr; - std::map characteristics; + std::unordered_map characteristics; }; struct BluetoothDeviceAgent { BluetoothLEDevice device; winrt::event_token connnectionStatusChangedToken; - std::map gatt_map_; + std::unordered_map gatt_map_; - BluetoothDeviceAgent(BluetoothLEDevice device, winrt::event_token connnectionStatusChangedToken, std::map gatt_map_) + BluetoothDeviceAgent(BluetoothLEDevice device, winrt::event_token connnectionStatusChangedToken, std::unordered_map gatt_map_) : device(device), connnectionStatusChangedToken(connnectionStatusChangedToken), gatt_map_(gatt_map_) {} @@ -60,19 +51,13 @@ namespace universal_ble device = nullptr; } - gatt_characteristic_t &_fetch_characteristic(const std::string &service_uuid, - const std::string &characteristic_uuid) + GattCharacteristicObject &_fetch_characteristic(const std::string &service_uuid, + const std::string &characteristic_uuid) { if (gatt_map_.count(service_uuid) == 0) - { throw FlutterError("Service not found"); - } - if (gatt_map_[service_uuid].characteristics.count(characteristic_uuid) == 0) - { throw FlutterError("Characteristic not found"); - } - return gatt_map_[service_uuid].characteristics.at(characteristic_uuid); } }; @@ -97,19 +82,31 @@ namespace universal_ble UniversalBlePlugin &operator=(const UniversalBlePlugin &) = delete; flutter::PluginRegistrarWindows *registrar_; - int64_t window_proc_delegate_id_ = -1; - HWND GetWindow(); - std::optional WindowProcDelegate(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); - winrt::fire_and_forget InitializeAsync(); + UniversalBleUiThreadHandler uiThreadHandler_; Radio bluetoothRadio{nullptr}; - void Radio_StateChanged(Radio sender, IInspectable args); RadioState oldRadioState = RadioState::Unknown; BluetoothLEAdvertisementWatcher bluetoothLEWatcher{nullptr}; + DeviceWatcher deviceWatcher{nullptr}; + std::unordered_map> connectedDevices{}; + std::unordered_map deviceWatcherDevices{}; + winrt::event_token bluetoothLEWatcherReceivedToken; + winrt::event_token deviceWatcherAddedToken; + winrt::event_token deviceWatcherUpdatedToken; + winrt::event_token deviceWatcherRemovedToken; + + winrt::fire_and_forget InitializeAsync(); + void Radio_StateChanged(Radio sender, IInspectable args); + + void setupDeviceWatcher(); + void disposeDeviceWatcher(); + void pushUniversalScanResult(UniversalBleScanResult scanResult); void BluetoothLEWatcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args); - std::map> connectedDevices{}; - std::map deviceConnectableStatus{}; + void onDeviceInfoReceived(DeviceInformation deviceInfo); + + std::string GattCommunicationStatusToString(GattCommunicationStatus status); + std::unordered_map scanResults{}; winrt::event_revoker radioStateChangedRevoker; winrt::fire_and_forget ConnectAsync(uint64_t bluetoothAddress); void BluetoothLEDevice_ConnectionStatusChanged(BluetoothLEDevice sender, IInspectable args); @@ -120,7 +117,6 @@ namespace universal_ble void GattCharacteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args); AvailabilityState getAvailabilityStateFromRadio(RadioState radioState); std::string parsePairingFailError(Enumeration::DevicePairingResult result); - void PostConnectionUpdate(uint64_t bluetoothAddress, ConnectionState connectionState); winrt::fire_and_forget GetConnectedDevicesAsync(std::vector with_services, std::function reply)> result); winrt::fire_and_forget IsPairedAsync(std::string device_id, std::function reply)> result); diff --git a/windows/universal_ble_plugin_c_api.cpp b/windows/universal_ble_plugin_c_api.cpp index fdbf1de..cb59edd 100644 --- a/windows/universal_ble_plugin_c_api.cpp +++ b/windows/universal_ble_plugin_c_api.cpp @@ -2,11 +2,12 @@ #include -#include "universal_ble_plugin.h" +#include "src/universal_ble_plugin.h" void UniversalBlePluginCApiRegisterWithRegistrar( - FlutterDesktopPluginRegistrarRef registrar) { - universal_ble::UniversalBlePlugin::RegisterWithRegistrar( - flutter::PluginRegistrarManager::GetInstance() - ->GetRegistrar(registrar)); + FlutterDesktopPluginRegistrarRef registrar) +{ + universal_ble::UniversalBlePlugin::RegisterWithRegistrar( + flutter::PluginRegistrarManager::GetInstance() + ->GetRegistrar(registrar)); }