filter saving
This commit is contained in:
parent
666757922d
commit
ab27faa832
|
|
@ -1,6 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ android {
|
||||||
minSdk 26
|
minSdk 26
|
||||||
targetSdk 34
|
targetSdk 34
|
||||||
versionCode 41
|
versionCode 41
|
||||||
versionName "1.4.12"
|
versionName "1.4.13"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables {
|
vectorDrawables {
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,8 @@ class BleMapper @Inject constructor(
|
||||||
tx = txMapper.map(input.state.tx)
|
tx = txMapper.map(input.state.tx)
|
||||||
),
|
),
|
||||||
hostState = BleView.Host.HostState(
|
hostState = BleView.Host.HostState(
|
||||||
historyInterval = input.hostState.historyInterval
|
historyInterval = input.hostState.historyInterval,
|
||||||
|
readInterval = input.hostState.readInterval
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,8 @@ class BleViewMapper @Inject constructor(
|
||||||
tx = txMapper.map(input.state.tx)
|
tx = txMapper.map(input.state.tx)
|
||||||
),
|
),
|
||||||
hostState = Ble.Host.HostState(
|
hostState = Ble.Host.HostState(
|
||||||
historyInterval = input.hostState.historyInterval
|
historyInterval = input.hostState.historyInterval,
|
||||||
|
readInterval = input.hostState.readInterval
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package llc.arma.ble.app.ui.model
|
package llc.arma.ble.app.ui.model
|
||||||
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableLongStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
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
|
||||||
|
|
@ -65,8 +66,10 @@ sealed class BleView(
|
||||||
|
|
||||||
class HostState(
|
class HostState(
|
||||||
historyInterval: Long,
|
historyInterval: Long,
|
||||||
|
readInterval: Long
|
||||||
) {
|
) {
|
||||||
var historyInterval by mutableStateOf(historyInterval)
|
var historyInterval by mutableLongStateOf(historyInterval)
|
||||||
|
var readInterval by mutableLongStateOf(readInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,15 @@ class HostContract {
|
||||||
|
|
||||||
data object OnShowIntervalEdit : Event()
|
data object OnShowIntervalEdit : Event()
|
||||||
|
|
||||||
data class OnSaveIntervalChanged(val interval: Long) : Event()
|
data class OnSaveIntervalChanged(
|
||||||
|
val interval: Long
|
||||||
|
) : Event()
|
||||||
|
|
||||||
|
data object OnShowReadIntervalEdit : Event()
|
||||||
|
|
||||||
|
data class OnSaveReadIntervalChanged(
|
||||||
|
val interval: Long
|
||||||
|
) : Event()
|
||||||
|
|
||||||
data object OnNavigateUpClicked : Event()
|
data object OnNavigateUpClicked : Event()
|
||||||
|
|
||||||
|
|
@ -87,6 +95,10 @@ class HostContract {
|
||||||
|
|
||||||
data object ShowIntervalPicker : Effect()
|
data object ShowIntervalPicker : Effect()
|
||||||
|
|
||||||
|
data object HideReadIntervalPicker : Effect()
|
||||||
|
|
||||||
|
data object ShowReadIntervalPicker : Effect()
|
||||||
|
|
||||||
sealed class Navigation : Effect() {
|
sealed class Navigation : Effect() {
|
||||||
|
|
||||||
data object NavigateToChangePassword : Navigation()
|
data object NavigateToChangePassword : Navigation()
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,12 @@ import llc.arma.ble.app.ui.common.rememberBottomDialogState
|
||||||
import llc.arma.ble.app.ui.screen.inspection.host.view.DisplayState
|
import llc.arma.ble.app.ui.screen.inspection.host.view.DisplayState
|
||||||
import llc.arma.ble.app.ui.screen.inspection.host.view.IntervalEdit
|
import llc.arma.ble.app.ui.screen.inspection.host.view.IntervalEdit
|
||||||
import llc.arma.ble.app.ui.screen.inspection.host.view.PowerEdit
|
import llc.arma.ble.app.ui.screen.inspection.host.view.PowerEdit
|
||||||
|
import llc.arma.ble.app.ui.screen.inspection.host.view.ReadIntervalEdit
|
||||||
import llc.arma.ble.app.ui.screen.inspection.host.view.Write
|
import llc.arma.ble.app.ui.screen.inspection.host.view.Write
|
||||||
import llc.arma.ble.domain.model.Ble
|
import llc.arma.ble.domain.model.Ble
|
||||||
|
|
||||||
enum class SheetPage {
|
enum class SheetPage {
|
||||||
WRITE, POWER_EDIT, INTERVAL_EDIT
|
WRITE, POWER_EDIT, INTERVAL_EDIT, READ_INTERVAL_EDIT
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -72,6 +73,15 @@ fun HostScreen(
|
||||||
delay(100)
|
delay(100)
|
||||||
sheetPage = SheetPage.INTERVAL_EDIT
|
sheetPage = SheetPage.INTERVAL_EDIT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HostContract.Effect.HideReadIntervalPicker -> launch {
|
||||||
|
sheetPage = null
|
||||||
|
}
|
||||||
|
HostContract.Effect.ShowReadIntervalPicker -> launch {
|
||||||
|
sheetPage = null
|
||||||
|
delay(100)
|
||||||
|
sheetPage = SheetPage.READ_INTERVAL_EDIT
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
|
|
@ -122,6 +132,18 @@ fun HostScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SheetPage.READ_INTERVAL_EDIT -> bottomDialog.show {
|
||||||
|
val currentState = viewModel.viewState.value
|
||||||
|
|
||||||
|
if(currentState is HostContract.State.Display) {
|
||||||
|
ReadIntervalEdit(
|
||||||
|
state = currentState.host,
|
||||||
|
onEvent = {
|
||||||
|
viewModel.setEvent(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
bottomDialog.hide()
|
bottomDialog.hide()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,39 @@ class HostViewModel @Inject constructor(
|
||||||
is HostContract.Event.OnShowHostBleTable -> reduce(viewState.value, event)
|
is HostContract.Event.OnShowHostBleTable -> reduce(viewState.value, event)
|
||||||
is HostContract.Event.OnSaveIntervalChanged -> reduce(viewState.value, event)
|
is HostContract.Event.OnSaveIntervalChanged -> reduce(viewState.value, event)
|
||||||
is HostContract.Event.OnShowIntervalEdit -> reduce(viewState.value, event)
|
is HostContract.Event.OnShowIntervalEdit -> reduce(viewState.value, event)
|
||||||
|
is HostContract.Event.OnSaveReadIntervalChanged -> reduce(viewState.value, event)
|
||||||
|
is HostContract.Event.OnShowReadIntervalEdit -> reduce(viewState.value, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun reduce(
|
||||||
|
state: HostContract.State,
|
||||||
|
event: HostContract.Event.OnSaveReadIntervalChanged
|
||||||
|
) {
|
||||||
|
|
||||||
|
if(state is HostContract.State.Display) {
|
||||||
|
|
||||||
|
state.host.hostState.readInterval = event.interval
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setEffect {
|
||||||
|
HostContract.Effect.HideReadIntervalPicker
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reduce(
|
||||||
|
state: HostContract.State,
|
||||||
|
event: HostContract.Event.OnShowReadIntervalEdit
|
||||||
|
) {
|
||||||
|
|
||||||
|
setEffect {
|
||||||
|
HostContract.Effect.ShowReadIntervalPicker
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private fun reduce(
|
private fun reduce(
|
||||||
state: HostContract.State,
|
state: HostContract.State,
|
||||||
event: HostContract.Event.OnSaveIntervalChanged
|
event: HostContract.Event.OnSaveIntervalChanged
|
||||||
|
|
@ -195,7 +225,8 @@ class HostViewModel @Inject constructor(
|
||||||
|
|
||||||
val writeRequest = Ble.Host.WriteRequest(
|
val writeRequest = Ble.Host.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,
|
||||||
interval = if(newBle.hostState.historyInterval == state.origin.hostState.historyInterval) null else newBle.hostState.historyInterval
|
interval = if(newBle.hostState.historyInterval == state.origin.hostState.historyInterval) null else newBle.hostState.historyInterval,
|
||||||
|
readInterval = if(newBle.hostState.readInterval == state.origin.hostState.readInterval) null else newBle.hostState.readInterval,
|
||||||
)
|
)
|
||||||
|
|
||||||
setState {
|
setState {
|
||||||
|
|
|
||||||
|
|
@ -67,12 +67,12 @@ fun DisplayState(
|
||||||
onEvent(HostContract.Event.OnPowerEdit)
|
onEvent(HostContract.Event.OnPowerEdit)
|
||||||
}
|
}
|
||||||
|
|
||||||
val hours =
|
var hours =
|
||||||
ble.hostState.historyInterval / llc.arma.ble.app.ui.screen.inspection.accelerometer.view.millisInHour
|
ble.hostState.historyInterval / millisInHour
|
||||||
val minutes =
|
var minutes =
|
||||||
(ble.hostState.historyInterval - (hours * llc.arma.ble.app.ui.screen.inspection.accelerometer.view.millisInHour)) / llc.arma.ble.app.ui.screen.inspection.accelerometer.view.millisInMinute
|
(ble.hostState.historyInterval - (hours * millisInHour)) / millisInMinute
|
||||||
val seconds =
|
var seconds =
|
||||||
(ble.hostState.historyInterval - (hours * llc.arma.ble.app.ui.screen.inspection.accelerometer.view.millisInHour) - (minutes * llc.arma.ble.app.ui.screen.inspection.accelerometer.view.millisInMinute)) / llc.arma.ble.app.ui.screen.inspection.accelerometer.view.millisInSecond
|
(ble.hostState.historyInterval - (hours * millisInHour) - (minutes * millisInMinute)) / millisInSecond
|
||||||
|
|
||||||
BleMenuItem(
|
BleMenuItem(
|
||||||
title = "Интервал измерений",
|
title = "Интервал измерений",
|
||||||
|
|
@ -82,6 +82,20 @@ fun DisplayState(
|
||||||
onEvent(HostContract.Event.OnShowIntervalEdit)
|
onEvent(HostContract.Event.OnShowIntervalEdit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hours = ble.hostState.readInterval / millisInHour
|
||||||
|
minutes =
|
||||||
|
(ble.hostState.readInterval - (hours * millisInHour)) / millisInMinute
|
||||||
|
seconds =
|
||||||
|
(ble.hostState.readInterval - (hours * millisInHour) - (minutes * millisInMinute)) / millisInSecond
|
||||||
|
|
||||||
|
BleMenuItem(
|
||||||
|
title = "Интервал чтения",
|
||||||
|
subtitle = "$hours ч. $minutes мин. $seconds сек.",
|
||||||
|
icon = rememberVectorPainter(Icons.Rounded.KeyboardArrowDown)
|
||||||
|
) {
|
||||||
|
onEvent(HostContract.Event.OnShowReadIntervalEdit)
|
||||||
|
}
|
||||||
|
|
||||||
BleMenuItem(
|
BleMenuItem(
|
||||||
title = "График измерений",
|
title = "График измерений",
|
||||||
icon = rememberVectorPainter(Icons.Rounded.KeyboardArrowRight)
|
icon = rememberVectorPainter(Icons.Rounded.KeyboardArrowRight)
|
||||||
|
|
|
||||||
|
|
@ -47,27 +47,6 @@ fun IntervalEdit(
|
||||||
mutableIntStateOf((state.hostState.historyInterval).toInt())
|
mutableIntStateOf((state.hostState.historyInterval).toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
val maxInterval = 10 * 24 * 60 * 60 * 1000
|
|
||||||
val minInterval = 10_000
|
|
||||||
|
|
||||||
if(value > maxInterval){
|
|
||||||
value = maxInterval
|
|
||||||
}
|
|
||||||
|
|
||||||
if(value < minInterval){
|
|
||||||
value = minInterval
|
|
||||||
}
|
|
||||||
|
|
||||||
val maxSeconds = maxInterval / millisInSecond
|
|
||||||
val maxMinutes = maxInterval / millisInMinute
|
|
||||||
val maxHours = maxInterval / millisInHour
|
|
||||||
val maxDays = maxInterval / millisInDay
|
|
||||||
|
|
||||||
val dayValue = value / millisInDay
|
|
||||||
val hourValue = (value - (dayValue * millisInDay)) / millisInHour
|
|
||||||
val minutesValue = (value - (dayValue * millisInDay) - (hourValue * millisInHour)) / millisInMinute
|
|
||||||
val secondsValue = (value - (dayValue * millisInDay) - (hourValue * millisInHour) - (minutesValue * millisInMinute)) / millisInSecond
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
|
@ -80,66 +59,11 @@ fun IntervalEdit(
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
DurationPicker(
|
||||||
Row(
|
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
value = value
|
||||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
|
||||||
) {
|
) {
|
||||||
|
value = it
|
||||||
NumberPicker(
|
|
||||||
range = -1..maxDays,
|
|
||||||
value = dayValue,
|
|
||||||
onValueChanged = {
|
|
||||||
value = (it * millisInDay) + (hourValue * millisInHour) + (minutesValue * millisInMinute) + (secondsValue * millisInSecond)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
|
|
||||||
Text(text = "Д.")
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
|
||||||
|
|
||||||
NumberPicker(
|
|
||||||
range = -1..maxHours,
|
|
||||||
value = hourValue,
|
|
||||||
onValueChanged = {
|
|
||||||
value = (it * millisInHour) + (dayValue * millisInDay) + (minutesValue * millisInMinute) + (secondsValue * millisInSecond)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
|
|
||||||
Text(text = "Ч.")
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
|
||||||
|
|
||||||
NumberPicker(
|
|
||||||
range = -1..maxMinutes,
|
|
||||||
value = minutesValue,
|
|
||||||
onValueChanged = {
|
|
||||||
value = (secondsValue * millisInSecond) + (it * millisInMinute) + (dayValue * millisInDay) + (hourValue * millisInHour)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
|
|
||||||
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 = "С.")
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
@ -177,6 +101,116 @@ fun IntervalEdit(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DurationPicker(
|
||||||
|
modifier: Modifier,
|
||||||
|
maxInterval: Int = 10 * 24 * 60 * 60 * 1000,
|
||||||
|
minInterval: Int = 10_000,
|
||||||
|
seconds: Boolean = true,
|
||||||
|
minutes: Boolean = true,
|
||||||
|
hours: Boolean = true,
|
||||||
|
days: Boolean = true,
|
||||||
|
value: Int,
|
||||||
|
onChanged: (duration: Int) -> Unit
|
||||||
|
){
|
||||||
|
|
||||||
|
if(value > maxInterval){
|
||||||
|
onChanged(maxInterval)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value < minInterval){
|
||||||
|
onChanged(minInterval)
|
||||||
|
}
|
||||||
|
|
||||||
|
val maxSeconds = maxInterval / millisInSecond
|
||||||
|
val maxMinutes = maxInterval / millisInMinute
|
||||||
|
val maxHours = maxInterval / millisInHour
|
||||||
|
val maxDays = maxInterval / millisInDay
|
||||||
|
|
||||||
|
val dayValue = value / millisInDay
|
||||||
|
val hourValue = (value - (dayValue * millisInDay)) / millisInHour
|
||||||
|
val minutesValue = (value - (dayValue * millisInDay) - (hourValue * millisInHour)) / millisInMinute
|
||||||
|
val secondsValue = (value - (dayValue * millisInDay) - (hourValue * millisInHour) - (minutesValue * millisInMinute)) / millisInSecond
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = modifier
|
||||||
|
) {
|
||||||
|
|
||||||
|
if(days) {
|
||||||
|
|
||||||
|
NumberPicker(
|
||||||
|
range = -1..maxDays,
|
||||||
|
value = dayValue,
|
||||||
|
onValueChanged = {
|
||||||
|
onChanged((it * millisInDay) + (hourValue * millisInHour) + (minutesValue * millisInMinute) + (secondsValue * millisInSecond))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
|
Text(text = "Д.")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hours) {
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
|
||||||
|
NumberPicker(
|
||||||
|
range = -1..maxHours,
|
||||||
|
value = hourValue,
|
||||||
|
onValueChanged = {
|
||||||
|
onChanged((it * millisInHour) + (dayValue * millisInDay) + (minutesValue * millisInMinute) + (secondsValue * millisInSecond))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
|
Text(text = "Ч.")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(minutes) {
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
|
||||||
|
NumberPicker(
|
||||||
|
range = -1..maxMinutes,
|
||||||
|
value = minutesValue,
|
||||||
|
onValueChanged = {
|
||||||
|
onChanged((secondsValue * millisInSecond) + (it * millisInMinute) + (dayValue * millisInDay) + (hourValue * millisInHour))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
|
Text(text = "М.")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(seconds) {
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
|
||||||
|
NumberPicker(
|
||||||
|
range = -1..maxSeconds,
|
||||||
|
value = secondsValue,
|
||||||
|
onValueChanged = {
|
||||||
|
onChanged((it * millisInSecond) + (minutesValue * millisInMinute) + (dayValue * millisInDay) + (hourValue * millisInHour))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
|
Text(text = "С.")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const val millisInSecond = 1000
|
const val millisInSecond = 1000
|
||||||
const val millisInMinute = millisInSecond * 60
|
const val millisInMinute = millisInSecond * 60
|
||||||
const val millisInHour = millisInMinute * 60
|
const val millisInHour = millisInMinute * 60
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
package llc.arma.ble.app.ui.screen.inspection.host.view
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedContent
|
||||||
|
import androidx.compose.animation.SizeTransform
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.slideInVertically
|
||||||
|
import androidx.compose.animation.slideOutVertically
|
||||||
|
import androidx.compose.animation.togetherWith
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.rounded.KeyboardArrowDown
|
||||||
|
import androidx.compose.material.icons.rounded.KeyboardArrowUp
|
||||||
|
import androidx.compose.material3.FilledIconButton
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import llc.arma.ble.app.ui.model.BleView
|
||||||
|
import llc.arma.ble.app.ui.screen.inspection.host.HostContract
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ReadIntervalEdit(
|
||||||
|
state: BleView.Host,
|
||||||
|
onEvent: (HostContract.Event) -> Unit,
|
||||||
|
){
|
||||||
|
|
||||||
|
var value by remember(state.hostState.readInterval) {
|
||||||
|
mutableIntStateOf((state.hostState.readInterval).toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
) {
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.padding(horizontal = 12.dp),
|
||||||
|
text = "Интервал чтения",
|
||||||
|
style = MaterialTheme.typography.titleLarge
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
DurationPicker(
|
||||||
|
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||||
|
value = value
|
||||||
|
) {
|
||||||
|
value = it
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp)
|
||||||
|
.height(50.dp),
|
||||||
|
shape = CircleShape,
|
||||||
|
color = MaterialTheme.colorScheme.primaryContainer,
|
||||||
|
onClick = {
|
||||||
|
onEvent(
|
||||||
|
HostContract.Event.OnSaveReadIntervalChanged(
|
||||||
|
value.toLong()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
|
||||||
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.align(Alignment.Center),
|
||||||
|
color = MaterialTheme.colorScheme.background,
|
||||||
|
style = MaterialTheme.typography.labelLarge,
|
||||||
|
text = "Применить"
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -49,7 +49,7 @@ fun Write(
|
||||||
when (state) {
|
when (state) {
|
||||||
is HostContract.State.Display.WriteState.DisplayPreview -> {
|
is HostContract.State.Display.WriteState.DisplayPreview -> {
|
||||||
|
|
||||||
if(state.writeRequest.tx != null || state.writeRequest.interval != null ) {
|
if(state.writeRequest.tx != null || state.writeRequest.interval != null || state.writeRequest.readInterval !== null) {
|
||||||
|
|
||||||
state.writeRequest.tx?.let {
|
state.writeRequest.tx?.let {
|
||||||
Box(
|
Box(
|
||||||
|
|
@ -110,9 +110,51 @@ fun Write(
|
||||||
text = "Интервал измерений"
|
text = "Интервал измерений"
|
||||||
)
|
)
|
||||||
|
|
||||||
val hours = it / llc.arma.ble.app.ui.screen.inspection.accelerometer.view.millisInHour
|
val hours = it / millisInHour
|
||||||
val minutes = (it - (hours * llc.arma.ble.app.ui.screen.inspection.accelerometer.view.millisInHour)) / llc.arma.ble.app.ui.screen.inspection.accelerometer.view.millisInMinute
|
val minutes = (it - (hours * millisInHour)) / millisInMinute
|
||||||
val seconds = (it - (hours * llc.arma.ble.app.ui.screen.inspection.accelerometer.view.millisInHour) - (minutes * llc.arma.ble.app.ui.screen.inspection.accelerometer.view.millisInMinute)) / llc.arma.ble.app.ui.screen.inspection.accelerometer.view.millisInSecond
|
val seconds = (it - (hours * millisInHour) - (minutes * millisInMinute)) / millisInSecond
|
||||||
|
|
||||||
|
Text(
|
||||||
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
text = "$hours ч. $minutes мин. $seconds сек."
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
state.writeRequest.readInterval?.let {
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.padding(
|
||||||
|
vertical = 0.dp,
|
||||||
|
horizontal = 8.dp
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(RoundedCornerShape(16.dp))
|
||||||
|
.padding(8.dp)
|
||||||
|
) {
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
|
||||||
|
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,
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ 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.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.client.main.service.ClientBleGattCharacteristic
|
||||||
import no.nordicsemi.android.kotlin.ble.core.scanner.BleNumOfMatches
|
import no.nordicsemi.android.kotlin.ble.core.scanner.BleNumOfMatches
|
||||||
import no.nordicsemi.android.kotlin.ble.core.scanner.BleScanMode
|
import no.nordicsemi.android.kotlin.ble.core.scanner.BleScanMode
|
||||||
import no.nordicsemi.android.kotlin.ble.core.scanner.BleScannerCallbackType
|
import no.nordicsemi.android.kotlin.ble.core.scanner.BleScannerCallbackType
|
||||||
|
|
@ -65,9 +66,6 @@ val passwordWriteUUID: UUID = UUID.fromString("a77db6f2-9bc4-11ed-a8fc-0242ac120
|
||||||
val txWriteUUID: UUID = UUID.fromString("00002a07-0000-1000-8000-00805f9b34fb")
|
val txWriteUUID: UUID = UUID.fromString("00002a07-0000-1000-8000-00805f9b34fb")
|
||||||
val flashWriteUUID: UUID = UUID.fromString("a77db6f2-9bc4-11ed-a8fc-0242ac120002")
|
val flashWriteUUID: UUID = UUID.fromString("a77db6f2-9bc4-11ed-a8fc-0242ac120002")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class BleRepositoryImpl @Inject constructor(
|
class BleRepositoryImpl @Inject constructor(
|
||||||
private val app: Application,
|
private val app: Application,
|
||||||
|
|
@ -135,200 +133,136 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
serial: String
|
serial: String
|
||||||
): Result<Flow<Ble>, BleException> {
|
): Result<Flow<Ble>, BleException> {
|
||||||
|
|
||||||
resultList[serial]?.let { result ->
|
val initialBle = resultList[serial]
|
||||||
|
|
||||||
return when(result.type) {
|
return if(initialBle == null){
|
||||||
BleInfo.Type.ACCELEROMETER -> {
|
|
||||||
|
|
||||||
val tState = readAccelState(
|
Result.failure(BleException.UnexpectedResponse)
|
||||||
result.serial,
|
|
||||||
result.tableStatus
|
|
||||||
).fold(
|
|
||||||
onFailure = {
|
|
||||||
return Result.failure(it)
|
|
||||||
},
|
|
||||||
onSuccess = {
|
|
||||||
it
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Result.success(
|
|
||||||
flow {
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
resultList[serial]?.let { newResult ->
|
|
||||||
|
|
||||||
emit(
|
|
||||||
|
|
||||||
Ble.Accelerometer(
|
|
||||||
info = newResult.copy(
|
|
||||||
rssi = if((SystemClock.elapsedRealtime() - newResult.scanTime) > 15_000) {
|
|
||||||
null
|
|
||||||
} else {
|
} else {
|
||||||
newResult.rssi
|
|
||||||
|
fun BleInfo.updateBleInfo(): BleInfo {
|
||||||
|
return copy(
|
||||||
|
rssi = if((SystemClock.elapsedRealtime() - scanTime) > 15_000) {
|
||||||
|
null
|
||||||
|
} else { rssi }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
),
|
|
||||||
state = Ble.BleState(
|
fun BleInfo.updateState(): Ble.BleState {
|
||||||
tx = Ble.BleState.TX.fromByte(result.tx.toByte())
|
return Ble.BleState(
|
||||||
|
tx = Ble.BleState.TX.fromByte(tx.toByte())
|
||||||
?: Ble.BleState.TX.ZERO
|
?: Ble.BleState.TX.ZERO
|
||||||
),
|
|
||||||
accelerometerState = tState
|
|
||||||
)
|
)
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(1_000)
|
val firstResult = when(initialBle.type){
|
||||||
|
BleInfo.Type.HOST -> {
|
||||||
|
|
||||||
}
|
val tState = readHostState(
|
||||||
|
initialBle.serial
|
||||||
}
|
).fold(
|
||||||
|
onFailure = { return Result.failure(it) },
|
||||||
|
onSuccess = { it }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Ble.Host(
|
||||||
|
info = initialBle.updateBleInfo(),
|
||||||
|
state = initialBle.updateState(),
|
||||||
|
hostState = tState
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
BleInfo.Type.BEACON -> {
|
BleInfo.Type.BEACON -> {
|
||||||
Result.success(
|
|
||||||
flow {
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
resultList[serial]?.let { newResult ->
|
|
||||||
|
|
||||||
val state = Ble.BleState(
|
|
||||||
tx = Ble.BleState.TX.fromByte(result.tx.toByte())
|
|
||||||
?: Ble.BleState.TX.ZERO
|
|
||||||
)
|
|
||||||
|
|
||||||
emit(
|
|
||||||
|
|
||||||
Ble.Beacon(
|
Ble.Beacon(
|
||||||
info = newResult.copy(
|
info = initialBle.updateBleInfo(),
|
||||||
rssi = if((SystemClock.elapsedRealtime() - newResult.scanTime) > 15_000) {
|
state = initialBle.updateState(),
|
||||||
null
|
|
||||||
} else {
|
|
||||||
newResult.rssi
|
|
||||||
}
|
|
||||||
|
|
||||||
),
|
|
||||||
state = state
|
|
||||||
)
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
delay(1_000)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BleInfo.Type.THERMOMETER -> {
|
BleInfo.Type.THERMOMETER -> {
|
||||||
|
|
||||||
val tState = readThermometerState(result.serial, result.tableStatus).fold(
|
val tState = readThermometerState(
|
||||||
onFailure = {
|
initialBle.serial,
|
||||||
return Result.failure(it)
|
initialBle.tableStatus
|
||||||
},
|
).fold(
|
||||||
onSuccess = {
|
onFailure = { return Result.failure(it) },
|
||||||
it
|
onSuccess = { it }
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Result.success(
|
|
||||||
flow {
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
resultList[serial]?.let { newResult ->
|
|
||||||
|
|
||||||
val state = Ble.BleState(
|
|
||||||
tx = Ble.BleState.TX.fromByte(result.tx.toByte())
|
|
||||||
?: Ble.BleState.TX.ZERO
|
|
||||||
)
|
|
||||||
|
|
||||||
emit(
|
|
||||||
|
|
||||||
Ble.Thermometer(
|
Ble.Thermometer(
|
||||||
info = newResult.copy(
|
info = initialBle.updateBleInfo(),
|
||||||
rssi = if((SystemClock.elapsedRealtime() - newResult.scanTime) > 15_000) {
|
state = initialBle.updateState(),
|
||||||
null
|
|
||||||
} else {
|
|
||||||
newResult.rssi
|
|
||||||
}
|
|
||||||
|
|
||||||
),
|
|
||||||
state = state,
|
|
||||||
thermometerState = tState
|
thermometerState = tState
|
||||||
)
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
BleInfo.Type.ACCELEROMETER -> {
|
||||||
|
|
||||||
|
val tState = readAccelState(
|
||||||
|
initialBle.serial,
|
||||||
|
initialBle.tableStatus
|
||||||
|
).fold(
|
||||||
|
onFailure = { return Result.failure(it) },
|
||||||
|
onSuccess = { it }
|
||||||
|
)
|
||||||
|
|
||||||
|
Ble.Accelerometer(
|
||||||
|
info = initialBle.updateBleInfo(),
|
||||||
|
state = initialBle.updateState(),
|
||||||
|
accelerometerState = tState
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(1_000)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
BleInfo.Type.HOST -> {
|
|
||||||
|
|
||||||
val tState = readHostState(result.serial).fold(
|
|
||||||
onFailure = {
|
|
||||||
return Result.failure(it)
|
|
||||||
},
|
|
||||||
onSuccess = {
|
|
||||||
it
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Result.success(
|
Result.success(
|
||||||
flow {
|
flow {
|
||||||
|
while (true){
|
||||||
|
|
||||||
while (true) {
|
resultList[serial]?.let { ble ->
|
||||||
|
|
||||||
resultList[serial]?.let { newResult ->
|
firstResult.state = ble.updateState()
|
||||||
|
firstResult.info = ble.updateBleInfo()
|
||||||
|
|
||||||
val state = Ble.BleState(
|
emit(when(firstResult){
|
||||||
tx = Ble.BleState.TX.fromByte(result.tx.toByte())
|
is Ble.Accelerometer -> {
|
||||||
?: Ble.BleState.TX.ZERO
|
Ble.Accelerometer(
|
||||||
|
info = ble.updateBleInfo(),
|
||||||
|
state = ble.updateState(),
|
||||||
|
accelerometerState = firstResult.accelerometerState
|
||||||
)
|
)
|
||||||
|
|
||||||
emit(
|
|
||||||
Ble.Host(
|
|
||||||
info = newResult.copy(
|
|
||||||
rssi = if((SystemClock.elapsedRealtime() - newResult.scanTime) > 15_000) {
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
newResult.rssi
|
|
||||||
}
|
}
|
||||||
|
is Ble.Beacon -> {
|
||||||
),
|
Ble.Beacon(
|
||||||
state = state,
|
info = ble.updateBleInfo(),
|
||||||
hostState = tState
|
state = ble.updateState()
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
is Ble.Host -> {
|
||||||
|
Ble.Host(
|
||||||
|
info = ble.updateBleInfo(),
|
||||||
|
state = ble.updateState(),
|
||||||
|
hostState = firstResult.hostState
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
is Ble.Thermometer -> {
|
||||||
|
Ble.Thermometer(
|
||||||
|
info = ble.updateBleInfo(),
|
||||||
|
state = ble.updateState(),
|
||||||
|
thermometerState = firstResult.thermometerState
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(1_000)
|
delay(1_000)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.failure(BleException.UnexpectedResponse)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -345,28 +279,25 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
val service = connection.discoverServices()
|
val service = connection.discoverServices().findService(serviceUUID)
|
||||||
.findService(serviceUUID) ?: return Result.failure(BleException.UnexpectedResponse)
|
?: return Result.failure(BleException.UnexpectedResponse)
|
||||||
|
|
||||||
var characteristic = service.findCharacteristic(temperatureReadUUID)
|
var characteristic = service.findCharacteristic(temperatureReadUUID)
|
||||||
?: return Result.failure(BleException.UnexpectedResponse)
|
?: return Result.failure(BleException.UnexpectedResponse)
|
||||||
|
|
||||||
characteristic.write(DataByteArray.from(1, 1))
|
characteristic.write(DataByteArray.from(1, 1))
|
||||||
|
|
||||||
delay(2_000)
|
delay(2_000)
|
||||||
|
|
||||||
val temperature = characteristic.read().value.toUByteArray().toTemperature()
|
val temperature = characteristic.read().value.toUByteArray().toTemperature()
|
||||||
|
|
||||||
characteristic = service.findCharacteristic(intervalReadUUID)
|
characteristic = service.findCharacteristic(intervalReadUUID)
|
||||||
?: return Result.failure(BleException.UnexpectedResponse)
|
?: return Result.failure(BleException.UnexpectedResponse)
|
||||||
|
|
||||||
characteristic.write(DataByteArray.from(3, 0, 0, 0, ))
|
val interval = characteristic.readWriteInterval().fold(
|
||||||
|
onFailure = { return Result.failure(it) },
|
||||||
val interval = characteristic.read().value.let {
|
onSuccess = { it }
|
||||||
if(it.size == 4){
|
)
|
||||||
it.get4byteUIntAt(0).toLong()
|
|
||||||
}else{
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
connection.close()
|
connection.close()
|
||||||
|
|
||||||
|
|
@ -406,33 +337,31 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
val service = connection.discoverServices()
|
val service = connection.discoverServices().findService(serviceUUID)
|
||||||
.findService(serviceUUID) ?: return Result.failure(BleException.UnexpectedResponse)
|
?: return Result.failure(BleException.UnexpectedResponse)
|
||||||
|
|
||||||
val characteristic = service.findCharacteristic(intervalReadUUID)
|
val characteristic = service.findCharacteristic(intervalReadUUID)
|
||||||
|
?: return Result.failure(BleException.UnexpectedResponse)
|
||||||
|
|
||||||
if(characteristic == null){
|
val interval = characteristic.readWriteInterval().fold(
|
||||||
service.characteristics.forEach {
|
onFailure = { return Result.failure(it) },
|
||||||
Log.d("ble", "characteristic ${it.uuid} ")
|
onSuccess = { it }
|
||||||
}
|
)
|
||||||
Log.d("ble", "${intervalReadUUID} not found")
|
|
||||||
return Result.failure(BleException.UnexpectedResponse)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/*characteristic.write(DataByteArray.from(2, 0, 0, 0))
|
||||||
|
|
||||||
characteristic.write(DataByteArray.from(3, 0, 0, 0))
|
val readTimeout = characteristic.read().value.let {
|
||||||
|
|
||||||
val interval = characteristic.read().value.let {
|
|
||||||
if(it.size == 4){
|
if(it.size == 4){
|
||||||
it.get4byteUIntAt(0).toLong()
|
it.get4byteUIntAt(0).toLong()
|
||||||
}else{
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
return Result.success(
|
return Result.success(
|
||||||
Ble.Host.HostState(
|
Ble.Host.HostState(
|
||||||
historyInterval = interval
|
historyInterval = interval,
|
||||||
|
readInterval = interval
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -453,6 +382,32 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun ClientBleGattCharacteristic.readWriteInterval(
|
||||||
|
|
||||||
|
): Result<Long, BleException> {
|
||||||
|
|
||||||
|
return if(app.checkPermission().not()) {
|
||||||
|
|
||||||
|
Result.failure(BleException.PermissionDenied)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
write(DataByteArray.from(3, 0, 0, 0))
|
||||||
|
|
||||||
|
val interval = read().value.let {
|
||||||
|
if (it.size == 4) {
|
||||||
|
it.get4byteUIntAt(0).toLong()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result.success(interval)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun readAccelState(
|
private suspend fun readAccelState(
|
||||||
address: String,
|
address: String,
|
||||||
timer: BleInfo.HistoryTableStatus
|
timer: BleInfo.HistoryTableStatus
|
||||||
|
|
@ -471,15 +426,10 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
var characteristic = service.findCharacteristic(intervalReadUUID)
|
var characteristic = service.findCharacteristic(intervalReadUUID)
|
||||||
?: return Result.failure(BleException.UnexpectedResponse)
|
?: return Result.failure(BleException.UnexpectedResponse)
|
||||||
|
|
||||||
characteristic.write(DataByteArray.from(3, 0, 0, 0, ))
|
val interval = characteristic.readWriteInterval().fold(
|
||||||
|
onFailure = { return Result.failure(it) },
|
||||||
val interval = characteristic.read().value.let {
|
onSuccess = { it }
|
||||||
if(it.size == 4){
|
)
|
||||||
it.get4byteUIntAt(0).toLong()
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val historySettingsParams = when(timer){
|
val historySettingsParams = when(timer){
|
||||||
BleInfo.HistoryTableStatus.EMPTY,
|
BleInfo.HistoryTableStatus.EMPTY,
|
||||||
|
|
@ -561,7 +511,7 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun addBleToHostTableBySerial(serial: String, ble: List<String>): Result<Int, BleException> {
|
override suspend fun addBleToHostTableBySerial(serial: String, ble: List<String>): Result<Int, BleException> {
|
||||||
return editBleToHostTable(serial, ble, app)
|
return editBleHostTable(serial, ble, app)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getHostHistoryBySerial(
|
override suspend fun getHostHistoryBySerial(
|
||||||
|
|
@ -747,6 +697,20 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request.readInterval?.let {
|
||||||
|
|
||||||
|
service.findCharacteristic(intervalWriteUUID)!!.write(
|
||||||
|
DataByteArray.from(
|
||||||
|
*mutableListOf<Byte>(2).apply {
|
||||||
|
addAll(
|
||||||
|
(it / 1000).toUInt().to4ByteArrayInLittleEndian().reversed().toList()
|
||||||
|
)
|
||||||
|
}.toByteArray()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
service.findCharacteristic(
|
service.findCharacteristic(
|
||||||
flashWriteUUID
|
flashWriteUUID
|
||||||
)!!.write(
|
)!!.write(
|
||||||
|
|
@ -790,9 +754,9 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
try {
|
try {
|
||||||
|
|
||||||
val services = connection.discoverServices()
|
val services = connection.discoverServices()
|
||||||
val service = services.findService(serviceUUID) ?: return Result.failure(
|
|
||||||
BleException.UnexpectedResponse
|
val service = services.findService(serviceUUID)
|
||||||
)
|
?: return Result.failure(BleException.UnexpectedResponse)
|
||||||
|
|
||||||
Log.d("write", request.toString())
|
Log.d("write", request.toString())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
package llc.arma.ble.data.repository
|
package llc.arma.ble.data.repository
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.annotation.RequiresPermission
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
@ -18,12 +22,11 @@ import llc.arma.ble.domain.model.Ble
|
||||||
import no.nordicsemi.android.common.core.DataByteArray
|
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.client.main.service.ClientBleGattCharacteristic
|
import no.nordicsemi.android.kotlin.ble.client.main.service.ClientBleGattCharacteristic
|
||||||
import okio.ByteString.Companion.decodeHex
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.util.BitSet
|
import java.util.BitSet
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@RequiresPermission(allOf = ["android.permission.BLUETOOTH_CONNECT"])
|
||||||
suspend fun readTable(
|
suspend fun readTable(
|
||||||
characteristic: ClientBleGattCharacteristic,
|
characteristic: ClientBleGattCharacteristic,
|
||||||
startRequest: ByteArray,
|
startRequest: ByteArray,
|
||||||
|
|
@ -172,20 +175,34 @@ fun readHostHistory(
|
||||||
var periods = mutableListOf<Pair<Boolean, List<String>>>()
|
var periods = mutableListOf<Pair<Boolean, List<String>>>()
|
||||||
|
|
||||||
var periodBle = mutableListOf<String>()
|
var periodBle = mutableListOf<String>()
|
||||||
var hasHit = false
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
val bleIdTableCell = firstTablePackage.drop(bleTableOffset).take(2).toByteArray()
|
val bleIdTableCell =
|
||||||
|
firstTablePackage.drop(bleTableOffset).take(2).toByteArray()
|
||||||
|
|
||||||
println("cell ${bleIdTableCell.toHexString()} ${bleIdTableCell.joinToString()}")
|
val intervalEnd = "ff0f"
|
||||||
|
val intervalEndAndHit = "fe0f"
|
||||||
|
|
||||||
if(bleIdTableCell.contentEquals(byteArrayOf(-1, 15)).not()) {
|
if (bleIdTableCell.contentEquals(intervalEnd.hexToByteArray())) {
|
||||||
|
|
||||||
if(bleIdTableCell.contentEquals(byteArrayOf(-2, 15))){
|
|
||||||
bleTableOffset += 2
|
bleTableOffset += 2
|
||||||
hasHit = true
|
if(periodBle.isEmpty()) bleTableOffset += 2
|
||||||
|
periods.add(Pair(false, periodBle))
|
||||||
|
periodBle = mutableListOf()
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bleIdTableCell.contentEquals(intervalEndAndHit.hexToByteArray())) {
|
||||||
|
bleTableOffset += 2
|
||||||
|
if(periodBle.isEmpty()) bleTableOffset += 2
|
||||||
|
periods.add(Pair(true, periodBle))
|
||||||
|
periodBle = mutableListOf()
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val innerIndex = getInnerIndex(bleIdTableCell[1])
|
val innerIndex = getInnerIndex(bleIdTableCell[1])
|
||||||
|
|
@ -204,6 +221,9 @@ fun readHostHistory(
|
||||||
val devDataSize = getDevDataSize(devTypeByte)
|
val devDataSize = getDevDataSize(devTypeByte)
|
||||||
bleTableOffset += 2
|
bleTableOffset += 2
|
||||||
|
|
||||||
|
if(innerIndex == 0)
|
||||||
|
bleTableOffset += 2
|
||||||
|
|
||||||
if (devDataSize != 0) {
|
if (devDataSize != 0) {
|
||||||
val payload = getBleIdIndex(
|
val payload = getBleIdIndex(
|
||||||
firstTablePackage.drop(bleTableOffset).take(devDataSize)
|
firstTablePackage.drop(bleTableOffset).take(devDataSize)
|
||||||
|
|
@ -214,24 +234,6 @@ fun readHostHistory(
|
||||||
|
|
||||||
periodBle.add(serial)
|
periodBle.add(serial)
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
bleTableOffset += 2
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var nextIndex = 0
|
|
||||||
|
|
||||||
if(bleTableOffset <= firstTablePackage.size - 2){
|
|
||||||
nextIndex = getInnerIndex(firstTablePackage.drop(bleTableOffset)[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
if(nextIndex == 0){
|
|
||||||
periods.add(Pair(hasHit, periodBle))
|
|
||||||
periodBle = mutableListOf()
|
|
||||||
hasHit = false
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (bleTableOffset < firstTablePackage.size)
|
} while (bleTableOffset < firstTablePackage.size)
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
|
|
@ -290,7 +292,7 @@ suspend fun readHostBleTable(
|
||||||
?.findCharacteristic(hostHistoryReadUUID)
|
?.findCharacteristic(hostHistoryReadUUID)
|
||||||
?: throw IllegalStateException()
|
?: throw IllegalStateException()
|
||||||
|
|
||||||
characteristic.write(DataByteArray.from(2))
|
characteristic.write(DataByteArray.from(7))
|
||||||
|
|
||||||
var value = characteristic.read().value
|
var value = characteristic.read().value
|
||||||
|
|
||||||
|
|
@ -346,7 +348,7 @@ suspend fun readHostBleTable(
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
suspend fun editBleToHostTable(
|
suspend fun editBleHostTable(
|
||||||
address: String,
|
address: String,
|
||||||
addBleAddress: List<String>,
|
addBleAddress: List<String>,
|
||||||
app: Application,
|
app: Application,
|
||||||
|
|
@ -366,7 +368,9 @@ suspend fun editBleToHostTable(
|
||||||
|
|
||||||
characteristic.write(DataByteArray.from(12, 1))
|
characteristic.write(DataByteArray.from(12, 1))
|
||||||
|
|
||||||
val writeCount = addBleAddress.chunked(40).sumOf { bleAddressBatch ->
|
Log.i("ScanRecord", "write")
|
||||||
|
|
||||||
|
val writeCount = addBleAddress.chunked(20).sumOf { bleAddressBatch ->
|
||||||
|
|
||||||
val countPayload = ByteBuffer.allocate(2).putShort(bleAddressBatch.size.toShort()).array().reversed().toByteArray()
|
val countPayload = ByteBuffer.allocate(2).putShort(bleAddressBatch.size.toShort()).array().reversed().toByteArray()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import androidx.datastore.preferences.core.Preferences
|
||||||
import androidx.datastore.preferences.core.edit
|
import androidx.datastore.preferences.core.edit
|
||||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||||
import androidx.datastore.preferences.preferencesDataStore
|
import androidx.datastore.preferences.preferencesDataStore
|
||||||
import com.google.gson.Gson
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,15 @@ import llc.arma.ble.domain.usecase.AccelScale
|
||||||
import llc.arma.ble.domain.usecase.AccelViewMode
|
import llc.arma.ble.domain.usecase.AccelViewMode
|
||||||
|
|
||||||
sealed class Ble(
|
sealed class Ble(
|
||||||
val info: BleInfo
|
var info: BleInfo,
|
||||||
|
var state: BleState,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
class Accelerometer(
|
class Accelerometer(
|
||||||
info: BleInfo,
|
info: BleInfo,
|
||||||
val state: BleState,
|
state: BleState,
|
||||||
val accelerometerState: AccelerometerState
|
val accelerometerState: AccelerometerState
|
||||||
): Ble(info) {
|
): Ble(info, state) {
|
||||||
|
|
||||||
sealed class HistorySettings {
|
sealed class HistorySettings {
|
||||||
|
|
||||||
|
|
@ -99,8 +100,8 @@ sealed class Ble(
|
||||||
|
|
||||||
class Beacon(
|
class Beacon(
|
||||||
info: BleInfo,
|
info: BleInfo,
|
||||||
val state: BleState
|
state: BleState,
|
||||||
) : Ble(info){
|
) : Ble(info, state){
|
||||||
|
|
||||||
data class WriteRequest(
|
data class WriteRequest(
|
||||||
val tx: BleState.TX?
|
val tx: BleState.TX?
|
||||||
|
|
@ -110,9 +111,9 @@ sealed class Ble(
|
||||||
|
|
||||||
class Host(
|
class Host(
|
||||||
info: BleInfo,
|
info: BleInfo,
|
||||||
val state: BleState,
|
state: BleState,
|
||||||
val hostState: HostState
|
val hostState: HostState
|
||||||
) : Ble(info){
|
) : Ble(info, state){
|
||||||
|
|
||||||
class HistoryPoint(
|
class HistoryPoint(
|
||||||
val date: Long,
|
val date: Long,
|
||||||
|
|
@ -121,21 +122,23 @@ sealed class Ble(
|
||||||
)
|
)
|
||||||
|
|
||||||
data class HostState(
|
data class HostState(
|
||||||
val historyInterval: Long
|
val historyInterval: Long,
|
||||||
|
val readInterval: Long
|
||||||
)
|
)
|
||||||
|
|
||||||
data class WriteRequest(
|
data class WriteRequest(
|
||||||
val tx: BleState.TX?,
|
val tx: BleState.TX?,
|
||||||
val interval: Long?
|
val interval: Long?,
|
||||||
|
val readInterval: Long?,
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Thermometer(
|
class Thermometer(
|
||||||
info: BleInfo,
|
info: BleInfo,
|
||||||
val state: BleState,
|
state: BleState,
|
||||||
val thermometerState: ThermometerState
|
val thermometerState: ThermometerState
|
||||||
) : Ble(info) {
|
) : Ble(info, state) {
|
||||||
|
|
||||||
class HistoryPoint(
|
class HistoryPoint(
|
||||||
val date: Long,
|
val date: Long,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue