|
|
@@ -18,12 +18,19 @@ import android.os.SystemClock
|
|
|
import com.iscs.comm.entity.BleConnectResult
|
|
|
import com.iscs.comm.entity.BleFrame
|
|
|
import com.iscs.comm.extension.byteArrayToHexString
|
|
|
+import com.iscs.comm.extension.hexToByteArray
|
|
|
import com.iscs.comm.protocol.BLEProtocol
|
|
|
import com.iscs.comm.utils.ISCSLog
|
|
|
import kotlinx.coroutines.CancellableContinuation
|
|
|
+import kotlinx.coroutines.CompletableDeferred
|
|
|
+import kotlinx.coroutines.Dispatchers
|
|
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
|
+import kotlinx.coroutines.TimeoutCancellationException
|
|
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
|
|
+import kotlinx.coroutines.withContext
|
|
|
+import kotlinx.coroutines.withTimeout
|
|
|
import java.util.UUID
|
|
|
+import java.util.concurrent.ConcurrentHashMap
|
|
|
|
|
|
/**
|
|
|
* 蓝牙连接管理器
|
|
|
@@ -56,6 +63,9 @@ class BLEManager(
|
|
|
// 连接回调
|
|
|
private var doneConnect: CancellableContinuation<BleConnectResult>? = null
|
|
|
|
|
|
+ // 待响应式的请求数据接收池
|
|
|
+ private val receiverPool = ConcurrentHashMap<String, CompletableDeferred<BleFrame>>()
|
|
|
+
|
|
|
// 蓝牙扫描回调
|
|
|
private val scanCallback = object : ScanCallback() {
|
|
|
|
|
|
@@ -84,6 +94,7 @@ class BLEManager(
|
|
|
@OptIn(ExperimentalCoroutinesApi::class)
|
|
|
private val gattCallback = object : BluetoothGattCallback() {
|
|
|
|
|
|
+ @SuppressLint("MissingPermission")
|
|
|
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
|
|
|
if (newState == BluetoothProfile.STATE_CONNECTED) {
|
|
|
ISCSLog.i(TAG, "gattCallback onConnectionStateChange() gatt connected")
|
|
|
@@ -93,6 +104,7 @@ class BLEManager(
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @SuppressLint("MissingPermission")
|
|
|
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
|
|
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
|
|
ISCSLog.i(TAG, "gattCallback onServicesDiscovered() find services success")
|
|
|
@@ -115,6 +127,7 @@ class BLEManager(
|
|
|
}.start()
|
|
|
}
|
|
|
|
|
|
+ @SuppressLint("MissingPermission")
|
|
|
override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray, status: Int) {
|
|
|
super.onCharacteristicRead(gatt, characteristic, value, status)
|
|
|
ISCSLog.i(TAG, "gattCallback onCharacteristicRead() ${gatt.readCharacteristic(characteristic)} ${value.contentToString()}")
|
|
|
@@ -128,6 +141,23 @@ class BLEManager(
|
|
|
override fun onCharacteristicChanged(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?) {
|
|
|
super.onCharacteristicChanged(gatt, characteristic)
|
|
|
ISCSLog.i(TAG, "gattCallback onCharacteristicChanged() get notification data ${characteristic?.value?.byteArrayToHexString(" ")}")
|
|
|
+ val data = characteristic?.value ?: byteArrayOf()
|
|
|
+ var key = ""
|
|
|
+ receiverPool.forEach { item ->
|
|
|
+ if (data.byteArrayToHexString().startsWith(item.key.split("_")[1])) {
|
|
|
+ // 找到指定响应体
|
|
|
+ key = item.key
|
|
|
+ return@forEach
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (key.isNotEmpty()) {
|
|
|
+ val deferred = receiverPool.remove(key)
|
|
|
+ if (deferred != null && !deferred.isCompleted) {
|
|
|
+ val spl = key.split("_")
|
|
|
+ val rspCodeLen = spl[1].length / 2
|
|
|
+ deferred.complete(BleFrame(spl[0].hexToByteArray(), data.copyOfRange(rspCodeLen, data.size), spl[1].hexToByteArray()))
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray) {
|
|
|
@@ -178,6 +208,7 @@ class BLEManager(
|
|
|
/**
|
|
|
* 连接设备,内部方法
|
|
|
*/
|
|
|
+ @SuppressLint("MissingPermission")
|
|
|
private fun innerConnect() {
|
|
|
// context -> app
|
|
|
// autoConnect -> false 避免设备连接异常
|
|
|
@@ -191,6 +222,7 @@ class BLEManager(
|
|
|
/**
|
|
|
* 断开连接
|
|
|
*/
|
|
|
+ @SuppressLint("MissingPermission")
|
|
|
fun disconnect() {
|
|
|
device?.let { gatt?.close() }
|
|
|
}
|
|
|
@@ -198,6 +230,7 @@ class BLEManager(
|
|
|
/**
|
|
|
* 是否使能Indicate
|
|
|
*/
|
|
|
+ @SuppressLint("MissingPermission")
|
|
|
private fun enableIndicate(): Boolean {
|
|
|
gatt?.getService(UUID.fromString(serviceUUID))?.getCharacteristic(UUID.fromString(indicateUUID))?.let {
|
|
|
// 开启通知
|
|
|
@@ -223,7 +256,10 @@ class BLEManager(
|
|
|
/**
|
|
|
* 写数据,带响应
|
|
|
*/
|
|
|
- fun writeByResponse(frame: BleFrame) {
|
|
|
+ @SuppressLint("MissingPermission")
|
|
|
+ suspend fun writeByResponse(frame: BleFrame) = withContext(Dispatchers.IO) {
|
|
|
+ val deferred = CompletableDeferred<BleFrame>()
|
|
|
+ receiverPool["${frame.reqCode.byteArrayToHexString()}_${frame.rspCode.byteArrayToHexString()}"] = deferred
|
|
|
// 发送数据方法兼容处理
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
|
gatt?.getService(UUID.fromString(serviceUUID))?.getCharacteristic(UUID.fromString(indicateUUID))?.let {
|
|
|
@@ -237,6 +273,11 @@ class BLEManager(
|
|
|
characteristic?.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
|
|
|
gatt?.writeCharacteristic(characteristic)
|
|
|
}
|
|
|
+ try {
|
|
|
+ withTimeout(1000) { deferred.await() }
|
|
|
+ } catch (_: TimeoutCancellationException) {
|
|
|
+ BleFrame(byteArrayOf(), byteArrayOf(), byteArrayOf())
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
}
|