Implement readRSSI on Android and Darwin (#203)
This commit is contained in:
@@ -1,3 +1,6 @@
|
|||||||
|
## 1.1.0
|
||||||
|
* Add readRssi method
|
||||||
|
|
||||||
## 1.0.1
|
## 1.0.1
|
||||||
* Enforce C++20 standard for Windows builds
|
* Enforce C++20 standard for Windows builds
|
||||||
|
|
||||||
|
|||||||
@@ -131,3 +131,19 @@ This method will **attempt** to set the MTU (Maximum Transmission Unit) but it i
|
|||||||
```dart
|
```dart
|
||||||
int mtu = await UniversalBle.requestMtu(widget.deviceId, 247);
|
int mtu = await UniversalBle.requestMtu(widget.deviceId, 247);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Read RSSI
|
||||||
|
|
||||||
|
Read the signal strength (RSSI) of a connected device.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
int rssi = await UniversalBle.readRssi(deviceId);
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ Note: The device must be connected before reading RSSI.
|
||||||
|
|
||||||
|
#### Platform Limitations
|
||||||
|
|
||||||
|
* **Android / iOS / macOS**: Fully supported.
|
||||||
|
|
||||||
|
* **Windows / Linux / Web**: Not supported.
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE
|
|||||||
- [Pairing](#pairing)
|
- [Pairing](#pairing)
|
||||||
- [Bluetooth Availability](#bluetooth-availability)
|
- [Bluetooth Availability](#bluetooth-availability)
|
||||||
- [Requesting MTU](#requesting-mtu)
|
- [Requesting MTU](#requesting-mtu)
|
||||||
|
- [Reading RSSI](#reading-rssi)
|
||||||
- [Command Queue](#command-queue)
|
- [Command Queue](#command-queue)
|
||||||
- [Timeout](#timeout)
|
- [Timeout](#timeout)
|
||||||
- [Error Handling](#error-handling)
|
- [Error Handling](#error-handling)
|
||||||
@@ -52,6 +53,7 @@ A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE
|
|||||||
| enable/disable Bluetooth | ✔️ | ❌ | ❌ | ✔️ | ✔️ | ❌ |
|
| enable/disable Bluetooth | ✔️ | ❌ | ❌ | ✔️ | ✔️ | ❌ |
|
||||||
| onAvailabilityChange | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
|
| onAvailabilityChange | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||||
| requestMtu | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ |
|
| requestMtu | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ |
|
||||||
|
| readRssi | ✔️ | ✔️ | ✔️ | ❌ | 🚧 | ❌ |
|
||||||
| requestPermissions | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
|
| requestPermissions | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
@@ -409,7 +411,7 @@ UniversalBle.disableBluetooth();
|
|||||||
|
|
||||||
```dart
|
```dart
|
||||||
int mtu = await bleDevice.requestMtu(256);
|
int mtu = await bleDevice.requestMtu(256);
|
||||||
````
|
```
|
||||||
|
|
||||||
> ⚠️ Note: Requesting an MTU is a *best-effort* operation.
|
> ⚠️ Note: Requesting an MTU is a *best-effort* operation.
|
||||||
> On many platforms the final MTU is fully controlled by the OS and remote device.
|
> On many platforms the final MTU is fully controlled by the OS and remote device.
|
||||||
@@ -460,6 +462,23 @@ When developing cross-platform BLE applications and devices:
|
|||||||
* Take advantage of higher MTUs when available, without depending on them
|
* Take advantage of higher MTUs when available, without depending on them
|
||||||
|
|
||||||
|
|
||||||
|
### Reading RSSI
|
||||||
|
|
||||||
|
Read the signal strength (RSSI) of a connected device.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
int rssi = await bleDevice.readRssi();
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ Note: The device must be connected before reading RSSI.
|
||||||
|
|
||||||
|
#### Platform Limitations
|
||||||
|
|
||||||
|
* **Android / iOS / macOS**: Fully supported.
|
||||||
|
|
||||||
|
* **Windows / Linux / Web**: Not supported.
|
||||||
|
|
||||||
|
|
||||||
## Command Queue
|
## Command Queue
|
||||||
|
|
||||||
By default, all commands are executed in a global queue (`QueueType.global`), with each command waiting for the previous one to finish. While this method is slower it is the safest to avoid command exceptions and therefore is the default.
|
By default, all commands are executed in a global queue (`QueueType.global`), with each command waiting for the previous one to finish. While this method is slower it is the safest to avoid command exceptions and therefore is the default.
|
||||||
|
|||||||
@@ -529,6 +529,7 @@ interface UniversalBlePlatformChannel {
|
|||||||
fun unPair(deviceId: String)
|
fun unPair(deviceId: String)
|
||||||
fun getSystemDevices(withServices: List<String>, callback: (Result<List<UniversalBleScanResult>>) -> Unit)
|
fun getSystemDevices(withServices: List<String>, callback: (Result<List<UniversalBleScanResult>>) -> Unit)
|
||||||
fun getConnectionState(deviceId: String): Long
|
fun getConnectionState(deviceId: String): Long
|
||||||
|
fun readRssi(deviceId: String, callback: (Result<Long>) -> Unit)
|
||||||
fun setLogLevel(logLevel: UniversalBleLogLevel)
|
fun setLogLevel(logLevel: UniversalBleLogLevel)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -919,6 +920,26 @@ interface UniversalBlePlatformChannel {
|
|||||||
channel.setMessageHandler(null)
|
channel.setMessageHandler(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
run {
|
||||||
|
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi$separatedMessageChannelSuffix", codec)
|
||||||
|
if (api != null) {
|
||||||
|
channel.setMessageHandler { message, reply ->
|
||||||
|
val args = message as List<Any?>
|
||||||
|
val deviceIdArg = args[0] as String
|
||||||
|
api.readRssi(deviceIdArg) { result: Result<Long> ->
|
||||||
|
val error = result.exceptionOrNull()
|
||||||
|
if (error != null) {
|
||||||
|
reply.reply(UniversalBlePigeonUtils.wrapError(error))
|
||||||
|
} else {
|
||||||
|
val data = result.getOrNull()
|
||||||
|
reply.reply(UniversalBlePigeonUtils.wrapResult(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
channel.setMessageHandler(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
run {
|
run {
|
||||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel$separatedMessageChannelSuffix", codec)
|
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel$separatedMessageChannelSuffix", codec)
|
||||||
if (api != null) {
|
if (api != null) {
|
||||||
|
|||||||
@@ -343,4 +343,9 @@ class SubscriptionResultFuture(
|
|||||||
val characteristicId: String,
|
val characteristicId: String,
|
||||||
val serviceId: String,
|
val serviceId: String,
|
||||||
val result: (Result<Unit>) -> Unit,
|
val result: (Result<Unit>) -> Unit,
|
||||||
|
)
|
||||||
|
|
||||||
|
class RssiResultFuture(
|
||||||
|
val deviceId: String,
|
||||||
|
val result: (Result<Long>) -> Unit,
|
||||||
)
|
)
|
||||||
@@ -60,6 +60,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
|||||||
private val writeResultFutureList = mutableListOf<WriteResultFuture>()
|
private val writeResultFutureList = mutableListOf<WriteResultFuture>()
|
||||||
private val subscriptionResultFutureList = mutableListOf<SubscriptionResultFuture>()
|
private val subscriptionResultFutureList = mutableListOf<SubscriptionResultFuture>()
|
||||||
private val pairResultFutures = mutableMapOf<String, (Result<Boolean>) -> Unit>()
|
private val pairResultFutures = mutableMapOf<String, (Result<Boolean>) -> Unit>()
|
||||||
|
private val rssiResultFutureList = mutableListOf<RssiResultFuture>()
|
||||||
|
|
||||||
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||||
UniversalBlePlatformChannel.setUp(flutterPluginBinding.binaryMessenger, this)
|
UniversalBlePlatformChannel.setUp(flutterPluginBinding.binaryMessenger, this)
|
||||||
@@ -279,6 +280,49 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
|||||||
UniversalBleLogger.setLogLevel(logLevel)
|
UniversalBleLogger.setLogLevel(logLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun readRssi(deviceId: String, callback: (Result<Long>) -> Unit) {
|
||||||
|
try {
|
||||||
|
val gatt = deviceId.toBluetoothGatt()
|
||||||
|
if (gatt.readRemoteRssi()) {
|
||||||
|
rssiResultFutureList.add(RssiResultFuture(deviceId, callback))
|
||||||
|
} else {
|
||||||
|
callback(
|
||||||
|
Result.failure(
|
||||||
|
createFlutterError(
|
||||||
|
UniversalBleErrorCode.FAILED,
|
||||||
|
"Failed to read RSSI"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (e: FlutterError) {
|
||||||
|
callback(Result.failure(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReadRemoteRssi(gatt: BluetoothGatt?, rssi: Int, status: Int) {
|
||||||
|
val deviceId = gatt?.device?.address ?: return
|
||||||
|
rssiResultFutureList.removeAll {
|
||||||
|
if (it.deviceId == deviceId) {
|
||||||
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
|
it.result(Result.success(rssi.toLong()))
|
||||||
|
} else {
|
||||||
|
it.result(
|
||||||
|
Result.failure(
|
||||||
|
createFlutterError(
|
||||||
|
UniversalBleErrorCode.FAILED,
|
||||||
|
"Failed to read RSSI"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun discoverServices(
|
override fun discoverServices(
|
||||||
deviceId: String,
|
deviceId: String,
|
||||||
withDescriptors: Boolean,
|
withDescriptors: Boolean,
|
||||||
@@ -311,36 +355,44 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
|||||||
|
|
||||||
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
|
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
|
||||||
if (status != BluetoothGatt.GATT_SUCCESS) {
|
if (status != BluetoothGatt.GATT_SUCCESS) {
|
||||||
discoverServicesFutureList.filter { it.deviceId == gatt.device.address }.forEach {
|
discoverServicesFutureList.removeAll {
|
||||||
discoverServicesFutureList.remove(it)
|
if (it.deviceId == gatt.device.address) {
|
||||||
it.result(
|
it.result(
|
||||||
Result.failure(
|
Result.failure(
|
||||||
createFlutterError(
|
createFlutterError(
|
||||||
UniversalBleErrorCode.FAILED,
|
UniversalBleErrorCode.FAILED,
|
||||||
"Failed to discover services"
|
"Failed to discover services"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setCachedServices(gatt.device.address, gatt.services.map { it.uuid.toString() })
|
setCachedServices(gatt.device.address, gatt.services.map { it.uuid.toString() })
|
||||||
discoverServicesFutureList.filter { it.deviceId == gatt.device.address }.forEach {
|
discoverServicesFutureList.removeAll {
|
||||||
discoverServicesFutureList.remove(it)
|
if (it.deviceId == gatt.device.address) {
|
||||||
it.result(Result.success(gatt.services.map { service ->
|
it.result(Result.success(gatt.services.map { service ->
|
||||||
UniversalBleService(
|
UniversalBleService(
|
||||||
uuid = service.uuid.toString(),
|
uuid = service.uuid.toString(),
|
||||||
characteristics = service.characteristics.map { char ->
|
characteristics = service.characteristics.map { char ->
|
||||||
UniversalBleCharacteristic(
|
UniversalBleCharacteristic(
|
||||||
uuid = char.uuid.toString(),
|
uuid = char.uuid.toString(),
|
||||||
properties = char.getPropertiesList(),
|
properties = char.getPropertiesList(),
|
||||||
descriptors = if (it.withDescriptors) char.descriptors.map { descriptor ->
|
descriptors = if (it.withDescriptors) char.descriptors.map { descriptor ->
|
||||||
UniversalBleDescriptor(descriptor.uuid.toString())
|
UniversalBleDescriptor(descriptor.uuid.toString())
|
||||||
} else listOf()
|
} else listOf()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,29 +569,31 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
|||||||
value: ByteArray,
|
value: ByteArray,
|
||||||
status: Int,
|
status: Int,
|
||||||
) {
|
) {
|
||||||
readResultFutureList.filter {
|
readResultFutureList.removeAll {
|
||||||
it.deviceId == gatt.device.address &&
|
if (it.deviceId == gatt.device.address &&
|
||||||
it.characteristicId == characteristic.uuid.toString() &&
|
it.characteristicId == characteristic.uuid.toString() &&
|
||||||
it.serviceId == characteristic.service.uuid.toString()
|
it.serviceId == characteristic.service.uuid.toString()
|
||||||
}.forEach {
|
) {
|
||||||
readResultFutureList.remove(it)
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
it.result(Result.success(value))
|
||||||
it.result(Result.success(value))
|
} else {
|
||||||
} else {
|
UniversalBleLogger.logError(
|
||||||
UniversalBleLogger.logError(
|
"READ_FAILED <- ${gatt.device.address} ${characteristic.uuid} status=$status"
|
||||||
"READ_FAILED <- ${gatt.device.address} ${characteristic.uuid} status=$status"
|
)
|
||||||
)
|
it.result(
|
||||||
it.result(
|
Result.failure(
|
||||||
Result.failure(
|
createFlutterError(
|
||||||
createFlutterError(
|
gattStatusToUniversalBleErrorCode(status),
|
||||||
gattStatusToUniversalBleErrorCode(status),
|
"Failed to read",
|
||||||
"Failed to read",
|
status.toString()
|
||||||
status.toString()
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,27 +694,30 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
|||||||
characteristic: BluetoothGattCharacteristic,
|
characteristic: BluetoothGattCharacteristic,
|
||||||
status: Int,
|
status: Int,
|
||||||
) {
|
) {
|
||||||
writeResultFutureList.filter {
|
writeResultFutureList.removeAll {
|
||||||
it.deviceId == gatt?.device?.address &&
|
if (it.deviceId == gatt?.device?.address &&
|
||||||
it.characteristicId == characteristic.uuid.toString() &&
|
it.characteristicId == characteristic.uuid.toString() &&
|
||||||
it.serviceId == characteristic.service.uuid.toString()
|
it.serviceId == characteristic.service.uuid.toString()
|
||||||
}.forEach {
|
) {
|
||||||
writeResultFutureList.remove(it)
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
it.result(Result.success(Unit))
|
||||||
it.result(Result.success(Unit))
|
} else {
|
||||||
} else {
|
UniversalBleLogger.logError(
|
||||||
UniversalBleLogger.logError(
|
"WRITE_FAILED <- ${gatt?.device?.address} ${characteristic.uuid} status=$status"
|
||||||
"WRITE_FAILED <- ${gatt?.device?.address} ${characteristic.uuid} status=$status"
|
)
|
||||||
)
|
it.result(
|
||||||
it.result(
|
Result.failure(
|
||||||
Result.failure(
|
createFlutterError(
|
||||||
createFlutterError(
|
gattStatusToUniversalBleErrorCode(status),
|
||||||
gattStatusToUniversalBleErrorCode(status),
|
"Failed to write",
|
||||||
"Failed to write",
|
status.toString()
|
||||||
status.toString()
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -679,19 +736,23 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
|||||||
|
|
||||||
override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) {
|
override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) {
|
||||||
val deviceId = gatt?.device?.address ?: return
|
val deviceId = gatt?.device?.address ?: return
|
||||||
mtuResultFutureList.filter { it.deviceId == deviceId }.forEach {
|
mtuResultFutureList.removeAll {
|
||||||
mtuResultFutureList.remove(it)
|
if (it.deviceId == deviceId) {
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
it.result(Result.success(mtu.toLong()))
|
it.result(Result.success(mtu.toLong()))
|
||||||
} else {
|
} else {
|
||||||
it.result(
|
it.result(
|
||||||
Result.failure(
|
Result.failure(
|
||||||
createFlutterError(
|
createFlutterError(
|
||||||
UniversalBleErrorCode.FAILED,
|
UniversalBleErrorCode.FAILED,
|
||||||
"Failed to change MTU"
|
"Failed to change MTU"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -941,6 +1002,14 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rssiResultFutureList.removeAll {
|
||||||
|
if (it.deviceId == gatt.device.address) {
|
||||||
|
it.result(Result.failure(deviceDisconnectedError))
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onBondStateUpdate(deviceId: String, bonded: Boolean, error: String? = null) {
|
private fun onBondStateUpdate(deviceId: String, bonded: Boolean, error: String? = null) {
|
||||||
@@ -1116,24 +1185,27 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
|
|||||||
service: String,
|
service: String,
|
||||||
status: Int,
|
status: Int,
|
||||||
) {
|
) {
|
||||||
subscriptionResultFutureList.filter {
|
subscriptionResultFutureList.removeAll {
|
||||||
it.deviceId == deviceId &&
|
if (it.deviceId == deviceId &&
|
||||||
it.characteristicId == characteristic &&
|
it.characteristicId == characteristic &&
|
||||||
it.serviceId == service
|
it.serviceId == service
|
||||||
}.forEach {
|
) {
|
||||||
subscriptionResultFutureList.remove(it)
|
if (status != BluetoothGatt.GATT_SUCCESS) {
|
||||||
if (status != BluetoothGatt.GATT_SUCCESS) {
|
it.result(
|
||||||
it.result(
|
Result.failure(
|
||||||
Result.failure(
|
createFlutterError(
|
||||||
createFlutterError(
|
gattStatusToUniversalBleErrorCode(status),
|
||||||
gattStatusToUniversalBleErrorCode(status),
|
"Failed to update subscription state",
|
||||||
"Failed to update subscription state",
|
status.toString()
|
||||||
status.toString()
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
} else {
|
||||||
|
it.result(Result.success(Unit))
|
||||||
|
}
|
||||||
|
true
|
||||||
} else {
|
} else {
|
||||||
it.result(Result.success(Unit))
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -548,6 +548,7 @@ protocol UniversalBlePlatformChannel {
|
|||||||
func unPair(deviceId: String) throws
|
func unPair(deviceId: String) throws
|
||||||
func getSystemDevices(withServices: [String], completion: @escaping (Result<[UniversalBleScanResult], Error>) -> Void)
|
func getSystemDevices(withServices: [String], completion: @escaping (Result<[UniversalBleScanResult], Error>) -> Void)
|
||||||
func getConnectionState(deviceId: String) throws -> Int64
|
func getConnectionState(deviceId: String) throws -> Int64
|
||||||
|
func readRssi(deviceId: String, completion: @escaping (Result<Int64, Error>) -> Void)
|
||||||
func setLogLevel(logLevel: UniversalBleLogLevel) throws
|
func setLogLevel(logLevel: UniversalBleLogLevel) throws
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -882,6 +883,23 @@ class UniversalBlePlatformChannelSetup {
|
|||||||
} else {
|
} else {
|
||||||
getConnectionStateChannel.setMessageHandler(nil)
|
getConnectionStateChannel.setMessageHandler(nil)
|
||||||
}
|
}
|
||||||
|
let readRssiChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
|
||||||
|
if let api = api {
|
||||||
|
readRssiChannel.setMessageHandler { message, reply in
|
||||||
|
let args = message as! [Any?]
|
||||||
|
let deviceIdArg = args[0] as! String
|
||||||
|
api.readRssi(deviceId: deviceIdArg) { result in
|
||||||
|
switch result {
|
||||||
|
case .success(let res):
|
||||||
|
reply(wrapResult(res))
|
||||||
|
case .failure(let error):
|
||||||
|
reply(wrapError(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
readRssiChannel.setMessageHandler(nil)
|
||||||
|
}
|
||||||
let setLogLevelChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
|
let setLogLevelChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
|
||||||
if let api = api {
|
if let api = api {
|
||||||
setLogLevelChannel.setMessageHandler { message, reply in
|
setLogLevelChannel.setMessageHandler { message, reply in
|
||||||
|
|||||||
@@ -258,3 +258,13 @@ class DiscoverServicesFuture {
|
|||||||
self.result = result
|
self.result = result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RssiReadFuture {
|
||||||
|
let deviceId: String
|
||||||
|
let result: (Result<Int64, Error>) -> Void
|
||||||
|
|
||||||
|
init(deviceId: String, result: @escaping (Result<Int64, Error>) -> Void) {
|
||||||
|
self.deviceId = deviceId
|
||||||
|
self.result = result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
|||||||
private var characteristicWriteWithoutResponseFutures = [CharacteristicWriteFuture]()
|
private var characteristicWriteWithoutResponseFutures = [CharacteristicWriteFuture]()
|
||||||
private var characteristicNotifyFutures = [CharacteristicNotifyFuture]()
|
private var characteristicNotifyFutures = [CharacteristicNotifyFuture]()
|
||||||
private var discoverServicesFutures = [DiscoverServicesFuture]()
|
private var discoverServicesFutures = [DiscoverServicesFuture]()
|
||||||
|
private var rssiReadFutures = [RssiReadFuture]()
|
||||||
private var isManageScanning = false
|
private var isManageScanning = false
|
||||||
|
|
||||||
init(callbackChannel: UniversalBleCallbackChannel) {
|
init(callbackChannel: UniversalBleCallbackChannel) {
|
||||||
@@ -200,6 +201,15 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
rssiReadFutures.removeAll { future in
|
||||||
|
if future.deviceId == deviceId {
|
||||||
|
future.result(
|
||||||
|
Result.failure(createFlutterError(code: .deviceDisconnected, message: "Device Disconnected"))
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
activeServiceDiscoveries[deviceId]?.cleanup()
|
activeServiceDiscoveries[deviceId]?.cleanup()
|
||||||
activeServiceDiscoveries[deviceId] = nil
|
activeServiceDiscoveries[deviceId] = nil
|
||||||
}
|
}
|
||||||
@@ -334,6 +344,16 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
|||||||
completion(Result.success(mtuResult))
|
completion(Result.success(mtuResult))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readRssi(deviceId: String, completion: @escaping (Result<Int64, Error>) -> Void) {
|
||||||
|
UniversalBleLogger.shared.logDebug("READ_RSSI -> \(deviceId)")
|
||||||
|
guard let peripheral = deviceId.findPeripheral(manager: manager) else {
|
||||||
|
completion(Result.failure(createFlutterError(code: .deviceNotFound, message: "Unknown deviceId:\(deviceId)")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
peripheral.readRSSI()
|
||||||
|
rssiReadFutures.append(RssiReadFuture(deviceId: deviceId, result: completion))
|
||||||
|
}
|
||||||
|
|
||||||
func isPaired(deviceId _: String, completion: @escaping (Result<Bool, Error>) -> Void) {
|
func isPaired(deviceId _: String, completion: @escaping (Result<Bool, Error>) -> Void) {
|
||||||
completion(Result.failure(createFlutterError(code: .notSupported)))
|
completion(Result.failure(createFlutterError(code: .notSupported)))
|
||||||
}
|
}
|
||||||
@@ -531,6 +551,21 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
|
||||||
|
rssiReadFutures.removeAll { future in
|
||||||
|
if future.deviceId == peripheral.uuid.uuidString {
|
||||||
|
if let flutterError = error?.toFlutterError() {
|
||||||
|
UniversalBleLogger.shared.logError("READ_RSSI_FAILED <- \(peripheral.uuid.uuidString): \(flutterError.message ?? "")")
|
||||||
|
future.result(Result.failure(flutterError))
|
||||||
|
} else {
|
||||||
|
future.result(Result.success(RSSI.int64Value))
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CBPeripheral {
|
extension CBPeripheral {
|
||||||
|
|||||||
@@ -113,6 +113,12 @@ class MockUniversalBle extends UniversalBlePlatform {
|
|||||||
return 512;
|
return 512;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int> readRssi(String deviceId) async {
|
||||||
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
|
return -50; // Mock RSSI value in dBm
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> setNotifiable(String deviceId, String service,
|
Future<void> setNotifiable(String deviceId, String service,
|
||||||
String characteristic, BleInputProperty bleInputProperty) async {}
|
String characteristic, BleInputProperty bleInputProperty) async {}
|
||||||
|
|||||||
@@ -1097,6 +1097,30 @@ class _PeripheralDetailPageState extends State<PeripheralDetailPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
OutlinedButton.icon(
|
||||||
|
onPressed: isConnected
|
||||||
|
? () async {
|
||||||
|
try {
|
||||||
|
int rssi = await bleDevice.readRssi();
|
||||||
|
_addLog('RSSI', '$rssi dBm');
|
||||||
|
} catch (e) {
|
||||||
|
_addLog('ReadRssiError (${e.runtimeType})', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
icon: const Icon(Icons.signal_cellular_alt),
|
||||||
|
label: const Text('Get RSSI'),
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
foregroundColor: colorScheme.onSurface,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 16,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
if (BleCapabilities.supportsRequestMtuApi)
|
if (BleCapabilities.supportsRequestMtuApi)
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
onPressed: isConnected
|
onPressed: isConnected
|
||||||
|
|||||||
@@ -26,6 +26,19 @@ class BleDevice {
|
|||||||
Future<BleConnectionState> get connectionState =>
|
Future<BleConnectionState> get connectionState =>
|
||||||
UniversalBle.getConnectionState(deviceId);
|
UniversalBle.getConnectionState(deviceId);
|
||||||
|
|
||||||
|
/// Read the RSSI value of this connected device.
|
||||||
|
///
|
||||||
|
/// Returns the current RSSI value in dBm. This value indicates the signal strength
|
||||||
|
/// between the device and the connected peripheral. Lower (more negative) values
|
||||||
|
/// indicate weaker signal, while higher (less negative) values indicate stronger signal.
|
||||||
|
///
|
||||||
|
/// **Note**: The device must be connected before reading RSSI.
|
||||||
|
///
|
||||||
|
/// Throws [BleException] if:
|
||||||
|
/// - The device is not connected
|
||||||
|
/// - Reading RSSI fails
|
||||||
|
Future<int> readRssi() => UniversalBle.readRssi(deviceId);
|
||||||
|
|
||||||
/// On web, it returns true if the web browser supports receiving advertisements from this device.
|
/// On web, it returns true if the web browser supports receiving advertisements from this device.
|
||||||
/// The rest of the platforms will always return true.
|
/// The rest of the platforms will always return true.
|
||||||
bool get receivesAdvertisements =>
|
bool get receivesAdvertisements =>
|
||||||
|
|||||||
@@ -340,6 +340,28 @@ class UniversalBle {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read the RSSI value of a connected device.
|
||||||
|
///
|
||||||
|
/// Returns the current RSSI value in dBm. This value indicates the signal strength
|
||||||
|
/// between the device and the connected peripheral. Lower (more negative) values
|
||||||
|
/// indicate weaker signal, while higher (less negative) values indicate stronger signal.
|
||||||
|
///
|
||||||
|
/// **Note**: The device must be connected before reading RSSI.
|
||||||
|
///
|
||||||
|
/// Throws [BleException] if:
|
||||||
|
/// - The device is not connected
|
||||||
|
/// - Reading RSSI fails
|
||||||
|
static Future<int> readRssi(
|
||||||
|
String deviceId, {
|
||||||
|
Duration? timeout,
|
||||||
|
}) async {
|
||||||
|
return await _bleCommandQueue.queueCommand(
|
||||||
|
() => _platform.readRssi(deviceId),
|
||||||
|
timeout: timeout,
|
||||||
|
deviceId: deviceId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if a device is paired.
|
/// Check if a device is paired.
|
||||||
///
|
///
|
||||||
/// For `Apple` and `Web`, you have to pass a "pairingCommand" with an encrypted read or write characteristic.
|
/// For `Apple` and `Web`, you have to pass a "pairingCommand" with an encrypted read or write characteristic.
|
||||||
|
|||||||
@@ -378,6 +378,14 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int> readRssi(String deviceId) async {
|
||||||
|
throw UniversalBleException(
|
||||||
|
code: UniversalBleErrorCode.notImplemented,
|
||||||
|
message: "readRssi is not implemented on Linux platform",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> pair(String deviceId) async {
|
Future<bool> pair(String deviceId) async {
|
||||||
BlueZDevice device = _findDeviceById(deviceId);
|
BlueZDevice device = _findDeviceById(deviceId);
|
||||||
|
|||||||
@@ -1106,6 +1106,35 @@ class UniversalBlePlatformChannel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<int> readRssi(String deviceId) async {
|
||||||
|
final pigeonVar_channelName =
|
||||||
|
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi$pigeonVar_messageChannelSuffix';
|
||||||
|
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||||
|
pigeonVar_channelName,
|
||||||
|
pigeonChannelCodec,
|
||||||
|
binaryMessenger: pigeonVar_binaryMessenger,
|
||||||
|
);
|
||||||
|
final Future<Object?> pigeonVar_sendFuture =
|
||||||
|
pigeonVar_channel.send(<Object?>[deviceId]);
|
||||||
|
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
|
||||||
|
if (pigeonVar_replyList == null) {
|
||||||
|
throw _createConnectionError(pigeonVar_channelName);
|
||||||
|
} else if (pigeonVar_replyList.length > 1) {
|
||||||
|
throw PlatformException(
|
||||||
|
code: pigeonVar_replyList[0]! as String,
|
||||||
|
message: pigeonVar_replyList[1] as String?,
|
||||||
|
details: pigeonVar_replyList[2],
|
||||||
|
);
|
||||||
|
} else if (pigeonVar_replyList[0] == null) {
|
||||||
|
throw PlatformException(
|
||||||
|
code: 'null-error',
|
||||||
|
message: 'Host platform returned null value for non-null return value.',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (pigeonVar_replyList[0] as int?)!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> setLogLevel(UniversalBleLogLevel logLevel) async {
|
Future<void> setLogLevel(UniversalBleLogLevel logLevel) async {
|
||||||
final pigeonVar_channelName =
|
final pigeonVar_channelName =
|
||||||
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel$pigeonVar_messageChannelSuffix';
|
'dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel$pigeonVar_messageChannelSuffix';
|
||||||
|
|||||||
@@ -133,6 +133,10 @@ class UniversalBlePigeonChannel extends UniversalBlePlatform {
|
|||||||
_executeWithErrorHandling(
|
_executeWithErrorHandling(
|
||||||
() => _channel.requestMtu(deviceId, expectedMtu));
|
() => _channel.requestMtu(deviceId, expectedMtu));
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int> readRssi(String deviceId) =>
|
||||||
|
_executeWithErrorHandling(() => _channel.readRssi(deviceId));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isPaired(String deviceId) =>
|
Future<bool> isPaired(String deviceId) =>
|
||||||
_executeWithErrorHandling(() => _channel.isPaired(deviceId));
|
_executeWithErrorHandling(() => _channel.isPaired(deviceId));
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ abstract class UniversalBlePlatform {
|
|||||||
|
|
||||||
Future<int> requestMtu(String deviceId, int expectedMtu);
|
Future<int> requestMtu(String deviceId, int expectedMtu);
|
||||||
|
|
||||||
|
Future<int> readRssi(String deviceId);
|
||||||
|
|
||||||
Future<bool> isPaired(String deviceId);
|
Future<bool> isPaired(String deviceId);
|
||||||
|
|
||||||
Future<bool> pair(String deviceId);
|
Future<bool> pair(String deviceId);
|
||||||
|
|||||||
@@ -283,6 +283,15 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `Unimplemented`
|
||||||
|
@override
|
||||||
|
Future<int> readRssi(String deviceId) {
|
||||||
|
throw UniversalBleException(
|
||||||
|
code: UniversalBleErrorCode.notImplemented,
|
||||||
|
message: "readRssi is not implemented on Web platform",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isPaired(String deviceId) {
|
Future<bool> isPaired(String deviceId) {
|
||||||
throw UniversalBleException(
|
throw UniversalBleException(
|
||||||
|
|||||||
@@ -93,6 +93,9 @@ abstract class UniversalBlePlatformChannel {
|
|||||||
|
|
||||||
int getConnectionState(String deviceId);
|
int getConnectionState(String deviceId);
|
||||||
|
|
||||||
|
@async
|
||||||
|
int readRssi(String deviceId);
|
||||||
|
|
||||||
void setLogLevel(UniversalBleLogLevel logLevel);
|
void setLogLevel(UniversalBleLogLevel logLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
name: universal_ble
|
name: universal_ble
|
||||||
description: A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE) plugin for Flutter
|
description: A cross-platform (Android/iOS/macOS/Windows/Linux/Web) Bluetooth Low Energy (BLE) plugin for Flutter
|
||||||
version: 1.0.1+3
|
version: 1.1.0
|
||||||
homepage: https://navideck.com
|
homepage: https://navideck.com
|
||||||
repository: https://github.com/Navideck/universal_ble
|
repository: https://github.com/Navideck/universal_ble
|
||||||
issue_tracker: https://github.com/Navideck/universal_ble/issues
|
issue_tracker: https://github.com/Navideck/universal_ble/issues
|
||||||
|
|||||||
@@ -132,4 +132,9 @@ class _UniversalBleMock extends UniversalBlePlatformMock {
|
|||||||
Future<void> requestPermissions({bool withAndroidFineLocation = false}) {
|
Future<void> requestPermissions({bool withAndroidFineLocation = false}) {
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int> readRssi(String deviceId) async {
|
||||||
|
return -50; // Mock RSSI value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1189,6 +1189,35 @@ void UniversalBlePlatformChannel::SetUp(
|
|||||||
channel.SetMessageHandler(nullptr);
|
channel.SetMessageHandler(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.readRssi" + prepended_suffix, &GetCodec());
|
||||||
|
if (api != nullptr) {
|
||||||
|
channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply<EncodableValue>& reply) {
|
||||||
|
try {
|
||||||
|
const auto& args = std::get<EncodableList>(message);
|
||||||
|
const auto& encodable_device_id_arg = args.at(0);
|
||||||
|
if (encodable_device_id_arg.IsNull()) {
|
||||||
|
reply(WrapError("device_id_arg unexpectedly null."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& device_id_arg = std::get<std::string>(encodable_device_id_arg);
|
||||||
|
api->ReadRssi(device_id_arg, [reply](ErrorOr<int64_t>&& output) {
|
||||||
|
if (output.has_error()) {
|
||||||
|
reply(WrapError(output.error()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EncodableList wrapped;
|
||||||
|
wrapped.push_back(EncodableValue(std::move(output).TakeValue()));
|
||||||
|
reply(EncodableValue(std::move(wrapped)));
|
||||||
|
});
|
||||||
|
} catch (const std::exception& exception) {
|
||||||
|
reply(WrapError(exception.what()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
channel.SetMessageHandler(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
{
|
{
|
||||||
BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel" + prepended_suffix, &GetCodec());
|
BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.universal_ble.UniversalBlePlatformChannel.setLogLevel" + prepended_suffix, &GetCodec());
|
||||||
if (api != nullptr) {
|
if (api != nullptr) {
|
||||||
|
|||||||
@@ -435,6 +435,9 @@ class UniversalBlePlatformChannel {
|
|||||||
const flutter::EncodableList& with_services,
|
const flutter::EncodableList& with_services,
|
||||||
std::function<void(ErrorOr<flutter::EncodableList> reply)> result) = 0;
|
std::function<void(ErrorOr<flutter::EncodableList> reply)> result) = 0;
|
||||||
virtual ErrorOr<int64_t> GetConnectionState(const std::string& device_id) = 0;
|
virtual ErrorOr<int64_t> GetConnectionState(const std::string& device_id) = 0;
|
||||||
|
virtual void ReadRssi(
|
||||||
|
const std::string& device_id,
|
||||||
|
std::function<void(ErrorOr<int64_t> reply)> result) = 0;
|
||||||
virtual std::optional<FlutterError> SetLogLevel(const UniversalBleLogLevel& log_level) = 0;
|
virtual std::optional<FlutterError> SetLogLevel(const UniversalBleLogLevel& log_level) = 0;
|
||||||
|
|
||||||
// The codec used by UniversalBlePlatformChannel.
|
// The codec used by UniversalBlePlatformChannel.
|
||||||
|
|||||||
@@ -451,6 +451,13 @@ void UniversalBlePlugin::RequestMtu(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UniversalBlePlugin::ReadRssi(
|
||||||
|
const std::string &device_id,
|
||||||
|
std::function<void(ErrorOr<int64_t> reply)> result) {
|
||||||
|
result(create_flutter_error(UniversalBleErrorCode::kNotImplemented,
|
||||||
|
"readRssi is not implemented on Windows platform"));
|
||||||
|
}
|
||||||
|
|
||||||
void UniversalBlePlugin::IsPaired(
|
void UniversalBlePlugin::IsPaired(
|
||||||
const std::string &device_id,
|
const std::string &device_id,
|
||||||
std::function<void(ErrorOr<bool> reply)> result) {
|
std::function<void(ErrorOr<bool> reply)> result) {
|
||||||
|
|||||||
@@ -200,6 +200,8 @@ private:
|
|||||||
std::function<void(std::optional<FlutterError> reply)> result) override;
|
std::function<void(std::optional<FlutterError> reply)> result) override;
|
||||||
void RequestMtu(const std::string &device_id, int64_t expected_mtu,
|
void RequestMtu(const std::string &device_id, int64_t expected_mtu,
|
||||||
std::function<void(ErrorOr<int64_t> reply)> result) override;
|
std::function<void(ErrorOr<int64_t> reply)> result) override;
|
||||||
|
void ReadRssi(const std::string &device_id,
|
||||||
|
std::function<void(ErrorOr<int64_t> reply)> result) override;
|
||||||
void IsPaired(const std::string &device_id,
|
void IsPaired(const std::string &device_id,
|
||||||
std::function<void(ErrorOr<bool> reply)> result) override;
|
std::function<void(ErrorOr<bool> reply)> result) override;
|
||||||
void Pair(const std::string &device_id,
|
void Pair(const std::string &device_id,
|
||||||
|
|||||||
Reference in New Issue
Block a user