kotlin ble migration
This commit is contained in:
parent
f65023b4c7
commit
ab1046fd61
|
|
@ -13,8 +13,8 @@ android {
|
||||||
applicationId "llc.arma.ble"
|
applicationId "llc.arma.ble"
|
||||||
minSdk 26
|
minSdk 26
|
||||||
targetSdk 34
|
targetSdk 34
|
||||||
versionCode 18
|
versionCode 22
|
||||||
versionName "1.2.18"
|
versionName "1.3.2"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables {
|
vectorDrawables {
|
||||||
|
|
@ -86,8 +86,8 @@ dependencies {
|
||||||
kapt('com.google.dagger:hilt-android-compiler:2.45')
|
kapt('com.google.dagger:hilt-android-compiler:2.45')
|
||||||
kapt("androidx.hilt:hilt-compiler:1.0.0")
|
kapt("androidx.hilt:hilt-compiler:1.0.0")
|
||||||
|
|
||||||
implementation 'no.nordicsemi.android.kotlin.ble:scanner:1.0.14'
|
implementation 'no.nordicsemi.android.kotlin.ble:scanner:1.0.19'
|
||||||
implementation 'no.nordicsemi.android.kotlin.ble:client:1.0.14'
|
implementation 'no.nordicsemi.android.kotlin.ble:client:1.0.19'
|
||||||
|
|
||||||
implementation "com.google.accompanist:accompanist-permissions:0.26.3-beta"
|
implementation "com.google.accompanist:accompanist-permissions:0.26.3-beta"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,10 @@
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
|
||||||
android:maxSdkVersion="30" />
|
android:maxSdkVersion="30" />
|
||||||
|
|
||||||
<uses-permission android:maxSdkVersion="30" android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
|
||||||
<uses-permission android:maxSdkVersion="30" android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
android:maxSdkVersion="30" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"
|
||||||
|
android:maxSdkVersion="30" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
|
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
|
||||||
|
|
@ -16,7 +18,9 @@
|
||||||
tools:targetApi="s" />
|
tools:targetApi="s" />
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.location.gps" />
|
<uses-feature android:name="android.hardware.location.gps" />
|
||||||
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
|
|
||||||
|
<uses-feature android:name="android.hardware.bluetooth_le"
|
||||||
|
android:required="true"/>
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class BleMapper @Inject constructor(
|
||||||
tx = txMapper.map(input.state.tx)
|
tx = txMapper.map(input.state.tx)
|
||||||
),
|
),
|
||||||
accelerometerState = BleView.Accelerometer.AccelerometerState(
|
accelerometerState = BleView.Accelerometer.AccelerometerState(
|
||||||
saveHistory = input.accelerometerState.saveHistory,
|
saveHistorySettings = input.accelerometerState.saveHistorySettings,
|
||||||
historyInterval = input.accelerometerState.historyInterval
|
historyInterval = input.accelerometerState.historyInterval
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class BleViewMapper @Inject constructor(
|
||||||
tx = txMapper.map(input.state.tx)
|
tx = txMapper.map(input.state.tx)
|
||||||
),
|
),
|
||||||
accelerometerState = Ble.Accelerometer.AccelerometerState(
|
accelerometerState = Ble.Accelerometer.AccelerometerState(
|
||||||
saveHistory = input.accelerometerState.saveHistory,
|
saveHistorySettings = input.accelerometerState.saveHistory,
|
||||||
historyInterval = input.accelerometerState.historyInterval,
|
historyInterval = input.accelerometerState.historyInterval,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,6 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
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.usecase.AccelScale
|
|
||||||
import llc.arma.ble.domain.usecase.AccelViewMode
|
|
||||||
|
|
||||||
sealed class BleView(
|
sealed class BleView(
|
||||||
val info: BleInfo
|
val info: BleInfo
|
||||||
|
|
@ -19,10 +17,10 @@ sealed class BleView(
|
||||||
) : BleView(info) {
|
) : BleView(info) {
|
||||||
|
|
||||||
class AccelerometerState(
|
class AccelerometerState(
|
||||||
saveHistory: Ble.Accelerometer.History,
|
saveHistorySettings: Ble.Accelerometer.HistorySettings,
|
||||||
historyInterval: Long,
|
historyInterval: Long,
|
||||||
) {
|
) {
|
||||||
var saveHistory by mutableStateOf(saveHistory)
|
var saveHistory by mutableStateOf(saveHistorySettings)
|
||||||
var historyInterval by mutableStateOf(historyInterval)
|
var historyInterval by mutableStateOf(historyInterval)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,23 @@ class BleListViewModel @Inject constructor(
|
||||||
|
|
||||||
var job: Job? = null
|
var job: Job? = null
|
||||||
|
|
||||||
while (true) {
|
getBleAroundFlow().fold(
|
||||||
|
onSuccess = {
|
||||||
|
it.onEach {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
connectedBleList = emptyList(),
|
||||||
|
bleList = it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.launchIn(viewModelScope)
|
||||||
|
},
|
||||||
|
onFailure = {
|
||||||
|
throw IllegalStateException()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
/*while (true) {
|
||||||
|
|
||||||
job?.cancel()
|
job?.cancel()
|
||||||
job = getBleAroundFlow().onEach {
|
job = getBleAroundFlow().onEach {
|
||||||
|
|
@ -46,7 +62,7 @@ class BleListViewModel @Inject constructor(
|
||||||
|
|
||||||
delay(30_000)
|
delay(30_000)
|
||||||
|
|
||||||
}
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,8 @@ class AccelerometerViewModel @Inject constructor(
|
||||||
|
|
||||||
var saveHistory = state.accelerometer.accelerometerState.saveHistory
|
var saveHistory = state.accelerometer.accelerometerState.saveHistory
|
||||||
|
|
||||||
if(saveHistory is Ble.Accelerometer.History.Enabled){
|
if(saveHistory is Ble.Accelerometer.HistorySettings.Enabled){
|
||||||
saveHistory = Ble.Accelerometer.History.Enabled(
|
saveHistory = Ble.Accelerometer.HistorySettings.Enabled(
|
||||||
mode = event.mode,
|
mode = event.mode,
|
||||||
scale = saveHistory.scale,
|
scale = saveHistory.scale,
|
||||||
detailed = saveHistory.detailed
|
detailed = saveHistory.detailed
|
||||||
|
|
@ -105,7 +105,7 @@ class AccelerometerViewModel @Inject constructor(
|
||||||
|
|
||||||
var saveHistory = state.accelerometer.accelerometerState.saveHistory
|
var saveHistory = state.accelerometer.accelerometerState.saveHistory
|
||||||
|
|
||||||
if(saveHistory is Ble.Accelerometer.History.Enabled){
|
if(saveHistory is Ble.Accelerometer.HistorySettings.Enabled){
|
||||||
saveHistory = saveHistory.copy(scale = event.scale)
|
saveHistory = saveHistory.copy(scale = event.scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,7 +199,7 @@ class AccelerometerViewModel @Inject constructor(
|
||||||
|
|
||||||
if(event.save){
|
if(event.save){
|
||||||
|
|
||||||
state.accelerometer.accelerometerState.saveHistory = Ble.Accelerometer.History.Enabled(
|
state.accelerometer.accelerometerState.saveHistory = Ble.Accelerometer.HistorySettings.Enabled(
|
||||||
scale = AccelScale.S_2,
|
scale = AccelScale.S_2,
|
||||||
mode = AccelViewMode.ACCELERATION,
|
mode = AccelViewMode.ACCELERATION,
|
||||||
detailed = true
|
detailed = true
|
||||||
|
|
@ -211,7 +211,7 @@ class AccelerometerViewModel @Inject constructor(
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
state.accelerometer.accelerometerState.saveHistory = Ble.Accelerometer.History.Disabled
|
state.accelerometer.accelerometerState.saveHistory = Ble.Accelerometer.HistorySettings.Disabled
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -397,7 +397,7 @@ class AccelerometerViewModel @Inject constructor(
|
||||||
|
|
||||||
val writeRequest = Ble.Accelerometer.WriteRequest(
|
val writeRequest = Ble.Accelerometer.WriteRequest(
|
||||||
tx = if(newBle.state.tx == state.origin.state.tx) null else newBle.state.tx,
|
tx = if(newBle.state.tx == state.origin.state.tx) null else newBle.state.tx,
|
||||||
saveHistory = if(newBle.accelerometerState.saveHistory == state.origin.accelerometerState.saveHistory) null else newBle.accelerometerState.saveHistory,
|
saveHistorySettings = if(newBle.accelerometerState.saveHistorySettings == state.origin.accelerometerState.saveHistorySettings) null else newBle.accelerometerState.saveHistorySettings,
|
||||||
historyInterval = if(newBle.accelerometerState.historyInterval == state.origin.accelerometerState.historyInterval) null else newBle.accelerometerState.historyInterval,
|
historyInterval = if(newBle.accelerometerState.historyInterval == state.origin.accelerometerState.historyInterval) null else newBle.accelerometerState.historyInterval,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -565,8 +565,8 @@ class AccelerometerViewModel @Inject constructor(
|
||||||
tx = request.writeRequest.tx ?: state.origin.state.tx
|
tx = request.writeRequest.tx ?: state.origin.state.tx
|
||||||
),
|
),
|
||||||
accelerometerState = currentState.origin.accelerometerState.copy(
|
accelerometerState = currentState.origin.accelerometerState.copy(
|
||||||
saveHistory = request.writeRequest.saveHistory
|
saveHistorySettings = request.writeRequest.saveHistorySettings
|
||||||
?: currentState.origin.accelerometerState.saveHistory
|
?: currentState.origin.accelerometerState.saveHistorySettings
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,8 @@ package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
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.MaterialTheme
|
||||||
import androidx.compose.material3.RadioButton
|
import androidx.compose.material3.RadioButton
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
|
|
@ -21,10 +16,6 @@ import androidx.compose.ui.unit.dp
|
||||||
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
|
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
|
||||||
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.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
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AccelScaleEdit(
|
fun AccelScaleEdit(
|
||||||
|
|
@ -39,7 +30,7 @@ fun AccelScaleEdit(
|
||||||
state.accelScale
|
state.accelScale
|
||||||
AccelerometerContract.Event.Next.HISTORY -> {
|
AccelerometerContract.Event.Next.HISTORY -> {
|
||||||
val history = state.accelerometer.accelerometerState.saveHistory
|
val history = state.accelerometer.accelerometerState.saveHistory
|
||||||
if (history is Ble.Accelerometer.History.Enabled)
|
if (history is Ble.Accelerometer.HistorySettings.Enabled)
|
||||||
history.scale
|
history.scale
|
||||||
else {
|
else {
|
||||||
state.accelScale
|
state.accelScale
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,6 @@ fun AccelerometerSpectre(
|
||||||
DisposableEffect(key1 = "ble", effect = {
|
DisposableEffect(key1 = "ble", effect = {
|
||||||
|
|
||||||
onDispose {
|
onDispose {
|
||||||
Log.d("history", "dispose")
|
|
||||||
viewModel.setEvent(AccelerometerSpectreContract.Event.StopMeasure)
|
viewModel.setEvent(AccelerometerSpectreContract.Event.StopMeasure)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -340,8 +339,8 @@ class AccelerometerSpectreContract {
|
||||||
sealed class State : ViewState {
|
sealed class State : ViewState {
|
||||||
|
|
||||||
data class Display(
|
data class Display(
|
||||||
val previousHistory : List<Ble.Accelerometer.MeasurePoint>?,
|
val previousHistory : List<Ble.Accelerometer.SpectrePoint>?,
|
||||||
val loadingHistoryState : ProgressState<List<Ble.Accelerometer.MeasurePoint>>
|
val loadingHistoryState : ProgressState<List<Ble.Accelerometer.SpectrePoint>>
|
||||||
) : State()
|
) : State()
|
||||||
|
|
||||||
object Exception : State()
|
object Exception : State()
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,6 @@ import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.rounded.Refresh
|
import androidx.compose.material.icons.rounded.Refresh
|
||||||
import androidx.compose.ui.draw.rotate
|
import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.graphics.StrokeCap
|
import androidx.compose.ui.graphics.StrokeCap
|
||||||
import androidx.compose.ui.graphics.TransformOrigin
|
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
|
||||||
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.line.lineChart
|
import com.patrykandpatrick.vico.compose.chart.line.lineChart
|
||||||
|
|
@ -39,10 +37,10 @@ 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.model.Ble
|
||||||
import llc.arma.ble.domain.usecase.AccelScale
|
import llc.arma.ble.domain.usecase.AccelScale
|
||||||
import llc.arma.ble.domain.usecase.AccelViewMode
|
import llc.arma.ble.domain.usecase.AccelViewMode
|
||||||
import llc.arma.ble.domain.usecase.AccelViewMode.*
|
import llc.arma.ble.domain.usecase.AccelViewMode.*
|
||||||
import llc.arma.ble.domain.usecase.MeasureData
|
|
||||||
import llc.arma.ble.domain.usecase.FftAxis
|
import llc.arma.ble.domain.usecase.FftAxis
|
||||||
import llc.arma.ble.domain.usecase.FftFrequency
|
import llc.arma.ble.domain.usecase.FftFrequency
|
||||||
import llc.arma.ble.domain.usecase.FftViewMode
|
import llc.arma.ble.domain.usecase.FftViewMode
|
||||||
|
|
@ -151,37 +149,40 @@ fun Display(
|
||||||
|
|
||||||
xProducer.setEntries(state.measureHistory.mapIndexed { index, measurePoint ->
|
xProducer.setEntries(state.measureHistory.mapIndexed { index, measurePoint ->
|
||||||
when(measurePoint){
|
when(measurePoint){
|
||||||
is MeasureData.Accelerate -> {
|
is Ble.Accelerometer.RealtimePoint.Common ->
|
||||||
FloatEntry(index.toFloat(), measurePoint.x )
|
FloatEntry(index.toFloat(), measurePoint.x )
|
||||||
}
|
is Ble.Accelerometer.RealtimePoint.Vibration ->
|
||||||
is MeasureData.Vibration -> FloatEntry(index.toFloat(), measurePoint.value)
|
FloatEntry(index.toFloat(), measurePoint.value)
|
||||||
is MeasureData.Angle -> {
|
is Ble.Accelerometer.RealtimePoint.Angle ->
|
||||||
FloatEntry(index.toFloat(), measurePoint.xAngle )
|
FloatEntry(index.toFloat(), measurePoint.x )
|
||||||
}
|
is Ble.Accelerometer.RealtimePoint.Rotation ->
|
||||||
|
FloatEntry(index.toFloat(), measurePoint.angle )
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
yProducer.setEntries(state.measureHistory.mapIndexed { index, measurePoint ->
|
yProducer.setEntries(state.measureHistory.mapIndexed { index, measurePoint ->
|
||||||
when(measurePoint){
|
when(measurePoint){
|
||||||
is MeasureData.Accelerate -> {
|
is Ble.Accelerometer.RealtimePoint.Common ->
|
||||||
FloatEntry(index.toFloat(), measurePoint.y )
|
FloatEntry(index.toFloat(), measurePoint.y )
|
||||||
}
|
is Ble.Accelerometer.RealtimePoint.Vibration ->
|
||||||
is MeasureData.Vibration -> FloatEntry(index.toFloat(), measurePoint.value)
|
FloatEntry(index.toFloat(), measurePoint.value)
|
||||||
is MeasureData.Angle -> {
|
is Ble.Accelerometer.RealtimePoint.Angle ->
|
||||||
FloatEntry(index.toFloat(), measurePoint.yAngle )
|
FloatEntry(index.toFloat(), measurePoint.y)
|
||||||
}
|
is Ble.Accelerometer.RealtimePoint.Rotation ->
|
||||||
|
FloatEntry(index.toFloat(), measurePoint.tmp)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
zProducer.setEntries(state.measureHistory.mapIndexed { index, measurePoint ->
|
zProducer.setEntries(state.measureHistory.mapIndexed { index, measurePoint ->
|
||||||
when(measurePoint){
|
when(measurePoint){
|
||||||
is MeasureData.Accelerate -> {
|
is Ble.Accelerometer.RealtimePoint.Common ->
|
||||||
FloatEntry(index.toFloat(), measurePoint.z)
|
FloatEntry(index.toFloat(), measurePoint.z)
|
||||||
}
|
is Ble.Accelerometer.RealtimePoint.Vibration ->
|
||||||
is MeasureData.Vibration -> FloatEntry(index.toFloat(), measurePoint.value)
|
FloatEntry(index.toFloat(), measurePoint.value)
|
||||||
is MeasureData.Angle -> {
|
is Ble.Accelerometer.RealtimePoint.Angle ->
|
||||||
FloatEntry(index.toFloat(), measurePoint.zAngle )
|
FloatEntry(index.toFloat(), measurePoint.z)
|
||||||
}
|
is Ble.Accelerometer.RealtimePoint.Rotation ->
|
||||||
|
FloatEntry(index.toFloat(), measurePoint.turnovers.toFloat())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -195,16 +196,7 @@ fun Display(
|
||||||
|
|
||||||
val lastMeasure = state.measureHistory.lastOrNull()
|
val lastMeasure = state.measureHistory.lastOrNull()
|
||||||
|
|
||||||
/*when(lastMeasure){
|
if(lastMeasure is Ble.Accelerometer.RealtimePoint.Common) {
|
||||||
is MeasureData.Accelerate -> TODO()
|
|
||||||
is MeasureData.Angle -> TODO()
|
|
||||||
is MeasureData.Vibration -> {
|
|
||||||
|
|
||||||
}
|
|
||||||
null -> {}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if(lastMeasure is MeasureData.Accelerate) {
|
|
||||||
|
|
||||||
when(state.mode){
|
when(state.mode){
|
||||||
ROTATIONS -> {
|
ROTATIONS -> {
|
||||||
|
|
@ -524,7 +516,7 @@ class AccelerometerAccelContract {
|
||||||
|
|
||||||
data class Display(
|
data class Display(
|
||||||
val mode: AccelViewMode,
|
val mode: AccelViewMode,
|
||||||
val measureHistory : List<MeasureData>
|
val measureHistory : List<Ble.Accelerometer.RealtimePoint>
|
||||||
) : State()
|
) : State()
|
||||||
|
|
||||||
object Exception : State()
|
object Exception : State()
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,6 @@ import llc.arma.ble.domain.usecase.FftFrequency
|
||||||
import llc.arma.ble.domain.usecase.FftViewMode
|
import llc.arma.ble.domain.usecase.FftViewMode
|
||||||
import llc.arma.ble.domain.usecase.GetAccelerometerHistoryBySerial
|
import llc.arma.ble.domain.usecase.GetAccelerometerHistoryBySerial
|
||||||
import llc.arma.ble.domain.usecase.GetBleBySerial
|
import llc.arma.ble.domain.usecase.GetBleBySerial
|
||||||
import llc.arma.ble.domain.usecase.MeasureData
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
class AccelEntry(
|
class AccelEntry(
|
||||||
|
|
@ -208,7 +207,7 @@ fun Display(
|
||||||
|
|
||||||
xProducer.setEntries(state.loadingHistoryState.data.mapIndexed { index, measurePoint ->
|
xProducer.setEntries(state.loadingHistoryState.data.mapIndexed { index, measurePoint ->
|
||||||
when(measurePoint){
|
when(measurePoint){
|
||||||
is Ble.Accelerometer.HistoryPoint.Accelerate -> {
|
is Ble.Accelerometer.HistoryPoint.Acceleration -> {
|
||||||
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.x )
|
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.x )
|
||||||
}
|
}
|
||||||
is Ble.Accelerometer.HistoryPoint.Vibration -> {
|
is Ble.Accelerometer.HistoryPoint.Vibration -> {
|
||||||
|
|
@ -217,12 +216,16 @@ fun Display(
|
||||||
is Ble.Accelerometer.HistoryPoint.Angle -> {
|
is Ble.Accelerometer.HistoryPoint.Angle -> {
|
||||||
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.x )
|
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.x )
|
||||||
}
|
}
|
||||||
|
is Ble.Accelerometer.HistoryPoint.Rotation -> {
|
||||||
|
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.value.toFloat() )
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
yProducer.setEntries(state.loadingHistoryState.data.mapIndexed { index, measurePoint ->
|
yProducer.setEntries(state.loadingHistoryState.data.mapIndexed { index, measurePoint ->
|
||||||
when(measurePoint){
|
when(measurePoint){
|
||||||
is Ble.Accelerometer.HistoryPoint.Accelerate -> {
|
is Ble.Accelerometer.HistoryPoint.Acceleration -> {
|
||||||
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.y )
|
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.y )
|
||||||
}
|
}
|
||||||
is Ble.Accelerometer.HistoryPoint.Vibration -> {
|
is Ble.Accelerometer.HistoryPoint.Vibration -> {
|
||||||
|
|
@ -231,12 +234,15 @@ fun Display(
|
||||||
is Ble.Accelerometer.HistoryPoint.Angle -> {
|
is Ble.Accelerometer.HistoryPoint.Angle -> {
|
||||||
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.y )
|
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.y )
|
||||||
}
|
}
|
||||||
|
is Ble.Accelerometer.HistoryPoint.Rotation -> {
|
||||||
|
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.value.toFloat() )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
zProducer.setEntries(state.loadingHistoryState.data.mapIndexed { index, measurePoint ->
|
zProducer.setEntries(state.loadingHistoryState.data.mapIndexed { index, measurePoint ->
|
||||||
when(measurePoint){
|
when(measurePoint){
|
||||||
is Ble.Accelerometer.HistoryPoint.Accelerate -> {
|
is Ble.Accelerometer.HistoryPoint.Acceleration -> {
|
||||||
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.z )
|
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.z )
|
||||||
}
|
}
|
||||||
is Ble.Accelerometer.HistoryPoint.Vibration -> {
|
is Ble.Accelerometer.HistoryPoint.Vibration -> {
|
||||||
|
|
@ -245,6 +251,9 @@ fun Display(
|
||||||
is Ble.Accelerometer.HistoryPoint.Angle -> {
|
is Ble.Accelerometer.HistoryPoint.Angle -> {
|
||||||
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.z )
|
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.z )
|
||||||
}
|
}
|
||||||
|
is Ble.Accelerometer.HistoryPoint.Rotation -> {
|
||||||
|
AccelEntry(measurePoint.date, index.toFloat(), measurePoint.value.toFloat() )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -258,9 +267,10 @@ fun Display(
|
||||||
|
|
||||||
val lastMeasure = state.loadingHistoryState.data.lastOrNull()
|
val lastMeasure = state.loadingHistoryState.data.lastOrNull()
|
||||||
|
|
||||||
if((lastMeasure is Ble.Accelerometer.HistoryPoint.Vibration).not()) {
|
when(lastMeasure){
|
||||||
|
is Ble.Accelerometer.HistoryPoint.Acceleration,
|
||||||
Column() {
|
is Ble.Accelerometer.HistoryPoint.Angle -> {
|
||||||
|
Column {
|
||||||
|
|
||||||
Text(text = "Ось X:")
|
Text(text = "Ось X:")
|
||||||
|
|
||||||
|
|
@ -330,9 +340,36 @@ fun Display(
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
is Ble.Accelerometer.HistoryPoint.Rotation -> {
|
||||||
|
Column {
|
||||||
|
|
||||||
} else {
|
Text(text = "Обороты:")
|
||||||
|
|
||||||
|
Chart(
|
||||||
|
chart = lineChart,
|
||||||
|
chartModelProducer = xProducer,
|
||||||
|
startAxis = startAxis(),
|
||||||
|
bottomAxis = bottomAxis(
|
||||||
|
tickLength = 0.dp,
|
||||||
|
valueFormatter = axisValueFormatter,
|
||||||
|
labelRotationDegrees = -90f,
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(1f),
|
||||||
|
autoScaleUp = AutoScaleUp.None,
|
||||||
|
diffAnimationSpec = tween(0),
|
||||||
|
chartScrollSpec = rememberChartScrollSpec(
|
||||||
|
initialScroll = InitialScroll.End,
|
||||||
|
autoScrollCondition = AutoScrollCondition.OnModelSizeIncreased,
|
||||||
|
autoScrollAnimationSpec = tween(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Ble.Accelerometer.HistoryPoint.Vibration -> {
|
||||||
Column {
|
Column {
|
||||||
|
|
||||||
Text(text = "Вибрация:")
|
Text(text = "Вибрация:")
|
||||||
|
|
@ -359,7 +396,8 @@ fun Display(
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
null -> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,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
|
||||||
|
|
@ -115,7 +114,7 @@ fun DisplayState(
|
||||||
|
|
||||||
val history = ble.accelerometerState.saveHistory
|
val history = ble.accelerometerState.saveHistory
|
||||||
|
|
||||||
if(history is Ble.Accelerometer.History.Enabled){
|
if(history is Ble.Accelerometer.HistorySettings.Enabled){
|
||||||
Text(
|
Text(
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
|
@ -133,7 +132,7 @@ fun DisplayState(
|
||||||
}
|
}
|
||||||
|
|
||||||
Switch(
|
Switch(
|
||||||
checked = ble.accelerometerState.saveHistory is Ble.Accelerometer.History.Enabled,
|
checked = ble.accelerometerState.saveHistory is Ble.Accelerometer.HistorySettings.Enabled,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
onEvent(AccelerometerContract.Event.OnSaveHistoryChanged(it))
|
onEvent(AccelerometerContract.Event.OnSaveHistoryChanged(it))
|
||||||
}
|
}
|
||||||
|
|
@ -168,13 +167,14 @@ fun DisplayState(
|
||||||
text = "Интервал измерений"
|
text = "Интервал измерений"
|
||||||
)
|
)
|
||||||
|
|
||||||
val hours = ble.accelerometerState.historyInterval / 1000 / 60 / 60
|
val hours = ble.accelerometerState.historyInterval / millisInHour
|
||||||
val minutes = (ble.accelerometerState.historyInterval - ( hours * 1000 * 60 * 60 )) / 1000 / 60
|
val minutes = (ble.accelerometerState.historyInterval - (hours * millisInHour)) / millisInMinute
|
||||||
|
val seconds = (ble.accelerometerState.historyInterval - (hours * millisInHour) - (minutes * millisInMinute)) / millisInSecond
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
text = "$hours ч. $minutes мин."
|
text = "$hours ч. $minutes мин. $seconds сек."
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,13 @@ package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
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.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.RadioButton
|
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Switch
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
|
@ -21,10 +17,6 @@ import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
|
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
|
||||||
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.FftAxis
|
|
||||||
import llc.arma.ble.domain.usecase.FftFrequency
|
|
||||||
import llc.arma.ble.domain.usecase.FftViewMode
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HistoryEdit(
|
fun HistoryEdit(
|
||||||
|
|
@ -34,9 +26,9 @@ fun HistoryEdit(
|
||||||
|
|
||||||
val history = state.accelerometer.accelerometerState.saveHistory
|
val history = state.accelerometer.accelerometerState.saveHistory
|
||||||
|
|
||||||
val detailed = if (history is Ble.Accelerometer.History.Enabled) history.detailed else false
|
val detailed = if (history is Ble.Accelerometer.HistorySettings.Enabled) history.detailed else false
|
||||||
val accelMode = if (history is Ble.Accelerometer.History.Enabled) history.mode else state.accelViewMode
|
val accelMode = if (history is Ble.Accelerometer.HistorySettings.Enabled) history.mode else state.accelViewMode
|
||||||
val accelScale = if (history is Ble.Accelerometer.History.Enabled) history.scale else state.accelScale
|
val accelScale = if (history is Ble.Accelerometer.HistorySettings.Enabled) history.scale else state.accelScale
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
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.*
|
import androidx.compose.animation.*
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
|
@ -26,15 +27,17 @@ fun IntervalEdit(
|
||||||
}
|
}
|
||||||
|
|
||||||
val maxInterval = 10 * 24 * 60 * 60 * 1000
|
val maxInterval = 10 * 24 * 60 * 60 * 1000
|
||||||
|
val minInterval = 10_000
|
||||||
|
|
||||||
if(value > maxInterval){
|
if(value > maxInterval){
|
||||||
value = maxInterval
|
value = maxInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
if(value < 1){
|
if(value < minInterval){
|
||||||
value = 1 * 60 * 1000
|
value = minInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val maxSeconds = maxInterval / millisInSecond
|
||||||
val maxMinutes = maxInterval / millisInMinute
|
val maxMinutes = maxInterval / millisInMinute
|
||||||
val maxHours = maxInterval / millisInHour
|
val maxHours = maxInterval / millisInHour
|
||||||
val maxDays = maxInterval / millisInDay
|
val maxDays = maxInterval / millisInDay
|
||||||
|
|
@ -42,6 +45,7 @@ fun IntervalEdit(
|
||||||
val dayValue = value / millisInDay
|
val dayValue = value / millisInDay
|
||||||
val hourValue = (value - (dayValue * millisInDay)) / millisInHour
|
val hourValue = (value - (dayValue * millisInDay)) / millisInHour
|
||||||
val minutesValue = (value - (dayValue * millisInDay) - (hourValue * millisInHour)) / millisInMinute
|
val minutesValue = (value - (dayValue * millisInDay) - (hourValue * millisInHour)) / millisInMinute
|
||||||
|
val secondsValue = (value - (dayValue * millisInDay) - (hourValue * millisInHour) - (minutesValue * millisInMinute)) / millisInSecond
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -65,13 +69,13 @@ fun IntervalEdit(
|
||||||
range = -1..maxDays,
|
range = -1..maxDays,
|
||||||
value = dayValue,
|
value = dayValue,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
value = (it * millisInDay) + (hourValue * millisInHour) + (minutesValue * millisInMinute)
|
value = (it * millisInDay) + (hourValue * millisInHour) + (minutesValue * millisInMinute) + (secondsValue * millisInSecond)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
Text(text = "Дни")
|
Text(text = "Д.")
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
|
||||||
|
|
@ -79,13 +83,13 @@ fun IntervalEdit(
|
||||||
range = -1..maxHours,
|
range = -1..maxHours,
|
||||||
value = hourValue,
|
value = hourValue,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
value = (it * millisInHour) + (dayValue * millisInDay) + (minutesValue * millisInMinute)
|
value = (it * millisInHour) + (dayValue * millisInDay) + (minutesValue * millisInMinute) + (secondsValue * millisInSecond)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
Text(text = "Часы")
|
Text(text = "Ч.")
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
|
||||||
|
|
@ -93,13 +97,27 @@ fun IntervalEdit(
|
||||||
range = -1..maxMinutes,
|
range = -1..maxMinutes,
|
||||||
value = minutesValue,
|
value = minutesValue,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
value = (it * millisInMinute) + (dayValue * millisInDay) + (hourValue * millisInHour)
|
value = (secondsValue * millisInSecond) + (it * millisInMinute) + (dayValue * millisInDay) + (hourValue * millisInHour)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
Text(text = "Минуты")
|
Text(text = "М.")
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
|
||||||
|
NumberPicker(
|
||||||
|
range = -1..maxSeconds,
|
||||||
|
value = secondsValue,
|
||||||
|
onValueChanged = {
|
||||||
|
value = (it * millisInSecond) + (minutesValue * millisInMinute) + (dayValue * millisInDay) + (hourValue * millisInHour)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
|
Text(text = "С.")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,7 +156,8 @@ fun IntervalEdit(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const val millisInMinute = 1000 * 60
|
const val millisInSecond = 1000
|
||||||
|
const val millisInMinute = millisInSecond * 60
|
||||||
const val millisInHour = millisInMinute * 60
|
const val millisInHour = millisInMinute * 60
|
||||||
const val millisInDay = millisInHour * 24
|
const val millisInDay = millisInHour * 24
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,14 @@ import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.StrokeCap
|
import androidx.compose.ui.graphics.StrokeCap
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import llc.arma.ble.R
|
import llc.arma.ble.R
|
||||||
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.app.ui.screen.inspection.thermometer.localizedName
|
import llc.arma.ble.app.ui.screen.inspection.thermometer.localizedName
|
||||||
import llc.arma.ble.domain.model.Ble
|
import llc.arma.ble.domain.model.Ble
|
||||||
|
|
||||||
|
|
@ -45,7 +42,7 @@ fun Write(
|
||||||
when (state) {
|
when (state) {
|
||||||
is AccelerometerContract.State.Display.WriteState.DisplayPreview -> {
|
is AccelerometerContract.State.Display.WriteState.DisplayPreview -> {
|
||||||
|
|
||||||
if(state.writeRequest.tx != null || state.writeRequest.saveHistory != null || state.writeRequest.historyInterval != null) {
|
if(state.writeRequest.tx != null || state.writeRequest.saveHistorySettings != null || state.writeRequest.historyInterval != null) {
|
||||||
|
|
||||||
state.writeRequest.tx?.let {
|
state.writeRequest.tx?.let {
|
||||||
Box(
|
Box(
|
||||||
|
|
@ -82,7 +79,7 @@ fun Write(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.writeRequest.saveHistory?.let {
|
state.writeRequest.saveHistorySettings?.let {
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.padding(
|
modifier = Modifier.padding(
|
||||||
|
|
@ -109,8 +106,8 @@ fun Write(
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
text = when(it){
|
text = when(it){
|
||||||
Ble.Accelerometer.History.Disabled -> "Выключено"
|
Ble.Accelerometer.HistorySettings.Disabled -> "Выключено"
|
||||||
is Ble.Accelerometer.History.Enabled -> "Включено"
|
is Ble.Accelerometer.HistorySettings.Enabled -> "Включено"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -142,17 +139,18 @@ fun Write(
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val hours = it / 1000 / 60 / 60
|
|
||||||
val minutes = (it - ( hours * 1000 * 60 * 60 )) / 1000 / 60
|
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "Интервал измерений"
|
text = "Интервал измерений"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val hours = it / millisInHour
|
||||||
|
val minutes = (it - (hours * millisInHour)) / millisInMinute
|
||||||
|
val seconds = (it - (hours * millisInHour) - (minutes * millisInMinute)) / millisInSecond
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
text = "$hours ч. $minutes мин."
|
text = "$hours ч. $minutes мин. $seconds сек."
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,15 +39,15 @@ val Boolean.localizedName: String
|
||||||
val Ble.BleState.TX.localizedName: String
|
val Ble.BleState.TX.localizedName: String
|
||||||
get() {
|
get() {
|
||||||
return when(this){
|
return when(this){
|
||||||
Ble.BleState.TX.MINUS_40 -> -40
|
Ble.BleState.TX.MINUS_40 -> "-40"
|
||||||
Ble.BleState.TX.MINUS_20 -> -20
|
Ble.BleState.TX.MINUS_20 -> "-20"
|
||||||
Ble.BleState.TX.MINUS_16 -> -16
|
Ble.BleState.TX.MINUS_16 -> "-16"
|
||||||
Ble.BleState.TX.MINUS_12 -> -12
|
Ble.BleState.TX.MINUS_12 -> "-12"
|
||||||
Ble.BleState.TX.MINUS_8 -> -8
|
Ble.BleState.TX.MINUS_8 -> "-8"
|
||||||
Ble.BleState.TX.MINUS_4 -> -4
|
Ble.BleState.TX.MINUS_4 -> "-4"
|
||||||
Ble.BleState.TX.ZERO -> 0
|
Ble.BleState.TX.ZERO -> "0"
|
||||||
Ble.BleState.TX.PLUS_3 -> 3
|
Ble.BleState.TX.PLUS_3 -> "3"
|
||||||
Ble.BleState.TX.PLUS_4 -> 4
|
Ble.BleState.TX.PLUS_4 -> "4"
|
||||||
}.toString()
|
}.toString()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -256,7 +256,7 @@ class TemperatureHistoryContract {
|
||||||
sealed class State : ViewState {
|
sealed class State : ViewState {
|
||||||
|
|
||||||
data class Display(
|
data class Display(
|
||||||
val loadingHistoryState : ProgressState<List<Ble.Thermometer.MeasurePoint>>
|
val loadingHistoryState : ProgressState<List<Ble.Thermometer.HistoryPoint>>
|
||||||
) : State()
|
) : State()
|
||||||
|
|
||||||
object Exception : State()
|
object Exception : State()
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -3,20 +3,8 @@ package llc.arma.ble.data
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import llc.arma.ble.R
|
|
||||||
import llc.arma.ble.domain.repository.EmailRepository
|
import llc.arma.ble.domain.repository.EmailRepository
|
||||||
import llc.arma.ble.domain.repository.XlsxRepository
|
|
||||||
import llc.arma.ble.domain.usecase.MeasureData
|
|
||||||
import org.apache.poi.ss.SpreadsheetVersion
|
|
||||||
import org.apache.poi.ss.usermodel.WorkbookFactory
|
|
||||||
import org.apache.poi.ss.util.AreaReference
|
|
||||||
import org.apache.poi.ss.util.CellReference
|
|
||||||
import org.apache.poi.util.IOUtils
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFSheet
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.util.UUID
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class EmailRepositoryImpl @Inject constructor(
|
class EmailRepositoryImpl @Inject constructor(
|
||||||
|
|
|
||||||
|
|
@ -10,56 +10,36 @@ import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import llc.arma.ble.data.extensions.checkPermission
|
||||||
|
import llc.arma.ble.data.extensions.fromByte
|
||||||
|
import llc.arma.ble.data.extensions.get2byteShortAt
|
||||||
|
import llc.arma.ble.data.extensions.get2byteUIntAt
|
||||||
|
import llc.arma.ble.data.extensions.get4byteUIntAt
|
||||||
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.common.ProgressState
|
||||||
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.AccelScale
|
||||||
import llc.arma.ble.domain.usecase.AccelViewMode
|
import llc.arma.ble.domain.usecase.AccelViewMode
|
||||||
import no.nordicsemi.android.common.core.DataByteArray
|
|
||||||
import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt
|
import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.data.util.DataByteArray
|
||||||
|
|
||||||
fun Application.checkPermission(): Boolean {
|
|
||||||
|
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
||||||
ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) ==
|
|
||||||
PackageManager.PERMISSION_GRANTED &&
|
|
||||||
ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) ==
|
|
||||||
PackageManager.PERMISSION_GRANTED
|
|
||||||
} else {
|
|
||||||
return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) ==
|
|
||||||
PackageManager.PERMISSION_GRANTED &&
|
|
||||||
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) ==
|
|
||||||
PackageManager.PERMISSION_GRANTED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ByteArray.get4byteUIntAt(idx: Int) =
|
|
||||||
((this[idx + 3].toUInt() and 0xFFu) shl 24) or
|
|
||||||
((this[idx + 2].toUInt() and 0xFFu) shl 16) or
|
|
||||||
((this[idx + 1].toUInt() and 0xFFu) shl 8) or
|
|
||||||
(this[idx].toUInt() and 0xFFu)
|
|
||||||
|
|
||||||
/*fun ByteArray.get2byteUIntAt(idx: Int) =
|
|
||||||
((this[idx + 1].toUInt() and 0xFFu) shl 8) or
|
|
||||||
(this[idx].toUInt() and 0xFFu)*/
|
|
||||||
|
|
||||||
@OptIn(ExperimentalUnsignedTypes::class)
|
@OptIn(ExperimentalUnsignedTypes::class)
|
||||||
fun readAccelerometerHistory(
|
fun getAccelerometerHistory(
|
||||||
address: String,
|
address: String,
|
||||||
mode: AccelViewMode,
|
|
||||||
scale: AccelScale,
|
|
||||||
app: Application,
|
app: Application,
|
||||||
): Flow<Result<ProgressState<List<Ble.Accelerometer.HistoryPoint>>, BleException>> {
|
): Flow<Result<ProgressState<List<Ble.Accelerometer.HistoryPoint>>, BleException>> {
|
||||||
|
|
||||||
return flow {
|
return flow {
|
||||||
|
|
||||||
var lastMeasureSystemTime: Long? = null
|
var lastMeasureSystemTime: Long? = null
|
||||||
|
|
||||||
var bleMeasureInterval: Long? = null
|
var bleMeasureInterval: Long? = null
|
||||||
var bleRealTime: Long? = null
|
var bleRealTime: Long? = null
|
||||||
var bleLastMeasureTime: Long? = null
|
var bleLastMeasureTime: Long? = null
|
||||||
|
|
||||||
val resultTemperaturePackage: MutableList<Float> = mutableListOf()
|
val resultPackage: MutableList<Float> = mutableListOf()
|
||||||
|
|
||||||
val result = mutableListOf<List<UByte>>()
|
val result = mutableListOf<List<UByte>>()
|
||||||
|
|
||||||
|
|
@ -67,18 +47,28 @@ fun readAccelerometerHistory(
|
||||||
|
|
||||||
if(app.checkPermission()) {
|
if(app.checkPermission()) {
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
val connection =
|
val connection =
|
||||||
ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.Default))
|
ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.Default))
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
val specData = connection.discoverServices()
|
||||||
|
.findService(serviceUUID)
|
||||||
|
?.findCharacteristic(accelerometerReadUUID)
|
||||||
|
?.let {
|
||||||
|
it.write(DataByteArray.from(4))
|
||||||
|
it.read()
|
||||||
|
} ?: throw IllegalStateException()
|
||||||
|
|
||||||
|
val scale = AccelScale.fromByte(specData.value[1]) ?: throw IllegalStateException()
|
||||||
|
val mode = AccelViewMode.fromByte(specData.value[0]) ?: throw IllegalStateException()
|
||||||
|
|
||||||
val characteristic = connection.discoverServices()
|
val characteristic = connection.discoverServices()
|
||||||
.findService(serviceUUID)
|
.findService(serviceUUID)
|
||||||
?.findCharacteristic(accelerometerHistoryReadUUID)
|
?.findCharacteristic(accelerometerHistoryReadUUID)
|
||||||
|
|
||||||
if(characteristic != null) {
|
if(characteristic != null) {
|
||||||
|
|
||||||
|
|
||||||
characteristic.write(DataByteArray.from(2))
|
characteristic.write(DataByteArray.from(2))
|
||||||
|
|
||||||
var value = characteristic.read().value
|
var value = characteristic.read().value
|
||||||
|
|
@ -89,7 +79,7 @@ fun readAccelerometerHistory(
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
Log.d("expected data size", value.get2byteUIntAt(0).toString())
|
var nextPackageDataCount = value.get2byteUIntAt(0)
|
||||||
|
|
||||||
val writeData = mutableListOf(
|
val writeData = mutableListOf(
|
||||||
1.toByte(),
|
1.toByte(),
|
||||||
|
|
@ -101,7 +91,7 @@ fun readAccelerometerHistory(
|
||||||
|
|
||||||
characteristic.write(DataByteArray(writeData))
|
characteristic.write(DataByteArray(writeData))
|
||||||
value = characteristic.read().value
|
value = characteristic.read().value
|
||||||
var nextPackageDataCount = value.get2byteUIntAt(2)
|
|
||||||
|
|
||||||
while (nextPackageDataCount.toInt() != 0) {
|
while (nextPackageDataCount.toInt() != 0) {
|
||||||
|
|
||||||
|
|
@ -112,7 +102,7 @@ fun readAccelerometerHistory(
|
||||||
bleRealTime = value.get4byteUIntAt(12).toLong()
|
bleRealTime = value.get4byteUIntAt(12).toLong()
|
||||||
|
|
||||||
lastMeasureSystemTime =
|
lastMeasureSystemTime =
|
||||||
System.currentTimeMillis() - ((bleRealTime!! - bleLastMeasureTime!!) * 1_000)
|
System.currentTimeMillis() - ((bleRealTime - bleLastMeasureTime) * 1_000)
|
||||||
|
|
||||||
value.toUByteArray().asList().subList(16, value.size)
|
value.toUByteArray().asList().subList(16, value.size)
|
||||||
|
|
||||||
|
|
@ -125,23 +115,17 @@ fun readAccelerometerHistory(
|
||||||
result.add(value.toUByteArray().toList())
|
result.add(value.toUByteArray().toList())
|
||||||
nextPackageDataCount = value.get2byteUIntAt(2)
|
nextPackageDataCount = value.get2byteUIntAt(2)
|
||||||
|
|
||||||
resultTemperaturePackage.addAll(
|
resultPackage.addAll(
|
||||||
temperatureDataArray.chunked(2).map {
|
temperatureDataArray.chunked(2).map {
|
||||||
it.toUByteArray().toByteArray().get2byteShortAt().toFloat()
|
it.toUByteArray().toByteArray().get2byteShortAt().toFloat()
|
||||||
}.toMutableList()
|
}.toMutableList()
|
||||||
)
|
)
|
||||||
|
|
||||||
Log.d(
|
|
||||||
"received data size",
|
|
||||||
(temperatureDataArray.chunked(2).size).toString()
|
|
||||||
)
|
|
||||||
Log.d("next data size", nextPackageDataCount.toString())
|
|
||||||
|
|
||||||
expectedDataSize =
|
expectedDataSize =
|
||||||
nextPackageDataCount.toInt() + resultTemperaturePackage.size
|
nextPackageDataCount.toInt() + resultPackage.size
|
||||||
|
|
||||||
emit(Result.success(ProgressState.Progress(0f / expectedDataSize.toFloat())))
|
emit(Result.success(ProgressState.Progress(0f / expectedDataSize.toFloat())))
|
||||||
emit(Result.success(ProgressState.Progress(resultTemperaturePackage.size.toFloat() / expectedDataSize.toFloat())))
|
emit(Result.success(ProgressState.Progress(resultPackage.size.toFloat() / expectedDataSize.toFloat())))
|
||||||
|
|
||||||
characteristic.write(DataByteArray.from(5))
|
characteristic.write(DataByteArray.from(5))
|
||||||
value = characteristic.read().value
|
value = characteristic.read().value
|
||||||
|
|
@ -152,13 +136,20 @@ fun readAccelerometerHistory(
|
||||||
Result.success(
|
Result.success(
|
||||||
ProgressState.Finished(
|
ProgressState.Finished(
|
||||||
when (mode) {
|
when (mode) {
|
||||||
AccelViewMode.ROTATIONS,
|
AccelViewMode.ROTATIONS -> {
|
||||||
|
resultPackage.withIndex().map {
|
||||||
|
Ble.Accelerometer.HistoryPoint.Rotation(
|
||||||
|
date = lastMeasureSystemTime!! - (((resultPackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||||
|
value = it.value.toLong()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
AccelViewMode.ACCELERATION,
|
AccelViewMode.ACCELERATION,
|
||||||
AccelViewMode.PEAK_ACCELERATION,
|
AccelViewMode.PEAK_ACCELERATION,
|
||||||
AccelViewMode.RMS -> {
|
AccelViewMode.RMS -> {
|
||||||
resultTemperaturePackage.chunked(3).withIndex().map {
|
resultPackage.chunked(3).withIndex().map {
|
||||||
Ble.Accelerometer.HistoryPoint.Angle(
|
Ble.Accelerometer.HistoryPoint.Angle(
|
||||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
date = lastMeasureSystemTime!! - (((resultPackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||||
x = (it.value[0] * scale.k) / Short.MAX_VALUE,
|
x = (it.value[0] * scale.k) / Short.MAX_VALUE,
|
||||||
y = (it.value[1] * scale.k) / Short.MAX_VALUE,
|
y = (it.value[1] * scale.k) / Short.MAX_VALUE,
|
||||||
z = (it.value[2] * scale.k) / Short.MAX_VALUE
|
z = (it.value[2] * scale.k) / Short.MAX_VALUE
|
||||||
|
|
@ -167,29 +158,29 @@ fun readAccelerometerHistory(
|
||||||
}
|
}
|
||||||
|
|
||||||
AccelViewMode.ANGLE -> {
|
AccelViewMode.ANGLE -> {
|
||||||
resultTemperaturePackage.chunked(3).withIndex().map {
|
resultPackage.chunked(3).withIndex().map {
|
||||||
Ble.Accelerometer.HistoryPoint.Angle(
|
Ble.Accelerometer.HistoryPoint.Angle(
|
||||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
date = lastMeasureSystemTime!! - (((resultPackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||||
x = calculateAngle(
|
x = calculateAngle(
|
||||||
it.value[2],
|
it.value[2],
|
||||||
it.value[1]
|
it.value[1]
|
||||||
) * 180f / Math.PI.toFloat(),
|
),
|
||||||
y = calculateAngle(
|
y = calculateAngle(
|
||||||
it.value[2],
|
it.value[2],
|
||||||
it.value[0]
|
it.value[0]
|
||||||
) * 180f / Math.PI.toFloat(),
|
),
|
||||||
z = calculateAngle(
|
z = calculateAngle(
|
||||||
it.value[0],
|
it.value[0],
|
||||||
it.value[1]
|
it.value[1]
|
||||||
) * 180f / Math.PI.toFloat()
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AccelViewMode.VIBRATION -> {
|
AccelViewMode.VIBRATION -> {
|
||||||
resultTemperaturePackage.withIndex().map {
|
resultPackage.withIndex().map {
|
||||||
Ble.Accelerometer.HistoryPoint.Vibration(
|
Ble.Accelerometer.HistoryPoint.Vibration(
|
||||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
date = lastMeasureSystemTime!! - (((resultPackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||||
value = (it.value * scale.k) / Short.MAX_VALUE
|
value = (it.value * scale.k) / Short.MAX_VALUE
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -210,13 +201,16 @@ fun readAccelerometerHistory(
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
|
err.printStackTrace()
|
||||||
emit(Result.failure(BleException.UnexpectedResponse))
|
emit(Result.failure(BleException.UnexpectedResponse))
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
|
||||||
|
connection.close()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
emit(Result.failure(BleException.PermissionDenied))
|
emit(Result.failure(BleException.PermissionDenied))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
package llc.arma.ble.data
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import llc.arma.ble.data.extensions.checkPermission
|
||||||
|
import llc.arma.ble.data.extensions.get2byteShortAt
|
||||||
|
import llc.arma.ble.data.extensions.sendData
|
||||||
|
import llc.arma.ble.domain.Result
|
||||||
|
import llc.arma.ble.domain.common.BleException
|
||||||
|
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.AccelViewMode.*
|
||||||
|
import llc.arma.ble.domain.usecase.FftAxis
|
||||||
|
import llc.arma.ble.domain.usecase.FftFrequency
|
||||||
|
import llc.arma.ble.domain.usecase.FftViewMode
|
||||||
|
import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.data.util.DataByteArray
|
||||||
|
|
||||||
|
fun getAccelerometerRealtimeData(
|
||||||
|
app: Application,
|
||||||
|
serial: String,
|
||||||
|
accelScale: AccelScale,
|
||||||
|
accelMode: AccelViewMode,
|
||||||
|
fftAxis: FftAxis,
|
||||||
|
fftMode: FftViewMode,
|
||||||
|
frequency: FftFrequency,
|
||||||
|
): Flow<Result<Ble.Accelerometer.RealtimePoint, BleException>> {
|
||||||
|
|
||||||
|
return flow {
|
||||||
|
|
||||||
|
if(app.checkPermission()) {
|
||||||
|
|
||||||
|
val connection =
|
||||||
|
ClientBleGatt.connect(app, serial, CoroutineScope(Dispatchers.Default))
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
val services = connection.discoverServices()
|
||||||
|
|
||||||
|
val characteristic =
|
||||||
|
services.findService(serviceUUID)
|
||||||
|
?.findCharacteristic(accelerometerReadUUID)
|
||||||
|
?: throw IllegalStateException()
|
||||||
|
|
||||||
|
characteristic.write(
|
||||||
|
DataByteArray.from(
|
||||||
|
4,
|
||||||
|
accelMode.sendData,
|
||||||
|
accelScale.sendData,
|
||||||
|
fftMode.sendData,
|
||||||
|
fftAxis.sendData,
|
||||||
|
frequency.sendData,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
characteristic.getNotifications().collect {
|
||||||
|
|
||||||
|
val value = it.value
|
||||||
|
|
||||||
|
val data = value.toList().chunked(2).map {
|
||||||
|
it.toByteArray().get2byteShortAt()
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = when(accelMode){
|
||||||
|
VIBRATION -> {
|
||||||
|
Ble.Accelerometer.RealtimePoint.Vibration(
|
||||||
|
(value.get2byteShortAt()
|
||||||
|
.toFloat() * accelScale.k) / Short.MAX_VALUE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ANGLE -> {
|
||||||
|
Ble.Accelerometer.RealtimePoint.Angle(
|
||||||
|
x = calculateAngle(
|
||||||
|
data[2].toFloat(),
|
||||||
|
data[1].toFloat()
|
||||||
|
),
|
||||||
|
y = calculateAngle(
|
||||||
|
data[2].toFloat(),
|
||||||
|
data[0].toFloat()
|
||||||
|
),
|
||||||
|
z = calculateAngle(
|
||||||
|
data[0].toFloat(),
|
||||||
|
data[1].toFloat()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ROTATIONS -> {
|
||||||
|
Ble.Accelerometer.RealtimePoint.Rotation(
|
||||||
|
angle = ((360f / 8f) * ((data[0] / 100f) + 1f)) - 45f,
|
||||||
|
tmp = data[1].toFloat(),
|
||||||
|
turnovers = data[2]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ACCELERATION,
|
||||||
|
PEAK_ACCELERATION,
|
||||||
|
RMS -> {
|
||||||
|
Ble.Accelerometer.RealtimePoint.Common(
|
||||||
|
x = (data[0].toFloat() * accelScale.k) / Short.MAX_VALUE,
|
||||||
|
y = (data[1].toFloat() * accelScale.k) / Short.MAX_VALUE,
|
||||||
|
z = (data[2].toFloat() * accelScale.k) / Short.MAX_VALUE,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(Result.success(result))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} catch (err: Exception) {
|
||||||
|
|
||||||
|
err.printStackTrace()
|
||||||
|
|
||||||
|
emit(Result.failure(BleException.UnexpectedResponse))
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
|
||||||
|
connection.disconnect()
|
||||||
|
connection.close()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
emit(Result.failure(BleException.PermissionDenied))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,21 @@
|
||||||
package llc.arma.ble.data
|
package llc.arma.ble.data
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.bluetooth.BluetoothGatt
|
import android.bluetooth.BluetoothGatt
|
||||||
import android.bluetooth.BluetoothGattCallback
|
import android.bluetooth.BluetoothGattCallback
|
||||||
import android.bluetooth.BluetoothGattCharacteristic
|
import android.bluetooth.BluetoothGattCharacteristic
|
||||||
import android.bluetooth.BluetoothGattDescriptor
|
import android.bluetooth.BluetoothGattDescriptor
|
||||||
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 kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import llc.arma.ble.data.extensions.checkPermission
|
||||||
|
import llc.arma.ble.data.extensions.get2byteShortAt
|
||||||
|
import llc.arma.ble.data.extensions.get2byteUIntAt
|
||||||
|
import llc.arma.ble.data.extensions.get4byteUIntAt
|
||||||
|
import llc.arma.ble.data.extensions.sendData
|
||||||
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.common.ProgressState
|
||||||
|
|
@ -23,441 +25,14 @@ import llc.arma.ble.domain.usecase.AccelViewMode
|
||||||
import llc.arma.ble.domain.usecase.FftAxis
|
import llc.arma.ble.domain.usecase.FftAxis
|
||||||
import llc.arma.ble.domain.usecase.FftFrequency
|
import llc.arma.ble.domain.usecase.FftFrequency
|
||||||
import llc.arma.ble.domain.usecase.FftViewMode
|
import llc.arma.ble.domain.usecase.FftViewMode
|
||||||
import no.nordicsemi.android.common.core.DataByteArray
|
|
||||||
import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt
|
import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.data.util.DataByteArray
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.nio.ByteOrder.LITTLE_ENDIAN
|
import java.nio.ByteOrder.LITTLE_ENDIAN
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
fun ByteArray.get2byteShortAt(): Int {
|
|
||||||
val shorts = ShortArray(1)
|
|
||||||
ByteBuffer.wrap(this).order(LITTLE_ENDIAN).asShortBuffer()[shorts]
|
|
||||||
return shorts[0].toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
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<ProgressState<List<Ble.Accelerometer.MeasurePoint>>, 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
|
|
||||||
((this[idx + 1].toUInt() and 0xFFu) shl 8) or
|
|
||||||
(this[idx].toUInt() and 0xFFu)
|
|
||||||
|
|
||||||
private fun ByteArray.get2byteUIntAt(idx: Int) =
|
|
||||||
((this[idx + 1].toUInt() and 0xFFu) shl 8) or
|
|
||||||
(this[idx].toUInt() and 0xFFu)
|
|
||||||
|
|
||||||
private var readProperty: Property? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
onResult(Result.success(ProgressState.Indeterminate))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onConnectionStateChange(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
status: Int,
|
|
||||||
newState: Int
|
|
||||||
) {
|
|
||||||
super.onConnectionStateChange(gatt, status, newState)
|
|
||||||
|
|
||||||
if(status == BluetoothGatt.GATT_SUCCESS){
|
|
||||||
|
|
||||||
if(newState == BluetoothGatt.STATE_CONNECTED){
|
|
||||||
|
|
||||||
if (app.checkPermission()) {
|
|
||||||
gatt.discoverServices()
|
|
||||||
} else {
|
|
||||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
||||||
gatt.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
||||||
gatt.close()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onServicesDiscovered(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
status: Int
|
|
||||||
) {
|
|
||||||
super.onServicesDiscovered(gatt, status)
|
|
||||||
|
|
||||||
if(status == BluetoothGatt.GATT_SUCCESS){
|
|
||||||
enableNotifications(gatt)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun enableNotifications(
|
|
||||||
gatt: BluetoothGatt
|
|
||||||
){
|
|
||||||
|
|
||||||
gatt.getService(serviceUUID)?.getCharacteristic(accelerometerReadUUID)?.let {
|
|
||||||
|
|
||||||
if (app.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 frequencyInterval: Long? = null
|
|
||||||
|
|
||||||
private val resultAccelerometerPackage: MutableList<Float> = mutableListOf()
|
|
||||||
|
|
||||||
private var expectedDataSize: Int? = null
|
|
||||||
|
|
||||||
@Deprecated("Deprecated in Java")
|
|
||||||
override fun onCharacteristicRead(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
characteristic: BluetoothGattCharacteristic,
|
|
||||||
status: Int
|
|
||||||
) {
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
super.onCharacteristicRead(gatt, characteristic, status)
|
|
||||||
onCommonCharacteristicRead(gatt, characteristic, characteristic.value, status)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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) {
|
|
||||||
|
|
||||||
readProperty = Property.DATA_SIZE
|
|
||||||
gatt.getService(serviceUUID).getCharacteristic(accelerometerHistoryReadUUID)?.let {
|
|
||||||
gatt.writeCharacteristic(it, byteArrayOf(2))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCharacteristicRead(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
characteristic: BluetoothGattCharacteristic,
|
|
||||||
value: ByteArray,
|
|
||||||
status: Int
|
|
||||||
) {
|
|
||||||
super.onCharacteristicRead(gatt, characteristic, value, status)
|
|
||||||
onCommonCharacteristicRead(gatt, characteristic, value, status)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onCommonCharacteristicRead(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
characteristic: BluetoothGattCharacteristic,
|
|
||||||
value: ByteArray,
|
|
||||||
status: Int
|
|
||||||
){
|
|
||||||
|
|
||||||
Log.d("value", value.joinToString(separator = ""))
|
|
||||||
|
|
||||||
if(status == BluetoothGatt.GATT_SUCCESS){
|
|
||||||
when(readProperty){
|
|
||||||
Property.DATA_SIZE -> {
|
|
||||||
|
|
||||||
if(value.contentEquals(byteArrayOf(0, 0))) {
|
|
||||||
onResult(
|
|
||||||
Result.success(
|
|
||||||
ProgressState.Finished(
|
|
||||||
emptyList()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
gatt.close()
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
val writeData = mutableListOf(
|
|
||||||
1.toByte(),
|
|
||||||
0.toByte(),
|
|
||||||
0.toByte()
|
|
||||||
).apply {
|
|
||||||
addAll(value.toList())
|
|
||||||
}.toByteArray()
|
|
||||||
|
|
||||||
readProperty = Property.PACKAGE
|
|
||||||
gatt.writeCharacteristic(characteristic, writeData)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Property.PACKAGE -> {
|
|
||||||
|
|
||||||
if(value[0] == 250.toByte()){
|
|
||||||
|
|
||||||
initialValue = value.get4byteUIntAt(8).toLong()
|
|
||||||
frequencyInterval = value.get4byteUIntAt(4).toLong()
|
|
||||||
|
|
||||||
val accelerometerDataArray = value.asList().subList(16, value.size)
|
|
||||||
|
|
||||||
resultAccelerometerPackage.addAll(
|
|
||||||
accelerometerDataArray.chunked(2).map {
|
|
||||||
it.toByteArray().get2byteShortAt().toFloat()
|
|
||||||
}.toMutableList()
|
|
||||||
)
|
|
||||||
|
|
||||||
val nextPackageDataCount = value.get2byteUIntAt(2)
|
|
||||||
expectedDataSize = nextPackageDataCount.toInt() + resultAccelerometerPackage.size
|
|
||||||
|
|
||||||
onResult(Result.success(ProgressState.Progress(0f / expectedDataSize!!.toFloat())))
|
|
||||||
onResult(Result.success(ProgressState.Progress(resultAccelerometerPackage.size.toFloat() / expectedDataSize!!.toFloat())))
|
|
||||||
|
|
||||||
if(nextPackageDataCount != 0.toUInt()){
|
|
||||||
|
|
||||||
if (app.checkPermission()) {
|
|
||||||
|
|
||||||
gatt.writeCharacteristic(characteristic, byteArrayOf(5))
|
|
||||||
gatt.readCharacteristic(characteristic)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
onResult(Result.failure(BleException.PermissionDenied))
|
|
||||||
gatt.close()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
onResult(
|
|
||||||
Result.success(
|
|
||||||
ProgressState.Finished(
|
|
||||||
resultAccelerometerPackage.withIndex().map {
|
|
||||||
Ble.Accelerometer.MeasurePoint(
|
|
||||||
frequency = frequencyInterval!! * it.index + initialValue!!,
|
|
||||||
value = (it.value * accelScale.k) / Short.MAX_VALUE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
start(gatt)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (value[0] == 251.toByte()) {
|
|
||||||
|
|
||||||
val nextPackageDataCount = value.get2byteUIntAt(2)
|
|
||||||
val temperatureDataArray = value.toList().subList(4, value.size)
|
|
||||||
|
|
||||||
resultAccelerometerPackage.addAll(
|
|
||||||
temperatureDataArray.chunked(2).map {
|
|
||||||
it.toByteArray().get2byteShortAt().toFloat()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
onResult(Result.success(ProgressState.Progress(resultAccelerometerPackage.size.toFloat() / expectedDataSize!!.toFloat())))
|
|
||||||
|
|
||||||
if (nextPackageDataCount != 0.toUInt()) {
|
|
||||||
|
|
||||||
val writeData = byteArrayOf(5)
|
|
||||||
|
|
||||||
gatt.writeCharacteristic(characteristic, writeData)
|
|
||||||
gatt.readCharacteristic(characteristic)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
onResult(
|
|
||||||
Result.success(
|
|
||||||
ProgressState.Finished(
|
|
||||||
resultAccelerometerPackage.withIndex().map {
|
|
||||||
Ble.Accelerometer.MeasurePoint(
|
|
||||||
frequency = frequencyInterval!! * it.index + initialValue!!,
|
|
||||||
value = (it.value * accelScale.k) / Short.MAX_VALUE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
start(gatt)
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
||||||
gatt.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
||||||
gatt.close()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCharacteristicWrite(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
characteristic: BluetoothGattCharacteristic,
|
|
||||||
status: Int
|
|
||||||
) {
|
|
||||||
super.onCharacteristicWrite(gatt, characteristic, status)
|
|
||||||
|
|
||||||
if(readProperty !== null) {
|
|
||||||
|
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
|
||||||
|
|
||||||
if (app.checkPermission()) {
|
|
||||||
|
|
||||||
gatt.readCharacteristic(characteristic)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
onResult(Result.failure(BleException.PermissionDenied))
|
|
||||||
gatt.close()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
||||||
gatt.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDescriptorWrite(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
descriptor: BluetoothGattDescriptor,
|
|
||||||
status: Int
|
|
||||||
) {
|
|
||||||
super.onDescriptorWrite(gatt, descriptor, status)
|
|
||||||
start(gatt)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun start(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
){
|
|
||||||
|
|
||||||
gatt.getService(serviceUUID)?.getCharacteristic(accelerometerReadUUID)?.let {
|
|
||||||
|
|
||||||
if (app.checkPermission()) {
|
|
||||||
|
|
||||||
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 {
|
|
||||||
|
|
||||||
onResult(Result.failure(BleException.PermissionDenied))
|
|
||||||
gatt.close()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun BluetoothGatt.writeCharacteristic(
|
|
||||||
characteristic: BluetoothGattCharacteristic,
|
|
||||||
data: ByteArray
|
|
||||||
): Result<Unit, BleException>{
|
|
||||||
|
|
||||||
return if(app.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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalUnsignedTypes::class)
|
|
||||||
fun readAccelerometerSpectre(
|
fun readAccelerometerSpectre(
|
||||||
address: String,
|
address: String,
|
||||||
app: Application,
|
app: Application,
|
||||||
|
|
@ -466,10 +41,47 @@ fun readAccelerometerSpectre(
|
||||||
fftAxis: FftAxis,
|
fftAxis: FftAxis,
|
||||||
fftMode: FftViewMode,
|
fftMode: FftViewMode,
|
||||||
frequency: FftFrequency,
|
frequency: FftFrequency,
|
||||||
): Flow<Result<ProgressState<List<Ble.Accelerometer.MeasurePoint>>, BleException>> {
|
): Flow<Result<ProgressState<List<Ble.Accelerometer.SpectrePoint>>, BleException>> {
|
||||||
|
|
||||||
return flow {
|
return flow {
|
||||||
|
|
||||||
|
if(app.checkPermission()) {
|
||||||
|
|
||||||
|
val connection =
|
||||||
|
ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.Default))
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
val service = connection.discoverServices()
|
||||||
|
.findService(serviceUUID) ?: throw IllegalStateException()
|
||||||
|
|
||||||
|
val characteristic = service.findCharacteristic(accelerometerReadUUID)
|
||||||
|
?: throw IllegalStateException()
|
||||||
|
|
||||||
|
val historyCharacteristic = service.findCharacteristic(accelerometerHistoryReadUUID)
|
||||||
|
?: throw IllegalStateException()
|
||||||
|
|
||||||
|
characteristic.findDescriptor(
|
||||||
|
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
|
||||||
|
)?.write(DataByteArray(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE))
|
||||||
|
?: throw IllegalStateException()
|
||||||
|
|
||||||
|
characteristic.write(
|
||||||
|
DataByteArray(byteArrayOf(
|
||||||
|
4,
|
||||||
|
accelMode.sendData,
|
||||||
|
accelScale.sendData,
|
||||||
|
fftMode.sendData,
|
||||||
|
fftAxis.sendData,
|
||||||
|
frequency.sendData,
|
||||||
|
2
|
||||||
|
))
|
||||||
|
)
|
||||||
|
|
||||||
|
val notifications = characteristic.getNotifications()
|
||||||
|
|
||||||
|
notifications.collect {
|
||||||
|
|
||||||
var initialValue: Long? = null
|
var initialValue: Long? = null
|
||||||
var frequencyInterval: Long? = null
|
var frequencyInterval: Long? = null
|
||||||
|
|
||||||
|
|
@ -477,61 +89,17 @@ fun readAccelerometerSpectre(
|
||||||
|
|
||||||
var expectedDataSize: Int? = null
|
var expectedDataSize: Int? = null
|
||||||
|
|
||||||
if(app.checkPermission()) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
val connection =
|
|
||||||
ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.Default))
|
|
||||||
|
|
||||||
val characteristic = connection.discoverServices()
|
|
||||||
.findService(serviceUUID)
|
|
||||||
?.findCharacteristic(accelerometerReadUUID)
|
|
||||||
?: throw IllegalStateException()
|
|
||||||
|
|
||||||
val historyCharacteristic = connection.discoverServices()
|
|
||||||
.findService(serviceUUID)
|
|
||||||
?.findCharacteristic(accelerometerHistoryReadUUID)
|
|
||||||
?: throw IllegalStateException()
|
|
||||||
|
|
||||||
Log.d("notification", "-1")
|
|
||||||
|
|
||||||
Log.d("notification", "0")
|
|
||||||
|
|
||||||
characteristic.write(DataByteArray(byteArrayOf(
|
|
||||||
4,
|
|
||||||
accelMode.sendData,
|
|
||||||
accelScale.sendData,
|
|
||||||
fftMode.sendData,
|
|
||||||
fftAxis.sendData,
|
|
||||||
frequency.sendData,
|
|
||||||
2
|
|
||||||
)))
|
|
||||||
|
|
||||||
Log.d("notification", "1")
|
|
||||||
|
|
||||||
val notifications = characteristic.getNotifications()
|
|
||||||
|
|
||||||
notifications.collect {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Log.d("notification", "0")
|
|
||||||
|
|
||||||
historyCharacteristic.write(DataByteArray.from(2))
|
historyCharacteristic.write(DataByteArray.from(2))
|
||||||
|
|
||||||
var value = historyCharacteristic.read().value
|
var value = historyCharacteristic.read().value
|
||||||
|
|
||||||
Log.d("value", value.joinToString(separator = ""))
|
|
||||||
Log.d("value", value.get2byteUIntAt(0).toString())
|
|
||||||
|
|
||||||
if (value.contentEquals(byteArrayOf(0, 0))) {
|
if (value.contentEquals(byteArrayOf(0, 0))) {
|
||||||
|
|
||||||
emit(Result.success(ProgressState.Finished(emptyList())))
|
emit(Result.success(ProgressState.Finished(emptyList())))
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
Log.d("expected data size", value.get2byteUIntAt(0).toString())
|
var nextPackageDataCount = value.get2byteUIntAt(0)
|
||||||
|
|
||||||
val writeData = mutableListOf(
|
val writeData = mutableListOf(
|
||||||
1.toByte(),
|
1.toByte(),
|
||||||
|
|
@ -543,7 +111,7 @@ fun readAccelerometerSpectre(
|
||||||
|
|
||||||
historyCharacteristic.write(DataByteArray(writeData))
|
historyCharacteristic.write(DataByteArray(writeData))
|
||||||
value = historyCharacteristic.read().value
|
value = historyCharacteristic.read().value
|
||||||
var nextPackageDataCount = value.get2byteUIntAt(2)
|
|
||||||
|
|
||||||
while (nextPackageDataCount.toInt() != 0) {
|
while (nextPackageDataCount.toInt() != 0) {
|
||||||
|
|
||||||
|
|
@ -569,8 +137,8 @@ fun readAccelerometerSpectre(
|
||||||
|
|
||||||
expectedDataSize = nextPackageDataCount.toInt() + resultAccelerometerPackage.size
|
expectedDataSize = nextPackageDataCount.toInt() + resultAccelerometerPackage.size
|
||||||
|
|
||||||
emit(Result.success(ProgressState.Progress(0f / expectedDataSize!!.toFloat())))
|
emit(Result.success(ProgressState.Progress(0f / expectedDataSize.toFloat())))
|
||||||
emit(Result.success(ProgressState.Progress(resultAccelerometerPackage.size.toFloat() / expectedDataSize!!.toFloat())))
|
emit(Result.success(ProgressState.Progress(resultAccelerometerPackage.size.toFloat() / expectedDataSize.toFloat())))
|
||||||
|
|
||||||
historyCharacteristic.write(DataByteArray.from(5))
|
historyCharacteristic.write(DataByteArray.from(5))
|
||||||
value = historyCharacteristic.read().value
|
value = historyCharacteristic.read().value
|
||||||
|
|
@ -581,7 +149,7 @@ fun readAccelerometerSpectre(
|
||||||
Result.success(
|
Result.success(
|
||||||
ProgressState.Finished(
|
ProgressState.Finished(
|
||||||
resultAccelerometerPackage.withIndex().map {
|
resultAccelerometerPackage.withIndex().map {
|
||||||
Ble.Accelerometer.MeasurePoint(
|
Ble.Accelerometer.SpectrePoint(
|
||||||
frequency = frequencyInterval!! * it.index + initialValue!!,
|
frequency = frequencyInterval!! * it.index + initialValue!!,
|
||||||
value = (it.value * accelScale.k) / Short.MAX_VALUE
|
value = (it.value * accelScale.k) / Short.MAX_VALUE
|
||||||
)
|
)
|
||||||
|
|
@ -611,6 +179,10 @@ fun readAccelerometerSpectre(
|
||||||
err.printStackTrace()
|
err.printStackTrace()
|
||||||
emit(Result.failure(BleException.UnexpectedResponse))
|
emit(Result.failure(BleException.UnexpectedResponse))
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
|
||||||
|
connection.close()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,339 +1,31 @@
|
||||||
package llc.arma.ble.data
|
package llc.arma.ble.data
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.bluetooth.BluetoothGatt
|
import android.bluetooth.BluetoothGatt
|
||||||
import android.bluetooth.BluetoothGattCallback
|
import android.bluetooth.BluetoothGattCallback
|
||||||
import android.bluetooth.BluetoothGattCharacteristic
|
import android.bluetooth.BluetoothGattCharacteristic
|
||||||
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 kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import llc.arma.ble.data.extensions.checkPermission
|
||||||
|
import llc.arma.ble.data.extensions.get2byteUIntAt
|
||||||
|
import llc.arma.ble.data.extensions.get4byteUIntAt
|
||||||
|
import llc.arma.ble.data.extensions.toTemperature
|
||||||
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.common.ProgressState
|
||||||
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 no.nordicsemi.android.common.core.DataByteArray
|
|
||||||
import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt
|
import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.data.util.DataByteArray
|
||||||
class ReadTemperatureHistoryCallback(
|
|
||||||
private val app: Application,
|
|
||||||
private val onResult: (Result<ProgressState<List<Ble.Thermometer.MeasurePoint>>, 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
|
|
||||||
((this[idx + 1].toUInt() and 0xFFu) shl 8) or
|
|
||||||
(this[idx].toUInt() and 0xFFu)
|
|
||||||
|
|
||||||
private fun ByteArray.get2byteUIntAt(idx: Int) =
|
|
||||||
((this[idx + 1].toUInt() and 0xFFu) shl 8) or
|
|
||||||
(this[idx].toUInt() and 0xFFu)
|
|
||||||
|
|
||||||
private var readProperty: Property? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
onResult(Result.success(ProgressState.Indeterminate))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onConnectionStateChange(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
status: Int,
|
|
||||||
newState: Int
|
|
||||||
) {
|
|
||||||
super.onConnectionStateChange(gatt, status, newState)
|
|
||||||
|
|
||||||
if(status == BluetoothGatt.GATT_SUCCESS){
|
|
||||||
|
|
||||||
if(newState == BluetoothGatt.STATE_CONNECTED){
|
|
||||||
|
|
||||||
if (app.checkPermission()) {
|
|
||||||
gatt.discoverServices()
|
|
||||||
|
|
||||||
} else {
|
|
||||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
||||||
gatt.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
||||||
gatt.close()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onServicesDiscovered(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
status: Int
|
|
||||||
) {
|
|
||||||
super.onServicesDiscovered(gatt, status)
|
|
||||||
if(status == BluetoothGatt.GATT_SUCCESS){
|
|
||||||
gatt.getService(serviceUUID)?.getCharacteristic(temperatureHistoryReadUUID)?.let {
|
|
||||||
|
|
||||||
if (app.checkPermission()) {
|
|
||||||
|
|
||||||
readProperty = Property.DATA_SIZE
|
|
||||||
gatt.writeCharacteristic(it, byteArrayOf(2))
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
onResult(Result.failure(BleException.PermissionDenied))
|
|
||||||
gatt.close()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private var lastMeasureSystemTime: Long? = null
|
|
||||||
|
|
||||||
private var bleMeasureInterval: Long? = null
|
|
||||||
private var bleRealTime: Long? = null
|
|
||||||
private var bleLastMeasureTime: Long? = null
|
|
||||||
|
|
||||||
private val resultTemperaturePackage: MutableList<Float> = mutableListOf()
|
|
||||||
|
|
||||||
var expectedDataSize: Int? = null
|
|
||||||
|
|
||||||
override fun onCharacteristicRead(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
characteristic: BluetoothGattCharacteristic,
|
|
||||||
status: Int
|
|
||||||
) {
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
super.onCharacteristicRead(gatt, characteristic, status)
|
|
||||||
onCommonCharacteristicRead(gatt, characteristic, characteristic.value, status)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCharacteristicRead(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
characteristic: BluetoothGattCharacteristic,
|
|
||||||
value: ByteArray,
|
|
||||||
status: Int
|
|
||||||
) {
|
|
||||||
super.onCharacteristicRead(gatt, characteristic, value, status)
|
|
||||||
onCommonCharacteristicRead(gatt, characteristic, value, status)
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalUnsignedTypes::class)
|
|
||||||
private fun onCommonCharacteristicRead(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
characteristic: BluetoothGattCharacteristic,
|
|
||||||
value: ByteArray,
|
|
||||||
status: Int
|
|
||||||
){
|
|
||||||
|
|
||||||
if(status == BluetoothGatt.GATT_SUCCESS){
|
|
||||||
when(readProperty){
|
|
||||||
Property.DATA_SIZE -> {
|
|
||||||
|
|
||||||
if(value.contentEquals(byteArrayOf(0, 0))) {
|
|
||||||
onResult(
|
|
||||||
Result.success(
|
|
||||||
ProgressState.Finished(
|
|
||||||
emptyList()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
gatt.close()
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
val writeData = mutableListOf(
|
|
||||||
1.toByte(),
|
|
||||||
0.toByte(),
|
|
||||||
0.toByte()
|
|
||||||
).apply {
|
|
||||||
addAll(value.toList())
|
|
||||||
}.toByteArray()
|
|
||||||
|
|
||||||
readProperty = Property.PACKAGE
|
|
||||||
gatt.writeCharacteristic(characteristic, writeData)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Property.PACKAGE -> {
|
|
||||||
|
|
||||||
if(value[0] == 250.toByte()){
|
|
||||||
|
|
||||||
bleMeasureInterval = value.get4byteUIntAt(4).toLong()
|
|
||||||
bleLastMeasureTime = value.get4byteUIntAt(8).toLong()
|
|
||||||
bleRealTime = value.get4byteUIntAt(12).toLong()
|
|
||||||
|
|
||||||
lastMeasureSystemTime = System.currentTimeMillis() - ((bleRealTime!! - bleLastMeasureTime!!) * 1_000)
|
|
||||||
|
|
||||||
val temperatureDataArray = value.toUByteArray().asList().subList(16, value.size)
|
|
||||||
|
|
||||||
resultTemperaturePackage.addAll(
|
|
||||||
temperatureDataArray.chunked(2).map {
|
|
||||||
it.toUByteArray().toTemperature()
|
|
||||||
}.toMutableList()
|
|
||||||
)
|
|
||||||
|
|
||||||
val nextPackageDataCount = value.get2byteUIntAt(2)
|
|
||||||
expectedDataSize = nextPackageDataCount.toInt() + resultTemperaturePackage.size
|
|
||||||
Log.d("read", expectedDataSize.toString())
|
|
||||||
onResult(Result.success(ProgressState.Progress(0f / expectedDataSize!!.toFloat())))
|
|
||||||
onResult(Result.success(ProgressState.Progress(resultTemperaturePackage.size.toFloat() / expectedDataSize!!.toFloat())))
|
|
||||||
|
|
||||||
if(nextPackageDataCount != 0.toUInt()){
|
|
||||||
|
|
||||||
if (app.checkPermission()) {
|
|
||||||
|
|
||||||
gatt.writeCharacteristic(characteristic, byteArrayOf(5))
|
|
||||||
gatt.readCharacteristic(characteristic)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
onResult(Result.failure(BleException.PermissionDenied))
|
|
||||||
gatt.close()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
onResult(
|
|
||||||
Result.success(
|
|
||||||
ProgressState.Finished(
|
|
||||||
resultTemperaturePackage.withIndex().map {
|
|
||||||
Ble.Thermometer.MeasurePoint(
|
|
||||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
|
||||||
value = it.value
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
gatt.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (value[0] == 251.toByte()) {
|
|
||||||
|
|
||||||
val nextPackageDataCount = value.get2byteUIntAt(2)
|
|
||||||
val temperatureDataArray = value.toUByteArray().toList().subList(4, value.size)
|
|
||||||
|
|
||||||
resultTemperaturePackage.addAll(
|
|
||||||
temperatureDataArray.chunked(2).map {
|
|
||||||
it.toUByteArray().toTemperature()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
onResult(Result.success(ProgressState.Progress(resultTemperaturePackage.size.toFloat() / expectedDataSize!!.toFloat())))
|
|
||||||
|
|
||||||
if (nextPackageDataCount != 0.toUInt()) {
|
|
||||||
|
|
||||||
val writeData = byteArrayOf(5)
|
|
||||||
|
|
||||||
gatt.writeCharacteristic(characteristic, writeData)
|
|
||||||
gatt.readCharacteristic(characteristic)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
onResult(
|
|
||||||
Result.success(
|
|
||||||
ProgressState.Finished(
|
|
||||||
resultTemperaturePackage.withIndex().map {
|
|
||||||
Ble.Thermometer.MeasurePoint(
|
|
||||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
|
||||||
value = it.value
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
gatt.close()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
||||||
gatt.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
||||||
gatt.close()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCharacteristicWrite(
|
|
||||||
gatt: BluetoothGatt,
|
|
||||||
characteristic: BluetoothGattCharacteristic,
|
|
||||||
status: Int
|
|
||||||
) {
|
|
||||||
super.onCharacteristicWrite(gatt, characteristic, status)
|
|
||||||
if(status == BluetoothGatt.GATT_SUCCESS){
|
|
||||||
|
|
||||||
if (app.checkPermission()) {
|
|
||||||
|
|
||||||
gatt.readCharacteristic(characteristic)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
onResult(Result.failure(BleException.PermissionDenied))
|
|
||||||
gatt.close()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
||||||
gatt.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun BluetoothGatt.writeCharacteristic(
|
|
||||||
characteristic: BluetoothGattCharacteristic,
|
|
||||||
data: ByteArray
|
|
||||||
): Result<Unit, BleException>{
|
|
||||||
|
|
||||||
return if(app.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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalUnsignedTypes::class)
|
@OptIn(ExperimentalUnsignedTypes::class)
|
||||||
fun readThermometerHistory(
|
fun readThermometerHistory(
|
||||||
address: String,
|
address: String,
|
||||||
app: Application,
|
app: Application,
|
||||||
): Flow<Result<ProgressState<List<Ble.Thermometer.MeasurePoint>>, BleException>> {
|
): Flow<Result<ProgressState<List<Ble.Thermometer.HistoryPoint>>, BleException>> {
|
||||||
|
|
||||||
return flow {
|
return flow {
|
||||||
|
|
||||||
|
|
@ -369,8 +61,6 @@ fun readThermometerHistory(
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
Log.d("expected data size", value.get2byteUIntAt(0).toString())
|
|
||||||
|
|
||||||
val writeData = mutableListOf(
|
val writeData = mutableListOf(
|
||||||
1.toByte(),
|
1.toByte(),
|
||||||
0.toByte(),
|
0.toByte(),
|
||||||
|
|
@ -410,12 +100,6 @@ fun readThermometerHistory(
|
||||||
}.toMutableList()
|
}.toMutableList()
|
||||||
)
|
)
|
||||||
|
|
||||||
Log.d(
|
|
||||||
"received data size",
|
|
||||||
(temperatureDataArray.chunked(2).size).toString()
|
|
||||||
)
|
|
||||||
Log.d("next data size", nextPackageDataCount.toString())
|
|
||||||
|
|
||||||
expectedDataSize =
|
expectedDataSize =
|
||||||
nextPackageDataCount.toInt() + resultTemperaturePackage.size
|
nextPackageDataCount.toInt() + resultTemperaturePackage.size
|
||||||
|
|
||||||
|
|
@ -431,7 +115,7 @@ fun readThermometerHistory(
|
||||||
Result.success(
|
Result.success(
|
||||||
ProgressState.Finished(
|
ProgressState.Finished(
|
||||||
resultTemperaturePackage.withIndex().map {
|
resultTemperaturePackage.withIndex().map {
|
||||||
Ble.Thermometer.MeasurePoint(
|
Ble.Thermometer.HistoryPoint(
|
||||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||||
value = it.value
|
value = it.value
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
package llc.arma.ble.data
|
package llc.arma.ble.data
|
||||||
|
|
||||||
import android.R.attr.src
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.icu.text.SimpleDateFormat
|
import android.icu.text.SimpleDateFormat
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.os.FileUtils
|
import android.util.Log
|
||||||
import llc.arma.ble.R
|
import llc.arma.ble.R
|
||||||
import llc.arma.ble.domain.model.Ble
|
import llc.arma.ble.domain.model.Ble
|
||||||
import llc.arma.ble.domain.repository.XlsxRepository
|
import llc.arma.ble.domain.repository.XlsxRepository
|
||||||
|
|
@ -15,7 +14,6 @@ import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.UUID
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -28,12 +26,14 @@ class XlsxRepositoryImpl @Inject constructor(
|
||||||
data: List<Ble.Accelerometer.HistoryPoint>
|
data: List<Ble.Accelerometer.HistoryPoint>
|
||||||
): File {
|
): File {
|
||||||
|
|
||||||
val fileNameDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
|
val fileNameDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm")
|
||||||
val fileName = "$bleName ${fileNameDateFormat.format(Date(System.currentTimeMillis()))}.xlsx"
|
val fileName = "${fileNameDateFormat.format(Date(System.currentTimeMillis()))}.xlsx".replace(' ', '_')
|
||||||
|
|
||||||
val formatter = SimpleDateFormat("dd.MM.yyyy HH:mm")
|
val formatter = SimpleDateFormat("dd.MM.yyyy HH:mm")
|
||||||
|
|
||||||
|
File(application.filesDir.absolutePath).mkdirs()
|
||||||
val mailFile = File(application.filesDir, fileName)
|
val mailFile = File(application.filesDir, fileName)
|
||||||
|
|
||||||
mailFile.createNewFile()
|
mailFile.createNewFile()
|
||||||
|
|
||||||
when(data.firstOrNull()){
|
when(data.firstOrNull()){
|
||||||
|
|
@ -73,7 +73,7 @@ class XlsxRepositoryImpl @Inject constructor(
|
||||||
x.setCellValue(value.value.toDouble())
|
x.setCellValue(value.value.toDouble())
|
||||||
}
|
}
|
||||||
|
|
||||||
is Ble.Accelerometer.HistoryPoint.Accelerate -> {
|
is Ble.Accelerometer.HistoryPoint.Acceleration -> {
|
||||||
dateX.setCellValue(formatter.format(Date(value.date)))
|
dateX.setCellValue(formatter.format(Date(value.date)))
|
||||||
dateY.setCellValue(formatter.format(Date(value.date)))
|
dateY.setCellValue(formatter.format(Date(value.date)))
|
||||||
dateZ.setCellValue(formatter.format(Date(value.date)))
|
dateZ.setCellValue(formatter.format(Date(value.date)))
|
||||||
|
|
@ -82,6 +82,10 @@ class XlsxRepositoryImpl @Inject constructor(
|
||||||
z.setCellValue(value.z.toDouble())
|
z.setCellValue(value.z.toDouble())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is Ble.Accelerometer.HistoryPoint.Rotation -> {
|
||||||
|
dateX.setCellValue(formatter.format(Date(value.date)))
|
||||||
|
x.setCellValue(value.value.toDouble())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package llc.arma.ble.data.extensions
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
|
||||||
|
fun Application.checkPermission(): Boolean {
|
||||||
|
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) ==
|
||||||
|
PackageManager.PERMISSION_GRANTED &&
|
||||||
|
ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) ==
|
||||||
|
PackageManager.PERMISSION_GRANTED
|
||||||
|
} else {
|
||||||
|
return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) ==
|
||||||
|
PackageManager.PERMISSION_GRANTED &&
|
||||||
|
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) ==
|
||||||
|
PackageManager.PERMISSION_GRANTED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
package llc.arma.ble.data.extensions
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
fun Ble.BleState.TX.Companion.fromByte(byte: Byte): Ble.BleState.TX? {
|
||||||
|
return Ble.BleState.TX.values().associateBy { it.sendData }[byte]
|
||||||
|
}
|
||||||
|
|
||||||
|
val Ble.BleState.TX.sendData: Byte
|
||||||
|
get() {
|
||||||
|
return when (this) {
|
||||||
|
Ble.BleState.TX.MINUS_40 -> -40
|
||||||
|
Ble.BleState.TX.MINUS_20 -> -20
|
||||||
|
Ble.BleState.TX.MINUS_16 -> -16
|
||||||
|
Ble.BleState.TX.MINUS_12 -> -12
|
||||||
|
Ble.BleState.TX.MINUS_8 -> -8
|
||||||
|
Ble.BleState.TX.MINUS_4 -> -4
|
||||||
|
Ble.BleState.TX.ZERO -> 0
|
||||||
|
Ble.BleState.TX.PLUS_3 -> 3
|
||||||
|
Ble.BleState.TX.PLUS_4 -> 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun AccelViewMode.Companion.fromByte(byte: Byte): AccelViewMode? {
|
||||||
|
return AccelViewMode.values().associateBy { it.sendData }[byte]
|
||||||
|
}
|
||||||
|
|
||||||
|
val AccelViewMode.sendData: Byte
|
||||||
|
get() {
|
||||||
|
return when(this){
|
||||||
|
AccelViewMode.ACCELERATION -> 0
|
||||||
|
AccelViewMode.PEAK_ACCELERATION -> 1
|
||||||
|
AccelViewMode.RMS -> 2
|
||||||
|
AccelViewMode.VIBRATION -> 3
|
||||||
|
AccelViewMode.ANGLE -> 4
|
||||||
|
AccelViewMode.ROTATIONS -> 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun AccelScale.Companion.fromByte(byte: Byte): AccelScale? {
|
||||||
|
return AccelScale.values().associateBy { it.sendData }[byte]
|
||||||
|
}
|
||||||
|
|
||||||
|
val AccelScale.sendData: Byte
|
||||||
|
get() {
|
||||||
|
return when(this){
|
||||||
|
AccelScale.S_2 -> 0
|
||||||
|
AccelScale.S_4 -> 1
|
||||||
|
AccelScale.S_8 -> 2
|
||||||
|
AccelScale.S_16 -> 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
package llc.arma.ble.data.extensions
|
||||||
|
|
||||||
|
import llc.arma.ble.domain.model.BleInfo
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.scanner.BleScanResult
|
||||||
|
|
||||||
|
val BleScanResult.timerEnabled: Boolean
|
||||||
|
get() {
|
||||||
|
return data?.scanRecord?.manufacturerSpecificData?.get(89)?.getByte(2) == 1.toByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
val BleScanResult.info: BleInfo
|
||||||
|
get() {
|
||||||
|
this.device.name
|
||||||
|
return BleInfo(
|
||||||
|
name = this.device.name ?: "",
|
||||||
|
serial = device.address,
|
||||||
|
batteryLevel = batteryLevel ?: 0,
|
||||||
|
rssi = data?.rssi,
|
||||||
|
type = type,
|
||||||
|
scanTime = (data?.timestampNanos ?: 0) / 1_000_000,
|
||||||
|
tx = data?.txPower ?: 0,
|
||||||
|
recordEnabled = timerEnabled
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val BleScanResult.batteryLevel: Int?
|
||||||
|
get() {
|
||||||
|
return data?.scanRecord?.manufacturerSpecificData?.get(89)?.getByte(1)
|
||||||
|
?.toUByte()?.toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
val BleScanResult.type: BleInfo.Type
|
||||||
|
get() {
|
||||||
|
return when(data?.scanRecord?.manufacturerSpecificData?.get(89)?.getByte(0)?.toUByte()?.toInt()){
|
||||||
|
1 -> BleInfo.Type.BEACON
|
||||||
|
2 -> BleInfo.Type.THERMOMETER
|
||||||
|
else -> BleInfo.Type.ACCELEROMETER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package llc.arma.ble.data.extensions
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.nio.ByteOrder
|
||||||
|
|
||||||
|
fun ByteArray.get2byteShortAt(): Int {
|
||||||
|
val shorts = ShortArray(1)
|
||||||
|
ByteBuffer.wrap(this).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer()[shorts]
|
||||||
|
return shorts[0].toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ByteArray.get4byteUIntAt(idx: Int) =
|
||||||
|
((this[idx + 3].toUInt() and 0xFFu) shl 24) or
|
||||||
|
((this[idx + 2].toUInt() and 0xFFu) shl 16) or
|
||||||
|
((this[idx + 1].toUInt() and 0xFFu) shl 8) or
|
||||||
|
(this[idx].toUInt() and 0xFFu)
|
||||||
|
|
||||||
|
fun ByteArray.get2byteUIntAt(idx: Int) =
|
||||||
|
((this[idx + 1].toUInt() and 0xFFu) shl 8) or
|
||||||
|
(this[idx].toUInt() and 0xFFu)
|
||||||
|
|
||||||
|
@OptIn(ExperimentalUnsignedTypes::class)
|
||||||
|
fun UByteArray.toTemperature(): Float {
|
||||||
|
|
||||||
|
val uShort = (this[0] + this[1] * 256u).toUShort()
|
||||||
|
|
||||||
|
val result = if (uShort > Short.MAX_VALUE.toUShort()) {
|
||||||
|
((uShort.inv() + 1u).toFloat().unaryMinus()) / 100f
|
||||||
|
} else {
|
||||||
|
uShort.toFloat() / 100f
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -13,21 +13,21 @@ sealed class Ble(
|
||||||
val accelerometerState: AccelerometerState
|
val accelerometerState: AccelerometerState
|
||||||
): Ble(info) {
|
): Ble(info) {
|
||||||
|
|
||||||
sealed class History {
|
sealed class HistorySettings {
|
||||||
|
|
||||||
data class Enabled(
|
data class Enabled(
|
||||||
val scale: AccelScale,
|
val scale: AccelScale,
|
||||||
val mode: AccelViewMode,
|
val mode: AccelViewMode,
|
||||||
val detailed: Boolean
|
val detailed: Boolean
|
||||||
) : History()
|
) : HistorySettings()
|
||||||
|
|
||||||
object Disabled : History()
|
object Disabled : HistorySettings()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class WriteRequest(
|
data class WriteRequest(
|
||||||
val tx: BleState.TX?,
|
val tx: BleState.TX?,
|
||||||
val saveHistory: History?,
|
val saveHistorySettings: HistorySettings?,
|
||||||
val historyInterval: Long?
|
val historyInterval: Long?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -38,7 +38,12 @@ sealed class Ble(
|
||||||
val value: Float
|
val value: Float
|
||||||
) : HistoryPoint()
|
) : HistoryPoint()
|
||||||
|
|
||||||
class Accelerate (
|
class Rotation (
|
||||||
|
val date: Long,
|
||||||
|
val value: Long
|
||||||
|
) : HistoryPoint()
|
||||||
|
|
||||||
|
class Acceleration (
|
||||||
val date: Long,
|
val date: Long,
|
||||||
val x: Float,
|
val x: Float,
|
||||||
val y: Float,
|
val y: Float,
|
||||||
|
|
@ -54,13 +59,39 @@ sealed class Ble(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MeasurePoint (
|
sealed class RealtimePoint {
|
||||||
|
|
||||||
|
data class Rotation(
|
||||||
|
val angle: Float,
|
||||||
|
val tmp: Float,
|
||||||
|
val turnovers: Int,
|
||||||
|
) : RealtimePoint()
|
||||||
|
|
||||||
|
data class Common(
|
||||||
|
val x: Float,
|
||||||
|
val y: Float,
|
||||||
|
val z: Float,
|
||||||
|
) : RealtimePoint()
|
||||||
|
|
||||||
|
data class Angle(
|
||||||
|
val x: Float,
|
||||||
|
val y: Float,
|
||||||
|
val z: Float,
|
||||||
|
) : RealtimePoint()
|
||||||
|
|
||||||
|
data class Vibration(
|
||||||
|
val value: Float
|
||||||
|
) : RealtimePoint()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class SpectrePoint (
|
||||||
val frequency: Long,
|
val frequency: Long,
|
||||||
val value: Float
|
val value: Float
|
||||||
)
|
)
|
||||||
|
|
||||||
data class AccelerometerState(
|
data class AccelerometerState(
|
||||||
val saveHistory: History,
|
val saveHistorySettings: HistorySettings,
|
||||||
val historyInterval: Long
|
val historyInterval: Long
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -83,7 +114,7 @@ sealed class Ble(
|
||||||
val thermometerState: ThermometerState
|
val thermometerState: ThermometerState
|
||||||
) : Ble(info) {
|
) : Ble(info) {
|
||||||
|
|
||||||
class MeasurePoint(
|
class HistoryPoint(
|
||||||
val date: Long,
|
val date: Long,
|
||||||
val value: Float
|
val value: Float
|
||||||
)
|
)
|
||||||
|
|
@ -107,7 +138,9 @@ sealed class Ble(
|
||||||
){
|
){
|
||||||
|
|
||||||
enum class TX {
|
enum class TX {
|
||||||
MINUS_40, MINUS_20, MINUS_16, MINUS_12, MINUS_8, MINUS_4, ZERO, PLUS_3, PLUS_4
|
MINUS_40, MINUS_20, MINUS_16, MINUS_12, MINUS_8, MINUS_4, ZERO, PLUS_3, PLUS_4;
|
||||||
|
|
||||||
|
companion object
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,20 +9,17 @@ 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.AccelScale
|
import llc.arma.ble.domain.usecase.AccelScale
|
||||||
import llc.arma.ble.domain.usecase.AccelViewMode
|
import llc.arma.ble.domain.usecase.AccelViewMode
|
||||||
import llc.arma.ble.domain.usecase.MeasureData
|
|
||||||
import llc.arma.ble.domain.usecase.FftAxis
|
import llc.arma.ble.domain.usecase.FftAxis
|
||||||
import llc.arma.ble.domain.usecase.FftFrequency
|
import llc.arma.ble.domain.usecase.FftFrequency
|
||||||
import llc.arma.ble.domain.usecase.FftViewMode
|
import llc.arma.ble.domain.usecase.FftViewMode
|
||||||
|
|
||||||
interface BleRepository {
|
interface BleRepository {
|
||||||
|
|
||||||
fun getConnectedBle(): List<ConnectedBleInfo>
|
fun getBleAroundFlow(): Result<Flow<List<BleInfo>>, BleException>
|
||||||
|
|
||||||
fun getBleAroundFlow(): Flow<Result<List<BleInfo>, BleException>>
|
|
||||||
|
|
||||||
suspend fun getBleBySerial(serial: String) : Result<Flow<Ble>, BleException>
|
suspend fun getBleBySerial(serial: String) : Result<Flow<Ble>, BleException>
|
||||||
|
|
||||||
suspend fun getTemperatureHistoryBySerial(serial: String): Flow<Result<ProgressState<List<Ble.Thermometer.MeasurePoint>>, BleException>>
|
suspend fun getTemperatureHistoryBySerial(serial: String): Flow<Result<ProgressState<List<Ble.Thermometer.HistoryPoint>>, BleException>>
|
||||||
|
|
||||||
suspend fun writeBle(serial: String, request: Ble.Thermometer.WriteRequest): Result<Unit, BleException>
|
suspend fun writeBle(serial: String, request: Ble.Thermometer.WriteRequest): Result<Unit, BleException>
|
||||||
|
|
||||||
|
|
@ -39,7 +36,7 @@ interface BleRepository {
|
||||||
fftAxis: FftAxis,
|
fftAxis: FftAxis,
|
||||||
fftMode: FftViewMode,
|
fftMode: FftViewMode,
|
||||||
frequency: FftFrequency
|
frequency: FftFrequency
|
||||||
): Flow<Result<MeasureData, BleException>>
|
): Flow<Result<Ble.Accelerometer.RealtimePoint, BleException>>
|
||||||
|
|
||||||
suspend fun getAccelerometerSpectreBySerial(
|
suspend fun getAccelerometerSpectreBySerial(
|
||||||
serial: String,
|
serial: String,
|
||||||
|
|
@ -48,7 +45,7 @@ interface BleRepository {
|
||||||
fftAxis: FftAxis,
|
fftAxis: FftAxis,
|
||||||
fftMode: FftViewMode,
|
fftMode: FftViewMode,
|
||||||
frequency: FftFrequency
|
frequency: FftFrequency
|
||||||
): Flow<Result<ProgressState<List<Ble.Accelerometer.MeasurePoint>>, BleException>>
|
): Flow<Result<ProgressState<List<Ble.Accelerometer.SpectrePoint>>, BleException>>
|
||||||
|
|
||||||
suspend fun getAccelerometerHistoryBySerial(serial: String): Flow<Result<ProgressState<List<Ble.Accelerometer.HistoryPoint>>, BleException>>
|
suspend fun getAccelerometerHistoryBySerial(serial: String): Flow<Result<ProgressState<List<Ble.Accelerometer.HistoryPoint>>, BleException>>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package llc.arma.ble.domain.repository
|
package llc.arma.ble.domain.repository
|
||||||
|
|
||||||
import llc.arma.ble.domain.model.Ble
|
import llc.arma.ble.domain.model.Ble
|
||||||
import llc.arma.ble.domain.usecase.MeasureData
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
interface XlsxRepository {
|
interface XlsxRepository {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ 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.model.Ble
|
||||||
import llc.arma.ble.domain.repository.BleRepository
|
import llc.arma.ble.domain.repository.BleRepository
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
@ -17,7 +18,7 @@ class GetAccelerometerMeasureBySerialFlow @Inject constructor(
|
||||||
fftAxis: FftAxis,
|
fftAxis: FftAxis,
|
||||||
fftMode: FftViewMode,
|
fftMode: FftViewMode,
|
||||||
frequency: FftFrequency
|
frequency: FftFrequency
|
||||||
): Flow<Result<MeasureData, BleException>> {
|
): Flow<Result<Ble.Accelerometer.RealtimePoint, BleException>> {
|
||||||
|
|
||||||
return bleRepository.getAccelerometerMeasureBySerialFlow(serial, accelScale, accelMode, fftAxis, fftMode, frequency)
|
return bleRepository.getAccelerometerMeasureBySerialFlow(serial, accelScale, accelMode, fftAxis, fftMode, frequency)
|
||||||
|
|
||||||
|
|
@ -26,38 +27,15 @@ class GetAccelerometerMeasureBySerialFlow @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class AccelViewMode {
|
enum class AccelViewMode {
|
||||||
ACCELERATION, PEAK_ACCELERATION, RMS, VIBRATION, ANGLE, ROTATIONS
|
ACCELERATION, PEAK_ACCELERATION, RMS, VIBRATION, ANGLE, ROTATIONS;
|
||||||
|
|
||||||
|
companion object
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class AccelScale(val k: Int) {
|
enum class AccelScale(val k: Int) {
|
||||||
S_2(2_000), S_4(4_000), S_8(8_000), S_16(16_000)
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class MeasureData {
|
S_2(2_000), S_4(4_000), S_8(8_000), S_16(16_000);
|
||||||
|
|
||||||
data class Angle(
|
companion object
|
||||||
val xAngle: Float,
|
|
||||||
val yAngle: Float,
|
|
||||||
val zAngle: Float,
|
|
||||||
val xAccelerate: Float,
|
|
||||||
val yAccelerate: Float,
|
|
||||||
val zAccelerate: Float,
|
|
||||||
) : MeasureData()
|
|
||||||
|
|
||||||
data class Accelerate(
|
|
||||||
val x: Float,
|
|
||||||
val y: Float,
|
|
||||||
val z: Float,
|
|
||||||
) : MeasureData()
|
|
||||||
|
|
||||||
data class Vibration(
|
|
||||||
val value: Float
|
|
||||||
) : MeasureData()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Accelerate(
|
|
||||||
val x: Float,
|
|
||||||
val y: Float,
|
|
||||||
val z: Float,
|
|
||||||
)
|
|
||||||
|
|
@ -19,7 +19,7 @@ class GetAccelerometerSpectreBySerial @Inject constructor(
|
||||||
fftAxis: FftAxis,
|
fftAxis: FftAxis,
|
||||||
fftMode: FftViewMode,
|
fftMode: FftViewMode,
|
||||||
frequency: FftFrequency
|
frequency: FftFrequency
|
||||||
): Flow<Result<ProgressState<List<Ble.Accelerometer.MeasurePoint>>, BleException>> {
|
): Flow<Result<ProgressState<List<Ble.Accelerometer.SpectrePoint>>, BleException>> {
|
||||||
|
|
||||||
return bleRepository.getAccelerometerSpectreBySerial(serial, accelScale, accelMode, fftAxis, fftMode, frequency)
|
return bleRepository.getAccelerometerSpectreBySerial(serial, accelScale, accelMode, fftAxis, fftMode, frequency)
|
||||||
|
|
||||||
|
|
@ -28,13 +28,19 @@ class GetAccelerometerSpectreBySerial @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class FftFrequency {
|
enum class FftFrequency {
|
||||||
OFF, F_1, F_10, F_25, F_50, F_100, F_200, F_400, F_1620, F_1344
|
OFF, F_1, F_10, F_25, F_50, F_100, F_200, F_400, F_1620, F_1344;
|
||||||
|
|
||||||
|
companion object
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class FftViewMode {
|
enum class FftViewMode {
|
||||||
SPECTRE, X, Y, Z
|
SPECTRE, X, Y, Z;
|
||||||
|
|
||||||
|
companion object
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class FftAxis {
|
enum class FftAxis {
|
||||||
AUTO, X, Y, Z
|
AUTO, X, Y, Z;
|
||||||
|
|
||||||
|
companion object
|
||||||
}
|
}
|
||||||
|
|
@ -12,6 +12,6 @@ class GetBleAroundFlow @Inject constructor(
|
||||||
private val bleRepository: BleRepository
|
private val bleRepository: BleRepository
|
||||||
) {
|
) {
|
||||||
|
|
||||||
operator fun invoke(): Flow<Result<List<BleInfo>, BleException>> = bleRepository.getBleAroundFlow()
|
operator fun invoke(): Result<Flow<List<BleInfo>>, BleException> = bleRepository.getBleAroundFlow()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
package llc.arma.ble.domain.usecase
|
|
||||||
|
|
||||||
import llc.arma.ble.domain.model.ConnectedBleInfo
|
|
||||||
import llc.arma.ble.domain.repository.BleRepository
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class GetConnectedBleDevices @Inject constructor(
|
|
||||||
private val bleRepository: BleRepository
|
|
||||||
) {
|
|
||||||
|
|
||||||
operator fun invoke(): List<ConnectedBleInfo>{
|
|
||||||
return bleRepository.getConnectedBle()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -12,7 +12,7 @@ class GetTemperatureHistoryBySerial @Inject constructor(
|
||||||
private val bleRepository: BleRepository
|
private val bleRepository: BleRepository
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend operator fun invoke(serial: String): Flow<Result<ProgressState<List<Ble.Thermometer.MeasurePoint>>, BleException>> {
|
suspend operator fun invoke(serial: String): Flow<Result<ProgressState<List<Ble.Thermometer.HistoryPoint>>, BleException>> {
|
||||||
|
|
||||||
return bleRepository.getTemperatureHistoryBySerial(serial)
|
return bleRepository.getTemperatureHistoryBySerial(serial)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue