diff --git a/android/src/main/kotlin/com/rohit/ble_peripheral/BleExtension.kt b/android/src/main/kotlin/com/rohit/ble_peripheral/BleExtension.kt index 999f3f6..c55f130 100644 --- a/android/src/main/kotlin/com/rohit/ble_peripheral/BleExtension.kt +++ b/android/src/main/kotlin/com/rohit/ble_peripheral/BleExtension.kt @@ -11,10 +11,17 @@ import java.lang.Exception import java.util.Collections import java.util.UUID -private val bluetoothGattCharacteristics: MutableMap = - HashMap() +data class BleCharCache( + val uuid: String, + val instanceId: Int?, + val char: BluetoothGattCharacteristic, +) + +private val bluetoothGattCharacteristics: MutableList = mutableListOf() private val descriptorValueReadMap: MutableMap = HashMap() +private val instanceIdMap: MutableMap = + HashMap() const val descriptorCCUUID = "00002902-0000-1000-8000-00805f9b34fb" @@ -51,6 +58,12 @@ fun BleCharacteristic.toGattCharacteristic(): BluetoothGattCharacteristic { properties.toPropertiesList(), permissions.toPermissionsList() ) + + // Store instance Id in map to identify + instanceId?.let { + instanceIdMap[char.instanceId] = it.toInt() + } + value?.let { char.value = it } @@ -62,9 +75,24 @@ fun BleCharacteristic.toGattCharacteristic(): BluetoothGattCharacteristic { addCCDescriptorIfRequired(this, char) - if (bluetoothGattCharacteristics[uuid] == null) { - bluetoothGattCharacteristics[uuid] = char + + if (instanceId == null) { + // Then all good, make sure only one char exists + if (bluetoothGattCharacteristics.any { it.uuid == char.uuid.toString() }) { + throw FlutterError(code = "Failed", message = "Char already exists") + } + bluetoothGattCharacteristics.add(BleCharCache(uuid, null, char)) + } else { + // Make sure this instanceId does not exists + if (bluetoothGattCharacteristics.any { it.uuid == char.uuid.toString() && it.instanceId == instanceId.toInt() }) { + throw FlutterError( + code = "Failed", + message = "Char already exists with this instance id" + ) + } + bluetoothGattCharacteristics.add(BleCharCache(uuid, instanceId.toInt(), char)) } + return char } @@ -123,14 +151,17 @@ fun BleDescriptor.toGattDescriptor(): BluetoothGattDescriptor { return descriptor } -fun String.findCharacteristic(): BluetoothGattCharacteristic? { - return bluetoothGattCharacteristics[this] +fun String.findCharacteristic(instanceId: Long?): BluetoothGattCharacteristic? { + if (instanceId != null) { + return bluetoothGattCharacteristics.find { it.uuid == this && instanceId.toInt() == it.instanceId }?.char + } + return bluetoothGattCharacteristics.find { it.uuid == this }?.char } fun String.findService(): BluetoothGattService? { - for (char in bluetoothGattCharacteristics.values) { - if (char.service?.uuid.toString() == this) { - return char.service + for (char in bluetoothGattCharacteristics) { + if (char.char.service?.uuid.toString() == this) { + return char.char.service } } return null @@ -175,4 +206,8 @@ fun Int.toBondState(): BondState { BluetoothDevice.BOND_NONE -> BondState.NONE else -> BondState.NONE } +} + +fun Int.toGivenInstanceId(): Long? { + return instanceIdMap[this]?.toLong() } \ No newline at end of file diff --git a/android/src/main/kotlin/com/rohit/ble_peripheral/BlePeripheral.g.kt b/android/src/main/kotlin/com/rohit/ble_peripheral/BlePeripheral.g.kt index 53f126e..267e225 100644 --- a/android/src/main/kotlin/com/rohit/ble_peripheral/BlePeripheral.g.kt +++ b/android/src/main/kotlin/com/rohit/ble_peripheral/BlePeripheral.g.kt @@ -149,7 +149,8 @@ data class BleCharacteristic ( val properties: List, val permissions: List, val descriptors: List? = null, - val value: ByteArray? = null + val value: ByteArray? = null, + val instanceId: Long? = null ) { companion object { @@ -159,7 +160,8 @@ data class BleCharacteristic ( val permissions = pigeonVar_list[2] as List val descriptors = pigeonVar_list[3] as List? val value = pigeonVar_list[4] as ByteArray? - return BleCharacteristic(uuid, properties, permissions, descriptors, value) + val instanceId = pigeonVar_list[5] as Long? + return BleCharacteristic(uuid, properties, permissions, descriptors, value, instanceId) } } fun toList(): List { @@ -169,6 +171,7 @@ data class BleCharacteristic ( permissions, descriptors, value, + instanceId, ) } } @@ -385,7 +388,7 @@ interface BlePeripheralChannel { fun getServices(): List fun getSubscribedClients(): List fun startAdvertising(services: List, localName: String?, timeout: Long?, manufacturerData: ManufacturerData?, addManufacturerDataInScanResponse: Boolean) - fun updateCharacteristic(characteristicId: String, value: ByteArray, deviceId: String?) + fun updateCharacteristic(characteristicId: String, value: ByteArray, deviceId: String?, instanceId: Long?) companion object { /** The codec used by BlePeripheralChannel. */ @@ -585,8 +588,9 @@ interface BlePeripheralChannel { val characteristicIdArg = args[0] as String val valueArg = args[1] as ByteArray val deviceIdArg = args[2] as String? + val instanceIdArg = args[3] as Long? val wrapped: List = try { - api.updateCharacteristic(characteristicIdArg, valueArg, deviceIdArg) + api.updateCharacteristic(characteristicIdArg, valueArg, deviceIdArg, instanceIdArg) listOf(null) } catch (exception: Throwable) { wrapError(exception) @@ -612,12 +616,12 @@ class BleCallback(private val binaryMessenger: BinaryMessenger, private val mess BlePeripheralPigeonCodec() } } - fun onReadRequest(deviceIdArg: String, characteristicIdArg: String, offsetArg: Long, valueArg: ByteArray?, callback: (Result) -> Unit) + fun onReadRequest(deviceIdArg: String, characteristicIdArg: String, offsetArg: Long, valueArg: ByteArray?, instanceIdArg: Long?, callback: (Result) -> Unit) { val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" val channelName = "dev.flutter.pigeon.ble_peripheral.BleCallback.onReadRequest$separatedMessageChannelSuffix" val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(deviceIdArg, characteristicIdArg, offsetArg, valueArg)) { + channel.send(listOf(deviceIdArg, characteristicIdArg, offsetArg, valueArg, instanceIdArg)) { if (it is List<*>) { if (it.size > 1) { callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) @@ -630,12 +634,12 @@ class BleCallback(private val binaryMessenger: BinaryMessenger, private val mess } } } - fun onWriteRequest(deviceIdArg: String, characteristicIdArg: String, offsetArg: Long, valueArg: ByteArray?, callback: (Result) -> Unit) + fun onWriteRequest(deviceIdArg: String, characteristicIdArg: String, offsetArg: Long, valueArg: ByteArray?, instanceIdArg: Long?, callback: (Result) -> Unit) { val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" val channelName = "dev.flutter.pigeon.ble_peripheral.BleCallback.onWriteRequest$separatedMessageChannelSuffix" val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(deviceIdArg, characteristicIdArg, offsetArg, valueArg)) { + channel.send(listOf(deviceIdArg, characteristicIdArg, offsetArg, valueArg, instanceIdArg)) { if (it is List<*>) { if (it.size > 1) { callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) @@ -648,12 +652,12 @@ class BleCallback(private val binaryMessenger: BinaryMessenger, private val mess } } } - fun onCharacteristicSubscriptionChange(deviceIdArg: String, characteristicIdArg: String, isSubscribedArg: Boolean, nameArg: String?, callback: (Result) -> Unit) + fun onCharacteristicSubscriptionChange(deviceIdArg: String, characteristicIdArg: String, isSubscribedArg: Boolean, nameArg: String?, instanceIdArg: Long?, callback: (Result) -> Unit) { val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" val channelName = "dev.flutter.pigeon.ble_peripheral.BleCallback.onCharacteristicSubscriptionChange$separatedMessageChannelSuffix" val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(deviceIdArg, characteristicIdArg, isSubscribedArg, nameArg)) { + channel.send(listOf(deviceIdArg, characteristicIdArg, isSubscribedArg, nameArg, instanceIdArg)) { if (it is List<*>) { if (it.size > 1) { callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) diff --git a/android/src/main/kotlin/com/rohit/ble_peripheral/BlePeripheralPlugin.kt b/android/src/main/kotlin/com/rohit/ble_peripheral/BlePeripheralPlugin.kt index 3af8047..5194a93 100644 --- a/android/src/main/kotlin/com/rohit/ble_peripheral/BlePeripheralPlugin.kt +++ b/android/src/main/kotlin/com/rohit/ble_peripheral/BlePeripheralPlugin.kt @@ -36,7 +36,6 @@ private const val TAG = "BlePeripheralPlugin" @SuppressLint("MissingPermission") class BlePeripheralPlugin : FlutterPlugin, BlePeripheralChannel, ActivityAware { - // PluginRegistry.ActivityResultListener { private val requestCodeBluetoothPermission = 0xa1c private var bleCallback: BleCallback? = null private val requestCodeBluetoothEnablePermission = 0xb1e @@ -47,7 +46,8 @@ class BlePeripheralPlugin : FlutterPlugin, BlePeripheralChannel, ActivityAware { private var bluetoothLeAdvertiser: BluetoothLeAdvertiser? = null private var gattServer: BluetoothGattServer? = null private val bluetoothDevicesMap: MutableMap = HashMap() - private val subscribedCharDevicesMap: MutableMap> = HashMap() + private val subscribedCharDevicesMap: MutableMap> = + HashMap() private val emptyBytes = byteArrayOf() private val listOfDevicesWaitingForBond = mutableListOf() private var isAdvertising: Boolean? = null @@ -108,7 +108,11 @@ class BlePeripheralPlugin : FlutterPlugin, BlePeripheralChannel, ActivityAware { } override fun getSubscribedClients(): List { - return subscribedCharDevicesMap.map { data -> SubscribedClient(data.key, data.value) } + return subscribedCharDevicesMap.map { data -> + SubscribedClient( + data.key, + data.value.map { it.uuid.toString() }) + } } override fun startAdvertising( @@ -183,9 +187,10 @@ class BlePeripheralPlugin : FlutterPlugin, BlePeripheralChannel, ActivityAware { characteristicId: String, value: ByteArray, deviceId: String?, + instanceId: Long?, ) { val char = - characteristicId.findCharacteristic() ?: throw Exception("Characteristic not found") + characteristicId.findCharacteristic(instanceId) ?: throw Exception("Characteristic not found") char.value = value if (deviceId != null) { val device = bluetoothDevicesMap[deviceId] ?: throw Exception("Device not found") @@ -238,17 +243,17 @@ class BlePeripheralPlugin : FlutterPlugin, BlePeripheralChannel, ActivityAware { private fun cleanConnection(device: BluetoothDevice) { val deviceAddress = device.address - // Notify char unsubscribe event on disconnect - val subscribedCharUUID: MutableList = + val subscribedCharUUID: MutableList = subscribedCharDevicesMap[deviceAddress] ?: mutableListOf() - subscribedCharUUID.forEach { charUUID -> + subscribedCharUUID.forEach { char -> handler?.post { bleCallback?.onCharacteristicSubscriptionChange( deviceAddress, - charUUID, + char.uuid.toString(), false, - device.name + device.name, + char.instanceId.toGivenInstanceId() ) {} } } @@ -342,6 +347,7 @@ class BlePeripheralPlugin : FlutterPlugin, BlePeripheralChannel, ActivityAware { characteristicIdArg = characteristic.uuid.toString(), offsetArg = offset.toLong(), valueArg = characteristic.value, + instanceIdArg = characteristic.instanceId.toGivenInstanceId() ) { it: Result -> val readRequestResult: ReadRequestResult? = it.getOrNull() if (readRequestResult == null) { @@ -389,6 +395,7 @@ class BlePeripheralPlugin : FlutterPlugin, BlePeripheralChannel, ActivityAware { characteristicIdArg = characteristic.uuid.toString(), offsetArg = offset.toLong(), valueArg = value, + instanceIdArg = characteristic.instanceId.toGivenInstanceId() ) { val writeResult: WriteRequestResult? = it.getOrNull() gattServer?.sendResponse( @@ -472,28 +479,31 @@ class BlePeripheralPlugin : FlutterPlugin, BlePeripheralChannel, ActivityAware { || BluetoothGattDescriptor.ENABLE_INDICATION_VALUE.contentEquals( value ) - val characteristicId = descriptor.characteristic.uuid.toString() + val characteristic = descriptor.characteristic + val characteristicId = characteristic.uuid.toString() device?.address?.let { handler?.post { bleCallback?.onCharacteristicSubscriptionChange( it, characteristicId, isSubscribed, - device.name + device.name, + instanceIdArg = descriptor.characteristic.instanceId.toGivenInstanceId() ) {} } // Update subscribed char list val charList = subscribedCharDevicesMap[it] ?: mutableListOf() + val item: BluetoothGattCharacteristic? = + charList.find { c -> c.uuid.toString() == characteristicId && c.instanceId == characteristic.instanceId } + if (isSubscribed) { - if (!charList.contains(characteristicId)) { - charList.add(characteristicId) - } - } else if (charList.contains(characteristicId)) { - if (charList.contains(characteristicId)) { - charList.remove(characteristicId) + if (item == null) { + charList.add(characteristic) } + } else if (item != null) { + charList.remove(item) } if (charList.isEmpty()) { @@ -645,13 +655,4 @@ class BlePeripheralPlugin : FlutterPlugin, BlePeripheralChannel, ActivityAware { } return false } - -// override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { -// if (requestCode == requestCodeBluetoothPermission) { -// Log.d(TAG, "onActivityResultForBlePermission: ${resultCode == Activity.RESULT_OK}") -// } else if (requestCode == requestCodeBluetoothEnablePermission) { -// Log.d(TAG, "onActivityResultForBleEnable: ${resultCode == Activity.RESULT_OK}") -// } -// return false -// } } diff --git a/darwin/Classes/BlePeripheral.g.swift b/darwin/Classes/BlePeripheral.g.swift index 62debc6..e8baa44 100644 --- a/darwin/Classes/BlePeripheral.g.swift +++ b/darwin/Classes/BlePeripheral.g.swift @@ -156,6 +156,7 @@ struct BleCharacteristic { var permissions: [AttributePermissions] var descriptors: [BleDescriptor]? = nil var value: FlutterStandardTypedData? = nil + var instanceId: Int64? = nil // swift-format-ignore: AlwaysUseLowerCamelCase @@ -165,13 +166,15 @@ struct BleCharacteristic { let permissions = pigeonVar_list[2] as! [AttributePermissions] let descriptors: [BleDescriptor]? = nilOrValue(pigeonVar_list[3]) let value: FlutterStandardTypedData? = nilOrValue(pigeonVar_list[4]) + let instanceId: Int64? = nilOrValue(pigeonVar_list[5]) return BleCharacteristic( uuid: uuid, properties: properties, permissions: permissions, descriptors: descriptors, - value: value + value: value, + instanceId: instanceId ) } func toList() -> [Any?] { @@ -181,6 +184,7 @@ struct BleCharacteristic { permissions, descriptors, value, + instanceId, ] } } @@ -401,7 +405,7 @@ protocol BlePeripheralChannel { func getServices() throws -> [String] func getSubscribedClients() throws -> [SubscribedClient] func startAdvertising(services: [String], localName: String?, timeout: Int64?, manufacturerData: ManufacturerData?, addManufacturerDataInScanResponse: Bool) throws - func updateCharacteristic(characteristicId: String, value: FlutterStandardTypedData, deviceId: String?) throws + func updateCharacteristic(characteristicId: String, value: FlutterStandardTypedData, deviceId: String?, instanceId: Int64?) throws } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. @@ -570,8 +574,9 @@ class BlePeripheralChannelSetup { let characteristicIdArg = args[0] as! String let valueArg = args[1] as! FlutterStandardTypedData let deviceIdArg: String? = nilOrValue(args[2]) + let instanceIdArg: Int64? = nilOrValue(args[3]) do { - try api.updateCharacteristic(characteristicId: characteristicIdArg, value: valueArg, deviceId: deviceIdArg) + try api.updateCharacteristic(characteristicId: characteristicIdArg, value: valueArg, deviceId: deviceIdArg, instanceId: instanceIdArg) reply(wrapResult(nil)) } catch { reply(wrapError(error)) @@ -586,9 +591,9 @@ class BlePeripheralChannelSetup { /// /// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift. protocol BleCallbackProtocol { - func onReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) - func onWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) - func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, completion: @escaping (Result) -> Void) + func onReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, instanceId instanceIdArg: Int64?, completion: @escaping (Result) -> Void) + func onWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, instanceId instanceIdArg: Int64?, completion: @escaping (Result) -> Void) + func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, instanceId instanceIdArg: Int64?, completion: @escaping (Result) -> Void) func onAdvertisingStatusUpdate(advertising advertisingArg: Bool, error errorArg: String?, completion: @escaping (Result) -> Void) func onBleStateChange(state stateArg: Bool, completion: @escaping (Result) -> Void) func onServiceAdded(serviceId serviceIdArg: String, error errorArg: String?, completion: @escaping (Result) -> Void) @@ -606,10 +611,10 @@ class BleCallback: BleCallbackProtocol { var codec: BlePeripheralPigeonCodec { return BlePeripheralPigeonCodec.shared } - func onReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) { + func onReadRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, instanceId instanceIdArg: Int64?, completion: @escaping (Result) -> Void) { let channelName: String = "dev.flutter.pigeon.ble_peripheral.BleCallback.onReadRequest\(messageChannelSuffix)" let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([deviceIdArg, characteristicIdArg, offsetArg, valueArg] as [Any?]) { response in + channel.sendMessage([deviceIdArg, characteristicIdArg, offsetArg, valueArg, instanceIdArg] as [Any?]) { response in guard let listResponse = response as? [Any?] else { completion(.failure(createConnectionError(withChannelName: channelName))) return @@ -625,10 +630,10 @@ class BleCallback: BleCallbackProtocol { } } } - func onWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) { + func onWriteRequest(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, offset offsetArg: Int64, value valueArg: FlutterStandardTypedData?, instanceId instanceIdArg: Int64?, completion: @escaping (Result) -> Void) { let channelName: String = "dev.flutter.pigeon.ble_peripheral.BleCallback.onWriteRequest\(messageChannelSuffix)" let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([deviceIdArg, characteristicIdArg, offsetArg, valueArg] as [Any?]) { response in + channel.sendMessage([deviceIdArg, characteristicIdArg, offsetArg, valueArg, instanceIdArg] as [Any?]) { response in guard let listResponse = response as? [Any?] else { completion(.failure(createConnectionError(withChannelName: channelName))) return @@ -644,10 +649,10 @@ class BleCallback: BleCallbackProtocol { } } } - func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, completion: @escaping (Result) -> Void) { + func onCharacteristicSubscriptionChange(deviceId deviceIdArg: String, characteristicId characteristicIdArg: String, isSubscribed isSubscribedArg: Bool, name nameArg: String?, instanceId instanceIdArg: Int64?, completion: @escaping (Result) -> Void) { let channelName: String = "dev.flutter.pigeon.ble_peripheral.BleCallback.onCharacteristicSubscriptionChange\(messageChannelSuffix)" let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([deviceIdArg, characteristicIdArg, isSubscribedArg, nameArg] as [Any?]) { response in + channel.sendMessage([deviceIdArg, characteristicIdArg, isSubscribedArg, nameArg, instanceIdArg] as [Any?]) { response in guard let listResponse = response as? [Any?] else { completion(.failure(createConnectionError(withChannelName: channelName))) return diff --git a/example/lib/home_controller.dart b/example/lib/home_controller.dart index a7a820d..5813960 100644 --- a/example/lib/home_controller.dart +++ b/example/lib/home_controller.dart @@ -56,6 +56,7 @@ class HomeController extends GetxController { String characteristicId, bool isSubscribed, String? name, + int? instanceId, ) { Get.log( "onCharacteristicSubscriptionChange: $deviceId : $characteristicId $isSubscribed Name: $name", @@ -84,13 +85,13 @@ class HomeController extends GetxController { }); BlePeripheral.setReadRequestCallback( - (deviceId, characteristicId, offset, value) { + (deviceId, characteristicId, offset, value, instanceId) { Get.log("ReadRequest: $deviceId $characteristicId : $offset : $value"); return ReadRequestResult(value: utf8.encode("Hello World")); }); BlePeripheral.setWriteRequestCallback( - (deviceId, characteristicId, offset, value) { + (deviceId, characteristicId, offset, value, instanceId) { Get.log("WriteRequest: $deviceId $characteristicId : $offset : $value"); // return WriteRequestResult(status: 144); return null; diff --git a/lib/src/ble_peripheral.dart b/lib/src/ble_peripheral.dart index aa5d5b6..5edaec1 100644 --- a/lib/src/ble_peripheral.dart +++ b/lib/src/ble_peripheral.dart @@ -64,9 +64,14 @@ class BlePeripheral { required String characteristicId, required Uint8List value, String? deviceId, + int? instanceId, }) { return _platform.updateCharacteristic( - characteristicId: characteristicId, value: value, deviceId: deviceId); + characteristicId: characteristicId, + value: value, + deviceId: deviceId, + instanceId: instanceId, + ); } /// Start advertising with the given services and local name diff --git a/lib/src/ble_peripheral_interface.dart b/lib/src/ble_peripheral_interface.dart index 5b59551..321629b 100644 --- a/lib/src/ble_peripheral_interface.dart +++ b/lib/src/ble_peripheral_interface.dart @@ -31,6 +31,7 @@ abstract class BlePeripheralInterface { required String characteristicId, required Uint8List value, String? deviceId, + int? instanceId, }); Future startAdvertising({ @@ -95,17 +96,32 @@ typedef BleStateCallback = void Function(bool state); typedef BondStateCallback = void Function(String deviceId, BondState bondState); typedef CharacteristicSubscriptionChangeCallback = void Function( - String deviceId, String characteristicId, bool isSubscribed, String? name); + String deviceId, + String characteristicId, + bool isSubscribed, + String? name, + int? instanceId, +); typedef ConnectionStateChangeCallback = void Function( String deviceId, bool connected); typedef ReadRequestCallback = ReadRequestResult? Function( - String deviceId, String characteristicId, int offset, Uint8List? value); + String deviceId, + String characteristicId, + int offset, + Uint8List? value, + int? instanceId, +); typedef ServiceAddedCallback = void Function(String serviceId, String? error); typedef WriteRequestCallback = WriteRequestResult? Function( - String deviceId, String characteristicId, int offset, Uint8List? value); + String deviceId, + String characteristicId, + int offset, + Uint8List? value, + int? instanceId, +); typedef MtuChangeCallback = void Function(String deviceId, int mtu); diff --git a/lib/src/generated/ble_peripheral.g.dart b/lib/src/generated/ble_peripheral.g.dart index 1a406fe..bcf0144 100644 --- a/lib/src/generated/ble_peripheral.g.dart +++ b/lib/src/generated/ble_peripheral.g.dart @@ -117,6 +117,7 @@ class BleCharacteristic { required this.permissions, this.descriptors, this.value, + this.instanceId, }); String uuid; @@ -129,6 +130,8 @@ class BleCharacteristic { Uint8List? value; + int? instanceId; + Object encode() { return [ uuid, @@ -136,6 +139,7 @@ class BleCharacteristic { permissions, descriptors, value, + instanceId, ]; } @@ -147,6 +151,7 @@ class BleCharacteristic { permissions: (result[2] as List?)!.cast(), descriptors: (result[3] as List?)?.cast(), value: result[4] as Uint8List?, + instanceId: result[5] as int?, ); } } @@ -621,7 +626,7 @@ class BlePeripheralChannel { } } - Future updateCharacteristic(String characteristicId, Uint8List value, String? deviceId) async { + Future updateCharacteristic(String characteristicId, Uint8List value, String? deviceId, int? instanceId) async { final String pigeonVar_channelName = 'dev.flutter.pigeon.ble_peripheral.BlePeripheralChannel.updateCharacteristic$pigeonVar_messageChannelSuffix'; final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, @@ -629,7 +634,7 @@ class BlePeripheralChannel { binaryMessenger: pigeonVar_binaryMessenger, ); final List? pigeonVar_replyList = - await pigeonVar_channel.send([characteristicId, value, deviceId]) as List?; + await pigeonVar_channel.send([characteristicId, value, deviceId, instanceId]) as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -648,11 +653,11 @@ class BlePeripheralChannel { abstract class BleCallback { static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - ReadRequestResult? onReadRequest(String deviceId, String characteristicId, int offset, Uint8List? value); + ReadRequestResult? onReadRequest(String deviceId, String characteristicId, int offset, Uint8List? value, int? instanceId); - WriteRequestResult? onWriteRequest(String deviceId, String characteristicId, int offset, Uint8List? value); + WriteRequestResult? onWriteRequest(String deviceId, String characteristicId, int offset, Uint8List? value, int? instanceId); - void onCharacteristicSubscriptionChange(String deviceId, String characteristicId, bool isSubscribed, String? name); + void onCharacteristicSubscriptionChange(String deviceId, String characteristicId, bool isSubscribed, String? name, int? instanceId); void onAdvertisingStatusUpdate(bool advertising, String? error); @@ -689,8 +694,9 @@ abstract class BleCallback { assert(arg_offset != null, 'Argument for dev.flutter.pigeon.ble_peripheral.BleCallback.onReadRequest was null, expected non-null int.'); final Uint8List? arg_value = (args[3] as Uint8List?); + final int? arg_instanceId = (args[4] as int?); try { - final ReadRequestResult? output = api.onReadRequest(arg_deviceId!, arg_characteristicId!, arg_offset!, arg_value); + final ReadRequestResult? output = api.onReadRequest(arg_deviceId!, arg_characteristicId!, arg_offset!, arg_value, arg_instanceId); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); @@ -721,8 +727,9 @@ abstract class BleCallback { assert(arg_offset != null, 'Argument for dev.flutter.pigeon.ble_peripheral.BleCallback.onWriteRequest was null, expected non-null int.'); final Uint8List? arg_value = (args[3] as Uint8List?); + final int? arg_instanceId = (args[4] as int?); try { - final WriteRequestResult? output = api.onWriteRequest(arg_deviceId!, arg_characteristicId!, arg_offset!, arg_value); + final WriteRequestResult? output = api.onWriteRequest(arg_deviceId!, arg_characteristicId!, arg_offset!, arg_value, arg_instanceId); return wrapResponse(result: output); } on PlatformException catch (e) { return wrapResponse(error: e); @@ -753,8 +760,9 @@ abstract class BleCallback { assert(arg_isSubscribed != null, 'Argument for dev.flutter.pigeon.ble_peripheral.BleCallback.onCharacteristicSubscriptionChange was null, expected non-null bool.'); final String? arg_name = (args[3] as String?); + final int? arg_instanceId = (args[4] as int?); try { - api.onCharacteristicSubscriptionChange(arg_deviceId!, arg_characteristicId!, arg_isSubscribed!, arg_name); + api.onCharacteristicSubscriptionChange(arg_deviceId!, arg_characteristicId!, arg_isSubscribed!, arg_name, arg_instanceId); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); diff --git a/lib/src/pigeon/ble_callback_handler.dart b/lib/src/pigeon/ble_callback_handler.dart index efaf319..78d7e03 100644 --- a/lib/src/pigeon/ble_callback_handler.dart +++ b/lib/src/pigeon/ble_callback_handler.dart @@ -37,13 +37,10 @@ class BleCallbackHandler extends BleCallback { String characteristicId, bool isSubscribed, String? name, + int? instanceId, ) { characteristicSubscriptionChange?.call( - deviceId, - characteristicId, - isSubscribed, - name, - ); + deviceId, characteristicId, isSubscribed, name, instanceId); } @override @@ -57,9 +54,11 @@ class BleCallbackHandler extends BleCallback { String characteristicId, int offset, Uint8List? value, + int? instanceId, ) { // Windows crash if return value is null - return readRequest?.call(deviceId, characteristicId, offset, value) ?? + return readRequest?.call( + deviceId, characteristicId, offset, value, instanceId) ?? ReadRequestResult( value: Uint8List.fromList([0]), ); @@ -73,8 +72,14 @@ class BleCallbackHandler extends BleCallback { @override WriteRequestResult? onWriteRequest( - String deviceId, String characteristicId, int offset, Uint8List? value) { - return writeRequest?.call(deviceId, characteristicId, offset, value) ?? + String deviceId, + String characteristicId, + int offset, + Uint8List? value, + int? instanceId, + ) { + return writeRequest?.call( + deviceId, characteristicId, offset, value, instanceId) ?? WriteRequestResult(); } diff --git a/lib/src/pigeon/ble_peripheral_pigeon.dart b/lib/src/pigeon/ble_peripheral_pigeon.dart index 5aada51..90c5c4d 100644 --- a/lib/src/pigeon/ble_peripheral_pigeon.dart +++ b/lib/src/pigeon/ble_peripheral_pigeon.dart @@ -85,8 +85,10 @@ class BlePeripheralPigeon extends BlePeripheralInterface { required String characteristicId, required Uint8List value, String? deviceId, + int? instanceId, }) { - return _channel.updateCharacteristic(characteristicId, value, deviceId); + return _channel.updateCharacteristic( + characteristicId, value, deviceId, instanceId); } /// Start advertising with the given services and local name diff --git a/pigeons/ble.dart b/pigeons/ble.dart index cb7e6e7..7234f52 100644 --- a/pigeons/ble.dart +++ b/pigeons/ble.dart @@ -60,14 +60,16 @@ class BleCharacteristic { List permissions; List? descriptors; Uint8List? value; + int? instanceId; BleCharacteristic( this.uuid, this.value, this.descriptors, this.properties, - this.permissions, - ); + this.permissions, { + this.instanceId, + }); } class BleDescriptor { @@ -132,6 +134,7 @@ abstract class BlePeripheralChannel { String characteristicId, Uint8List value, String? deviceId, + int? instanceId, ); } @@ -143,6 +146,7 @@ abstract class BleCallback { String characteristicId, int offset, Uint8List? value, + int? instanceId, ); WriteRequestResult? onWriteRequest( @@ -150,6 +154,7 @@ abstract class BleCallback { String characteristicId, int offset, Uint8List? value, + int? instanceId, ); void onCharacteristicSubscriptionChange( @@ -157,6 +162,7 @@ abstract class BleCallback { String characteristicId, bool isSubscribed, String? name, + int? instanceId, ); void onAdvertisingStatusUpdate(bool advertising, String? error); diff --git a/windows/BlePeripheral.g.cpp b/windows/BlePeripheral.g.cpp index 61767af..0add893 100644 --- a/windows/BlePeripheral.g.cpp +++ b/windows/BlePeripheral.g.cpp @@ -138,12 +138,14 @@ BleCharacteristic::BleCharacteristic( const EncodableList& properties, const EncodableList& permissions, const EncodableList* descriptors, - const std::vector* value) + const std::vector* value, + const int64_t* instance_id) : uuid_(uuid), properties_(properties), permissions_(permissions), descriptors_(descriptors ? std::optional(*descriptors) : std::nullopt), - value_(value ? std::optional>(*value) : std::nullopt) {} + value_(value ? std::optional>(*value) : std::nullopt), + instance_id_(instance_id ? std::optional(*instance_id) : std::nullopt) {} const std::string& BleCharacteristic::uuid() const { return uuid_; @@ -198,14 +200,28 @@ void BleCharacteristic::set_value(const std::vector& value_arg) { } +const int64_t* BleCharacteristic::instance_id() const { + return instance_id_ ? &(*instance_id_) : nullptr; +} + +void BleCharacteristic::set_instance_id(const int64_t* value_arg) { + instance_id_ = value_arg ? std::optional(*value_arg) : std::nullopt; +} + +void BleCharacteristic::set_instance_id(int64_t value_arg) { + instance_id_ = value_arg; +} + + EncodableList BleCharacteristic::ToEncodableList() const { EncodableList list; - list.reserve(5); + list.reserve(6); list.push_back(EncodableValue(uuid_)); list.push_back(EncodableValue(properties_)); list.push_back(EncodableValue(permissions_)); list.push_back(descriptors_ ? EncodableValue(*descriptors_) : EncodableValue()); list.push_back(value_ ? EncodableValue(*value_) : EncodableValue()); + list.push_back(instance_id_ ? EncodableValue(*instance_id_) : EncodableValue()); return list; } @@ -222,6 +238,10 @@ BleCharacteristic BleCharacteristic::FromEncodableList(const EncodableList& list if (!encodable_value.IsNull()) { decoded.set_value(std::get>(encodable_value)); } + auto& encodable_instance_id = list[5]; + if (!encodable_instance_id.IsNull()) { + decoded.set_instance_id(std::get(encodable_instance_id)); + } return decoded; } @@ -897,7 +917,9 @@ void BlePeripheralChannel::SetUp( const auto& value_arg = std::get>(encodable_value_arg); const auto& encodable_device_id_arg = args.at(2); const auto* device_id_arg = std::get_if(&encodable_device_id_arg); - std::optional output = api->UpdateCharacteristic(characteristic_id_arg, value_arg, device_id_arg); + const auto& encodable_instance_id_arg = args.at(3); + const auto* instance_id_arg = std::get_if(&encodable_instance_id_arg); + std::optional output = api->UpdateCharacteristic(characteristic_id_arg, value_arg, device_id_arg, instance_id_arg); if (output.has_value()) { reply(WrapError(output.value())); return; @@ -951,6 +973,7 @@ void BleCallback::OnReadRequest( const std::string& characteristic_id_arg, int64_t offset_arg, const std::vector* value_arg, + const int64_t* instance_id_arg, std::function&& on_success, std::function&& on_error) { const std::string channel_name = "dev.flutter.pigeon.ble_peripheral.BleCallback.onReadRequest" + message_channel_suffix_; @@ -960,6 +983,7 @@ void BleCallback::OnReadRequest( EncodableValue(characteristic_id_arg), EncodableValue(offset_arg), value_arg ? EncodableValue(*value_arg) : EncodableValue(), + instance_id_arg ? EncodableValue(*instance_id_arg) : EncodableValue(), }); 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); @@ -983,6 +1007,7 @@ void BleCallback::OnWriteRequest( const std::string& characteristic_id_arg, int64_t offset_arg, const std::vector* value_arg, + const int64_t* instance_id_arg, std::function&& on_success, std::function&& on_error) { const std::string channel_name = "dev.flutter.pigeon.ble_peripheral.BleCallback.onWriteRequest" + message_channel_suffix_; @@ -992,6 +1017,7 @@ void BleCallback::OnWriteRequest( EncodableValue(characteristic_id_arg), EncodableValue(offset_arg), value_arg ? EncodableValue(*value_arg) : EncodableValue(), + instance_id_arg ? EncodableValue(*instance_id_arg) : EncodableValue(), }); 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); @@ -1015,6 +1041,7 @@ void BleCallback::OnCharacteristicSubscriptionChange( const std::string& characteristic_id_arg, bool is_subscribed_arg, const std::string* name_arg, + const int64_t* instance_id_arg, std::function&& on_success, std::function&& on_error) { const std::string channel_name = "dev.flutter.pigeon.ble_peripheral.BleCallback.onCharacteristicSubscriptionChange" + message_channel_suffix_; @@ -1024,6 +1051,7 @@ void BleCallback::OnCharacteristicSubscriptionChange( EncodableValue(characteristic_id_arg), EncodableValue(is_subscribed_arg), name_arg ? EncodableValue(*name_arg) : EncodableValue(), + instance_id_arg ? EncodableValue(*instance_id_arg) : EncodableValue(), }); 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); diff --git a/windows/BlePeripheral.g.h b/windows/BlePeripheral.g.h index 1d4f0c2..ef7ab24 100644 --- a/windows/BlePeripheral.g.h +++ b/windows/BlePeripheral.g.h @@ -161,7 +161,8 @@ class BleCharacteristic { const flutter::EncodableList& properties, const flutter::EncodableList& permissions, const flutter::EncodableList* descriptors, - const std::vector* value); + const std::vector* value, + const int64_t* instance_id); const std::string& uuid() const; void set_uuid(std::string_view value_arg); @@ -180,6 +181,10 @@ class BleCharacteristic { void set_value(const std::vector* value_arg); void set_value(const std::vector& value_arg); + const int64_t* instance_id() const; + void set_instance_id(const int64_t* value_arg); + void set_instance_id(int64_t value_arg); + private: static BleCharacteristic FromEncodableList(const flutter::EncodableList& list); @@ -192,6 +197,7 @@ class BleCharacteristic { flutter::EncodableList permissions_; std::optional descriptors_; std::optional> value_; + std::optional instance_id_; }; @@ -381,7 +387,8 @@ class BlePeripheralChannel { virtual std::optional UpdateCharacteristic( const std::string& characteristic_id, const std::vector& value, - const std::string* device_id) = 0; + const std::string* device_id, + const int64_t* instance_id) = 0; // The codec used by BlePeripheralChannel. static const flutter::StandardMessageCodec& GetCodec(); @@ -415,6 +422,7 @@ class BleCallback { const std::string& characteristic_id, int64_t offset, const std::vector* value, + const int64_t* instance_id, std::function&& on_success, std::function&& on_error); void OnWriteRequest( @@ -422,6 +430,7 @@ class BleCallback { const std::string& characteristic_id, int64_t offset, const std::vector* value, + const int64_t* instance_id, std::function&& on_success, std::function&& on_error); void OnCharacteristicSubscriptionChange( @@ -429,6 +438,7 @@ class BleCallback { const std::string& characteristic_id, bool is_subscribed, const std::string* name, + const int64_t* instance_id, std::function&& on_success, std::function&& on_error); void OnAdvertisingStatusUpdate(