Поправки по графикам
This commit is contained in:
parent
4528a7cd9a
commit
d974df953d
|
|
@ -13,8 +13,8 @@ android {
|
||||||
applicationId "llc.arma.ble"
|
applicationId "llc.arma.ble"
|
||||||
minSdk 24
|
minSdk 24
|
||||||
targetSdk 33
|
targetSdk 33
|
||||||
versionCode 2
|
versionCode 4
|
||||||
versionName "1.1"
|
versionName "1.2.1"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables {
|
vectorDrawables {
|
||||||
|
|
@ -46,6 +46,13 @@ android {
|
||||||
excludes += '/META-INF/{AL2.0,LGPL2.1}'
|
excludes += '/META-INF/{AL2.0,LGPL2.1}'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applicationVariants.all { variant ->
|
||||||
|
variant.outputs.all {
|
||||||
|
outputFileName = "Arma BLE v${defaultConfig.versionName}.apk"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
@ -76,8 +83,8 @@ dependencies {
|
||||||
|
|
||||||
implementation "com.google.accompanist:accompanist-permissions:0.26.3-beta"
|
implementation "com.google.accompanist:accompanist-permissions:0.26.3-beta"
|
||||||
|
|
||||||
implementation "com.patrykandpatrick.vico:core:1.6.6"
|
implementation "com.patrykandpatrick.vico:core:1.7.1"
|
||||||
implementation "com.patrykandpatrick.vico:compose:1.6.6"
|
implementation "com.patrykandpatrick.vico:compose:1.7.1"
|
||||||
implementation "com.patrykandpatrick.vico:compose-m3:1.6.6"
|
implementation "com.patrykandpatrick.vico:compose-m3:1.7.1"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +122,14 @@ fun BleListScreen(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(state.bleList.isEmpty()){
|
val filteredData = state.bleList.filter {
|
||||||
|
(it.type == state.filter.bleType || state.filter.bleType == null) &&
|
||||||
|
it.name.contains(state.filter.name) &&
|
||||||
|
it.serial.contains(state.filter.mac) &&
|
||||||
|
state.filter.rssi.contains(it.rssi?.toFloat() ?: Float.MIN_VALUE)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(filteredData.isEmpty()){
|
||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
strokeCap = StrokeCap.Round,
|
strokeCap = StrokeCap.Round,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -131,37 +138,44 @@ fun BleListScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyColumn(
|
if(filteredData.isEmpty()){
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
modifier = Modifier.fillMaxSize()
|
|
||||||
) {
|
|
||||||
|
|
||||||
items(items = state.connectedBleList){
|
Box(modifier = Modifier.fillMaxSize()){
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.align(Alignment.Center),
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
text = "Метки в области не найдены"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
LazyColumn(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
|
||||||
|
items(items = state.connectedBleList){
|
||||||
|
|
||||||
|
ConnectedBleItem(ble = it) {
|
||||||
|
viewModel.setEvent(BleListContract.Event.OnConnectToBle(it.serial))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
items(items = filteredData.sortedBy { it.name }.reversed()) {
|
||||||
|
|
||||||
|
BleItem(
|
||||||
|
ble = it,
|
||||||
|
onClick = {
|
||||||
|
viewModel.setEvent(BleListContract.Event.OnConnectToBle(it.serial))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
ConnectedBleItem(ble = it) {
|
|
||||||
viewModel.setEvent(BleListContract.Event.OnConnectToBle(it.serial))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val filteredData = state.bleList.filter {
|
|
||||||
(it.type == state.filter.bleType || state.filter.bleType == null) &&
|
|
||||||
it.name.contains(state.filter.name) &&
|
|
||||||
it.serial.contains(state.filter.mac) &&
|
|
||||||
state.filter.rssi.contains(it.rssi?.toFloat() ?: Float.MIN_VALUE)
|
|
||||||
}
|
|
||||||
|
|
||||||
items(items = filteredData.sortedBy { it.name }.reversed()) {
|
|
||||||
|
|
||||||
BleItem(
|
|
||||||
ble = it,
|
|
||||||
onClick = {
|
|
||||||
viewModel.setEvent(BleListContract.Event.OnConnectToBle(it.serial))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -374,12 +388,6 @@ private fun BleItem(
|
||||||
modifier = Modifier.alpha(0.7f)
|
modifier = Modifier.alpha(0.7f)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val color = if(ble.batteryLevel < 100){
|
|
||||||
MaterialTheme.colorScheme.error
|
|
||||||
} else {
|
|
||||||
LocalContentColor.current
|
|
||||||
}
|
|
||||||
|
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.size(16.dp),
|
modifier = Modifier.size(16.dp),
|
||||||
imageVector = Icons.Rounded.ArrowRightAlt,
|
imageVector = Icons.Rounded.ArrowRightAlt,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
|
||||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.foundation.gestures.detectTransformGestures
|
||||||
import androidx.compose.foundation.gestures.scrollBy
|
import androidx.compose.foundation.gestures.scrollBy
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
|
|
@ -27,12 +28,15 @@ import llc.arma.ble.domain.model.BleInfo
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.rounded.Refresh
|
import androidx.compose.material.icons.rounded.Refresh
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.StrokeCap
|
import androidx.compose.ui.graphics.StrokeCap
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import com.patrykandpatrick.vico.compose.chart.column.columnChart
|
import com.patrykandpatrick.vico.compose.chart.column.columnChart
|
||||||
import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollState
|
import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollState
|
||||||
import com.patrykandpatrick.vico.core.axis.AxisPosition
|
import com.patrykandpatrick.vico.core.axis.AxisPosition
|
||||||
import com.patrykandpatrick.vico.core.axis.formatter.AxisValueFormatter
|
import com.patrykandpatrick.vico.core.axis.formatter.AxisValueFormatter
|
||||||
|
import com.patrykandpatrick.vico.core.component.shape.LineComponent
|
||||||
import com.patrykandpatrick.vico.core.entry.ChartEntry
|
import com.patrykandpatrick.vico.core.entry.ChartEntry
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
@ -157,15 +161,28 @@ fun Display(
|
||||||
AxisValueFormatter<AxisPosition.Horizontal.Bottom> { value, chartValues ->
|
AxisValueFormatter<AxisPosition.Horizontal.Bottom> { value, chartValues ->
|
||||||
(chartValues.chartEntryModel.entries.firstOrNull()
|
(chartValues.chartEntryModel.entries.firstOrNull()
|
||||||
?.getOrNull(value.toInt()) as? AccelerometerEntry)
|
?.getOrNull(value.toInt()) as? AccelerometerEntry)
|
||||||
?.frequency?.toString()
|
?.frequency?.let { it.toFloat() / 16f }?.toString()
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
val lineChart = columnChart()
|
val lineChart = columnChart(
|
||||||
|
spacing = 1.5.dp
|
||||||
|
)
|
||||||
|
|
||||||
|
LaunchedEffect(state.loadingHistoryState.data){
|
||||||
|
lineChart.bounds
|
||||||
|
lineChart.setBounds(
|
||||||
|
left = lineChart.bounds.left / 20,
|
||||||
|
top = lineChart.bounds.top,
|
||||||
|
right = lineChart.bounds.right / 20,
|
||||||
|
bottom = lineChart.bounds.bottom,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val scrollState = rememberChartScrollState()
|
val scrollState = rememberChartScrollState()
|
||||||
|
|
||||||
Chart(
|
Chart(
|
||||||
|
isZoomEnabled = true,
|
||||||
chartScrollState = scrollState,
|
chartScrollState = scrollState,
|
||||||
chart = lineChart,
|
chart = lineChart,
|
||||||
chartModelProducer = producer,
|
chartModelProducer = producer,
|
||||||
|
|
@ -175,12 +192,13 @@ fun Display(
|
||||||
valueFormatter = axisValueFormatter,
|
valueFormatter = axisValueFormatter,
|
||||||
labelRotationDegrees = -90f,
|
labelRotationDegrees = -90f,
|
||||||
),
|
),
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize()
|
||||||
)
|
)
|
||||||
|
|
||||||
LaunchedEffect(scrollState.maxValue) {
|
|
||||||
|
/*LaunchedEffect(scrollState.maxValue) {
|
||||||
scrollState.scrollBy(scrollState.maxValue)
|
scrollState.scrollBy(scrollState.maxValue)
|
||||||
}
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,10 @@ fun UByteArray.toTemperature(): Float {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ByteArray.get2byteUIntAt(idx: Int) =
|
||||||
|
((this[idx + 1].toUInt() and 0xFFu) shl 8) or
|
||||||
|
(this[idx].toUInt() and 0xFFu)
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class BleRepositoryImpl @Inject constructor(
|
class BleRepositoryImpl @Inject constructor(
|
||||||
private val app: Application
|
private val app: Application
|
||||||
|
|
@ -510,6 +514,54 @@ class BleRepositoryImpl @Inject constructor(
|
||||||
|
|
||||||
if (checkPermission()) {
|
if (checkPermission()) {
|
||||||
|
|
||||||
|
writeCharacteristic(
|
||||||
|
device = it,
|
||||||
|
serviceId = serviceUUID,
|
||||||
|
characteristicId = accelerometerReadUUID,
|
||||||
|
writeData = byteArrayOf(4, 1)
|
||||||
|
).onFailure {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
send(Result.failure(BleException.PermissionDenied))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = false
|
||||||
|
|
||||||
|
while (result.not()){
|
||||||
|
|
||||||
|
writeCharacteristic(
|
||||||
|
device = it,
|
||||||
|
serviceId = serviceUUID,
|
||||||
|
characteristicId = accelerometerReadUUID,
|
||||||
|
writeData = byteArrayOf(4, 0)
|
||||||
|
).onFailure {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
send(Result.failure(BleException.PermissionDenied))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readCharacteristic(
|
||||||
|
device = it,
|
||||||
|
serviceId = serviceUUID,
|
||||||
|
characteristicId = accelerometerReadUUID
|
||||||
|
).fold(
|
||||||
|
onSuccess = { readData ->
|
||||||
|
Log.d("a read", readData.joinToString("-"))
|
||||||
|
if(readData.isNotEmpty() && readData.first() == (0).toByte()){
|
||||||
|
result = true
|
||||||
|
} else {
|
||||||
|
delay(200)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onFailure = {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
send(Result.failure(BleException.PermissionDenied))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
gatt = it.connectGatt(app, false, ReadAccelerometerHistoryCallback(app) {
|
gatt = it.connectGatt(app, false, ReadAccelerometerHistoryCallback(app) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
send(it)
|
send(it)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ 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 java.nio.ByteBuffer
|
||||||
|
import java.nio.ByteOrder.LITTLE_ENDIAN
|
||||||
|
|
||||||
class ReadAccelerometerHistoryCallback(
|
class ReadAccelerometerHistoryCallback(
|
||||||
private val app: Application,
|
private val app: Application,
|
||||||
|
|
@ -29,6 +31,12 @@ class ReadAccelerometerHistoryCallback(
|
||||||
((this[idx + 1].toUInt() and 0xFFu) shl 8) or
|
((this[idx + 1].toUInt() and 0xFFu) shl 8) or
|
||||||
(this[idx].toUInt() and 0xFFu)
|
(this[idx].toUInt() and 0xFFu)
|
||||||
|
|
||||||
|
private fun ByteArray.get2byteShortAt(idx: Int): Int {
|
||||||
|
val shorts = ShortArray(1)
|
||||||
|
ByteBuffer.wrap(this).order(LITTLE_ENDIAN).asShortBuffer()[shorts]
|
||||||
|
return shorts[0].toInt()//(this[0].toInt() + (this[1].toInt() shl 8)).toShort()
|
||||||
|
}
|
||||||
|
|
||||||
private var readProperty: Property? = null
|
private var readProperty: Property? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
@ -97,11 +105,11 @@ class ReadAccelerometerHistoryCallback(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastMeasureSystemTime: Long? = null
|
//private var lastMeasureSystemTime: Long? = null
|
||||||
|
|
||||||
private var bleMeasureInterval: Long? = null
|
private var initialValue: Long? = null
|
||||||
private var bleRealTime: Long? = null
|
//private var bleRealTime: Long? = null
|
||||||
private var bleLastMeasureTime: Long? = null
|
private var frequencyInterval: Long? = null
|
||||||
|
|
||||||
private val resultAccelerometerPackage: MutableList<Float> = mutableListOf()
|
private val resultAccelerometerPackage: MutableList<Float> = mutableListOf()
|
||||||
|
|
||||||
|
|
@ -171,23 +179,20 @@ class ReadAccelerometerHistoryCallback(
|
||||||
|
|
||||||
if(value[0] == 250.toByte()){
|
if(value[0] == 250.toByte()){
|
||||||
|
|
||||||
bleMeasureInterval = value.get4byteUIntAt(4).toLong()
|
initialValue = value.get4byteUIntAt(8).toLong()
|
||||||
bleLastMeasureTime = value.get4byteUIntAt(8).toLong()
|
frequencyInterval = value.get4byteUIntAt(4).toLong()
|
||||||
bleRealTime = value.get4byteUIntAt(12).toLong()
|
|
||||||
|
|
||||||
lastMeasureSystemTime = ((bleRealTime!! - bleLastMeasureTime!!) * 1_000)
|
val accelerometerDataArray = value.asList().subList(16, value.size)
|
||||||
|
|
||||||
val accelerometerDataArray = value.toUByteArray().asList().subList(16, value.size)
|
|
||||||
|
|
||||||
resultAccelerometerPackage.addAll(
|
resultAccelerometerPackage.addAll(
|
||||||
accelerometerDataArray.chunked(2).map {
|
accelerometerDataArray.chunked(2).map {
|
||||||
it.toUByteArray().toTemperature()
|
it.toByteArray().get2byteShortAt(0).toFloat()
|
||||||
}.toMutableList()
|
}.toMutableList()
|
||||||
)
|
)
|
||||||
|
|
||||||
val nextPackageDataCount = value.get2byteUIntAt(2)
|
val nextPackageDataCount = value.get2byteUIntAt(2)
|
||||||
expectedDataSize = nextPackageDataCount.toInt() + resultAccelerometerPackage.size
|
expectedDataSize = nextPackageDataCount.toInt() + resultAccelerometerPackage.size
|
||||||
Log.d("read", expectedDataSize.toString())
|
|
||||||
onResult(Result.success(ProgressState.Progress(0f / expectedDataSize!!.toFloat())))
|
onResult(Result.success(ProgressState.Progress(0f / expectedDataSize!!.toFloat())))
|
||||||
onResult(Result.success(ProgressState.Progress(resultAccelerometerPackage.size.toFloat() / expectedDataSize!!.toFloat())))
|
onResult(Result.success(ProgressState.Progress(resultAccelerometerPackage.size.toFloat() / expectedDataSize!!.toFloat())))
|
||||||
|
|
||||||
|
|
@ -211,7 +216,7 @@ class ReadAccelerometerHistoryCallback(
|
||||||
ProgressState.Finished(
|
ProgressState.Finished(
|
||||||
resultAccelerometerPackage.withIndex().map {
|
resultAccelerometerPackage.withIndex().map {
|
||||||
Ble.Accelerometer.MeasurePoint(
|
Ble.Accelerometer.MeasurePoint(
|
||||||
frequency = lastMeasureSystemTime!! - (((resultAccelerometerPackage.size - 1) - it.index) * bleMeasureInterval!!),
|
frequency = frequencyInterval!! * it.index + initialValue!!,
|
||||||
value = it.value
|
value = it.value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -226,11 +231,11 @@ class ReadAccelerometerHistoryCallback(
|
||||||
if (value[0] == 251.toByte()) {
|
if (value[0] == 251.toByte()) {
|
||||||
|
|
||||||
val nextPackageDataCount = value.get2byteUIntAt(2)
|
val nextPackageDataCount = value.get2byteUIntAt(2)
|
||||||
val temperatureDataArray = value.toUByteArray().toList().subList(4, value.size)
|
val temperatureDataArray = value.toList().subList(4, value.size)
|
||||||
|
|
||||||
resultAccelerometerPackage.addAll(
|
resultAccelerometerPackage.addAll(
|
||||||
temperatureDataArray.chunked(2).map {
|
temperatureDataArray.chunked(2).map {
|
||||||
it.toUByteArray().toTemperature()
|
it.toByteArray().get2byteShortAt(0).toFloat()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -249,7 +254,7 @@ class ReadAccelerometerHistoryCallback(
|
||||||
ProgressState.Finished(
|
ProgressState.Finished(
|
||||||
resultAccelerometerPackage.withIndex().map {
|
resultAccelerometerPackage.withIndex().map {
|
||||||
Ble.Accelerometer.MeasurePoint(
|
Ble.Accelerometer.MeasurePoint(
|
||||||
frequency = lastMeasureSystemTime!! - (((resultAccelerometerPackage.size - 1) - it.index) * bleMeasureInterval!!),
|
frequency = frequencyInterval!! * it.index + initialValue!!,
|
||||||
value = it.value
|
value = it.value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue