From f65023b4c7f51a1d9a421b1d2f4c9ae84da41207 Mon Sep 17 00:00:00 2001 From: Vineyro Date: Thu, 13 Jun 2024 14:06:48 +0700 Subject: [PATCH] kotlin ble migration --- .../ble/app/ui/screen/ble/BleListViewModel.kt | 2 - .../llc/arma/ble/data/BleRepositoryImpl.kt | 42 +--- .../arma/ble/data/ReadAccelerometerHistory.kt | 6 +- .../data/ReadAccelerometerSpectreCallback.kt | 167 ++++++------- .../data/ReadTemperatureHistoryCallback.kt | 139 +++++++++++ .../arma/ble/data/WriteThermometerCallback.kt | 230 ------------------ 6 files changed, 228 insertions(+), 358 deletions(-) delete mode 100644 app/src/main/java/llc/arma/ble/data/WriteThermometerCallback.kt diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/ble/BleListViewModel.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/ble/BleListViewModel.kt index 59bbc6d..85b5bff 100644 --- a/app/src/main/java/llc/arma/ble/app/ui/screen/ble/BleListViewModel.kt +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/ble/BleListViewModel.kt @@ -11,8 +11,6 @@ import kotlinx.coroutines.launch import llc.arma.ble.app.ui.common.BaseViewModel import llc.arma.ble.domain.usecase.ExportToXlsx import llc.arma.ble.domain.usecase.GetBleAroundFlow -import llc.arma.ble.domain.usecase.GetConnectedBleDevices -import llc.arma.ble.domain.usecase.MeasureData import javax.inject.Inject @HiltViewModel diff --git a/app/src/main/java/llc/arma/ble/data/BleRepositoryImpl.kt b/app/src/main/java/llc/arma/ble/data/BleRepositoryImpl.kt index e2f4fe8..e92e17e 100644 --- a/app/src/main/java/llc/arma/ble/data/BleRepositoryImpl.kt +++ b/app/src/main/java/llc/arma/ble/data/BleRepositoryImpl.kt @@ -1,26 +1,17 @@ package llc.arma.ble.data -import android.Manifest import android.app.Application import android.bluetooth.* import android.bluetooth.le.ScanCallback import android.bluetooth.le.ScanResult import android.bluetooth.le.ScanSettings -import android.content.pm.PackageManager -import android.os.Build import android.os.SystemClock import android.util.Log -import androidx.core.app.ActivityCompat import kotlinx.coroutines.* import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach import llc.arma.ble.domain.Result import llc.arma.ble.domain.common.BleException import llc.arma.ble.domain.common.ProgressState @@ -37,22 +28,13 @@ import llc.arma.ble.domain.usecase.FftFrequency import llc.arma.ble.domain.usecase.FftViewMode import no.nordicsemi.android.common.core.DataByteArray import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt -import no.nordicsemi.android.kotlin.ble.core.scanner.BleNumOfMatches -import no.nordicsemi.android.kotlin.ble.core.scanner.BleScanMode import no.nordicsemi.android.kotlin.ble.core.scanner.BleScanResult -import no.nordicsemi.android.kotlin.ble.core.scanner.BleScannerCallbackType -import no.nordicsemi.android.kotlin.ble.core.scanner.BleScannerMatchMode -import no.nordicsemi.android.kotlin.ble.core.scanner.BleScannerSettings -import no.nordicsemi.android.kotlin.ble.scanner.BleScanner import no.nordicsemi.android.kotlin.ble.scanner.aggregator.BleScanResultAggregator import java.util.* import javax.inject.Inject import javax.inject.Singleton -import kotlin.coroutines.resume import kotlin.math.PI import kotlin.math.atan -import kotlin.math.pow -import kotlin.math.sqrt val FftFrequency.sendData: Byte @@ -728,6 +710,8 @@ class BleRepositoryImpl @Inject constructor( frequency: FftFrequency ): Flow>, BleException>> { + //return readAccelerometerSpectre(serial, app, accelScale, accelMode, fftAxis, fftMode, frequency) + var gatt: BluetoothGatt? = null return callbackFlow { @@ -769,7 +753,9 @@ class BleRepositoryImpl @Inject constructor( serial: String ): Flow>, BleException>> { - var gatt: BluetoothGatt? = null + return readThermometerHistory(serial, app) + + /*var gatt: BluetoothGatt? = null return callbackFlow { @@ -799,7 +785,7 @@ class BleRepositoryImpl @Inject constructor( gatt?.close() } - } + }*/ } @@ -1199,15 +1185,15 @@ class BleRepositoryImpl @Inject constructor( when(accelMode){ ANGLE -> { - x = calculateZAngle( + x = calculateAngle( data[2].toFloat(), data[1].toFloat() ) * 180f / Math.PI.toFloat() - y = calculateZAngle( + y = calculateAngle( data[2].toFloat(), data[0].toFloat() ) * 180f / Math.PI.toFloat() - z = calculateZAngle( + z = calculateAngle( data[0].toFloat(), data[1].toFloat() ) * 180f / Math.PI.toFloat() @@ -1287,16 +1273,6 @@ class BleRepositoryImpl @Inject constructor( } fun calculateAngle( - targetAxis: Float, - firstAxis: Float, - secondAxis: Float -): Float { - - return atan(targetAxis.div(sqrt(firstAxis.pow(2) + secondAxis.pow(2)))) - -} - -public fun calculateZAngle( x: Float, y: Float ): Float { diff --git a/app/src/main/java/llc/arma/ble/data/ReadAccelerometerHistory.kt b/app/src/main/java/llc/arma/ble/data/ReadAccelerometerHistory.kt index 969a7fa..e7905be 100644 --- a/app/src/main/java/llc/arma/ble/data/ReadAccelerometerHistory.kt +++ b/app/src/main/java/llc/arma/ble/data/ReadAccelerometerHistory.kt @@ -170,15 +170,15 @@ fun readAccelerometerHistory( resultTemperaturePackage.chunked(3).withIndex().map { Ble.Accelerometer.HistoryPoint.Angle( date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!), - x = calculateZAngle( + x = calculateAngle( it.value[2], it.value[1] ) * 180f / Math.PI.toFloat(), - y = calculateZAngle( + y = calculateAngle( it.value[2], it.value[0] ) * 180f / Math.PI.toFloat(), - z = calculateZAngle( + z = calculateAngle( it.value[0], it.value[1] ) * 180f / Math.PI.toFloat() diff --git a/app/src/main/java/llc/arma/ble/data/ReadAccelerometerSpectreCallback.kt b/app/src/main/java/llc/arma/ble/data/ReadAccelerometerSpectreCallback.kt index 2a4ee2c..067afa7 100644 --- a/app/src/main/java/llc/arma/ble/data/ReadAccelerometerSpectreCallback.kt +++ b/app/src/main/java/llc/arma/ble/data/ReadAccelerometerSpectreCallback.kt @@ -214,6 +214,8 @@ class ReadAccelerometerSpectreCallback( status: Int ){ + Log.d("value", value.joinToString(separator = "")) + if(status == BluetoothGatt.GATT_SUCCESS){ when(readProperty){ Property.DATA_SIZE -> { @@ -454,25 +456,24 @@ class ReadAccelerometerSpectreCallback( } -/* + @OptIn(ExperimentalUnsignedTypes::class) fun readAccelerometerSpectre( address: String, - mode: AccelViewMode, - scale: AccelScale, app: Application, + accelScale: AccelScale, + accelMode: AccelViewMode, + fftAxis: FftAxis, + fftMode: FftViewMode, + frequency: FftFrequency, ): Flow>, BleException>> { return flow { - var lastMeasureSystemTime: Long? = null - var bleMeasureInterval: Long? = null - var bleRealTime: Long? = null - var bleLastMeasureTime: Long? = null + var initialValue: Long? = null + var frequencyInterval: Long? = null - val resultTemperaturePackage: MutableList = mutableListOf() - - val result = mutableListOf>() + val resultAccelerometerPackage: MutableList = mutableListOf() var expectedDataSize: Int? = null @@ -484,15 +485,45 @@ fun readAccelerometerSpectre( ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.Default)) val characteristic = connection.discoverServices() + .findService(serviceUUID) + ?.findCharacteristic(accelerometerReadUUID) + ?: throw IllegalStateException() + + val historyCharacteristic = connection.discoverServices() .findService(serviceUUID) ?.findCharacteristic(accelerometerHistoryReadUUID) + ?: throw IllegalStateException() - if(characteristic != null) { + Log.d("notification", "-1") + + Log.d("notification", "0") + + characteristic.write(DataByteArray(byteArrayOf( + 4, + accelMode.sendData, + accelScale.sendData, + fftMode.sendData, + fftAxis.sendData, + frequency.sendData, + 2 + ))) + + Log.d("notification", "1") + + val notifications = characteristic.getNotifications() + + notifications.collect { - characteristic.write(DataByteArray.from(2)) - var value = characteristic.read().value + Log.d("notification", "0") + + historyCharacteristic.write(DataByteArray.from(2)) + + var value = historyCharacteristic.read().value + + Log.d("value", value.joinToString(separator = "")) + Log.d("value", value.get2byteUIntAt(0).toString()) if (value.contentEquals(byteArrayOf(0, 0))) { @@ -510,118 +541,74 @@ fun readAccelerometerSpectre( addAll(value.toList()) }.toByteArray() - characteristic.write(DataByteArray(writeData)) - value = characteristic.read().value + historyCharacteristic.write(DataByteArray(writeData)) + value = historyCharacteristic.read().value var nextPackageDataCount = value.get2byteUIntAt(2) while (nextPackageDataCount.toInt() != 0) { - val temperatureDataArray = if (value[0] == 250.toByte()) { + val accelerometerDataArray = if (value[0] == 250.toByte()) { - bleMeasureInterval = value.get4byteUIntAt(4).toLong() - bleLastMeasureTime = value.get4byteUIntAt(8).toLong() - bleRealTime = value.get4byteUIntAt(12).toLong() + initialValue = value.get4byteUIntAt(8).toLong() + frequencyInterval = value.get4byteUIntAt(4).toLong() - lastMeasureSystemTime = - System.currentTimeMillis() - ((bleRealTime!! - bleLastMeasureTime!!) * 1_000) - - value.toUByteArray().asList().subList(16, value.size) + value.asList().subList(16, value.size) } else { - - value.toUByteArray().asList().subList(4, value.size) + value.asList().subList(4, value.size) } - result.add(value.toUByteArray().toList()) nextPackageDataCount = value.get2byteUIntAt(2) - resultTemperaturePackage.addAll( - temperatureDataArray.chunked(2).map { - it.toUByteArray().toByteArray().get2byteShortAt().toFloat() + resultAccelerometerPackage.addAll( + accelerometerDataArray.chunked(2).map { + it.toByteArray().get2byteShortAt().toFloat() }.toMutableList() ) - Log.d( - "received data size", - (temperatureDataArray.chunked(2).size).toString() - ) - Log.d("next data size", nextPackageDataCount.toString()) + expectedDataSize = nextPackageDataCount.toInt() + resultAccelerometerPackage.size - expectedDataSize = - nextPackageDataCount.toInt() + resultTemperaturePackage.size + emit(Result.success(ProgressState.Progress(0f / expectedDataSize!!.toFloat()))) + emit(Result.success(ProgressState.Progress(resultAccelerometerPackage.size.toFloat() / expectedDataSize!!.toFloat()))) - emit(Result.success(ProgressState.Progress(0f / expectedDataSize.toFloat()))) - emit(Result.success(ProgressState.Progress(resultTemperaturePackage.size.toFloat() / expectedDataSize.toFloat()))) - - characteristic.write(DataByteArray.from(5)) - value = characteristic.read().value + historyCharacteristic.write(DataByteArray.from(5)) + value = historyCharacteristic.read().value } emit( Result.success( ProgressState.Finished( - when (mode) { - AccelViewMode.ROTATIONS, - AccelViewMode.ACCELERATION, - AccelViewMode.PEAK_ACCELERATION, - AccelViewMode.RMS -> { - resultTemperaturePackage.chunked(3).withIndex().map { - Ble.Accelerometer.HistoryPoint.Angle( - date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!), - x = (it.value[0] * scale.k) / Short.MAX_VALUE, - y = (it.value[1] * scale.k) / Short.MAX_VALUE, - z = (it.value[2] * scale.k) / Short.MAX_VALUE - ) - } - } - - AccelViewMode.ANGLE -> { - resultTemperaturePackage.chunked(3).withIndex().map { - Ble.Accelerometer.HistoryPoint.Angle( - date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!), - x = calculateZAngle( - it.value[2], - it.value[1] - ) * 180f / Math.PI.toFloat(), - y = calculateZAngle( - it.value[2], - it.value[0] - ) * 180f / Math.PI.toFloat(), - z = calculateZAngle( - it.value[0], - it.value[1] - ) * 180f / Math.PI.toFloat() - ) - } - } - - AccelViewMode.VIBRATION -> { - resultTemperaturePackage.withIndex().map { - Ble.Accelerometer.HistoryPoint.Vibration( - date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!), - value = (it.value * scale.k) / Short.MAX_VALUE - ) - } - } + resultAccelerometerPackage.withIndex().map { + Ble.Accelerometer.MeasurePoint( + frequency = frequencyInterval!! * it.index + initialValue!!, + value = (it.value * accelScale.k) / Short.MAX_VALUE + ) } ) ) ) + characteristic.write(DataByteArray(byteArrayOf( + 4, + accelMode.sendData, + accelScale.sendData, + fftMode.sendData, + fftAxis.sendData, + frequency.sendData, + 2 + ))) + } - - } else { - - emit(Result.failure(BleException.UnexpectedResponse)) - } + } catch (err: Throwable) { + err.printStackTrace() emit(Result.failure(BleException.UnexpectedResponse)) } @@ -636,4 +623,4 @@ fun readAccelerometerSpectre( -}*/ \ No newline at end of file +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/data/ReadTemperatureHistoryCallback.kt b/app/src/main/java/llc/arma/ble/data/ReadTemperatureHistoryCallback.kt index 70fe95c..256554d 100644 --- a/app/src/main/java/llc/arma/ble/data/ReadTemperatureHistoryCallback.kt +++ b/app/src/main/java/llc/arma/ble/data/ReadTemperatureHistoryCallback.kt @@ -9,10 +9,18 @@ import android.content.pm.PackageManager import android.os.Build import android.util.Log import androidx.core.app.ActivityCompat +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow import llc.arma.ble.domain.Result import llc.arma.ble.domain.common.BleException import llc.arma.ble.domain.common.ProgressState import llc.arma.ble.domain.model.Ble +import llc.arma.ble.domain.usecase.AccelScale +import llc.arma.ble.domain.usecase.AccelViewMode +import no.nordicsemi.android.common.core.DataByteArray +import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt class ReadTemperatureHistoryCallback( private val app: Application, @@ -319,4 +327,135 @@ class ReadTemperatureHistoryCallback( } +} + +@OptIn(ExperimentalUnsignedTypes::class) +fun readThermometerHistory( + address: String, + app: Application, +): Flow>, BleException>> { + + return flow { + + var lastMeasureSystemTime: Long? = null + + var bleMeasureInterval: Long? = null + var bleRealTime: Long? = null + var bleLastMeasureTime: Long? = null + + val resultTemperaturePackage: MutableList = mutableListOf() + + var expectedDataSize: Int? = null + + if (app.checkPermission()) { + + try { + + val connection = + ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.Default)) + + val characteristic = connection.discoverServices() + .findService(serviceUUID) + ?.findCharacteristic(temperatureHistoryReadUUID) + ?: throw IllegalStateException() + + characteristic.write(DataByteArray.from(2)) + + var value = characteristic.read().value + + if (value.contentEquals(byteArrayOf(0, 0))) { + + emit(Result.success(ProgressState.Finished(emptyList()))) + + } else { + + Log.d("expected data size", value.get2byteUIntAt(0).toString()) + + val writeData = mutableListOf( + 1.toByte(), + 0.toByte(), + 0.toByte() + ).apply { + addAll(value.toList()) + }.toByteArray() + + characteristic.write(DataByteArray(writeData)) + value = characteristic.read().value + var nextPackageDataCount = value.get2byteUIntAt(2) + + while (nextPackageDataCount.toInt() != 0) { + + val temperatureDataArray = if (value[0] == 250.toByte()) { + + bleMeasureInterval = value.get4byteUIntAt(4).toLong() + bleLastMeasureTime = value.get4byteUIntAt(8).toLong() + bleRealTime = value.get4byteUIntAt(12).toLong() + + lastMeasureSystemTime = + System.currentTimeMillis() - ((bleRealTime - bleLastMeasureTime) * 1_000) + + value.toUByteArray().asList().subList(16, value.size) + + } else { + + value.toUByteArray().asList().subList(4, value.size) + + } + + nextPackageDataCount = value.get2byteUIntAt(2) + + resultTemperaturePackage.addAll( + temperatureDataArray.chunked(2).map { + it.toUByteArray().toTemperature() + }.toMutableList() + ) + + Log.d( + "received data size", + (temperatureDataArray.chunked(2).size).toString() + ) + Log.d("next data size", nextPackageDataCount.toString()) + + expectedDataSize = + nextPackageDataCount.toInt() + resultTemperaturePackage.size + + emit(Result.success(ProgressState.Progress(0f / expectedDataSize.toFloat()))) + emit(Result.success(ProgressState.Progress(resultTemperaturePackage.size.toFloat() / expectedDataSize.toFloat()))) + + characteristic.write(DataByteArray.from(5)) + value = characteristic.read().value + + } + + emit( + Result.success( + ProgressState.Finished( + resultTemperaturePackage.withIndex().map { + Ble.Thermometer.MeasurePoint( + date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!), + value = it.value + ) + } + ) + ) + + ) + + } + + + } catch (err: Throwable) { + + emit(Result.failure(BleException.UnexpectedResponse)) + + } + + } else { + + emit(Result.failure(BleException.PermissionDenied)) + + } + + } + } \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/data/WriteThermometerCallback.kt b/app/src/main/java/llc/arma/ble/data/WriteThermometerCallback.kt deleted file mode 100644 index c8b1a6c..0000000 --- a/app/src/main/java/llc/arma/ble/data/WriteThermometerCallback.kt +++ /dev/null @@ -1,230 +0,0 @@ -package llc.arma.ble.data - -import android.Manifest -import android.app.Application -import android.bluetooth.BluetoothGatt -import android.bluetooth.BluetoothGattCallback -import android.bluetooth.BluetoothGattCharacteristic -import android.bluetooth.BluetoothProfile -import android.content.pm.PackageManager -import android.os.Build -import android.util.Log -import androidx.core.app.ActivityCompat -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import llc.arma.ble.domain.Result -import llc.arma.ble.domain.common.BleException -import llc.arma.ble.domain.model.Ble -import java.util.UUID - -class WriteThermometerCallback( - private val app: Application, - private var request: Ble.Thermometer.WriteRequest, - private val onResult: (Result) -> Unit -) : BluetoothGattCallback() { - - private var flashed = false - - override fun onConnectionStateChange( - gatt: BluetoothGatt, - status: Int, - newState: Int - ) { - super.onConnectionStateChange(gatt, status, newState) - - if(app.checkPermission()) { - - if(status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) { - - gatt.discoverServices() - - } else { - - onResult(Result.failure(BleException.UnexpectedResponse)) - - } - - } else { - - onResult(Result.failure(BleException.PermissionDenied)) - - } - - } - - override fun onServicesDiscovered( - gatt: BluetoothGatt, - status: Int - ) { - super.onServicesDiscovered(gatt, status) - onCycle(gatt, status) - - } - - private fun onCycle( - gatt: BluetoothGatt, - status: Int - ){ - - if(request.tx != null || request.saveHistory != null || request.historyInterval != null) { - - fun UInt.to4ByteArrayInLittleEndian(): ByteArray = - (3 downTo 0).map { - (this shr (it * Byte.SIZE_BITS)).toByte() - }.toByteArray() - - var uuid: Triple? = null - - uuid = request.historyInterval?.let { - - Triple( - intervalWriteUUID, - mutableListOf(3).apply { - addAll((it).toUInt().to4ByteArrayInLittleEndian().reversed().toList()) - }.toByteArray(), - request.copy( - historyInterval = null - ) - ) - } - - uuid = request.saveHistory?.let { - - Triple( - saveEnabledWriteUUID, - mutableListOf(4).apply { - add(if (it) 1 else 0) - }.toByteArray(), - request.copy( - saveHistory = null - ) - ) - } ?: uuid - - uuid = request.tx?.let { - - Triple( - txWriteUUID, - byteArrayOf( - when (it) { - Ble.BleState.TX.MINUS_40 -> -40 - Ble.BleState.TX.MINUS_20 -> -20 - Ble.BleState.TX.MINUS_16 -> -16 - Ble.BleState.TX.MINUS_12 -> -12 - Ble.BleState.TX.MINUS_8 -> -8 - Ble.BleState.TX.MINUS_4 -> -4 - Ble.BleState.TX.ZERO -> 0 - Ble.BleState.TX.PLUS_3 -> 3 - Ble.BleState.TX.PLUS_4 -> 4 - } - ), - request.copy( - tx = null - ) - ) - - } ?: uuid - - uuid?.let { uuid -> - - gatt.services.firstOrNull { it.uuid == serviceUUID }?.characteristics?.firstOrNull { - it.uuid == uuid.first - }?.let { - - gatt.writeCharacteristic(it, uuid.second) - request = uuid.third - return - - } - - } - - onResult(Result.failure(BleException.UnexpectedResponse)) - - } else { - - if(flashed.not()){ - - flashed = true - - gatt.services.firstOrNull { it.uuid == serviceUUID }?.characteristics?.firstOrNull { - it.uuid == flashWriteUUID - }?.let { - - gatt.writeCharacteristic(it, byteArrayOf(9)) - - return - - } - - onResult(Result.failure(BleException.UnexpectedResponse)) - - } else { - - onResult(Result.success(Unit)) - - } - - } - - } - - override fun onCharacteristicWrite( - gatt: BluetoothGatt, - characteristic: BluetoothGattCharacteristic, - status: Int - ) { - - super.onCharacteristicWrite(gatt, characteristic, status) - - if(app.checkPermission()) { - - if(status == BluetoothGatt.GATT_SUCCESS || flashed) { - - onCycle(gatt, status) - - } else { - - onResult(Result.failure(BleException.UnexpectedResponse)) - - } - - } else { - - onResult(Result.failure(BleException.PermissionDenied)) - - } - - } - - private fun BluetoothGatt.writeCharacteristic( - characteristic: BluetoothGattCharacteristic, - data: ByteArray - ): Result { - - return if(app.checkPermission()){ - - Log.d("write", data.asUByteArray().joinToString(" ") { it.toString(16).padStart(2, '0') }) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - writeCharacteristic(characteristic, data, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT) - }else{ - - characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT - characteristic.value = data - writeCharacteristic(characteristic) - } - - Result.success(Unit) - - } else { - Result.failure(BleException.PermissionDenied) - } - - } - - - -} \ No newline at end of file