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

This commit is contained in:
Vineyro 2023-07-25 12:32:13 +07:00
parent 4528a7cd9a
commit d974df953d
5 changed files with 149 additions and 59 deletions

View File

@ -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"
} }

View File

@ -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,

View File

@ -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)
} }*/
} }

View File

@ -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)

View File

@ -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
) )
} }