Skip to content

Commit

Permalink
feat: Signal Quality in NodeItem (#1425)
Browse files Browse the repository at this point in the history
* Composable that provides the snr and rssi within a row, along with docs for the two exposed functions in LoraSignalIndicator.kt.

* Fancied up the signal data within the NodeItem.
  • Loading branch information
Robert-0410 authored Nov 21, 2024
1 parent c7841b1 commit 75003bb
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 43 deletions.
19 changes: 9 additions & 10 deletions app/src/main/java/com/geeksville/mesh/ui/SignalInfo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.tooling.preview.PreviewParameter
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.ui.components.NodeSignalQuality
import com.geeksville.mesh.ui.preview.NodeEntityPreviewParameterProvider
import com.geeksville.mesh.ui.theme.AppTheme

Expand All @@ -21,7 +22,7 @@ fun signalInfo(
modifier: Modifier = Modifier,
node: NodeEntity,
isThisNode: Boolean
): Boolean {
) {
val text = if (isThisNode) {
stringResource(R.string.channel_air_util).format(
node.deviceMetrics.channelUtilization,
Expand All @@ -40,24 +41,22 @@ fun signalInfo(
if (node.channel > 0) {
add("ch:${node.channel}")
}
if (node.hopsAway <= 0) {
if (node.snr < MAX_VALID_SNR && node.rssi < MAX_VALID_RSSI) {
add("RSSI: %d SNR: %.1f".format(node.rssi, node.snr))
}
}
if (node.hopsAway != 0) add(hopsString)
}.joinToString(" | ")
}
return if (text.isNotEmpty()) {
if (text.isNotEmpty()) {
Text(
modifier = modifier,
text = text,
color = MaterialTheme.colors.onSurface,
fontSize = MaterialTheme.typography.button.fontSize
)
true
} else {
false
}
/* We only know the Signal Quality from direct nodes aka 0 hop. */
if (node.hopsAway <= 0) {
if (node.snr < MAX_VALID_SNR && node.rssi < MAX_VALID_RSSI) {
NodeSignalQuality(node.snr, node.rssi)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package com.geeksville.mesh.ui.components

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
Expand Down Expand Up @@ -38,8 +40,69 @@ private enum class Quality(
GOOD(R.string.good, Icons.Default.SignalCellular4Bar, Color.Green)
}

/**
* Displays the `snr` and `rssi` color coded based on the signal quality, along with
* a human readable description and related icon.
*/
@Composable
fun Snr(snr: Float) {
fun NodeSignalQuality(snr: Float, rssi: Int) {
val quality = determineSignalQuality(snr, rssi)
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Snr(snr)
Rssi(rssi)
Text(text = "${stringResource(R.string.signal)} ${stringResource(quality.nameRes)}")
Icon(
imageVector = quality.imageVector,
contentDescription = stringResource(R.string.signal_quality),
tint = quality.color
)
}
}

/**
* Displays the `snr` and `rssi` with color depending on the values respectively.
*/
@Composable
fun SnrAndRssi(snr: Float, rssi: Int) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Snr(snr)
Rssi(rssi)
}
}

/**
* Displays a human readable description and icon representing the signal quality.
*/
@Composable
fun LoraSignalIndicator(snr: Float, rssi: Int) {

val quality = determineSignalQuality(snr, rssi)

Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.padding(8.dp)
) {
Icon(
imageVector = quality.imageVector,
contentDescription = stringResource(R.string.signal_quality),
tint = quality.color
)
Text(text = "${stringResource(R.string.signal)} ${stringResource(quality.nameRes)}")
}
}

@Composable
private fun Snr(snr: Float) {
val color: Color = if (snr > SNR_GOOD_THRESHOLD) {
Quality.GOOD.color
} else if (snr > SNR_FAIR_THRESHOLD) {
Expand All @@ -53,13 +116,13 @@ fun Snr(snr: Float) {
stringResource(id = R.string.snr),
snr
),
color = color,
fontSize = MaterialTheme.typography.button.fontSize
)
color = color,
fontSize = MaterialTheme.typography.button.fontSize
)
}

@Composable
fun Rssi(rssi: Int) {
private fun Rssi(rssi: Int) {
val color: Color = if (rssi > RSSI_GOOD_THRESHOLD) {
Quality.GOOD.color
} else if (rssi > RSSI_FAIR_THRESHOLD) {
Expand All @@ -77,27 +140,6 @@ fun Rssi(rssi: Int) {
)
}

@Composable
fun LoraSignalIndicator(snr: Float, rssi: Int) {

val quality = determineSignalQuality(snr, rssi)

Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.padding(8.dp)
) {
Icon(
imageVector = quality.imageVector,
contentDescription = stringResource(R.string.signal_quality),
tint = quality.color
)
Text(text = "${stringResource(R.string.signal)} ${stringResource(quality.nameRes)}")
}
}

private fun determineSignalQuality(snr: Float, rssi: Int): Quality = when {
snr > SNR_GOOD_THRESHOLD && rssi > RSSI_GOOD_THRESHOLD -> Quality.GOOD
snr > SNR_GOOD_THRESHOLD && rssi > RSSI_FAIR_THRESHOLD -> Quality.FAIR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,13 +266,7 @@ private fun SignalMetricsCard(meshPacket: MeshPacket) {
Spacer(modifier = Modifier.height(8.dp))

/* SNR and RSSI */
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Snr(meshPacket.rxSnr)
Rssi(meshPacket.rxRssi)
}
SnrAndRssi(meshPacket.rxSnr, meshPacket.rxRssi)
}
}

Expand Down

0 comments on commit 75003bb

Please sign in to comment.