add rotations
This commit is contained in:
parent
b915659217
commit
a059cacda9
|
|
@ -13,8 +13,8 @@ android {
|
|||
applicationId "llc.arma.ble"
|
||||
minSdk 26
|
||||
targetSdk 34
|
||||
versionCode 17
|
||||
versionName "1.2.17"
|
||||
versionCode 18
|
||||
versionName "1.2.18"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
|
|
@ -86,6 +86,9 @@ dependencies {
|
|||
kapt('com.google.dagger:hilt-android-compiler:2.45')
|
||||
kapt("androidx.hilt:hilt-compiler:1.0.0")
|
||||
|
||||
implementation 'no.nordicsemi.android.kotlin.ble:scanner:1.0.14'
|
||||
implementation 'no.nordicsemi.android.kotlin.ble:client:1.0.14'
|
||||
|
||||
implementation "com.google.accompanist:accompanist-permissions:0.26.3-beta"
|
||||
|
||||
implementation "com.patrykandpatrick.vico:core:1.7.1"
|
||||
|
|
|
|||
|
|
@ -24,16 +24,6 @@ import llc.arma.ble.domain.usecase.FftAxis
|
|||
import llc.arma.ble.domain.usecase.FftFrequency
|
||||
import llc.arma.ble.domain.usecase.FftViewMode
|
||||
|
||||
/*val AccelViewMode.localized: String
|
||||
get() {
|
||||
return when(this){
|
||||
ACCELERATION -> "Ускорение"
|
||||
PEAK_ACCELERATION -> "Пиковое ускорение"
|
||||
RMS -> "Среднеквадратичное ускорение"
|
||||
ANGLE -> "Угол"
|
||||
}
|
||||
}*/
|
||||
|
||||
@Composable
|
||||
fun AccelFrequencyEdit(
|
||||
state: AccelerometerContract.State.Display,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ val AccelViewMode.localized: String
|
|||
RMS -> "Среднеквадратичное ускорение"
|
||||
VIBRATION -> "Вибрация"
|
||||
ANGLE -> "Угол"
|
||||
ROTATIONS -> "Обороты"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import kotlinx.coroutines.flow.launchIn
|
|||
import kotlinx.coroutines.flow.onEach
|
||||
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.FftFrequency
|
||||
|
|
@ -194,10 +195,64 @@ fun Display(
|
|||
|
||||
val lastMeasure = state.measureHistory.lastOrNull()
|
||||
|
||||
/*when(lastMeasure){
|
||||
is MeasureData.Accelerate -> TODO()
|
||||
is MeasureData.Angle -> TODO()
|
||||
is MeasureData.Vibration -> {
|
||||
|
||||
}
|
||||
null -> {}
|
||||
}*/
|
||||
|
||||
if(lastMeasure is MeasureData.Accelerate) {
|
||||
|
||||
if(state.mode == AccelViewMode.ANGLE){
|
||||
when(state.mode){
|
||||
ROTATIONS -> {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
|
||||
|
||||
Text(text = "Ось Y: ${lastMeasure.y}")
|
||||
|
||||
Column(
|
||||
modifier = Modifier.weight(1f),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
|
||||
Text(text = "Ось X: ${lastMeasure.x}")
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Angle(
|
||||
angle = lastMeasure.x,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
Text(text = "Ось Z:")
|
||||
Chart(
|
||||
chart = lineChart,
|
||||
chartModelProducer = zProducer,
|
||||
startAxis = startAxis(),
|
||||
bottomAxis = bottomAxis(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f),
|
||||
autoScaleUp = AutoScaleUp.None,
|
||||
diffAnimationSpec = tween(0),
|
||||
chartScrollSpec = rememberChartScrollSpec(
|
||||
initialScroll = InitialScroll.End,
|
||||
autoScrollCondition = AutoScrollCondition.OnModelSizeIncreased,
|
||||
autoScrollAnimationSpec = tween(0)
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
ANGLE -> {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
|
|
@ -252,8 +307,8 @@ fun Display(
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
}
|
||||
else -> {
|
||||
|
||||
Column() {
|
||||
|
||||
|
|
@ -315,6 +370,7 @@ fun Display(
|
|||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -349,7 +405,7 @@ fun Display(
|
|||
}
|
||||
|
||||
@Composable
|
||||
public fun Angle(
|
||||
fun Angle(
|
||||
modifier: Modifier = Modifier,
|
||||
angle: Float
|
||||
) {
|
||||
|
|
@ -493,7 +549,7 @@ class AccelerometerAccelViewModel @Inject constructor(
|
|||
private var lastSerial: String? = null
|
||||
|
||||
override fun setInitialState() = AccelerometerAccelContract.State.Display(
|
||||
mode = AccelViewMode.ACCELERATION,
|
||||
mode = ACCELERATION,
|
||||
measureHistory = emptyList()
|
||||
)
|
||||
|
||||
|
|
@ -515,7 +571,7 @@ class AccelerometerAccelViewModel @Inject constructor(
|
|||
|
||||
setState {
|
||||
AccelerometerAccelContract.State.Display(
|
||||
mode = AccelViewMode.ACCELERATION,
|
||||
mode = ACCELERATION,
|
||||
measureHistory = emptyList()
|
||||
)
|
||||
}
|
||||
|
|
@ -555,7 +611,7 @@ class AccelerometerAccelViewModel @Inject constructor(
|
|||
|
||||
setState {
|
||||
AccelerometerAccelContract.State.Display(
|
||||
mode = AccelViewMode.ACCELERATION,
|
||||
mode = ACCELERATION,
|
||||
measureHistory = emptyList()
|
||||
)
|
||||
}
|
||||
|
|
@ -569,8 +625,8 @@ class AccelerometerAccelViewModel @Inject constructor(
|
|||
var dataList = this.measureHistory.toMutableList().apply {
|
||||
add(it)
|
||||
}
|
||||
if(accelMode != AccelViewMode.ANGLE) {
|
||||
dataList = dataList.takeLast(10).toMutableList()
|
||||
if(accelMode != ANGLE) {
|
||||
dataList = dataList.takeLast(100).toMutableList()
|
||||
}
|
||||
AccelerometerAccelContract.State.Display(accelMode, dataList)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,19 +44,6 @@ val LightColorScheme = lightColorScheme(
|
|||
surfaceTint = Color(0xFF755B00),
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun BleTheme(
|
||||
colorScheme: ColorScheme,
|
||||
content: @Composable () -> Unit
|
||||
){
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content,
|
||||
shapes = shapes
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun BleTheme(
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,297 +0,0 @@
|
|||
package llc.arma.ble.data
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Application
|
||||
import android.bluetooth.BluetoothGatt
|
||||
import android.bluetooth.BluetoothGattCallback
|
||||
import android.bluetooth.BluetoothGattCharacteristic
|
||||
import android.bluetooth.BluetoothGattDescriptor
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import llc.arma.ble.domain.Result
|
||||
import llc.arma.ble.domain.common.BleException
|
||||
import llc.arma.ble.domain.usecase.AccelScale
|
||||
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.FftFrequency
|
||||
import llc.arma.ble.domain.usecase.FftViewMode
|
||||
import java.util.UUID
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.atan
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
|
||||
class ReadAccelerometerCallback(
|
||||
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<MeasureData, BleException>) -> Unit
|
||||
) : BluetoothGattCallback() {
|
||||
|
||||
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 (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)
|
||||
|
||||
Log.d("accel", "onServicesDiscovered")
|
||||
|
||||
if(status == BluetoothGatt.GATT_SUCCESS){
|
||||
|
||||
gatt.getService(serviceUUID)?.getCharacteristic(accelerometerReadUUID)?.let {
|
||||
|
||||
if (checkPermission()) {
|
||||
|
||||
val payload = byteArrayOf(
|
||||
4,
|
||||
accelMode.sendData,
|
||||
accelScale.sendData,
|
||||
fftMode.sendData,
|
||||
fftAxis.sendData,
|
||||
frequency.sendData,
|
||||
1
|
||||
)
|
||||
|
||||
gatt.writeCharacteristic(it, payload)
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.failure(BleException.PermissionDenied))
|
||||
gatt.close()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onCharacteristicWrite(
|
||||
gatt: BluetoothGatt,
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
status: Int
|
||||
) {
|
||||
super.onCharacteristicWrite(gatt, characteristic, status)
|
||||
|
||||
Log.d("accel", "request written")
|
||||
|
||||
if(status == BluetoothGatt.GATT_SUCCESS){
|
||||
|
||||
gatt.getService(serviceUUID)?.getCharacteristic(accelerometerReadUUID)?.let {
|
||||
|
||||
if (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)
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.failure(BleException.PermissionDenied))
|
||||
gatt.close()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onCharacteristicChanged(
|
||||
gatt: BluetoothGatt,
|
||||
characteristic: BluetoothGattCharacteristic
|
||||
) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
super.onCharacteristicChanged(gatt, characteristic)
|
||||
onCommonCharacteristicRead(characteristic.value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCharacteristicChanged(
|
||||
gatt: BluetoothGatt,
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
value: ByteArray
|
||||
) {
|
||||
super.onCharacteristicChanged(gatt, characteristic, value)
|
||||
onCommonCharacteristicRead(value)
|
||||
}
|
||||
|
||||
private fun onCommonCharacteristicRead(
|
||||
value: ByteArray,
|
||||
){
|
||||
|
||||
|
||||
|
||||
val result = if(accelMode == AccelViewMode.VIBRATION){
|
||||
|
||||
MeasureData.Vibration((value.get2byteShortAt().toFloat() * accelScale.k) / Short.MAX_VALUE)
|
||||
|
||||
} else {
|
||||
|
||||
val data = value.toList().chunked(2).map {
|
||||
it.toByteArray().get2byteShortAt()
|
||||
}
|
||||
|
||||
Log.d("accel", "x: ${data[0]} y: ${data[1]} z: ${data[2]} bytes: ${value.joinToString { it.toString() }}")
|
||||
|
||||
val x: Float
|
||||
val y: Float
|
||||
val z: Float
|
||||
|
||||
if (accelMode == AccelViewMode.ANGLE) {
|
||||
|
||||
x = calculateZAngle(data[2].toFloat(), data[1].toFloat()) * 180f / Math.PI.toFloat()
|
||||
y = calculateZAngle(data[2].toFloat(), data[0].toFloat()) * 180f / Math.PI.toFloat()
|
||||
z = calculateZAngle(data[0].toFloat(), data[1].toFloat()) * 180f / Math.PI.toFloat()
|
||||
|
||||
} else {
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
val state = MeasureData.Accelerate(
|
||||
x = x,
|
||||
y = y,
|
||||
z = z
|
||||
)
|
||||
|
||||
state
|
||||
|
||||
}
|
||||
|
||||
onResult(Result.success(result))
|
||||
|
||||
}
|
||||
|
||||
private fun checkPermission(): Boolean {
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_CONNECT) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_SCAN) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
return ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_FINE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_COARSE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
}
|
||||
|
||||
private fun BluetoothGatt.writeCharacteristic(
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
data: ByteArray
|
||||
): Result<Unit, BleException>{
|
||||
|
||||
return if(checkPermission()){
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
writeCharacteristic(characteristic, data, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
|
||||
}else{
|
||||
characteristic.value = data
|
||||
writeCharacteristic(characteristic)
|
||||
}
|
||||
|
||||
Result.success(Unit)
|
||||
|
||||
} else {
|
||||
Result.failure(BleException.PermissionDenied)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun calculateAngle(
|
||||
targetAxis: Float,
|
||||
firstAxis: Float,
|
||||
secondAxis: Float
|
||||
): Float {
|
||||
|
||||
return atan(targetAxis.div(sqrt(firstAxis.pow(2) + secondAxis.pow(2))))
|
||||
|
||||
}
|
||||
|
||||
public fun calculateZAngle(
|
||||
x: Float,
|
||||
y: Float
|
||||
): Float {
|
||||
|
||||
var x = x
|
||||
|
||||
if(x == 0f && y == 0f){
|
||||
x = 0.0001f
|
||||
}
|
||||
|
||||
if(x > 0){
|
||||
return atan(y/x)
|
||||
}
|
||||
|
||||
if(x < 0 && y >= 0){
|
||||
return atan(y/x) + PI.toFloat()
|
||||
}
|
||||
|
||||
if(x < 0 && y < 0){
|
||||
return atan(y/x) - PI.toFloat()
|
||||
}
|
||||
|
||||
if(x == 0f && y > 0){
|
||||
return PI.toFloat() / 2f
|
||||
}
|
||||
|
||||
if(x == 0f && y < 0){
|
||||
return -PI.toFloat() / 2f
|
||||
}
|
||||
|
||||
return 0f
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
package llc.arma.ble.data
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Application
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import llc.arma.ble.domain.Result
|
||||
import llc.arma.ble.domain.common.BleException
|
||||
import llc.arma.ble.domain.common.ProgressState
|
||||
import llc.arma.ble.domain.model.Ble
|
||||
import llc.arma.ble.domain.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
|
||||
|
||||
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)
|
||||
fun readAccelerometerHistory(
|
||||
address: String,
|
||||
mode: AccelViewMode,
|
||||
scale: AccelScale,
|
||||
app: Application,
|
||||
): Flow<Result<ProgressState<List<Ble.Accelerometer.HistoryPoint>>, BleException>> {
|
||||
|
||||
return flow {
|
||||
var lastMeasureSystemTime: Long? = null
|
||||
|
||||
var bleMeasureInterval: Long? = null
|
||||
var bleRealTime: Long? = null
|
||||
var bleLastMeasureTime: Long? = null
|
||||
|
||||
val resultTemperaturePackage: MutableList<Float> = mutableListOf()
|
||||
|
||||
val result = mutableListOf<List<UByte>>()
|
||||
|
||||
var expectedDataSize: Int? = null
|
||||
|
||||
if(app.checkPermission()) {
|
||||
|
||||
try {
|
||||
|
||||
val connection =
|
||||
ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.Default))
|
||||
|
||||
val characteristic = connection.discoverServices()
|
||||
.findService(serviceUUID)
|
||||
?.findCharacteristic(accelerometerHistoryReadUUID)
|
||||
|
||||
if(characteristic != null) {
|
||||
|
||||
|
||||
characteristic.write(DataByteArray.from(2))
|
||||
|
||||
var value = characteristic.read().value
|
||||
|
||||
if (value.contentEquals(byteArrayOf(0, 0))) {
|
||||
|
||||
emit(Result.success(ProgressState.Finished(emptyList())))
|
||||
|
||||
} else {
|
||||
|
||||
Log.d("expected data size", value.get2byteUIntAt(0).toString())
|
||||
|
||||
val writeData = mutableListOf(
|
||||
1.toByte(),
|
||||
0.toByte(),
|
||||
0.toByte()
|
||||
).apply {
|
||||
addAll(value.toList())
|
||||
}.toByteArray()
|
||||
|
||||
characteristic.write(DataByteArray(writeData))
|
||||
value = characteristic.read().value
|
||||
var nextPackageDataCount = value.get2byteUIntAt(2)
|
||||
|
||||
while (nextPackageDataCount.toInt() != 0) {
|
||||
|
||||
val temperatureDataArray = 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)
|
||||
|
||||
value.toUByteArray().asList().subList(16, value.size)
|
||||
|
||||
} else {
|
||||
|
||||
value.toUByteArray().asList().subList(4, value.size)
|
||||
|
||||
}
|
||||
|
||||
result.add(value.toUByteArray().toList())
|
||||
nextPackageDataCount = value.get2byteUIntAt(2)
|
||||
|
||||
resultTemperaturePackage.addAll(
|
||||
temperatureDataArray.chunked(2).map {
|
||||
it.toUByteArray().toByteArray().get2byteShortAt().toFloat()
|
||||
}.toMutableList()
|
||||
)
|
||||
|
||||
Log.d(
|
||||
"received data size",
|
||||
(temperatureDataArray.chunked(2).size).toString()
|
||||
)
|
||||
Log.d("next data size", nextPackageDataCount.toString())
|
||||
|
||||
expectedDataSize =
|
||||
nextPackageDataCount.toInt() + resultTemperaturePackage.size
|
||||
|
||||
emit(Result.success(ProgressState.Progress(0f / expectedDataSize.toFloat())))
|
||||
emit(Result.success(ProgressState.Progress(resultTemperaturePackage.size.toFloat() / expectedDataSize.toFloat())))
|
||||
|
||||
characteristic.write(DataByteArray.from(5))
|
||||
value = characteristic.read().value
|
||||
|
||||
}
|
||||
|
||||
emit(
|
||||
Result.success(
|
||||
ProgressState.Finished(
|
||||
when (mode) {
|
||||
AccelViewMode.ROTATIONS,
|
||||
AccelViewMode.ACCELERATION,
|
||||
AccelViewMode.PEAK_ACCELERATION,
|
||||
AccelViewMode.RMS -> {
|
||||
resultTemperaturePackage.chunked(3).withIndex().map {
|
||||
Ble.Accelerometer.HistoryPoint.Angle(
|
||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||
x = (it.value[0] * scale.k) / Short.MAX_VALUE,
|
||||
y = (it.value[1] * scale.k) / Short.MAX_VALUE,
|
||||
z = (it.value[2] * scale.k) / Short.MAX_VALUE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
AccelViewMode.ANGLE -> {
|
||||
resultTemperaturePackage.chunked(3).withIndex().map {
|
||||
Ble.Accelerometer.HistoryPoint.Angle(
|
||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||
x = calculateZAngle(
|
||||
it.value[2],
|
||||
it.value[1]
|
||||
) * 180f / Math.PI.toFloat(),
|
||||
y = calculateZAngle(
|
||||
it.value[2],
|
||||
it.value[0]
|
||||
) * 180f / Math.PI.toFloat(),
|
||||
z = calculateZAngle(
|
||||
it.value[0],
|
||||
it.value[1]
|
||||
) * 180f / Math.PI.toFloat()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
AccelViewMode.VIBRATION -> {
|
||||
resultTemperaturePackage.withIndex().map {
|
||||
Ble.Accelerometer.HistoryPoint.Vibration(
|
||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||
value = (it.value * scale.k) / Short.MAX_VALUE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
emit(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
}
|
||||
|
||||
} catch (err: Throwable) {
|
||||
|
||||
emit(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
emit(Result.failure(BleException.PermissionDenied))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,410 +0,0 @@
|
|||
package llc.arma.ble.data
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Application
|
||||
import android.bluetooth.BluetoothGatt
|
||||
import android.bluetooth.BluetoothGattCallback
|
||||
import android.bluetooth.BluetoothGattCharacteristic
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import llc.arma.ble.domain.Result
|
||||
import llc.arma.ble.domain.common.BleException
|
||||
import llc.arma.ble.domain.common.ProgressState
|
||||
import llc.arma.ble.domain.model.Ble
|
||||
import llc.arma.ble.domain.usecase.AccelScale
|
||||
import llc.arma.ble.domain.usecase.AccelViewMode
|
||||
|
||||
class ReadAccelerometerHistoryCallback(
|
||||
private val mode: AccelViewMode,
|
||||
private val scale: AccelScale,
|
||||
private val app: Application,
|
||||
private val onResult: (Result<ProgressState<List<Ble.Accelerometer.HistoryPoint>>, 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 {
|
||||
Log.d("history", scale.name)
|
||||
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 (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(accelerometerHistoryReadUUID)?.let {
|
||||
|
||||
if (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()
|
||||
|
||||
private val result = mutableListOf<List<UByte>>()
|
||||
|
||||
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 {
|
||||
|
||||
Log.d("expected data size", value.get2byteUIntAt(0).toString())
|
||||
|
||||
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()){
|
||||
|
||||
result.add(value.toUByteArray().toList())
|
||||
|
||||
bleMeasureInterval = value.get4byteUIntAt(4).toLong()
|
||||
bleLastMeasureTime = value.get4byteUIntAt(8).toLong()
|
||||
bleRealTime = value.get4byteUIntAt(12).toLong()
|
||||
|
||||
lastMeasureSystemTime = System.currentTimeMillis() - ((bleRealTime!! - bleLastMeasureTime!!) * 1_000)
|
||||
|
||||
val nextPackageDataCount = value.get2byteUIntAt(2)
|
||||
val temperatureDataArray = value.toUByteArray().asList().subList(16, value.size)
|
||||
|
||||
|
||||
|
||||
resultTemperaturePackage.addAll(
|
||||
temperatureDataArray.chunked(2).map {
|
||||
it.toUByteArray().toByteArray().get2byteShortAt().toFloat()
|
||||
}.toMutableList()
|
||||
)
|
||||
|
||||
Log.d("received data size", (temperatureDataArray.chunked(2).size).toString())
|
||||
Log.d("next data size", nextPackageDataCount.toString())
|
||||
|
||||
expectedDataSize = nextPackageDataCount.toInt() + resultTemperaturePackage.size
|
||||
|
||||
onResult(Result.success(ProgressState.Progress(0f / expectedDataSize!!.toFloat())))
|
||||
onResult(Result.success(ProgressState.Progress(resultTemperaturePackage.size.toFloat() / expectedDataSize!!.toFloat())))
|
||||
|
||||
if(nextPackageDataCount != 0.toUInt()){
|
||||
|
||||
if (checkPermission()) {
|
||||
|
||||
gatt.writeCharacteristic(characteristic, byteArrayOf(5))
|
||||
gatt.readCharacteristic(characteristic)
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.failure(BleException.PermissionDenied))
|
||||
gatt.close()
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
onResult(
|
||||
Result.success(
|
||||
ProgressState.Finished(
|
||||
when(mode){
|
||||
AccelViewMode.ACCELERATION,
|
||||
AccelViewMode.PEAK_ACCELERATION,
|
||||
AccelViewMode.RMS -> {
|
||||
resultTemperaturePackage.chunked(3).withIndex().map {
|
||||
Ble.Accelerometer.HistoryPoint.Angle(
|
||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||
x = (it.value[0] * scale.k) / Short.MAX_VALUE,
|
||||
y = (it.value[1] * scale.k) / Short.MAX_VALUE,
|
||||
z = (it.value[2] * scale.k) / Short.MAX_VALUE
|
||||
)
|
||||
}
|
||||
}
|
||||
AccelViewMode.ANGLE -> {
|
||||
resultTemperaturePackage.chunked(3).withIndex().map {
|
||||
Ble.Accelerometer.HistoryPoint.Angle(
|
||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||
x = calculateZAngle(it.value[2], it.value[1]) * 180f / Math.PI.toFloat(),
|
||||
y = calculateZAngle(it.value[2], it.value[0]) * 180f / Math.PI.toFloat(),
|
||||
z = calculateZAngle(it.value[0], it.value[1]) * 180f / Math.PI.toFloat()
|
||||
)
|
||||
}
|
||||
}
|
||||
AccelViewMode.VIBRATION -> {
|
||||
resultTemperaturePackage.withIndex().map {
|
||||
Ble.Accelerometer.HistoryPoint.Vibration(
|
||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||
value = (it.value * scale.k) / Short.MAX_VALUE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
gatt.close()
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (value[0] == 251.toByte()) {
|
||||
|
||||
result.add(value.toUByteArray().toList())
|
||||
|
||||
val nextPackageDataCount = value.get2byteUIntAt(2)
|
||||
val temperatureDataArray = value.toUByteArray().toList().subList(4, value.size)
|
||||
|
||||
resultTemperaturePackage.addAll(
|
||||
temperatureDataArray.chunked(2).map {
|
||||
it.toUByteArray().toByteArray().get2byteShortAt().toFloat()
|
||||
}
|
||||
)
|
||||
|
||||
Log.d("received data size", (temperatureDataArray.chunked(2).size).toString())
|
||||
Log.d("next data size", nextPackageDataCount.toString())
|
||||
|
||||
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(
|
||||
when(mode){
|
||||
AccelViewMode.ACCELERATION,
|
||||
AccelViewMode.PEAK_ACCELERATION,
|
||||
AccelViewMode.RMS -> {
|
||||
resultTemperaturePackage.chunked(3).withIndex().map {
|
||||
Ble.Accelerometer.HistoryPoint.Angle(
|
||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||
x = (it.value[0] * scale.k) / Short.MAX_VALUE,
|
||||
y = (it.value[1] * scale.k) / Short.MAX_VALUE,
|
||||
z = (it.value[2] * scale.k) / Short.MAX_VALUE
|
||||
)
|
||||
}
|
||||
}
|
||||
AccelViewMode.ANGLE -> {
|
||||
resultTemperaturePackage.chunked(3).withIndex().map {
|
||||
Ble.Accelerometer.HistoryPoint.Angle(
|
||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||
x = calculateZAngle(it.value[2], it.value[1]) * 180f / Math.PI.toFloat(),
|
||||
y = calculateZAngle(it.value[2], it.value[0]) * 180f / Math.PI.toFloat(),
|
||||
z = calculateZAngle(it.value[0], it.value[1]) * 180f / Math.PI.toFloat()
|
||||
)
|
||||
}
|
||||
}
|
||||
AccelViewMode.VIBRATION -> {
|
||||
resultTemperaturePackage.withIndex().map {
|
||||
Ble.Accelerometer.HistoryPoint.Vibration(
|
||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||
value = (it.value * scale.k) / Short.MAX_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 (checkPermission()) {
|
||||
|
||||
gatt.readCharacteristic(characteristic)
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.failure(BleException.PermissionDenied))
|
||||
gatt.close()
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
||||
gatt.close()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun checkPermission(): Boolean {
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_CONNECT) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_SCAN) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
return ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_FINE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_COARSE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
}
|
||||
|
||||
fun BluetoothGatt.writeCharacteristic(
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
data: ByteArray
|
||||
): Result<Unit, BleException>{
|
||||
|
||||
return if(checkPermission()){
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
writeCharacteristic(characteristic, data, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
|
||||
}else{
|
||||
characteristic.value = data
|
||||
writeCharacteristic(characteristic)
|
||||
}
|
||||
|
||||
Result.success(Unit)
|
||||
|
||||
} else {
|
||||
Result.failure(BleException.PermissionDenied)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -10,6 +10,10 @@ import android.content.pm.PackageManager
|
|||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import llc.arma.ble.domain.Result
|
||||
import llc.arma.ble.domain.common.BleException
|
||||
import llc.arma.ble.domain.common.ProgressState
|
||||
|
|
@ -19,6 +23,8 @@ 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.common.core.DataByteArray
|
||||
import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder.LITTLE_ENDIAN
|
||||
import java.util.UUID
|
||||
|
|
@ -70,7 +76,7 @@ class ReadAccelerometerSpectreCallback(
|
|||
|
||||
if(newState == BluetoothGatt.STATE_CONNECTED){
|
||||
|
||||
if (checkPermission()) {
|
||||
if (app.checkPermission()) {
|
||||
gatt.discoverServices()
|
||||
} else {
|
||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
||||
|
|
@ -105,7 +111,7 @@ class ReadAccelerometerSpectreCallback(
|
|||
|
||||
gatt.getService(serviceUUID)?.getCharacteristic(accelerometerReadUUID)?.let {
|
||||
|
||||
if (checkPermission()) {
|
||||
if (app.checkPermission()) {
|
||||
|
||||
gatt.setCharacteristicNotification(it, true)
|
||||
|
||||
|
|
@ -260,7 +266,7 @@ class ReadAccelerometerSpectreCallback(
|
|||
|
||||
if(nextPackageDataCount != 0.toUInt()){
|
||||
|
||||
if (checkPermission()) {
|
||||
if (app.checkPermission()) {
|
||||
|
||||
gatt.writeCharacteristic(characteristic, byteArrayOf(5))
|
||||
gatt.readCharacteristic(characteristic)
|
||||
|
|
@ -360,7 +366,7 @@ class ReadAccelerometerSpectreCallback(
|
|||
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
|
||||
if (checkPermission()) {
|
||||
if (app.checkPermission()) {
|
||||
|
||||
gatt.readCharacteristic(characteristic)
|
||||
|
||||
|
|
@ -394,7 +400,7 @@ class ReadAccelerometerSpectreCallback(
|
|||
|
||||
gatt.getService(serviceUUID)?.getCharacteristic(accelerometerReadUUID)?.let {
|
||||
|
||||
if (checkPermission()) {
|
||||
if (app.checkPermission()) {
|
||||
|
||||
val payload = byteArrayOf(
|
||||
4,
|
||||
|
|
@ -424,27 +430,12 @@ class ReadAccelerometerSpectreCallback(
|
|||
|
||||
}
|
||||
|
||||
private fun checkPermission(): Boolean {
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_CONNECT) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_SCAN) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
return ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_FINE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_COARSE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
}
|
||||
|
||||
private fun BluetoothGatt.writeCharacteristic(
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
data: ByteArray
|
||||
): Result<Unit, BleException>{
|
||||
|
||||
return if(checkPermission()){
|
||||
return if(app.checkPermission()){
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
writeCharacteristic(characteristic, data, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
|
||||
|
|
@ -462,3 +453,187 @@ class ReadAccelerometerSpectreCallback(
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@OptIn(ExperimentalUnsignedTypes::class)
|
||||
fun readAccelerometerSpectre(
|
||||
address: String,
|
||||
mode: AccelViewMode,
|
||||
scale: AccelScale,
|
||||
app: Application,
|
||||
): Flow<Result<ProgressState<List<Ble.Accelerometer.MeasurePoint>>, BleException>> {
|
||||
|
||||
return flow {
|
||||
var lastMeasureSystemTime: Long? = null
|
||||
|
||||
var bleMeasureInterval: Long? = null
|
||||
var bleRealTime: Long? = null
|
||||
var bleLastMeasureTime: Long? = null
|
||||
|
||||
val resultTemperaturePackage: MutableList<Float> = mutableListOf()
|
||||
|
||||
val result = mutableListOf<List<UByte>>()
|
||||
|
||||
var expectedDataSize: Int? = null
|
||||
|
||||
if(app.checkPermission()) {
|
||||
|
||||
try {
|
||||
|
||||
val connection =
|
||||
ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.Default))
|
||||
|
||||
val characteristic = connection.discoverServices()
|
||||
.findService(serviceUUID)
|
||||
?.findCharacteristic(accelerometerHistoryReadUUID)
|
||||
|
||||
if(characteristic != null) {
|
||||
|
||||
|
||||
characteristic.write(DataByteArray.from(2))
|
||||
|
||||
var value = characteristic.read().value
|
||||
|
||||
if (value.contentEquals(byteArrayOf(0, 0))) {
|
||||
|
||||
emit(Result.success(ProgressState.Finished(emptyList())))
|
||||
|
||||
} else {
|
||||
|
||||
Log.d("expected data size", value.get2byteUIntAt(0).toString())
|
||||
|
||||
val writeData = mutableListOf(
|
||||
1.toByte(),
|
||||
0.toByte(),
|
||||
0.toByte()
|
||||
).apply {
|
||||
addAll(value.toList())
|
||||
}.toByteArray()
|
||||
|
||||
characteristic.write(DataByteArray(writeData))
|
||||
value = characteristic.read().value
|
||||
var nextPackageDataCount = value.get2byteUIntAt(2)
|
||||
|
||||
while (nextPackageDataCount.toInt() != 0) {
|
||||
|
||||
val temperatureDataArray = 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)
|
||||
|
||||
value.toUByteArray().asList().subList(16, value.size)
|
||||
|
||||
} else {
|
||||
|
||||
value.toUByteArray().asList().subList(4, value.size)
|
||||
|
||||
}
|
||||
|
||||
result.add(value.toUByteArray().toList())
|
||||
nextPackageDataCount = value.get2byteUIntAt(2)
|
||||
|
||||
resultTemperaturePackage.addAll(
|
||||
temperatureDataArray.chunked(2).map {
|
||||
it.toUByteArray().toByteArray().get2byteShortAt().toFloat()
|
||||
}.toMutableList()
|
||||
)
|
||||
|
||||
Log.d(
|
||||
"received data size",
|
||||
(temperatureDataArray.chunked(2).size).toString()
|
||||
)
|
||||
Log.d("next data size", nextPackageDataCount.toString())
|
||||
|
||||
expectedDataSize =
|
||||
nextPackageDataCount.toInt() + resultTemperaturePackage.size
|
||||
|
||||
emit(Result.success(ProgressState.Progress(0f / expectedDataSize.toFloat())))
|
||||
emit(Result.success(ProgressState.Progress(resultTemperaturePackage.size.toFloat() / expectedDataSize.toFloat())))
|
||||
|
||||
characteristic.write(DataByteArray.from(5))
|
||||
value = characteristic.read().value
|
||||
|
||||
}
|
||||
|
||||
emit(
|
||||
Result.success(
|
||||
ProgressState.Finished(
|
||||
when (mode) {
|
||||
AccelViewMode.ROTATIONS,
|
||||
AccelViewMode.ACCELERATION,
|
||||
AccelViewMode.PEAK_ACCELERATION,
|
||||
AccelViewMode.RMS -> {
|
||||
resultTemperaturePackage.chunked(3).withIndex().map {
|
||||
Ble.Accelerometer.HistoryPoint.Angle(
|
||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||
x = (it.value[0] * scale.k) / Short.MAX_VALUE,
|
||||
y = (it.value[1] * scale.k) / Short.MAX_VALUE,
|
||||
z = (it.value[2] * scale.k) / Short.MAX_VALUE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
AccelViewMode.ANGLE -> {
|
||||
resultTemperaturePackage.chunked(3).withIndex().map {
|
||||
Ble.Accelerometer.HistoryPoint.Angle(
|
||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||
x = calculateZAngle(
|
||||
it.value[2],
|
||||
it.value[1]
|
||||
) * 180f / Math.PI.toFloat(),
|
||||
y = calculateZAngle(
|
||||
it.value[2],
|
||||
it.value[0]
|
||||
) * 180f / Math.PI.toFloat(),
|
||||
z = calculateZAngle(
|
||||
it.value[0],
|
||||
it.value[1]
|
||||
) * 180f / Math.PI.toFloat()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
AccelViewMode.VIBRATION -> {
|
||||
resultTemperaturePackage.withIndex().map {
|
||||
Ble.Accelerometer.HistoryPoint.Vibration(
|
||||
date = lastMeasureSystemTime!! - (((resultTemperaturePackage.size - 1) - it.index) * bleMeasureInterval!!),
|
||||
value = (it.value * scale.k) / Short.MAX_VALUE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
emit(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
}
|
||||
|
||||
} catch (err: Throwable) {
|
||||
|
||||
emit(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
emit(Result.failure(BleException.PermissionDenied))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}*/
|
||||
|
|
@ -50,7 +50,7 @@ class ReadTemperatureHistoryCallback(
|
|||
|
||||
if(newState == BluetoothGatt.STATE_CONNECTED){
|
||||
|
||||
if (checkPermission()) {
|
||||
if (app.checkPermission()) {
|
||||
gatt.discoverServices()
|
||||
|
||||
} else {
|
||||
|
|
@ -76,7 +76,7 @@ class ReadTemperatureHistoryCallback(
|
|||
if(status == BluetoothGatt.GATT_SUCCESS){
|
||||
gatt.getService(serviceUUID)?.getCharacteristic(temperatureHistoryReadUUID)?.let {
|
||||
|
||||
if (checkPermission()) {
|
||||
if (app.checkPermission()) {
|
||||
|
||||
readProperty = Property.DATA_SIZE
|
||||
gatt.writeCharacteristic(it, byteArrayOf(2))
|
||||
|
|
@ -188,7 +188,7 @@ class ReadTemperatureHistoryCallback(
|
|||
|
||||
if(nextPackageDataCount != 0.toUInt()){
|
||||
|
||||
if (checkPermission()) {
|
||||
if (app.checkPermission()) {
|
||||
|
||||
gatt.writeCharacteristic(characteristic, byteArrayOf(5))
|
||||
gatt.readCharacteristic(characteristic)
|
||||
|
|
@ -279,7 +279,7 @@ class ReadTemperatureHistoryCallback(
|
|||
super.onCharacteristicWrite(gatt, characteristic, status)
|
||||
if(status == BluetoothGatt.GATT_SUCCESS){
|
||||
|
||||
if (checkPermission()) {
|
||||
if (app.checkPermission()) {
|
||||
|
||||
gatt.readCharacteristic(characteristic)
|
||||
|
||||
|
|
@ -297,27 +297,12 @@ class ReadTemperatureHistoryCallback(
|
|||
|
||||
}
|
||||
|
||||
fun checkPermission(): Boolean {
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_CONNECT) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_SCAN) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
return ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_FINE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_COARSE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
}
|
||||
|
||||
fun BluetoothGatt.writeCharacteristic(
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
data: ByteArray
|
||||
): Result<Unit, BleException>{
|
||||
|
||||
return if(checkPermission()){
|
||||
return if(app.checkPermission()){
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
writeCharacteristic(characteristic, data, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
|
||||
|
|
|
|||
|
|
@ -1,245 +0,0 @@
|
|||
package llc.arma.ble.data
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Application
|
||||
import android.bluetooth.BluetoothGatt
|
||||
import android.bluetooth.BluetoothGattCallback
|
||||
import android.bluetooth.BluetoothGattCharacteristic
|
||||
import android.bluetooth.BluetoothProfile
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import llc.arma.ble.domain.Result
|
||||
import llc.arma.ble.domain.common.BleException
|
||||
import llc.arma.ble.domain.model.Ble
|
||||
import java.util.UUID
|
||||
|
||||
class WriteAccelerometerCallback(
|
||||
private val app: Application,
|
||||
private var request: Ble.Accelerometer.WriteRequest,
|
||||
private val onResult: (Result<Unit, BleException>) -> Unit
|
||||
) : BluetoothGattCallback() {
|
||||
|
||||
private var flashed = false
|
||||
|
||||
override fun onConnectionStateChange(
|
||||
gatt: BluetoothGatt,
|
||||
status: Int,
|
||||
newState: Int
|
||||
) {
|
||||
super.onConnectionStateChange(gatt, status, newState)
|
||||
|
||||
if(checkPermission()) {
|
||||
|
||||
if(status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
|
||||
gatt.discoverServices()
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.failure(BleException.PermissionDenied))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onServicesDiscovered(
|
||||
gatt: BluetoothGatt,
|
||||
status: Int
|
||||
) {
|
||||
super.onServicesDiscovered(gatt, status)
|
||||
onCycle(gatt, status)
|
||||
|
||||
}
|
||||
|
||||
private fun onCycle(
|
||||
gatt: BluetoothGatt,
|
||||
status: Int
|
||||
){
|
||||
|
||||
Log.d("write", "${request.tx != null} ${request.saveHistory != null} ${request.historyInterval != null}")
|
||||
|
||||
if(request.tx != null || request.saveHistory != null || request.historyInterval != null) {
|
||||
|
||||
fun UInt.to4ByteArrayInLittleEndian(): ByteArray =
|
||||
(3 downTo 0).map {
|
||||
(this shr (it * Byte.SIZE_BITS)).toByte()
|
||||
}.toByteArray()
|
||||
|
||||
var uuid: Triple<UUID, ByteArray, Ble.Accelerometer.WriteRequest>? = null
|
||||
|
||||
uuid = request.historyInterval?.let {
|
||||
|
||||
Triple(
|
||||
intervalWriteUUID,
|
||||
mutableListOf<Byte>(3).apply {
|
||||
addAll((it).toUInt().to4ByteArrayInLittleEndian().reversed().toList())
|
||||
}.toByteArray(),
|
||||
request.copy(
|
||||
historyInterval = null
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
uuid = request.saveHistory?.let {
|
||||
|
||||
Triple(
|
||||
saveEnabledWriteUUID,
|
||||
mutableListOf<Byte>(4).apply {
|
||||
add(if (it is Ble.Accelerometer.History.Enabled) 1 else 0)
|
||||
if(it is Ble.Accelerometer.History.Enabled) {
|
||||
add(it.mode.sendData)
|
||||
add(it.scale.sendData)
|
||||
}
|
||||
}.toByteArray(),
|
||||
request.copy(
|
||||
saveHistory = null
|
||||
)
|
||||
)
|
||||
} ?: uuid
|
||||
|
||||
uuid = request.tx?.let {
|
||||
|
||||
Triple(
|
||||
txWriteUUID,
|
||||
byteArrayOf(
|
||||
when (it) {
|
||||
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
|
||||
}
|
||||
),
|
||||
request.copy(
|
||||
tx = null
|
||||
)
|
||||
)
|
||||
|
||||
} ?: uuid
|
||||
|
||||
uuid?.let { uuid ->
|
||||
|
||||
gatt.services.firstOrNull { it.uuid == serviceUUID }?.characteristics?.firstOrNull {
|
||||
it.uuid == uuid.first
|
||||
}?.let {
|
||||
|
||||
gatt.writeCharacteristic(it, uuid.second)
|
||||
|
||||
request = uuid.third
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
} else {
|
||||
|
||||
if(flashed.not()){
|
||||
|
||||
flashed = true
|
||||
|
||||
gatt.services.firstOrNull { it.uuid == serviceUUID }?.characteristics?.firstOrNull {
|
||||
it.uuid == flashWriteUUID
|
||||
}?.let {
|
||||
|
||||
gatt.writeCharacteristic(it, byteArrayOf(9))
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.success(Unit))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onCharacteristicWrite(
|
||||
gatt: BluetoothGatt,
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
status: Int
|
||||
) {
|
||||
|
||||
super.onCharacteristicWrite(gatt, characteristic, status)
|
||||
|
||||
if(checkPermission()) {
|
||||
|
||||
if(status == BluetoothGatt.GATT_SUCCESS || flashed) {
|
||||
|
||||
onCycle(gatt, status)
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.failure(BleException.PermissionDenied))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun BluetoothGatt.writeCharacteristic(
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
data: ByteArray
|
||||
): Result<Unit, BleException> {
|
||||
|
||||
return if(checkPermission()){
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
writeCharacteristic(characteristic, data, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
|
||||
}else{
|
||||
|
||||
characteristic.writeType
|
||||
characteristic.value = data
|
||||
writeCharacteristic(characteristic)
|
||||
}
|
||||
|
||||
Result.success(Unit)
|
||||
|
||||
} else {
|
||||
Result.failure(BleException.PermissionDenied)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun checkPermission(): Boolean {
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_CONNECT) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_SCAN) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
return ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_FINE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_COARSE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
package llc.arma.ble.data
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Application
|
||||
import android.bluetooth.BluetoothGatt
|
||||
import android.bluetooth.BluetoothGattCallback
|
||||
import android.bluetooth.BluetoothGattCharacteristic
|
||||
import android.bluetooth.BluetoothProfile
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import llc.arma.ble.domain.Result
|
||||
import llc.arma.ble.domain.common.BleException
|
||||
import llc.arma.ble.domain.model.Ble
|
||||
import java.util.UUID
|
||||
|
||||
class WriteBeaconCallback(
|
||||
private val app: Application,
|
||||
private var request: Ble.Beacon.WriteRequest,
|
||||
private val onResult: (Result<Unit, BleException>) -> Unit
|
||||
) : BluetoothGattCallback() {
|
||||
|
||||
private var flashed = false
|
||||
|
||||
override fun onConnectionStateChange(
|
||||
gatt: BluetoothGatt,
|
||||
status: Int,
|
||||
newState: Int
|
||||
) {
|
||||
super.onConnectionStateChange(gatt, status, newState)
|
||||
|
||||
if(checkPermission()) {
|
||||
|
||||
if(status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
|
||||
gatt.discoverServices()
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.failure(BleException.PermissionDenied))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onServicesDiscovered(
|
||||
gatt: BluetoothGatt,
|
||||
status: Int
|
||||
) {
|
||||
super.onServicesDiscovered(gatt, status)
|
||||
onCycle(gatt, status)
|
||||
|
||||
}
|
||||
|
||||
private fun onCycle(
|
||||
gatt: BluetoothGatt,
|
||||
status: Int
|
||||
){
|
||||
|
||||
if(request.tx != null) {
|
||||
|
||||
var uuid: Pair<UUID, ByteArray>? = null
|
||||
|
||||
uuid = request.tx?.let {
|
||||
|
||||
this.request = request.copy(
|
||||
tx = null
|
||||
)
|
||||
|
||||
Pair(
|
||||
txWriteUUID,
|
||||
byteArrayOf(
|
||||
when (it) {
|
||||
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
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
} ?: uuid
|
||||
|
||||
uuid?.let { uuid ->
|
||||
|
||||
gatt.services.firstOrNull { it.uuid == serviceUUID }?.characteristics?.firstOrNull {
|
||||
it.uuid == uuid.first
|
||||
}?.let {
|
||||
|
||||
gatt.writeCharacteristic(it, uuid.second)
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
} else {
|
||||
|
||||
if(flashed.not()){
|
||||
|
||||
flashed = true
|
||||
|
||||
gatt.services.firstOrNull { it.uuid == serviceUUID }?.characteristics?.firstOrNull {
|
||||
it.uuid == flashWriteUUID
|
||||
}?.let {
|
||||
|
||||
gatt.writeCharacteristic(it, byteArrayOf(9))
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.success(Unit))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onCharacteristicWrite(
|
||||
gatt: BluetoothGatt,
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
status: Int
|
||||
) {
|
||||
|
||||
Log.d("beacon", "onCharacteristicWrite $status")
|
||||
|
||||
super.onCharacteristicWrite(gatt, characteristic, status)
|
||||
|
||||
if(checkPermission()) {
|
||||
|
||||
if(status == BluetoothGatt.GATT_SUCCESS || flashed) {
|
||||
|
||||
onCycle(gatt, status)
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.failure(BleException.UnexpectedResponse))
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
onResult(Result.failure(BleException.PermissionDenied))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun BluetoothGatt.writeCharacteristic(
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
data: ByteArray
|
||||
): Result<Unit, BleException> {
|
||||
|
||||
return if(checkPermission()){
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
writeCharacteristic(characteristic, data, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
|
||||
}else{
|
||||
|
||||
characteristic.writeType
|
||||
characteristic.value = data
|
||||
writeCharacteristic(characteristic)
|
||||
}
|
||||
|
||||
Result.success(Unit)
|
||||
|
||||
} else {
|
||||
Result.failure(BleException.PermissionDenied)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun checkPermission(): Boolean {
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_CONNECT) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_SCAN) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
return ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_FINE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_COARSE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ class WriteThermometerCallback(
|
|||
) {
|
||||
super.onConnectionStateChange(gatt, status, newState)
|
||||
|
||||
if(checkPermission()) {
|
||||
if(app.checkPermission()) {
|
||||
|
||||
if(status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
|
||||
|
|
@ -179,7 +179,7 @@ class WriteThermometerCallback(
|
|||
|
||||
super.onCharacteristicWrite(gatt, characteristic, status)
|
||||
|
||||
if(checkPermission()) {
|
||||
if(app.checkPermission()) {
|
||||
|
||||
if(status == BluetoothGatt.GATT_SUCCESS || flashed) {
|
||||
|
||||
|
|
@ -204,7 +204,7 @@ class WriteThermometerCallback(
|
|||
data: ByteArray
|
||||
): Result<Unit, BleException> {
|
||||
|
||||
return if(checkPermission()){
|
||||
return if(app.checkPermission()){
|
||||
|
||||
Log.d("write", data.asUByteArray().joinToString(" ") { it.toString(16).padStart(2, '0') })
|
||||
|
||||
|
|
@ -225,19 +225,6 @@ class WriteThermometerCallback(
|
|||
|
||||
}
|
||||
|
||||
private fun checkPermission(): Boolean {
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_CONNECT) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_SCAN) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
return ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_FINE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED &&
|
||||
ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_COARSE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ class GetAccelerometerMeasureBySerialFlow @Inject constructor(
|
|||
}
|
||||
|
||||
enum class AccelViewMode {
|
||||
ACCELERATION, PEAK_ACCELERATION, RMS, VIBRATION, ANGLE
|
||||
ACCELERATION, PEAK_ACCELERATION, RMS, VIBRATION, ANGLE, ROTATIONS
|
||||
}
|
||||
|
||||
enum class AccelScale(val k: Int) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue