Add experimental connection error message

This commit is contained in:
Sylwester Zielinski
2023-04-05 16:44:24 +02:00
parent 60c6e03559
commit 06ea417cb7
10 changed files with 26 additions and 24 deletions

View File

@@ -1,13 +1,13 @@
package no.nordicsemi.android.cgms.data package no.nordicsemi.android.cgms.data
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionStateWithStatus
import no.nordicsemi.android.kotlin.ble.profile.cgm.data.CGMRecord import no.nordicsemi.android.kotlin.ble.profile.cgm.data.CGMRecord
import no.nordicsemi.android.kotlin.ble.profile.gls.data.RequestStatus import no.nordicsemi.android.kotlin.ble.profile.gls.data.RequestStatus
internal data class CGMServiceData( internal data class CGMServiceData(
val records: List<CGMRecordWithSequenceNumber> = emptyList(), val records: List<CGMRecordWithSequenceNumber> = emptyList(),
val batteryLevel: Int? = null, val batteryLevel: Int? = null,
val connectionState: GattConnectionState? = null, val connectionState: GattConnectionStateWithStatus? = null,
val requestStatus: RequestStatus = RequestStatus.IDLE, val requestStatus: RequestStatus = RequestStatus.IDLE,
val deviceName: String? = null val deviceName: String? = null
) )

View File

@@ -43,6 +43,7 @@ import no.nordicsemi.android.cgms.data.CGMServiceData
import no.nordicsemi.android.common.core.simpleSharedFlow import no.nordicsemi.android.common.core.simpleSharedFlow
import no.nordicsemi.android.kotlin.ble.core.ServerDevice import no.nordicsemi.android.kotlin.ble.core.ServerDevice
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionStateWithStatus
import no.nordicsemi.android.kotlin.ble.profile.gls.data.RequestStatus import no.nordicsemi.android.kotlin.ble.profile.gls.data.RequestStatus
import no.nordicsemi.android.service.DisconnectAndStopEvent import no.nordicsemi.android.service.DisconnectAndStopEvent
import no.nordicsemi.android.service.OpenLoggerEvent import no.nordicsemi.android.service.OpenLoggerEvent
@@ -68,7 +69,7 @@ class CGMRepository @Inject constructor(
private val _loggerEvent = simpleSharedFlow<OpenLoggerEvent>() private val _loggerEvent = simpleSharedFlow<OpenLoggerEvent>()
internal val loggerEvent = _loggerEvent.asSharedFlow() internal val loggerEvent = _loggerEvent.asSharedFlow()
val isRunning = data.map { it.connectionState == GattConnectionState.STATE_CONNECTED } val isRunning = data.map { it.connectionState?.state == GattConnectionState.STATE_CONNECTED }
val hasRecords = data.value.records.isNotEmpty() val hasRecords = data.value.records.isNotEmpty()
val highestSequenceNumber = data.value.records.maxOfOrNull { it.sequenceNumber } ?: -1 val highestSequenceNumber = data.value.records.maxOfOrNull { it.sequenceNumber } ?: -1
@@ -85,7 +86,7 @@ class CGMRepository @Inject constructor(
_command.tryEmit(command) _command.tryEmit(command)
} }
fun onConnectionStateChanged(connectionState: GattConnectionState?) { fun onConnectionStateChanged(connectionState: GattConnectionStateWithStatus?) {
_data.value = _data.value.copy(connectionState = connectionState) _data.value = _data.value.copy(connectionState = connectionState)
} }

View File

@@ -50,6 +50,7 @@ import no.nordicsemi.android.kotlin.ble.client.main.service.BleGattCharacteristi
import no.nordicsemi.android.kotlin.ble.client.main.service.BleGattServices import no.nordicsemi.android.kotlin.ble.client.main.service.BleGattServices
import no.nordicsemi.android.kotlin.ble.core.ServerDevice import no.nordicsemi.android.kotlin.ble.core.ServerDevice
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionStateWithStatus
import no.nordicsemi.android.kotlin.ble.profile.battery.BatteryLevelParser import no.nordicsemi.android.kotlin.ble.profile.battery.BatteryLevelParser
import no.nordicsemi.android.kotlin.ble.profile.cgm.CGMFeatureParser import no.nordicsemi.android.kotlin.ble.profile.cgm.CGMFeatureParser
import no.nordicsemi.android.kotlin.ble.profile.cgm.CGMMeasurementParser import no.nordicsemi.android.kotlin.ble.profile.cgm.CGMMeasurementParser
@@ -139,7 +140,7 @@ internal class CGMService : NotificationService() {
.onEach { logger.launch() } .onEach { logger.launch() }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
client.connectionState client.connectionStateWithStatus
.onEach { repository.onConnectionStateChanged(it) } .onEach { repository.onConnectionStateChanged(it) }
.filterNotNull() .filterNotNull()
.onEach { stopIfDisconnected(it) } .onEach { stopIfDisconnected(it) }
@@ -187,10 +188,10 @@ internal class CGMService : NotificationService() {
.mapNotNull { CGMSpecificOpsControlPointParser.parse(it) } .mapNotNull { CGMSpecificOpsControlPointParser.parse(it) }
.onEach { .onEach {
if (it.isOperationCompleted) { if (it.isOperationCompleted) {
if (it.requestCode == CGMOpCode.CGM_OP_CODE_START_SESSION) { sessionStartTime = if (it.requestCode == CGMOpCode.CGM_OP_CODE_START_SESSION) {
sessionStartTime = System.currentTimeMillis() System.currentTimeMillis()
} else { } else {
sessionStartTime = 0 0
} }
} else { } else {
if (it.requestCode == CGMOpCode.CGM_OP_CODE_START_SESSION && it.errorCode == CGMErrorCode.CGM_ERROR_PROCEDURE_NOT_COMPLETED) { if (it.requestCode == CGMOpCode.CGM_OP_CODE_START_SESSION && it.errorCode == CGMErrorCode.CGM_ERROR_PROCEDURE_NOT_COMPLETED) {
@@ -298,8 +299,8 @@ internal class CGMService : NotificationService() {
recordAccessControlPointCharacteristic.write(RecordAccessControlPointInputParser.reportNumberOfAllStoredRecords().value) recordAccessControlPointCharacteristic.write(RecordAccessControlPointInputParser.reportNumberOfAllStoredRecords().value)
} }
private fun stopIfDisconnected(connectionState: GattConnectionState) { private fun stopIfDisconnected(connectionState: GattConnectionStateWithStatus) {
if (connectionState == GattConnectionState.STATE_DISCONNECTED) { if (connectionState.state == GattConnectionState.STATE_DISCONNECTED) {
stopSelf() stopSelf()
} }
} }

View File

@@ -72,11 +72,11 @@ fun CGMScreen() {
.padding(16.dp) .padding(16.dp)
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) { ) {
when (state.connectionState) { when (state.connectionState?.state) {
null, null,
GattConnectionState.STATE_CONNECTING -> DeviceConnectingView { NavigateUpButton(navigateUp) } GattConnectionState.STATE_CONNECTING -> DeviceConnectingView { NavigateUpButton(navigateUp) }
GattConnectionState.STATE_DISCONNECTED, GattConnectionState.STATE_DISCONNECTED,
GattConnectionState.STATE_DISCONNECTING -> DeviceDisconnectedView(Reason.UNKNOWN) { GattConnectionState.STATE_DISCONNECTING -> DeviceDisconnectedView(state.connectionState.status) {
NavigateUpButton(navigateUp) NavigateUpButton(navigateUp)
} }
GattConnectionState.STATE_CONNECTED -> CGMContentView(state) { viewModel.onEvent(it) } GattConnectionState.STATE_CONNECTED -> CGMContentView(state) { viewModel.onEvent(it) }
@@ -88,7 +88,7 @@ fun CGMScreen() {
@Composable @Composable
private fun AppBar(state: CGMServiceData, navigateUp: () -> Unit, viewModel: CGMViewModel) { private fun AppBar(state: CGMServiceData, navigateUp: () -> Unit, viewModel: CGMViewModel) {
if (state.deviceName?.isNotBlank() == true) { if (state.deviceName?.isNotBlank() == true) {
if (state.connectionState == GattConnectionState.STATE_DISCONNECTING || state.connectionState == GattConnectionState.STATE_DISCONNECTED) { if (state.connectionState?.state == GattConnectionState.STATE_DISCONNECTING || state.connectionState?.state == GattConnectionState.STATE_DISCONNECTED) {
LoggerBackIconAppBar(state.deviceName) { viewModel.onEvent(OpenLoggerEvent) } LoggerBackIconAppBar(state.deviceName) { viewModel.onEvent(OpenLoggerEvent) }
} else { } else {
LoggerIconAppBar(state.deviceName, navigateUp, { viewModel.onEvent(DisconnectEvent) }) { LoggerIconAppBar(state.deviceName, navigateUp, { viewModel.onEvent(DisconnectEvent) }) {

View File

@@ -35,8 +35,6 @@ import android.os.ParcelUuid
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@@ -76,7 +74,7 @@ internal class CGMViewModel @Inject constructor(
} }
repository.data.onEach { repository.data.onEach {
if (it.connectionState == GattConnectionState.STATE_CONNECTED) { if (it.connectionState?.state == GattConnectionState.STATE_CONNECTED) {
analytics.logEvent(ProfileConnectedEvent(Profile.CGMS)) analytics.logEvent(ProfileConnectedEvent(Profile.CGMS))
} }
}.launchIn(viewModelScope) }.launchIn(viewModelScope)

View File

@@ -2,13 +2,14 @@ package no.nordicsemi.android.prx.data
import no.nordicsemi.android.kotlin.ble.core.data.BleGattConnectionStatus import no.nordicsemi.android.kotlin.ble.core.data.BleGattConnectionStatus
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionStateWithStatus
import no.nordicsemi.android.kotlin.ble.profile.prx.AlarmLevel import no.nordicsemi.android.kotlin.ble.profile.prx.AlarmLevel
data class PRXServiceData( data class PRXServiceData(
val localAlarmLevel: AlarmLevel = AlarmLevel.NONE, val localAlarmLevel: AlarmLevel = AlarmLevel.NONE,
val linkLossAlarmLevel: AlarmLevel = AlarmLevel.HIGH, val linkLossAlarmLevel: AlarmLevel = AlarmLevel.HIGH,
val batteryLevel: Int? = null, val batteryLevel: Int? = null,
val connectionState: GattConnectionState? = null, val connectionState: GattConnectionStateWithStatus? = null,
val connectionStatus: BleGattConnectionStatus? = null, val connectionStatus: BleGattConnectionStatus? = null,
val isRemoteAlarm: Boolean = false, val isRemoteAlarm: Boolean = false,
val deviceName: String? = null val deviceName: String? = null

View File

@@ -41,6 +41,7 @@ import no.nordicsemi.android.common.core.simpleSharedFlow
import no.nordicsemi.android.kotlin.ble.core.ServerDevice import no.nordicsemi.android.kotlin.ble.core.ServerDevice
import no.nordicsemi.android.kotlin.ble.core.data.BleGattConnectionStatus import no.nordicsemi.android.kotlin.ble.core.data.BleGattConnectionStatus
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionStateWithStatus
import no.nordicsemi.android.kotlin.ble.profile.prx.AlarmLevel import no.nordicsemi.android.kotlin.ble.profile.prx.AlarmLevel
import no.nordicsemi.android.prx.data.PRXServiceData import no.nordicsemi.android.prx.data.PRXServiceData
import no.nordicsemi.android.service.DisconnectAndStopEvent import no.nordicsemi.android.service.DisconnectAndStopEvent
@@ -68,7 +69,7 @@ class PRXRepository @Inject internal constructor(
private val _remoteAlarmLevel = simpleSharedFlow<AlarmLevel>() private val _remoteAlarmLevel = simpleSharedFlow<AlarmLevel>()
internal val remoteAlarmLevel = _remoteAlarmLevel.asSharedFlow() internal val remoteAlarmLevel = _remoteAlarmLevel.asSharedFlow()
val isRunning = data.map { it.connectionState == GattConnectionState.STATE_CONNECTED } val isRunning = data.map { it.connectionState?.state == GattConnectionState.STATE_CONNECTED }
fun launch(device: ServerDevice) { fun launch(device: ServerDevice) {
serviceManager.startService(PRXService::class.java, device) serviceManager.startService(PRXService::class.java, device)
@@ -78,8 +79,8 @@ class PRXRepository @Inject internal constructor(
_data.value = _data.value.copy(deviceName = device.name) _data.value = _data.value.copy(deviceName = device.name)
} }
fun onConnectionStateChanged(connection: Pair<GattConnectionState, BleGattConnectionStatus>) { fun onConnectionStateChanged(connection: GattConnectionStateWithStatus) {
_data.value = _data.value.copy(connectionState = connection.first, connectionStatus = connection.second) _data.value = _data.value.copy(connectionState = connection)
} }
fun setLocalAlarmLevel(alarmLevel: AlarmLevel) { fun setLocalAlarmLevel(alarmLevel: AlarmLevel) {

View File

@@ -173,7 +173,7 @@ internal class PRXService : NotificationService() {
.filterNotNull() .filterNotNull()
.onEach { repository.onConnectionStateChanged(it) } .onEach { repository.onConnectionStateChanged(it) }
.filterNotNull() .filterNotNull()
.onEach { stopIfDisconnected(it.first, it.second) } .onEach { stopIfDisconnected(it.state, it.status) }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
client.services client.services

View File

@@ -71,11 +71,11 @@ fun PRXScreen() {
.padding(16.dp) .padding(16.dp)
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) { ) {
when (state.connectionState) { when (state.connectionState?.state) {
null, null,
GattConnectionState.STATE_CONNECTING -> DeviceConnectingView { NavigateUpButton(navigateUp) } GattConnectionState.STATE_CONNECTING -> DeviceConnectingView { NavigateUpButton(navigateUp) }
GattConnectionState.STATE_DISCONNECTED, GattConnectionState.STATE_DISCONNECTED,
GattConnectionState.STATE_DISCONNECTING -> DeviceDisconnectedView(getReason(state.isLinkLossDisconnected)) { GattConnectionState.STATE_DISCONNECTING -> DeviceDisconnectedView(state.connectionState.status) {
NavigateUpButton(navigateUp) NavigateUpButton(navigateUp)
} }
GattConnectionState.STATE_CONNECTED -> ContentView(state) { viewModel.onEvent(it) } GattConnectionState.STATE_CONNECTED -> ContentView(state) { viewModel.onEvent(it) }

View File

@@ -83,7 +83,7 @@ internal class PRXViewModel @Inject constructor(
alarmHandler.playAlarm(it.linkLossAlarmLevel) alarmHandler.playAlarm(it.linkLossAlarmLevel)
} }
if (it.connectionState == GattConnectionState.STATE_CONNECTED) { if (it.connectionState?.state == GattConnectionState.STATE_CONNECTED) {
analytics.logEvent(ProfileConnectedEvent(Profile.PRX)) analytics.logEvent(ProfileConnectedEvent(Profile.PRX))
} }
}.launchIn(viewModelScope) }.launchIn(viewModelScope)