Поправки по графикам

This commit is contained in:
Vineyro 2023-07-27 14:43:07 +07:00
parent d974df953d
commit 62205d27a0
21 changed files with 1440 additions and 153 deletions

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="jbr-17" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

View File

@ -1,8 +1,15 @@
package llc.arma.ble.app.ui package llc.arma.ble.app.ui
import android.Manifest import android.Manifest
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.KeyEvent
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
@ -16,8 +23,6 @@ import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -34,6 +39,7 @@ import llc.arma.ble.app.ui.theme.BleTheme
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@OptIn(ExperimentalPermissionsApi::class, ExperimentalMaterialApi::class) @OptIn(ExperimentalPermissionsApi::class, ExperimentalMaterialApi::class)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)

View File

@ -38,7 +38,7 @@ class BottomDialogState @OptIn(ExperimentalMaterialApi::class) constructor(
content: @Composable () -> Unit content: @Composable () -> Unit
){ ){
setContent(content) setContent(content)
if(sheetState?.currentValue != ModalBottomSheetValue.Expanded) //if(sheetState?.currentValue != ModalBottomSheetValue.Expanded)
sheetState?.show() sheetState?.show()
} }

View File

@ -4,20 +4,37 @@ import llc.arma.ble.app.ui.common.ViewEvent
import llc.arma.ble.app.ui.common.ViewSideEffect import llc.arma.ble.app.ui.common.ViewSideEffect
import llc.arma.ble.app.ui.common.ViewState import llc.arma.ble.app.ui.common.ViewState
import llc.arma.ble.app.ui.model.BleView import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.inspection.thermometer.ThermometerContract
import llc.arma.ble.domain.model.Ble 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
class AccelerometerContract { class AccelerometerContract {
sealed class Event : ViewEvent { sealed class Event : ViewEvent {
object OnShowAccelerometerMeasure : Event() object OnShowAccelerometerMeasure : Event()
object OnHideAccelerometerMeasure : Event() object OnHideAccelerometerMeasure : Event()
object OnShowAccelerometerHistory : Event() object OnShowAccelerometerSpectre : Event()
object OnHideAccelerometerSpectre : Event()
object OnHideAccelerometerHistory : Event() data class OnAccelViewModeEdit(
val next: Next
) : Event(){
enum class Next {
ACCEL, SPECTRE
}
}
object OnSpectreEdit : Event()
object OnFftFrequencyEdit : Event()
object OnFftAxisEdit : Event()
object OnFftModeEdit : Event()
object OnPowerEdit : Event() object OnPowerEdit : Event()
@ -35,6 +52,22 @@ class AccelerometerContract {
val tx: BleView.BleState.TX val tx: BleView.BleState.TX
) : Event() ) : Event()
data class OnAccelViewModelChanged(
val mode: AccelViewMode
) : Event()
data class OnFftFrequencyChanged(
val frequency: FftFrequency
) : Event()
data class OnFftAxisChanged(
val axis: FftAxis
) : Event()
data class OnFftModeChanged(
val mode: FftViewMode
) : Event()
} }
sealed class State : ViewState { sealed class State : ViewState {
@ -44,7 +77,12 @@ class AccelerometerContract {
data class Display( data class Display(
val origin: Ble.Accelerometer, val origin: Ble.Accelerometer,
val accelerometer: BleView.Accelerometer, val accelerometer: BleView.Accelerometer,
val writeState: WriteState? val writeState: WriteState?,
val accelViewMode: AccelViewMode,
val accelScale: AccelScale,
val fftViewMode: FftViewMode,
val fftAxis: FftAxis,
val fftFrequency: FftFrequency
) : State() { ) : State() {
sealed class WriteState { sealed class WriteState {
@ -70,17 +108,23 @@ class AccelerometerContract {
sealed class Effect : ViewSideEffect { sealed class Effect : ViewSideEffect {
object ShowAccelerometerMeasure : Effect() object ShowAccelerometerMeasure : Effect()
object ShowAccelerometerHistory : Effect() object ShowAccelerometerHistory : Effect()
object ShowPowerPicker : Effect() object ShowPowerPicker : Effect()
object HidePowerPicker : Effect() object HidePowerPicker : Effect()
object ShowWriteBle : Effect() object ShowWriteBle : Effect()
object HideWriteBle : Effect() object HideWriteBle : Effect()
data class ShowAccelEdit(
val next: Event.OnAccelViewModeEdit.Next
) : Effect()
object ShowSpectreEdit : Effect()
object ShowFftFrequencyEdit : Effect()
object ShowFftAxisEdit : Effect()
object ShowFftModeEdit : Effect()
} }
} }

View File

@ -15,6 +15,11 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import llc.arma.ble.app.ui.common.rememberBottomDialogState import llc.arma.ble.app.ui.common.rememberBottomDialogState
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelFftAxisEdit
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelFftModeEdit
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelFrequencyEdit
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelSpectreEdit
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelViewEdit
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelerometerHistory import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelerometerHistory
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelerometerMeasure import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelerometerMeasure
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.DisplayState import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.DisplayState
@ -24,7 +29,7 @@ import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.Write
import llc.arma.ble.domain.model.Ble import llc.arma.ble.domain.model.Ble
enum class SheetPage { enum class SheetPage {
MEASURE, POWER, WRITE, HISTORY MEASURE, POWER, WRITE, HISTORY, ACCEL_MODE_EDIT, SPECTRE_MODE_EDIT, SPECTRE_EDIT, FREQUENCY_EDIT, AXIS_EDIT, FFT_MODE_EDIT
} }
@Composable @Composable
@ -54,7 +59,14 @@ fun AccelerometerScreen(
if (currentState is AccelerometerContract.State.Display) { if (currentState is AccelerometerContract.State.Display) {
bottomDialog.show { bottomDialog.show {
AccelerometerMeasure(ble = currentState.accelerometer.info) AccelerometerMeasure(
ble = currentState.accelerometer.info,
accelMode = currentState.accelViewMode,
fftAxis = currentState.fftAxis,
fftMode = currentState.fftViewMode,
frequency = currentState.fftFrequency,
accelScale = currentState.accelScale
)
} }
} }
} }
@ -63,7 +75,14 @@ fun AccelerometerScreen(
if (currentState is AccelerometerContract.State.Display) { if (currentState is AccelerometerContract.State.Display) {
bottomDialog.show { bottomDialog.show {
AccelerometerHistory(ble = currentState.accelerometer.info) AccelerometerHistory(
ble = currentState.accelerometer.info,
accelMode = currentState.accelViewMode,
fftAxis = currentState.fftAxis,
fftMode = currentState.fftViewMode,
frequency = currentState.fftFrequency,
accelScale = currentState.accelScale
)
} }
} }
} }
@ -100,6 +119,92 @@ fun AccelerometerScreen(
} }
} }
SheetPage.ACCEL_MODE_EDIT -> bottomDialog.show {
val currentState = viewModel.viewState.value
if(currentState is AccelerometerContract.State.Display) {
AccelViewEdit(
next = AccelerometerContract.Event.OnAccelViewModeEdit.Next.ACCEL,
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
)
}
}
SheetPage.SPECTRE_MODE_EDIT -> bottomDialog.show {
val currentState = viewModel.viewState.value
if(currentState is AccelerometerContract.State.Display) {
AccelViewEdit(
next = AccelerometerContract.Event.OnAccelViewModeEdit.Next.SPECTRE,
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
)
}
}
SheetPage.SPECTRE_EDIT -> bottomDialog.show {
val currentState = viewModel.viewState.value
if(currentState is AccelerometerContract.State.Display) {
AccelSpectreEdit(
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
)
}
}
SheetPage.FREQUENCY_EDIT -> bottomDialog.show {
val currentState = viewModel.viewState.value
if(currentState is AccelerometerContract.State.Display) {
AccelFrequencyEdit(
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
)
}
}
SheetPage.AXIS_EDIT -> bottomDialog.show {
val currentState = viewModel.viewState.value
if(currentState is AccelerometerContract.State.Display) {
AccelFftAxisEdit(
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
)
}
}
SheetPage.FFT_MODE_EDIT -> bottomDialog.show {
val currentState = viewModel.viewState.value
if(currentState is AccelerometerContract.State.Display) {
AccelFftModeEdit(
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
)
}
}
null -> { null -> {
bottomDialog.hide() bottomDialog.hide()
} }
@ -117,7 +222,7 @@ fun AccelerometerScreen(
LaunchedEffect("effect"){ LaunchedEffect("effect"){
viewModel.effect.onEach { viewModel.effect.onEach {
when(it){ when(it){
AccelerometerContract.Effect.ShowAccelerometerMeasure -> { is AccelerometerContract.Effect.ShowAccelerometerMeasure -> launch {
sheetPage = null sheetPage = null
delay(100) delay(100)
sheetPage = SheetPage.MEASURE sheetPage = SheetPage.MEASURE
@ -131,21 +236,48 @@ fun AccelerometerScreen(
delay(100) delay(100)
sheetPage = SheetPage.POWER sheetPage = SheetPage.POWER
} }
is AccelerometerContract.Effect.HideWriteBle -> { is AccelerometerContract.Effect.HideWriteBle -> launch {
sheetPage = null sheetPage = null
delay(100) delay(100)
} }
is AccelerometerContract.Effect.ShowWriteBle -> { is AccelerometerContract.Effect.ShowWriteBle -> launch {
sheetPage = null sheetPage = null
delay(100) delay(100)
sheetPage = SheetPage.WRITE sheetPage = SheetPage.WRITE
} }
is AccelerometerContract.Effect.ShowAccelerometerHistory -> launch {
AccelerometerContract.Effect.ShowAccelerometerHistory -> {
sheetPage = null sheetPage = null
delay(100) delay(100)
sheetPage = SheetPage.HISTORY sheetPage = SheetPage.HISTORY
} }
is AccelerometerContract.Effect.ShowAccelEdit -> launch {
sheetPage = null
delay(100)
sheetPage = when(it.next){
AccelerometerContract.Event.OnAccelViewModeEdit.Next.ACCEL -> SheetPage.ACCEL_MODE_EDIT
AccelerometerContract.Event.OnAccelViewModeEdit.Next.SPECTRE -> SheetPage.SPECTRE_MODE_EDIT
}
}
is AccelerometerContract.Effect.ShowSpectreEdit -> launch {
sheetPage = null
delay(100)
sheetPage = SheetPage.SPECTRE_EDIT
}
is AccelerometerContract.Effect.ShowFftFrequencyEdit -> launch {
sheetPage = null
delay(100)
sheetPage = SheetPage.FREQUENCY_EDIT
}
is AccelerometerContract.Effect.ShowFftAxisEdit -> launch {
sheetPage = null
delay(100)
sheetPage = SheetPage.AXIS_EDIT
}
is AccelerometerContract.Effect.ShowFftModeEdit -> launch {
sheetPage = null
delay(100)
sheetPage = SheetPage.FFT_MODE_EDIT
}
} }
}.launchIn(this) }.launchIn(this)
} }

View File

@ -1,14 +1,20 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer package llc.arma.ble.app.ui.screen.inspection.accelerometer
import android.util.Log
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import llc.arma.ble.app.ui.common.BaseViewModel import llc.arma.ble.app.ui.common.BaseViewModel
import llc.arma.ble.app.ui.mapper.BleMapper import llc.arma.ble.app.ui.mapper.BleMapper
import llc.arma.ble.app.ui.mapper.BleViewMapper import llc.arma.ble.app.ui.mapper.BleViewMapper
import llc.arma.ble.app.ui.model.BleView import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.inspection.thermometer.ThermometerContract
import llc.arma.ble.domain.model.Ble 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 llc.arma.ble.domain.usecase.WriteBle import llc.arma.ble.domain.usecase.WriteBle
import javax.inject.Inject import javax.inject.Inject
@ -31,14 +37,118 @@ class AccelerometerViewModel @Inject constructor(
is AccelerometerContract.Event.OnShowWriteBlePreview -> reduce(viewState.value, event) is AccelerometerContract.Event.OnShowWriteBlePreview -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnHideWriteBlePreview -> reduce(viewState.value, event) is AccelerometerContract.Event.OnHideWriteBlePreview -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnWriteBle -> reduce(viewState.value, event) is AccelerometerContract.Event.OnWriteBle -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnHideAccelerometerHistory -> reduce(viewState.value, event) is AccelerometerContract.Event.OnHideAccelerometerSpectre -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnShowAccelerometerHistory -> reduce(viewState.value, event) is AccelerometerContract.Event.OnShowAccelerometerSpectre -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnAccelViewModeEdit -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnAccelViewModelChanged -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnSpectreEdit -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnFftFrequencyEdit -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnFftAxisChanged -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnFftFrequencyChanged -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnFftModeChanged -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnFftAxisEdit -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnFftModeEdit -> reduce(viewState.value, event)
} }
} }
private fun reduce( private fun reduce(
state: AccelerometerContract.State, state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnShowAccelerometerHistory event: AccelerometerContract.Event.OnFftModeEdit
) {
setEffect {
AccelerometerContract.Effect.ShowFftModeEdit
}
}
private fun reduce(
state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnFftAxisEdit
) {
setEffect {
AccelerometerContract.Effect.ShowFftAxisEdit
}
}
private fun reduce(
state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnFftAxisChanged
) {
if(state is AccelerometerContract.State.Display){
setState {
state.copy(
fftAxis = event.axis
)
}
}
}
private fun reduce(
state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnFftModeChanged
) {
if(state is AccelerometerContract.State.Display){
setState {
state.copy(
fftViewMode = event.mode
)
}
}
}
private fun reduce(
state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnFftFrequencyChanged
) {
if(state is AccelerometerContract.State.Display){
setState {
state.copy(
fftFrequency = event.frequency
)
}
}
}
private fun reduce(
state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnFftFrequencyEdit
) {
setEffect {
AccelerometerContract.Effect.ShowFftFrequencyEdit
}
}
private fun reduce(
state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnSpectreEdit
) {
setEffect {
AccelerometerContract.Effect.ShowSpectreEdit
}
}
private fun reduce(
state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnShowAccelerometerSpectre
) { ) {
setEffect { setEffect {
@ -49,7 +159,7 @@ class AccelerometerViewModel @Inject constructor(
private fun reduce( private fun reduce(
state: AccelerometerContract.State, state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnHideAccelerometerHistory event: AccelerometerContract.Event.OnHideAccelerometerSpectre
) { ) {
@ -123,6 +233,27 @@ class AccelerometerViewModel @Inject constructor(
} }
private fun reduce(
state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnAccelViewModelChanged
) {
if(state is AccelerometerContract.State.Display) {
setState {
state.copy(
accelViewMode = event.mode
)
}
}
setEffect {
AccelerometerContract.Effect.HidePowerPicker
}
}
private fun reduce( private fun reduce(
state: AccelerometerContract.State, state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnPowerEdit event: AccelerometerContract.Event.OnPowerEdit
@ -132,6 +263,15 @@ class AccelerometerViewModel @Inject constructor(
} }
} }
private fun reduce(
state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnAccelViewModeEdit
) {
setEffect {
AccelerometerContract.Effect.ShowAccelEdit(event.next)
}
}
private fun reduce( private fun reduce(
state: AccelerometerContract.State, state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnHideAccelerometerMeasure event: AccelerometerContract.Event.OnHideAccelerometerMeasure
@ -146,10 +286,16 @@ class AccelerometerViewModel @Inject constructor(
event: AccelerometerContract.Event.OnShowAccelerometerMeasure event: AccelerometerContract.Event.OnShowAccelerometerMeasure
) { ) {
setEffect { viewModelScope.launch {
AccelerometerContract.Effect.ShowAccelerometerMeasure
setEffect {
AccelerometerContract.Effect.ShowAccelerometerMeasure
}
} }
} }
private fun reduce( private fun reduce(
@ -171,7 +317,12 @@ class AccelerometerViewModel @Inject constructor(
AccelerometerContract.State.Display( AccelerometerContract.State.Display(
origin = event.ble, origin = event.ble,
accelerometer = bleMapper.map(event.ble) as BleView.Accelerometer, accelerometer = bleMapper.map(event.ble) as BleView.Accelerometer,
writeState = null writeState = null,
accelViewMode = AccelViewMode.ACCELERATION,
fftAxis = FftAxis.AUTO,
fftFrequency = FftFrequency.F_400,
fftViewMode = FftViewMode.SPECTRE,
accelScale = AccelScale.S_2
) )
} }
} }

View File

@ -0,0 +1,100 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
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
@Composable
fun AccelFftAxisEdit(
state: AccelerometerContract.State.Display,
onEvent: (AccelerometerContract.Event) -> Unit,
){
var fftAxis = state.fftAxis
Column(
modifier = Modifier
) {
Text(
modifier = Modifier.padding(horizontal = 12.dp),
text = "Fft axis",
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(16.dp))
FftAxis.values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable { onEvent(AccelerometerContract.Event.OnFftAxisChanged(it)) }
.padding(4.dp)
) {
RadioButton(
selected = it == fftAxis,
onClick = {
onEvent(AccelerometerContract.Event.OnFftAxisChanged(it))
}
)
Text(text = it.localized)
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnSpectreEdit)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
}
}
}

View File

@ -0,0 +1,100 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
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
@Composable
fun AccelFftModeEdit(
state: AccelerometerContract.State.Display,
onEvent: (AccelerometerContract.Event) -> Unit,
){
var fftMode = state.fftViewMode
Column(
modifier = Modifier
) {
Text(
modifier = Modifier.padding(horizontal = 12.dp),
text = "Fft view mode",
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(16.dp))
FftViewMode.values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable { onEvent(AccelerometerContract.Event.OnFftModeChanged(it)) }
.padding(4.dp)
) {
RadioButton(
selected = it == fftMode,
onClick = {
onEvent(AccelerometerContract.Event.OnFftModeChanged(it))
}
)
Text(text = it.localized)
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnSpectreEdit)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
}
}
}

View File

@ -0,0 +1,110 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
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
/*val AccelViewMode.localized: String
get() {
return when(this){
ACCELERATION -> "Ускорение"
PEAK_ACCELERATION -> "Пиковое ускорение"
RMS -> "Среднеквадратичное ускорение"
ANGLE -> "Угол"
}
}*/
@Composable
fun AccelFrequencyEdit(
state: AccelerometerContract.State.Display,
onEvent: (AccelerometerContract.Event) -> Unit,
){
var fftFrequency = state.fftFrequency
Column(
modifier = Modifier
) {
Text(
modifier = Modifier.padding(horizontal = 12.dp),
text = "Fft frequency",
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(16.dp))
FftFrequency.values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable { onEvent(AccelerometerContract.Event.OnFftFrequencyChanged(it)) }
.padding(4.dp)
) {
RadioButton(
selected = it == fftFrequency,
onClick = {
onEvent(AccelerometerContract.Event.OnFftFrequencyChanged(it))
}
)
Text(text = it.localized)
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnSpectreEdit)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
}
}
}

View File

@ -0,0 +1,282 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.domain.usecase.FftAxis
import llc.arma.ble.domain.usecase.FftFrequency
import llc.arma.ble.domain.usecase.FftViewMode
val FftFrequency.localized: String
get() {
return when(this){
FftFrequency.OFF -> "откл"
FftFrequency.F_1 -> "1 Гц"
FftFrequency.F_10 -> "10 Гц"
FftFrequency.F_25 -> "25 Гц"
FftFrequency.F_50 -> "50 Гц"
FftFrequency.F_100 -> "100 Гц"
FftFrequency.F_200 -> "200 Гц"
FftFrequency.F_400 -> "400 Гц"
FftFrequency.F_1620 -> "1620 Гц"
FftFrequency.F_1344 -> "1344 Гц"
}
}
val FftAxis.localized: String
get() {
return when(this){
FftAxis.AUTO -> "Авто"
FftAxis.X -> "Ось X"
FftAxis.Y -> "Ось Y"
FftAxis.Z -> "Ось Z"
}
}
val FftViewMode.localized: String
get() {
return when(this){
FftViewMode.SPECTRE -> "Спектр"
FftViewMode.X -> "Ось X"
FftViewMode.Y -> "Ось Y"
FftViewMode.Z -> "Ось Z"
}
}
@Composable
fun AccelSpectreEdit(
state: AccelerometerContract.State.Display,
onEvent: (AccelerometerContract.Event) -> Unit,
){
val accelMode = state.accelViewMode
val fftMode = state.fftViewMode
val fftAxis = state.fftAxis
val fftFrequency = state.fftFrequency
Column(
modifier = Modifier
) {
Text(
modifier = Modifier.padding(horizontal = 12.dp),
text = "Спектр",
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(16.dp))
Column(
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,
horizontal = 8.dp
)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.clickable {
onEvent(AccelerometerContract.Event.OnFftModeEdit)
}
.padding(8.dp)
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "Fft view mode"
)
Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
text = fftMode.localized
)
}
Icon(
imageVector = Icons.Rounded.KeyboardArrowDown,
contentDescription = null
)
}
}
Box(
modifier = Modifier.padding(
vertical = 8.dp,
horizontal = 8.dp
)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.clickable { onEvent(AccelerometerContract.Event.OnFftAxisEdit) }
.padding(8.dp)
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "Fft axis"
)
Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
text = fftAxis.localized
)
}
Icon(
imageVector = Icons.Rounded.KeyboardArrowDown,
contentDescription = null
)
}
}
Box(
modifier = Modifier.padding(
vertical = 8.dp,
horizontal = 8.dp
)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.clickable {
onEvent(AccelerometerContract.Event.OnFftFrequencyEdit)
}
.padding(8.dp)
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "Fft frequency"
)
Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
text = fftFrequency.localized
)
}
Icon(
imageVector = Icons.Rounded.KeyboardArrowDown,
contentDescription = null
)
}
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnShowAccelerometerSpectre)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Продолжить"
)
}
}
}
}

View File

@ -0,0 +1,118 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.app.ui.screen.inspection.thermometer.ThermometerContract
import llc.arma.ble.domain.usecase.AccelViewMode
import llc.arma.ble.domain.usecase.AccelViewMode.*
val AccelViewMode.localized: String
get() {
return when(this){
ACCELERATION -> "Ускорение"
PEAK_ACCELERATION -> "Пиковое ускорение"
RMS -> "Среднеквадратичное ускорение"
ANGLE -> "Угол"
}
}
@Composable
fun AccelViewEdit(
next: AccelerometerContract.Event.OnAccelViewModeEdit.Next,
state: AccelerometerContract.State.Display,
onEvent: (AccelerometerContract.Event) -> Unit,
){
var value by remember(state.accelViewMode) {
mutableStateOf(state.accelViewMode)
}
Column(
modifier = Modifier
) {
Text(
modifier = Modifier.padding(horizontal = 12.dp),
text = "Accel view mode",
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(16.dp))
values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable { value = it }
.padding(4.dp)
) {
RadioButton(
selected = it == value,
onClick = {
value = it
}
)
Text(text = it.localized)
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnAccelViewModelChanged(value))
when(next){
AccelerometerContract.Event.OnAccelViewModeEdit.Next.ACCEL -> {
onEvent(AccelerometerContract.Event.OnShowAccelerometerMeasure)
}
AccelerometerContract.Event.OnAccelViewModeEdit.Next.SPECTRE -> {
onEvent(AccelerometerContract.Event.OnSpectreEdit)
}
}
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Продолжить"
)
}
}
}
}

View File

@ -1,10 +1,9 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import android.util.Log
import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.foundation.gestures.detectTransformGestures
import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
@ -16,7 +15,6 @@ import androidx.lifecycle.viewModelScope
import com.patrykandpatrick.vico.compose.axis.horizontal.bottomAxis import com.patrykandpatrick.vico.compose.axis.horizontal.bottomAxis
import com.patrykandpatrick.vico.compose.axis.vertical.startAxis import com.patrykandpatrick.vico.compose.axis.vertical.startAxis
import com.patrykandpatrick.vico.compose.chart.Chart import com.patrykandpatrick.vico.compose.chart.Chart
import com.patrykandpatrick.vico.compose.chart.line.lineChart
import com.patrykandpatrick.vico.core.entry.ChartEntryModelProducer import com.patrykandpatrick.vico.core.entry.ChartEntryModelProducer
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -28,22 +26,23 @@ import llc.arma.ble.domain.model.BleInfo
import javax.inject.Inject import javax.inject.Inject
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Refresh import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import com.patrykandpatrick.vico.compose.chart.column.columnChart import com.patrykandpatrick.vico.compose.chart.column.columnChart
import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollState import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollState
import com.patrykandpatrick.vico.core.axis.AxisPosition import com.patrykandpatrick.vico.core.axis.AxisPosition
import com.patrykandpatrick.vico.core.axis.formatter.AxisValueFormatter import com.patrykandpatrick.vico.core.axis.formatter.AxisValueFormatter
import com.patrykandpatrick.vico.core.component.shape.LineComponent
import com.patrykandpatrick.vico.core.entry.ChartEntry import com.patrykandpatrick.vico.core.entry.ChartEntry
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import llc.arma.ble.domain.common.ProgressState import llc.arma.ble.domain.common.ProgressState
import llc.arma.ble.domain.model.Ble import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.usecase.GetAccelerometerHistoryBySerial import llc.arma.ble.domain.usecase.AccelScale
import java.util.* 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 llc.arma.ble.domain.usecase.GetAccelerometerSpectreBySerial
class AccelerometerEntry( class AccelerometerEntry(
val frequency: Long, val frequency: Long,
@ -57,14 +56,19 @@ class AccelerometerEntry(
@Composable @Composable
fun AccelerometerHistory( fun AccelerometerHistory(
ble: BleInfo ble: BleInfo,
accelMode: AccelViewMode,
fftAxis: FftAxis,
fftMode: FftViewMode,
frequency: FftFrequency,
accelScale: AccelScale
) { ) {
val viewModel = hiltViewModel<AccelerometerHistoryViewModel>() val viewModel = hiltViewModel<AccelerometerHistoryViewModel>()
val state = viewModel.viewState.value val state = viewModel.viewState.value
LaunchedEffect(ble.serial) { LaunchedEffect(ble.serial, accelMode, fftAxis, fftMode, frequency) {
viewModel.setEvent(AccelerometerHistoryContract.Event.OnStart(ble.serial)) viewModel.setEvent(AccelerometerHistoryContract.Event.OnStart(ble.serial, accelMode, fftAxis, fftMode, frequency, accelScale))
} }
Column( Column(
@ -79,12 +83,11 @@ fun AccelerometerHistory(
val title = when(state){ val title = when(state){
is AccelerometerHistoryContract.State.Display -> { is AccelerometerHistoryContract.State.Display -> {
when (state.loadingHistoryState) { when (state.loadingHistoryState) {
is ProgressState.Finished -> "История измерений (${state.loadingHistoryState.data.size})" is ProgressState.Finished -> "${fftMode.localized} (${state.loadingHistoryState.data.size})"
is ProgressState.Indeterminate -> "История измерений" else -> fftMode.localized
is ProgressState.Progress -> "История измерений"
} }
} }
AccelerometerHistoryContract.State.Exception -> "История измерений" AccelerometerHistoryContract.State.Exception -> fftMode.localized
} }
Text( Text(
@ -95,7 +98,7 @@ fun AccelerometerHistory(
IconButton( IconButton(
onClick = { onClick = {
viewModel.setEvent(AccelerometerHistoryContract.Event.OnRefreshHistory(ble.serial)) viewModel.setEvent(AccelerometerHistoryContract.Event.OnRefreshHistory(ble.serial, accelMode, fftAxis, fftMode, frequency, accelScale))
}, },
enabled = when(state){ enabled = when(state){
is AccelerometerHistoryContract.State.Display -> state.loadingHistoryState is ProgressState.Finished is AccelerometerHistoryContract.State.Display -> state.loadingHistoryState is ProgressState.Finished
@ -161,7 +164,7 @@ fun Display(
AxisValueFormatter<AxisPosition.Horizontal.Bottom> { value, chartValues -> AxisValueFormatter<AxisPosition.Horizontal.Bottom> { value, chartValues ->
(chartValues.chartEntryModel.entries.firstOrNull() (chartValues.chartEntryModel.entries.firstOrNull()
?.getOrNull(value.toInt()) as? AccelerometerEntry) ?.getOrNull(value.toInt()) as? AccelerometerEntry)
?.frequency?.let { it.toFloat() / 16f }?.toString() ?.frequency?.let { String.format("%.1f", (it.toFloat() / 256f)) }
.orEmpty() .orEmpty()
} }
@ -261,11 +264,21 @@ class AccelerometerHistoryContract {
sealed class Event : ViewEvent { sealed class Event : ViewEvent {
data class OnStart( data class OnStart(
val serial: String val serial: String,
val accelMode: AccelViewMode,
val fftAxis: FftAxis,
val fftMode: FftViewMode,
val frequency: FftFrequency,
val accelScale: AccelScale
) : Event() ) : Event()
data class OnRefreshHistory( data class OnRefreshHistory(
val serial: String val serial: String,
val accelMode: AccelViewMode,
val fftAxis: FftAxis,
val fftMode: FftViewMode,
val frequency: FftFrequency,
val accelScale: AccelScale
) : Event() ) : Event()
} }
@ -290,7 +303,7 @@ class AccelerometerHistoryContract {
@HiltViewModel @HiltViewModel
class AccelerometerHistoryViewModel @Inject constructor( class AccelerometerHistoryViewModel @Inject constructor(
private val getAccelerometerHistoryBySerial: GetAccelerometerHistoryBySerial private val getAccelerometerSpectreBySerial: GetAccelerometerSpectreBySerial
) : BaseViewModel<AccelerometerHistoryContract.State, AccelerometerHistoryContract.Event, AccelerometerHistoryContract.Effect>() { ) : BaseViewModel<AccelerometerHistoryContract.State, AccelerometerHistoryContract.Event, AccelerometerHistoryContract.Effect>() {
private var lastSerial: String? = null private var lastSerial: String? = null
@ -314,7 +327,7 @@ class AccelerometerHistoryViewModel @Inject constructor(
if(state is AccelerometerHistoryContract.State.Display) { if(state is AccelerometerHistoryContract.State.Display) {
if(lastSerial != event.serial) { //if(lastSerial != event.serial) {
lastSerial = event.serial lastSerial = event.serial
@ -322,7 +335,14 @@ class AccelerometerHistoryViewModel @Inject constructor(
AccelerometerHistoryContract.State.Display(ProgressState.Indeterminate) AccelerometerHistoryContract.State.Display(ProgressState.Indeterminate)
} }
getAccelerometerHistoryBySerial(event.serial).onEach { getAccelerometerSpectreBySerial(
serial = event.serial,
accelMode = event.accelMode,
fftAxis = event.fftAxis,
fftMode = event.fftMode,
frequency = event.frequency,
accelScale = event.accelScale
).onEach {
it.fold( it.fold(
onSuccess = { onSuccess = {
setState { setState {
@ -337,7 +357,7 @@ class AccelerometerHistoryViewModel @Inject constructor(
) )
}.launchIn(this) }.launchIn(this)
} //}
} }
@ -355,7 +375,14 @@ class AccelerometerHistoryViewModel @Inject constructor(
AccelerometerHistoryContract.State.Display(ProgressState.Indeterminate) AccelerometerHistoryContract.State.Display(ProgressState.Indeterminate)
} }
getAccelerometerHistoryBySerial(event.serial).onEach { getAccelerometerSpectreBySerial(
serial = event.serial,
accelMode = event.accelMode,
fftAxis = event.fftAxis,
fftMode = event.fftMode,
frequency = event.frequency,
accelScale = event.accelScale
).onEach {
it.fold( it.fold(
onSuccess = { onSuccess = {
setState { setState {

View File

@ -1,6 +1,5 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import android.util.Log
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material3.* import androidx.compose.material3.*
@ -26,7 +25,6 @@ import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import com.patrykandpatrick.vico.compose.axis.horizontal.bottomAxis import com.patrykandpatrick.vico.compose.axis.horizontal.bottomAxis
import com.patrykandpatrick.vico.compose.chart.column.columnChart
import com.patrykandpatrick.vico.compose.chart.line.lineChart import com.patrykandpatrick.vico.compose.chart.line.lineChart
import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollSpec import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollSpec
import com.patrykandpatrick.vico.core.chart.decoration.ThresholdLine import com.patrykandpatrick.vico.core.chart.decoration.ThresholdLine
@ -37,12 +35,22 @@ import com.patrykandpatrick.vico.core.scroll.InitialScroll
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import llc.arma.ble.domain.usecase.Accelereate import llc.arma.ble.domain.usecase.AccelScale
import llc.arma.ble.domain.usecase.AccelViewMode
import llc.arma.ble.domain.usecase.Accelerate
import llc.arma.ble.domain.usecase.FftAxis
import llc.arma.ble.domain.usecase.FftFrequency
import llc.arma.ble.domain.usecase.FftViewMode
import llc.arma.ble.domain.usecase.GetAccelerometerMeasureBySerialFlow import llc.arma.ble.domain.usecase.GetAccelerometerMeasureBySerialFlow
@Composable @Composable
fun AccelerometerMeasure( fun AccelerometerMeasure(
ble: BleInfo ble: BleInfo,
accelScale: AccelScale,
accelMode: AccelViewMode,
fftAxis: FftAxis,
fftMode: FftViewMode,
frequency: FftFrequency
) { ) {
val viewModel = hiltViewModel<AccelerometerMeasureViewModel>() val viewModel = hiltViewModel<AccelerometerMeasureViewModel>()
@ -52,7 +60,7 @@ fun AccelerometerMeasure(
viewModel.setEvent(AccelerometerMeasureContract.Event.OnStart(ble.serial)) viewModel.setEvent(AccelerometerMeasureContract.Event.OnStart(ble.serial))
}*/ }*/
viewModel.setEvent(AccelerometerMeasureContract.Event.OnStart(ble.serial)) viewModel.setEvent(AccelerometerMeasureContract.Event.OnStart(ble.serial, accelScale, accelMode, fftAxis, fftMode, frequency))
DisposableEffect(key1 = ble, effect = { DisposableEffect(key1 = ble, effect = {
@ -71,22 +79,15 @@ fun AccelerometerMeasure(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
val title = when(state){
is AccelerometerMeasureContract.State.Display -> {
"История измерений"
}
AccelerometerMeasureContract.State.Exception -> "История измерений"
}
Text( Text(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
text = title, text = accelMode.localized,
style = MaterialTheme.typography.titleLarge style = MaterialTheme.typography.titleLarge
) )
IconButton( IconButton(
onClick = { onClick = {
viewModel.setEvent(AccelerometerMeasureContract.Event.OnRefreshHistory(ble.serial)) viewModel.setEvent(AccelerometerMeasureContract.Event.OnRefreshHistory(ble.serial, accelScale, accelMode, fftAxis, fftMode, frequency))
}, },
enabled = true enabled = true
) { ) {
@ -147,7 +148,7 @@ fun Display(
} }
xProducer.setEntries(state.measureHistory.mapIndexed { index, measurePoint -> xProducer.setEntries(state.measureHistory.mapIndexed { index, measurePoint ->
FloatEntry(index.toFloat(), measurePoint.x) FloatEntry(index.toFloat(), measurePoint.x )
}) })
yProducer.setEntries(state.measureHistory.mapIndexed { index, measurePoint -> yProducer.setEntries(state.measureHistory.mapIndexed { index, measurePoint ->
@ -259,11 +260,21 @@ class AccelerometerMeasureContract {
object StopMeasure : Event() object StopMeasure : Event()
data class OnStart( data class OnStart(
val serial: String val serial: String,
val accelScale: AccelScale,
val accelMode: AccelViewMode,
val fftAxis: FftAxis,
val fftMode: FftViewMode,
val frequency: FftFrequency
) : Event() ) : Event()
data class OnRefreshHistory( data class OnRefreshHistory(
val serial: String val serial: String,
val accelScale: AccelScale,
val accelMode: AccelViewMode,
val fftAxis: FftAxis,
val fftMode: FftViewMode,
val frequency: FftFrequency
) : Event() ) : Event()
} }
@ -271,7 +282,7 @@ class AccelerometerMeasureContract {
sealed class State : ViewState { sealed class State : ViewState {
data class Display( data class Display(
val measureHistory : List<Accelereate> val measureHistory : List<Accelerate>
) : State() ) : State()
object Exception : State() object Exception : State()
@ -326,7 +337,7 @@ class AccelerometerMeasureViewModel @Inject constructor(
event: AccelerometerMeasureContract.Event.OnStart event: AccelerometerMeasureContract.Event.OnStart
) { ) {
startReadMeasure(event.serial, false) startReadMeasure(event.serial, event.accelScale, event.accelMode, event.fftAxis, event.fftMode, event.frequency, false)
} }
@ -334,10 +345,18 @@ class AccelerometerMeasureViewModel @Inject constructor(
state: AccelerometerMeasureContract.State, state: AccelerometerMeasureContract.State,
event: AccelerometerMeasureContract.Event.OnRefreshHistory event: AccelerometerMeasureContract.Event.OnRefreshHistory
) { ) {
startReadMeasure(event.serial, true) startReadMeasure(event.serial, event.accelScale, event.accelMode, event.fftAxis, event.fftMode, event.frequency, true)
} }
private fun startReadMeasure(serial: String, restartJob: Boolean){ private fun startReadMeasure(
serial: String,
accelScale: AccelScale,
accelMode: AccelViewMode,
fftAxis: FftAxis,
fftMode: FftViewMode,
frequency: FftFrequency,
restartJob: Boolean
){
if(restartJob || measureJob == null) { if(restartJob || measureJob == null) {
measureJob?.cancel() measureJob?.cancel()
@ -348,14 +367,20 @@ class AccelerometerMeasureViewModel @Inject constructor(
AccelerometerMeasureContract.State.Display(emptyList()) AccelerometerMeasureContract.State.Display(emptyList())
} }
getAccelerometerMeasureBySerialFlow(serial).onEach { getAccelerometerMeasureBySerialFlow(serial, accelScale, accelMode, fftAxis, fftMode, frequency).onEach {
it.fold( it.fold(
onSuccess = { onSuccess = {
setState { setState {
when (this) { when (this) {
is AccelerometerMeasureContract.State.Display -> { is AccelerometerMeasureContract.State.Display -> {
val dataList = this.measureHistory.toMutableList().apply { val dataList = this.measureHistory.toMutableList().apply {
add(it) add(
Accelerate(
x = ((9806.65f / (Short.MAX_VALUE / 2)) * it.x) * (accelScale.k / 2),
y = ((9806.65f / (Short.MAX_VALUE / 2)) * it.y) * (accelScale.k / 2),
z = ((9806.65f / (Short.MAX_VALUE / 2)) * it.z) * (accelScale.k / 2)
)
)
} }
AccelerometerMeasureContract.State.Display(dataList) AccelerometerMeasureContract.State.Display(dataList)
} }

View File

@ -9,7 +9,6 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material.icons.rounded.KeyboardArrowRight import androidx.compose.material.icons.rounded.KeyboardArrowRight
import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -19,7 +18,6 @@ import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.model.BleView import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.BleInfoView import llc.arma.ble.app.ui.screen.BleInfoView
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.app.ui.screen.inspection.thermometer.ThermometerContract
import llc.arma.ble.domain.model.Ble import llc.arma.ble.domain.model.Ble
@Composable @Composable
@ -102,9 +100,7 @@ fun DisplayState(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
.clip(RoundedCornerShape(16.dp)) .clip(RoundedCornerShape(16.dp))
.clickable { .clickable { onEvent(AccelerometerContract.Event.OnAccelViewModeEdit(next = AccelerometerContract.Event.OnAccelViewModeEdit.Next.ACCEL)) }
onEvent(AccelerometerContract.Event.OnShowAccelerometerMeasure)
}
.padding(8.dp) .padding(8.dp)
) { ) {
@ -113,7 +109,7 @@ fun DisplayState(
) { ) {
Text( Text(
text = "График" text = "Ускорение"
) )
} }
@ -139,7 +135,7 @@ fun DisplayState(
modifier = Modifier modifier = Modifier
.clip(RoundedCornerShape(16.dp)) .clip(RoundedCornerShape(16.dp))
.clickable { .clickable {
onEvent(AccelerometerContract.Event.OnShowAccelerometerHistory) onEvent(AccelerometerContract.Event.OnSpectreEdit)
} }
.padding(8.dp) .padding(8.dp)
) { ) {
@ -149,7 +145,7 @@ fun DisplayState(
) { ) {
Text( Text(
text = "История" text = "Спектр"
) )
} }

View File

@ -11,7 +11,6 @@ import android.os.Build
import android.os.SystemClock import android.os.SystemClock
import android.util.Log import android.util.Log
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.util.toRange
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -24,12 +23,73 @@ import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.model.BleInfo import llc.arma.ble.domain.model.BleInfo
import llc.arma.ble.domain.model.ConnectedBleInfo import llc.arma.ble.domain.model.ConnectedBleInfo
import llc.arma.ble.domain.repository.BleRepository import llc.arma.ble.domain.repository.BleRepository
import llc.arma.ble.domain.usecase.Accelereate import llc.arma.ble.domain.usecase.AccelScale
import llc.arma.ble.domain.usecase.AccelViewMode
import llc.arma.ble.domain.usecase.Accelerate
import llc.arma.ble.domain.usecase.FftAxis
import llc.arma.ble.domain.usecase.FftFrequency
import llc.arma.ble.domain.usecase.FftViewMode
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.random.Random
val FftFrequency.sendData: Byte
get() {
return when(this){
FftFrequency.OFF -> 0
FftFrequency.F_1 -> 1
FftFrequency.F_10 -> 2
FftFrequency.F_25 -> 3
FftFrequency.F_50 -> 4
FftFrequency.F_100 -> 5
FftFrequency.F_200 -> 6
FftFrequency.F_400 -> 7
FftFrequency.F_1620 -> 8
FftFrequency.F_1344 -> 9
}
}
val FftAxis.sendData: Byte
get() {
return when(this){
FftAxis.AUTO -> 0
FftAxis.X -> 1
FftAxis.Y -> 2
FftAxis.Z -> 3
}
}
val FftViewMode.sendData: Byte
get() {
return when(this){
FftViewMode.SPECTRE -> 0
FftViewMode.X -> 1
FftViewMode.Y -> 2
FftViewMode.Z -> 3
}
}
val AccelViewMode.sendData: Byte
get() {
return when(this){
AccelViewMode.ACCELERATION -> 0
AccelViewMode.PEAK_ACCELERATION -> 1
AccelViewMode.RMS -> 2
AccelViewMode.ANGLE -> 3
}
}
val AccelScale.sendData: Byte
get() {
return when(this){
AccelScale.S_2 -> 0
AccelScale.S_4 -> 1
AccelScale.S_8 -> 2
AccelScale.S_16 -> 3
}
}
val serviceUUID: UUID = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002") val serviceUUID: UUID = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002")
@ -502,8 +562,13 @@ class BleRepositoryImpl @Inject constructor(
} }
override suspend fun getAccelerometerHistoryBySerial( override suspend fun getAccelerometerSpectreBySerial(
serial: String serial: String,
accelScale: AccelScale,
accelMode: AccelViewMode,
fftAxis: FftAxis,
fftMode: FftViewMode,
frequency: FftFrequency
): Flow<Result<ProgressState<List<Ble.Accelerometer.MeasurePoint>>, BleException>> { ): Flow<Result<ProgressState<List<Ble.Accelerometer.MeasurePoint>>, BleException>> {
var gatt: BluetoothGatt? = null var gatt: BluetoothGatt? = null
@ -518,7 +583,15 @@ class BleRepositoryImpl @Inject constructor(
device = it, device = it,
serviceId = serviceUUID, serviceId = serviceUUID,
characteristicId = accelerometerReadUUID, characteristicId = accelerometerReadUUID,
writeData = byteArrayOf(4, 1) writeData = byteArrayOf(
4,
accelMode.sendData,
accelScale.sendData,
fftMode.sendData,
fftAxis.sendData,
frequency.sendData,
1
)
).onFailure { ).onFailure {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
send(Result.failure(BleException.PermissionDenied)) send(Result.failure(BleException.PermissionDenied))
@ -546,7 +619,7 @@ class BleRepositoryImpl @Inject constructor(
characteristicId = accelerometerReadUUID characteristicId = accelerometerReadUUID
).fold( ).fold(
onSuccess = { readData -> onSuccess = { readData ->
Log.d("a read", readData.joinToString("-")) Log.d("read", readData.joinToString(", "))
if(readData.isNotEmpty() && readData.first() == (0).toByte()){ if(readData.isNotEmpty() && readData.first() == (0).toByte()){
result = true result = true
} else { } else {
@ -562,7 +635,7 @@ class BleRepositoryImpl @Inject constructor(
} }
gatt = it.connectGatt(app, false, ReadAccelerometerHistoryCallback(app) { gatt = it.connectGatt(app, false, ReadAccelerometerSpectreCallback(app) {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
send(it) send(it)
} }
@ -758,7 +831,14 @@ class BleRepositoryImpl @Inject constructor(
return Result.success(Unit) return Result.success(Unit)
} }
override fun getAccelerometerMeasureBySerialFlow(serial: String): Flow<Result<Accelereate, BleException>> { override fun getAccelerometerMeasureBySerialFlow(
serial: String,
accelScale: AccelScale,
accelMode: AccelViewMode,
fftAxis: FftAxis,
fftMode: FftViewMode,
frequency: FftFrequency,
): Flow<Result<Accelerate, BleException>> {
return callbackFlow { return callbackFlow {
@ -769,7 +849,14 @@ class BleRepositoryImpl @Inject constructor(
gatt = it.device.connectGatt( gatt = it.device.connectGatt(
app, app,
false, false,
ReadAccelerometerCallback(app){ result -> ReadAccelerometerCallback(
app = app,
accelScale = accelScale,
accelMode = accelMode,
fftAxis = fftAxis,
fftMode = fftMode,
frequency = frequency
){ result ->
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
send(result) send(result)
} }
@ -778,7 +865,6 @@ class BleRepositoryImpl @Inject constructor(
} }
awaitClose { awaitClose {
Log.d("acc", "close")
gatt?.close() gatt?.close()
} }
@ -803,8 +889,6 @@ class BleRepositoryImpl @Inject constructor(
newState: Int newState: Int
) { ) {
Log.d("read", "onConnectionStateChange $newState $status")
if(status == BluetoothGatt.GATT_SUCCESS) { if(status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) { if (newState == BluetoothProfile.STATE_CONNECTED) {
@ -947,8 +1031,6 @@ class BleRepositoryImpl @Inject constructor(
newState: Int newState: Int
) { ) {
Log.d("write", "onConnectionStateChange $status $newState")
if (status == BluetoothGatt.GATT_SUCCESS) { if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) { if (newState == BluetoothProfile.STATE_CONNECTED) {

View File

@ -10,22 +10,25 @@ import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import llc.arma.ble.domain.Result import llc.arma.ble.domain.Result
import llc.arma.ble.domain.common.BleException import llc.arma.ble.domain.common.BleException
import llc.arma.ble.domain.common.ProgressState import llc.arma.ble.domain.usecase.AccelScale
import llc.arma.ble.domain.model.Ble import llc.arma.ble.domain.usecase.AccelViewMode
import llc.arma.ble.domain.usecase.Accelereate import llc.arma.ble.domain.usecase.Accelerate
import llc.arma.ble.domain.usecase.FftAxis
import llc.arma.ble.domain.usecase.FftFrequency
import llc.arma.ble.domain.usecase.FftViewMode
import java.util.UUID import java.util.UUID
import java.util.stream.Collectors
class ReadAccelerometerCallback( class ReadAccelerometerCallback(
private val app: Application, private val app: Application,
private val onResult: (Result<Accelereate, BleException>) -> Unit private val accelScale: AccelScale,
private val accelMode: AccelViewMode,
private val fftAxis: FftAxis,
private val fftMode: FftViewMode,
private val frequency: FftFrequency,
private val onResult: (Result<Accelerate, BleException>) -> Unit
) : BluetoothGattCallback() { ) : BluetoothGattCallback() {
override fun onConnectionStateChange( override fun onConnectionStateChange(
@ -70,6 +73,48 @@ class ReadAccelerometerCallback(
if (checkPermission()) { if (checkPermission()) {
val payload = byteArrayOf(
4,
accelMode.sendData,
accelScale.sendData,
fftMode.sendData,
fftAxis.sendData,
frequency.sendData,
2
)
Log.d("payload", payload.joinToString(" - "))
gatt.writeCharacteristic(it, payload)
} else {
onResult(Result.failure(BleException.PermissionDenied))
gatt.close()
}
}
}
}
override fun onCharacteristicWrite(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic,
status: Int
) {
super.onCharacteristicWrite(gatt, characteristic, status)
if(status == BluetoothGatt.GATT_SUCCESS){
gatt.getService(serviceUUID)?.getCharacteristic(accelerometerReadUUID)?.let {
if (checkPermission()) {
Log.d("write", "enable notifications")
gatt.setCharacteristicNotification(it, true) gatt.setCharacteristicNotification(it, true)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
@ -93,13 +138,14 @@ class ReadAccelerometerCallback(
} }
@Deprecated("Deprecated in Java")
override fun onCharacteristicChanged( override fun onCharacteristicChanged(
gatt: BluetoothGatt, gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic characteristic: BluetoothGattCharacteristic
) { ) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
super.onCharacteristicChanged(gatt, characteristic) super.onCharacteristicChanged(gatt, characteristic)
onCommonCharacteristicRead(gatt, characteristic, characteristic.value) onCommonCharacteristicRead(characteristic.value)
} }
} }
@ -109,23 +155,20 @@ class ReadAccelerometerCallback(
value: ByteArray value: ByteArray
) { ) {
super.onCharacteristicChanged(gatt, characteristic, value) super.onCharacteristicChanged(gatt, characteristic, value)
onCommonCharacteristicRead(gatt, characteristic, value) onCommonCharacteristicRead(value)
} }
private fun onCommonCharacteristicRead( private fun onCommonCharacteristicRead(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic,
value: ByteArray, value: ByteArray,
){ ){
val data = value.toList().chunked(2).map { val data = value.toList().chunked(2).map {
it[1].toInt() it.toByteArray().get2byteShortAt(0)
} }
onResult( onResult(
Result.success( Result.success(
Accelereate( Accelerate(
x = data[0].toFloat(), x = data[0].toFloat(),
y = data[1].toFloat(), y = data[1].toFloat(),
z = data[2].toFloat() z = data[2].toFloat()
@ -150,4 +193,26 @@ class ReadAccelerometerCallback(
} }
} }
private fun BluetoothGatt.writeCharacteristic(
characteristic: BluetoothGattCharacteristic,
data: ByteArray
): Result<Unit, BleException>{
return if(checkPermission()){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
writeCharacteristic(characteristic, data, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
}else{
characteristic.value = data
writeCharacteristic(characteristic)
}
Result.success(Unit)
} else {
Result.failure(BleException.PermissionDenied)
}
}
} }

View File

@ -16,7 +16,13 @@ import llc.arma.ble.domain.model.Ble
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.ByteOrder.LITTLE_ENDIAN import java.nio.ByteOrder.LITTLE_ENDIAN
class ReadAccelerometerHistoryCallback( fun ByteArray.get2byteShortAt(idx: Int): Int {
val shorts = ShortArray(1)
ByteBuffer.wrap(this).order(LITTLE_ENDIAN).asShortBuffer()[shorts]
return shorts[0].toInt()//(this[0].toInt() + (this[1].toInt() shl 8)).toShort()
}
class ReadAccelerometerSpectreCallback(
private val app: Application, private val app: Application,
private val onResult: (Result<ProgressState<List<Ble.Accelerometer.MeasurePoint>>, BleException>) -> Unit private val onResult: (Result<ProgressState<List<Ble.Accelerometer.MeasurePoint>>, BleException>) -> Unit
) : BluetoothGattCallback() { ) : BluetoothGattCallback() {
@ -31,12 +37,6 @@ class ReadAccelerometerHistoryCallback(
((this[idx + 1].toUInt() and 0xFFu) shl 8) or ((this[idx + 1].toUInt() and 0xFFu) shl 8) or
(this[idx].toUInt() and 0xFFu) (this[idx].toUInt() and 0xFFu)
private fun ByteArray.get2byteShortAt(idx: Int): Int {
val shorts = ShortArray(1)
ByteBuffer.wrap(this).order(LITTLE_ENDIAN).asShortBuffer()[shorts]
return shorts[0].toInt()//(this[0].toInt() + (this[1].toInt() shl 8)).toShort()
}
private var readProperty: Property? = null private var readProperty: Property? = null
init { init {
@ -137,14 +137,12 @@ class ReadAccelerometerHistoryCallback(
onCommonCharacteristicRead(gatt, characteristic, value, status) onCommonCharacteristicRead(gatt, characteristic, value, status)
} }
@OptIn(ExperimentalUnsignedTypes::class)
private fun onCommonCharacteristicRead( private fun onCommonCharacteristicRead(
gatt: BluetoothGatt, gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic, characteristic: BluetoothGattCharacteristic,
value: ByteArray, value: ByteArray,
status: Int status: Int
){ ){
Log.d("read", value[0].toString())
if(status == BluetoothGatt.GATT_SUCCESS){ if(status == BluetoothGatt.GATT_SUCCESS){
when(readProperty){ when(readProperty){

View File

@ -7,8 +7,12 @@ import llc.arma.ble.domain.common.ProgressState
import llc.arma.ble.domain.model.Ble import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.model.BleInfo import llc.arma.ble.domain.model.BleInfo
import llc.arma.ble.domain.model.ConnectedBleInfo import llc.arma.ble.domain.model.ConnectedBleInfo
import llc.arma.ble.domain.usecase.Accelereate import llc.arma.ble.domain.usecase.AccelScale
import llc.arma.ble.domain.usecase.GetBleBySerial import llc.arma.ble.domain.usecase.AccelViewMode
import llc.arma.ble.domain.usecase.Accelerate
import llc.arma.ble.domain.usecase.FftAxis
import llc.arma.ble.domain.usecase.FftFrequency
import llc.arma.ble.domain.usecase.FftViewMode
interface BleRepository { interface BleRepository {
@ -28,8 +32,22 @@ interface BleRepository {
suspend fun changeBlePassword(password: String, serial: String): Result<Unit, BleException> suspend fun changeBlePassword(password: String, serial: String): Result<Unit, BleException>
fun getAccelerometerMeasureBySerialFlow(serial: String): Flow<Result<Accelereate, BleException>> fun getAccelerometerMeasureBySerialFlow(
serial: String,
accelScale: AccelScale,
accelMode: AccelViewMode,
fftAxis: FftAxis,
fftMode: FftViewMode,
frequency: FftFrequency
): Flow<Result<Accelerate, BleException>>
suspend fun getAccelerometerHistoryBySerial(serial: String): Flow<Result<ProgressState<List<Ble.Accelerometer.MeasurePoint>>, BleException>> suspend fun getAccelerometerSpectreBySerial(
serial: String,
accelScale: AccelScale,
accelMode: AccelViewMode,
fftAxis: FftAxis,
fftMode: FftViewMode,
frequency: FftFrequency
): Flow<Result<ProgressState<List<Ble.Accelerometer.MeasurePoint>>, BleException>>
} }

View File

@ -1,21 +0,0 @@
package llc.arma.ble.domain.usecase
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.repository.BleRepository
import javax.inject.Inject
class GetAccelerometerHistoryBySerial @Inject constructor(
private val bleRepository: BleRepository
) {
suspend operator fun invoke(serial: String): Flow<Result<ProgressState<List<Ble.Accelerometer.MeasurePoint>>, BleException>> {
return bleRepository.getAccelerometerHistoryBySerial(serial)
}
}

View File

@ -3,8 +3,6 @@ package llc.arma.ble.domain.usecase
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import llc.arma.ble.domain.Result import llc.arma.ble.domain.Result
import llc.arma.ble.domain.common.BleException 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.repository.BleRepository import llc.arma.ble.domain.repository.BleRepository
import javax.inject.Inject import javax.inject.Inject
@ -12,15 +10,30 @@ class GetAccelerometerMeasureBySerialFlow @Inject constructor(
private val bleRepository: BleRepository private val bleRepository: BleRepository
) { ) {
operator fun invoke(serial: String): Flow<Result<Accelereate, BleException>> { operator fun invoke(
serial: String,
accelScale: AccelScale,
accelMode: AccelViewMode,
fftAxis: FftAxis,
fftMode: FftViewMode,
frequency: FftFrequency
): Flow<Result<Accelerate, BleException>> {
return bleRepository.getAccelerometerMeasureBySerialFlow(serial) return bleRepository.getAccelerometerMeasureBySerialFlow(serial, accelScale, accelMode, fftAxis, fftMode, frequency)
} }
} }
data class Accelereate( enum class AccelViewMode {
ACCELERATION, PEAK_ACCELERATION, RMS, ANGLE
}
enum class AccelScale(val k: Int) {
S_2(2), S_4(4), S_8(8), S_16(16)
}
data class Accelerate(
val x: Float, val x: Float,
val y: Float, val y: Float,
val z: Float, val z: Float,

View File

@ -0,0 +1,40 @@
package llc.arma.ble.domain.usecase
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.repository.BleRepository
import javax.inject.Inject
class GetAccelerometerSpectreBySerial @Inject constructor(
private val bleRepository: BleRepository
) {
suspend operator fun invoke(
serial: String,
accelScale: AccelScale,
accelMode: AccelViewMode,
fftAxis: FftAxis,
fftMode: FftViewMode,
frequency: FftFrequency
): Flow<Result<ProgressState<List<Ble.Accelerometer.MeasurePoint>>, BleException>> {
return bleRepository.getAccelerometerSpectreBySerial(serial, accelScale, accelMode, fftAxis, fftMode, frequency)
}
}
enum class FftFrequency {
OFF, F_1, F_10, F_25, F_50, F_100, F_200, F_400, F_1620, F_1344
}
enum class FftViewMode {
SPECTRE, X, Y, Z
}
enum class FftAxis {
AUTO, X, Y, Z
}