diff --git a/.idea/misc.xml b/.idea/misc.xml index 0ad17cb..8978d23 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/app/build.gradle b/app/build.gradle index de104bc..bb587ea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { applicationId "llc.arma.ble" minSdk 24 targetSdk 33 - versionCode 4 - versionName "1.2.1" + versionCode 5 + versionName "1.2.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/AccelerometerScreen.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/AccelerometerScreen.kt index 711ad7c..db13006 100644 --- a/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/AccelerometerScreen.kt +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/AccelerometerScreen.kt @@ -1,6 +1,8 @@ package llc.arma.ble.app.ui.screen.inspection.accelerometer import androidx.compose.foundation.layout.Column +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.ModalBottomSheetValue import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect @@ -32,6 +34,7 @@ enum class SheetPage { MEASURE, POWER, WRITE, HISTORY, ACCEL_MODE_EDIT, SPECTRE_MODE_EDIT, SPECTRE_EDIT, FREQUENCY_EDIT, AXIS_EDIT, FFT_MODE_EDIT } +@OptIn(ExperimentalMaterialApi::class) @Composable fun AccelerometerScreen( ble: Ble.Accelerometer, @@ -42,6 +45,7 @@ fun AccelerometerScreen( val bottomDialog = rememberBottomDialogState() + LaunchedEffect(ble){ viewModel.setEvent(AccelerometerContract.Event.OnBleChanged(ble)) } @@ -50,6 +54,15 @@ fun AccelerometerScreen( mutableStateOf(null) } + LaunchedEffect( + key1 = bottomDialog.sheetState?.currentValue, + block = { + if(bottomDialog.sheetState?.currentValue == ModalBottomSheetValue.Hidden) { + sheetPage = null + } + } + ) + val scope = rememberCoroutineScope() LaunchedEffect(sheetPage) { diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AccelSpectreEdit.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AccelSpectreEdit.kt index 535bc14..7f86f83 100644 --- a/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AccelSpectreEdit.kt +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AccelSpectreEdit.kt @@ -86,47 +86,6 @@ fun AccelSpectreEdit( modifier = Modifier ) { - Box( - modifier = Modifier.padding( - vertical = 8.dp, - horizontal = 8.dp - ) - ) { - - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .clip(RoundedCornerShape(16.dp)) - .clickable { - onEvent(AccelerometerContract.Event.OnAccelViewModeEdit(next = AccelerometerContract.Event.OnAccelViewModeEdit.Next.SPECTRE)) - } - .padding(8.dp) - ) { - - Column( - modifier = Modifier.weight(1f) - ) { - - Text( - text = "Accel view mode" - ) - Text( - color = MaterialTheme.colorScheme.secondary, - style = MaterialTheme.typography.bodyMedium, - text = accelMode.localized - ) - - } - - Icon( - imageVector = Icons.Rounded.KeyboardArrowDown, - contentDescription = null - ) - - } - - } - Box( modifier = Modifier.padding( vertical = 8.dp, diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AcceleromterHistory.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AcceleromterHistory.kt index 98bf445..9186059 100644 --- a/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AcceleromterHistory.kt +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AcceleromterHistory.kt @@ -33,6 +33,9 @@ import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollState import com.patrykandpatrick.vico.core.axis.AxisPosition import com.patrykandpatrick.vico.core.axis.formatter.AxisValueFormatter import com.patrykandpatrick.vico.core.entry.ChartEntry +import com.patrykandpatrick.vico.core.entry.FloatEntry +import com.patrykandpatrick.vico.core.extension.sumByFloat +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import llc.arma.ble.domain.common.ProgressState @@ -82,23 +85,67 @@ fun AccelerometerHistory( val title = when(state){ is AccelerometerHistoryContract.State.Display -> { - when (state.loadingHistoryState) { - is ProgressState.Finished -> "${fftMode.localized} (${state.loadingHistoryState.data.size})" - else -> fftMode.localized + if (state.previousHistory !== null) { + "${fftMode.localized} (${state.previousHistory.size})" + }else { + fftMode.localized } } AccelerometerHistoryContract.State.Exception -> fftMode.localized } - Text( + Row( modifier = Modifier.weight(1f), - text = title, - style = MaterialTheme.typography.titleLarge - ) + verticalAlignment = Alignment.CenterVertically + ) { + + Text( + modifier = Modifier.padding(end = 16.dp), + text = title, + style = MaterialTheme.typography.titleLarge + ) + + if(state is AccelerometerHistoryContract.State.Display) { + + when (state.loadingHistoryState) { + is ProgressState.Indeterminate -> { + + CircularProgressIndicator( + modifier = Modifier.size(16.dp), + strokeWidth = 2.dp, + strokeCap = StrokeCap.Round, + ) + + } + is ProgressState.Progress -> { + + val progressAnimDuration = 1500 + val progressAnimation by animateFloatAsState( + targetValue = state.loadingHistoryState.value, + animationSpec = tween( + durationMillis = progressAnimDuration, + easing = FastOutSlowInEasing + ) + ) + + CircularProgressIndicator( + modifier = Modifier.size(16.dp), + strokeWidth = 2.dp, + strokeCap = StrokeCap.Round, + progress = progressAnimation, + ) + + } + else -> {} + } + + } + + } IconButton( onClick = { - viewModel.setEvent(AccelerometerHistoryContract.Event.OnRefreshHistory(ble.serial, accelMode, fftAxis, fftMode, frequency, accelScale)) + viewModel.setEvent(AccelerometerHistoryContract.Event.OnStart(ble.serial, accelMode, fftAxis, fftMode, frequency, accelScale)) }, enabled = when(state){ is AccelerometerHistoryContract.State.Display -> state.loadingHistoryState is ProgressState.Finished @@ -127,7 +174,14 @@ fun AccelerometerHistory( } } - + +val axisValueFormatter = AxisValueFormatter { value, chartValues -> + (chartValues.chartEntryModel.entries.firstOrNull() + ?.getOrNull(value.toInt()) as? AccelerometerEntry) + ?.frequency?.let { String.format("%.1f", (it.toFloat() / 256f)) } + .orEmpty() +} + @Composable fun Display( @@ -139,100 +193,89 @@ fun Display( .fillMaxSize() ) { - when (state.loadingHistoryState) { + val data = if(state.loadingHistoryState is ProgressState.Finished){ + state.loadingHistoryState.data + } else { + state.previousHistory + } - is ProgressState.Finished -> { + val producer = remember { + ChartEntryModelProducer(listOf()) + } - if(state.loadingHistoryState.data.isEmpty()){ + if(data != null){ - Text( - modifier = Modifier.align(Alignment.Center), - text = "Нет данных" - ) + if(data.isEmpty()){ - } else { + Text( + modifier = Modifier.align(Alignment.Center), + text = "Нет данных" + ) - val producer = remember(state.loadingHistoryState.data) { - state.loadingHistoryState.data.mapIndexed { index, measurePoint -> + } else { + + LaunchedEffect(data){ + producer.setEntries( + data.mapIndexed { index, measurePoint -> AccelerometerEntry(measurePoint.frequency, index.toFloat(), measurePoint.value) - }.let { - ChartEntryModelProducer(it) } - } - - val axisValueFormatter = - AxisValueFormatter { value, chartValues -> - (chartValues.chartEntryModel.entries.firstOrNull() - ?.getOrNull(value.toInt()) as? AccelerometerEntry) - ?.frequency?.let { String.format("%.1f", (it.toFloat() / 256f)) } - .orEmpty() - } - - val lineChart = columnChart( - spacing = 1.5.dp ) - - LaunchedEffect(state.loadingHistoryState.data){ - lineChart.bounds - lineChart.setBounds( - left = lineChart.bounds.left / 20, - top = lineChart.bounds.top, - right = lineChart.bounds.right / 20, - bottom = lineChart.bounds.bottom, - ) - } - - val scrollState = rememberChartScrollState() - - Chart( - isZoomEnabled = true, - chartScrollState = scrollState, - chart = lineChart, - chartModelProducer = producer, - startAxis = startAxis(), - bottomAxis = bottomAxis( - tickLength = 0.dp, - valueFormatter = axisValueFormatter, - labelRotationDegrees = -90f, - ), - modifier = Modifier.fillMaxSize() - ) - - - /*LaunchedEffect(scrollState.maxValue) { - scrollState.scrollBy(scrollState.maxValue) - }*/ - } - } - is ProgressState.Indeterminate -> { - - CircularProgressIndicator( - strokeCap = StrokeCap.Round, - modifier = Modifier.align(Alignment.Center) + val lineChart = columnChart( + spacing = 1.5.dp ) - } - is ProgressState.Progress -> { + val scrollState = rememberChartScrollState() - val progressAnimDuration = 1500 - val progressAnimation by animateFloatAsState( - targetValue = state.loadingHistoryState.value, - animationSpec = tween( - durationMillis = progressAnimDuration, - easing = FastOutSlowInEasing + Chart( + diffAnimationSpec = tween(0), + isZoomEnabled = true, + chartScrollState = scrollState, + chart = lineChart, + chartModelProducer = producer, + startAxis = startAxis(), + bottomAxis = bottomAxis( + tickLength = 0.dp, + valueFormatter = axisValueFormatter, + labelRotationDegrees = -90f, + ), + modifier = Modifier.fillMaxSize() + ) + + + } + + } else { + when (state.loadingHistoryState) { + is ProgressState.Indeterminate -> { + + CircularProgressIndicator( + strokeCap = StrokeCap.Round, + modifier = Modifier.align(Alignment.Center) ) - ) - CircularProgressIndicator( - strokeCap = StrokeCap.Round, - progress = progressAnimation, - modifier = Modifier.align(Alignment.Center) - ) + } + is ProgressState.Progress -> { + val progressAnimDuration = 1500 + val progressAnimation by animateFloatAsState( + targetValue = state.loadingHistoryState.value, + animationSpec = tween( + durationMillis = progressAnimDuration, + easing = FastOutSlowInEasing + ) + ) + + CircularProgressIndicator( + strokeCap = StrokeCap.Round, + progress = progressAnimation, + modifier = Modifier.align(Alignment.Center) + ) + + } + else -> {} } - } } @@ -286,6 +329,7 @@ class AccelerometerHistoryContract { sealed class State : ViewState { data class Display( + val previousHistory : List?, val loadingHistoryState : ProgressState> ) : State() @@ -306,10 +350,12 @@ class AccelerometerHistoryViewModel @Inject constructor( private val getAccelerometerSpectreBySerial: GetAccelerometerSpectreBySerial ) : BaseViewModel() { + private var job: Job? = null private var lastSerial: String? = null override fun setInitialState() = AccelerometerHistoryContract.State.Display( - ProgressState.Indeterminate + loadingHistoryState = ProgressState.Indeterminate, + previousHistory = null ) override fun handleEvents(event: AccelerometerHistoryContract.Event) { @@ -323,44 +369,81 @@ class AccelerometerHistoryViewModel @Inject constructor( state: AccelerometerHistoryContract.State, event: AccelerometerHistoryContract.Event.OnStart ) { + viewModelScope.launch { if(state is AccelerometerHistoryContract.State.Display) { //if(lastSerial != event.serial) { - lastSerial = event.serial + lastSerial = event.serial - setState { - AccelerometerHistoryContract.State.Display(ProgressState.Indeterminate) - } + setState { + AccelerometerHistoryContract.State.Display( + loadingHistoryState = ProgressState.Indeterminate, + previousHistory = when(state.loadingHistoryState){ + is ProgressState.Finished -> state.loadingHistoryState.data + is ProgressState.Indeterminate -> null + is ProgressState.Progress -> null + } + ) + } - getAccelerometerSpectreBySerial( - serial = event.serial, - accelMode = event.accelMode, - fftAxis = event.fftAxis, - fftMode = event.fftMode, - frequency = event.frequency, - accelScale = event.accelScale - ).onEach { - it.fold( - onSuccess = { - setState { - AccelerometerHistoryContract.State.Display(it) - } - }, - onFailure = { - setState { - AccelerometerHistoryContract.State.Exception - } - } - ) - }.launchIn(this) - - //} + } else { + setState { + AccelerometerHistoryContract.State.Display( + loadingHistoryState = ProgressState.Indeterminate, + previousHistory = null + ) + } } + job?.cancel() + job = getAccelerometerSpectreBySerial( + serial = event.serial, + accelMode = event.accelMode, + fftAxis = event.fftAxis, + fftMode = event.fftMode, + frequency = event.frequency, + accelScale = event.accelScale + ).onEach { + + val currentState = viewState.value + + Log.d("currentState", currentState.toString()) + + + if(currentState is AccelerometerHistoryContract.State.Display) { + + it.fold( + onSuccess = { + setState { + + AccelerometerHistoryContract.State.Display( + loadingHistoryState = it, + previousHistory = when (it) { + is ProgressState.Finished -> { + it.data + } + is ProgressState.Indeterminate -> currentState.previousHistory + is ProgressState.Progress -> currentState.previousHistory + } + ) + + } + }, + onFailure = { + setState { + AccelerometerHistoryContract.State.Exception + } + } + ) + + } + + }.launchIn(this) + } } @@ -369,7 +452,7 @@ class AccelerometerHistoryViewModel @Inject constructor( state: AccelerometerHistoryContract.State, event: AccelerometerHistoryContract.Event.OnRefreshHistory ) { - viewModelScope.launch { + /*viewModelScope.launch { setState { AccelerometerHistoryContract.State.Display(ProgressState.Indeterminate) @@ -397,7 +480,7 @@ class AccelerometerHistoryViewModel @Inject constructor( ) }.launchIn(this) - } + }*/ } } \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AcceleromterMeasure.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AcceleromterMeasure.kt index 21bbd02..ebddb5b 100644 --- a/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AcceleromterMeasure.kt +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AcceleromterMeasure.kt @@ -381,7 +381,7 @@ class AccelerometerMeasureViewModel @Inject constructor( z = ((9806.65f / (Short.MAX_VALUE / 2)) * it.z) * (accelScale.k / 2) ) ) - } + }.takeLast(10) AccelerometerMeasureContract.State.Display(dataList) } 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 5fa03c8..e4974dc 100644 --- a/app/src/main/java/llc/arma/ble/data/BleRepositoryImpl.kt +++ b/app/src/main/java/llc/arma/ble/data/BleRepositoryImpl.kt @@ -579,63 +579,9 @@ class BleRepositoryImpl @Inject constructor( if (checkPermission()) { - writeCharacteristic( - device = it, - serviceId = serviceUUID, - characteristicId = accelerometerReadUUID, - writeData = byteArrayOf( - 4, - accelMode.sendData, - accelScale.sendData, - fftMode.sendData, - fftAxis.sendData, - frequency.sendData, - 1 - ) - ).onFailure { - CoroutineScope(Dispatchers.IO).launch { - send(Result.failure(BleException.PermissionDenied)) - } - } - - var result = false - - while (result.not()){ - - writeCharacteristic( - device = it, - serviceId = serviceUUID, - characteristicId = accelerometerReadUUID, - writeData = byteArrayOf(4, 0) - ).onFailure { - CoroutineScope(Dispatchers.IO).launch { - send(Result.failure(BleException.PermissionDenied)) - } - } - - readCharacteristic( - device = it, - serviceId = serviceUUID, - characteristicId = accelerometerReadUUID - ).fold( - onSuccess = { readData -> - Log.d("read", readData.joinToString(", ")) - if(readData.isNotEmpty() && readData.first() == (0).toByte()){ - result = true - } else { - delay(200) - } - }, - onFailure = { - CoroutineScope(Dispatchers.IO).launch { - send(Result.failure(BleException.PermissionDenied)) - } - } - ) - - } - - gatt = it.connectGatt(app, false, ReadAccelerometerSpectreCallback(app) { + gatt = it.connectGatt(app, false, ReadAccelerometerSpectreCallback( + app, accelScale, accelMode, fftAxis, fftMode, frequency + ) { CoroutineScope(Dispatchers.IO).launch { send(it) } @@ -919,8 +865,6 @@ class BleRepositoryImpl @Inject constructor( ) { super.onServicesDiscovered(gatt, status) - Log.d("read", "onServicesDiscovered $status") - if (status == BluetoothGatt.GATT_SUCCESS) { gatt.services?.firstOrNull { service -> @@ -1068,8 +1012,6 @@ class BleRepositoryImpl @Inject constructor( ) { super.onServicesDiscovered(gatt, status) - Log.d("write", "onServicesDiscovered $status") - if (status == BluetoothGatt.GATT_SUCCESS) { gatt.services?.firstOrNull { service -> @@ -1114,8 +1056,6 @@ class BleRepositoryImpl @Inject constructor( ) { super.onCharacteristicWrite(gatt, characteristic, status) - Log.d("write", "onCharacteristicWrite $status") - if (checkPermission()) { gatt.close() diff --git a/app/src/main/java/llc/arma/ble/data/ReadAccelerometerCallback.kt b/app/src/main/java/llc/arma/ble/data/ReadAccelerometerCallback.kt index f2c4e0b..8e5624c 100644 --- a/app/src/main/java/llc/arma/ble/data/ReadAccelerometerCallback.kt +++ b/app/src/main/java/llc/arma/ble/data/ReadAccelerometerCallback.kt @@ -67,6 +67,8 @@ class ReadAccelerometerCallback( ) { super.onServicesDiscovered(gatt, status) + Log.d("accel", "onServicesDiscovered") + if(status == BluetoothGatt.GATT_SUCCESS){ gatt.getService(serviceUUID)?.getCharacteristic(accelerometerReadUUID)?.let { @@ -80,11 +82,9 @@ class ReadAccelerometerCallback( fftMode.sendData, fftAxis.sendData, frequency.sendData, - 2 + 1 ) - Log.d("payload", payload.joinToString(" - ")) - gatt.writeCharacteristic(it, payload) } else { @@ -107,14 +107,14 @@ class ReadAccelerometerCallback( ) { super.onCharacteristicWrite(gatt, characteristic, status) + Log.d("accel", "request written") + if(status == BluetoothGatt.GATT_SUCCESS){ gatt.getService(serviceUUID)?.getCharacteristic(accelerometerReadUUID)?.let { if (checkPermission()) { - Log.d("write", "enable notifications") - gatt.setCharacteristicNotification(it, true) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { @@ -162,6 +162,8 @@ class ReadAccelerometerCallback( value: ByteArray, ){ + Log.d("accel", "notification") + val data = value.toList().chunked(2).map { it.toByteArray().get2byteShortAt(0) } 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 b25a157..b278d3d 100644 --- a/app/src/main/java/llc/arma/ble/data/ReadAccelerometerSpectreCallback.kt +++ b/app/src/main/java/llc/arma/ble/data/ReadAccelerometerSpectreCallback.kt @@ -5,6 +5,7 @@ import android.app.Application import android.bluetooth.BluetoothGatt import android.bluetooth.BluetoothGattCallback import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothGattDescriptor import android.content.pm.PackageManager import android.os.Build import android.util.Log @@ -13,8 +14,14 @@ 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 llc.arma.ble.domain.usecase.FftAxis +import llc.arma.ble.domain.usecase.FftFrequency +import llc.arma.ble.domain.usecase.FftViewMode import java.nio.ByteBuffer import java.nio.ByteOrder.LITTLE_ENDIAN +import java.util.UUID fun ByteArray.get2byteShortAt(idx: Int): Int { val shorts = ShortArray(1) @@ -22,11 +29,21 @@ fun ByteArray.get2byteShortAt(idx: Int): Int { return shorts[0].toInt()//(this[0].toInt() + (this[1].toInt() shl 8)).toShort() } + class ReadAccelerometerSpectreCallback( private val app: Application, + private val accelScale: AccelScale, + private val accelMode: AccelViewMode, + private val fftAxis: FftAxis, + private val fftMode: FftViewMode, + private val frequency: FftFrequency, private val onResult: (Result>, BleException>) -> Unit ) : BluetoothGattCallback() { + enum class Property { + DATA_SIZE, PACKAGE + } + private fun ByteArray.get4byteUIntAt(idx: Int) = ((this[idx + 3].toUInt() and 0xFFu) shl 24) or ((this[idx + 2].toUInt() and 0xFFu) shl 16) or @@ -50,13 +67,17 @@ class ReadAccelerometerSpectreCallback( ) { super.onConnectionStateChange(gatt, status, newState) + Log.d("spectre", "onConnectionStateChange") + + + + if(status == BluetoothGatt.GATT_SUCCESS){ if(newState == BluetoothGatt.STATE_CONNECTED){ if (checkPermission()) { gatt.discoverServices() - } else { onResult(Result.failure(BleException.UnexpectedResponse)) gatt.close() @@ -77,38 +98,52 @@ class ReadAccelerometerSpectreCallback( status: Int ) { super.onServicesDiscovered(gatt, status) - Log.d("read", "discover ${status}") + Log.d("spectre", "onServicesDiscovered") if(status == BluetoothGatt.GATT_SUCCESS){ - gatt.getService(serviceUUID)?.getCharacteristic(accelerometerHistoryReadUUID)?.let { - - if (checkPermission()) { - - Log.d("read", "discovered") - - readProperty = Property.DATA_SIZE - gatt.writeCharacteristic(it, byteArrayOf(2)) - - } else { - - onResult(Result.failure(BleException.PermissionDenied)) - gatt.close() - - } - - return - - } - - onResult(Result.failure(BleException.UnexpectedResponse)) + enableNotifications(gatt) } } - //private var lastMeasureSystemTime: Long? = null + private fun enableNotifications( + gatt: BluetoothGatt + ){ + + gatt.getService(serviceUUID)?.getCharacteristic(accelerometerReadUUID)?.let { + + if (checkPermission()) { + + gatt.setCharacteristicNotification(it, true) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + gatt.writeDescriptor(it.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")), + BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) + } else { + val descriptor = it.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")) + descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE + gatt.writeDescriptor(descriptor) + } + + Log.d("spectre", "enable notification") + + onResult(Result.success(ProgressState.Indeterminate)) + resultAccelerometerPackage.clear() + + } else { + onResult(Result.failure(BleException.PermissionDenied)) + gatt.close() + } + + return + + } + + onResult(Result.failure(BleException.UnexpectedResponse)) + + } private var initialValue: Long? = null - //private var bleRealTime: Long? = null private var frequencyInterval: Long? = null private val resultAccelerometerPackage: MutableList = mutableListOf() @@ -127,6 +162,42 @@ class ReadAccelerometerSpectreCallback( } } + @Deprecated("Deprecated in Java") + override fun onCharacteristicChanged( + gatt: BluetoothGatt, + characteristic: BluetoothGattCharacteristic + ) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + super.onCharacteristicChanged(gatt, characteristic) + onCommonCharacteristicChanged(gatt, characteristic, characteristic.value) + } + } + + override fun onCharacteristicChanged( + gatt: BluetoothGatt, + characteristic: BluetoothGattCharacteristic, + value: ByteArray + ) { + super.onCharacteristicChanged(gatt, characteristic, value) + onCommonCharacteristicChanged(gatt, characteristic, value) + } + + private fun onCommonCharacteristicChanged( + gatt: BluetoothGatt, + characteristic: BluetoothGattCharacteristic, + value: ByteArray, + ){ + + if(characteristic.uuid == accelerometerReadUUID) { + Log.d("spectre", "changed") + readProperty = Property.DATA_SIZE + gatt.getService(serviceUUID).getCharacteristic(accelerometerHistoryReadUUID)?.let { + gatt.writeCharacteristic(it, byteArrayOf(2)) + } + + } + } + override fun onCharacteristicRead( gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, @@ -144,6 +215,8 @@ class ReadAccelerometerSpectreCallback( status: Int ){ + Log.d("spectre", "onCharacteristicRead") + if(status == BluetoothGatt.GATT_SUCCESS){ when(readProperty){ Property.DATA_SIZE -> { @@ -209,6 +282,7 @@ class ReadAccelerometerSpectreCallback( } } else { + onResult( Result.success( ProgressState.Finished( @@ -221,7 +295,9 @@ class ReadAccelerometerSpectreCallback( ) ) ) - gatt.close() + + start(gatt) + } } else { @@ -247,6 +323,7 @@ class ReadAccelerometerSpectreCallback( gatt.readCharacteristic(characteristic) } else { + onResult( Result.success( ProgressState.Finished( @@ -259,7 +336,9 @@ class ReadAccelerometerSpectreCallback( ) ) ) - gatt.close() + + start(gatt) + } } else { onResult(Result.failure(BleException.UnexpectedResponse)) @@ -285,11 +364,73 @@ class ReadAccelerometerSpectreCallback( status: Int ) { super.onCharacteristicWrite(gatt, characteristic, status) - if(status == BluetoothGatt.GATT_SUCCESS){ + + Log.d("spectre", "request written $readProperty") + + if(readProperty !== null) { + + if (status == BluetoothGatt.GATT_SUCCESS) { + + if (checkPermission()) { + + gatt.readCharacteristic(characteristic) + + } else { + + onResult(Result.failure(BleException.PermissionDenied)) + gatt.close() + + } + + } else { + onResult(Result.failure(BleException.UnexpectedResponse)) + gatt.close() + } + } + + } + + override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) { + super.onMtuChanged(gatt, mtu, status) + Log.d("spectre", "mtu $mtu") + } + + override fun onDescriptorWrite( + gatt: BluetoothGatt, + descriptor: BluetoothGattDescriptor, + status: Int + ) { + + Log.d("spectre", "descriptor written") + super.onDescriptorWrite(gatt, descriptor, status) + start(gatt) + + } + + private fun start( + gatt: BluetoothGatt, + ){ + + Log.d("spectre", "start") + + gatt.getService(serviceUUID)?.getCharacteristic(accelerometerReadUUID)?.let { if (checkPermission()) { - gatt.readCharacteristic(characteristic) + val payload = byteArrayOf( + 4, + accelMode.sendData, + accelScale.sendData, + fftMode.sendData, + fftAxis.sendData, + frequency.sendData, + 2 + ) + readProperty = null + gatt.writeCharacteristic(it, payload) + + onResult(Result.success(ProgressState.Indeterminate)) + resultAccelerometerPackage.clear() } else { @@ -298,14 +439,13 @@ class ReadAccelerometerSpectreCallback( } - } else { - onResult(Result.failure(BleException.UnexpectedResponse)) - gatt.close() + return + } } - fun checkPermission(): Boolean { + private fun checkPermission(): Boolean { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_CONNECT) == @@ -320,7 +460,7 @@ class ReadAccelerometerSpectreCallback( } } - fun BluetoothGatt.writeCharacteristic( + private fun BluetoothGatt.writeCharacteristic( characteristic: BluetoothGattCharacteristic, data: ByteArray ): Result{ diff --git a/app/src/main/java/llc/arma/ble/data/ReadHistoryCallback.kt b/app/src/main/java/llc/arma/ble/data/ReadHistoryCallback.kt index a8fcb0a..8fd0a37 100644 --- a/app/src/main/java/llc/arma/ble/data/ReadHistoryCallback.kt +++ b/app/src/main/java/llc/arma/ble/data/ReadHistoryCallback.kt @@ -133,7 +133,6 @@ class ReadHistoryCallback( value: ByteArray, status: Int ){ - Log.d("read", value[0].toString()) if(status == BluetoothGatt.GATT_SUCCESS){ when(readProperty){