mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-09-08 11:25:25 -04:00
Merge pull request #265 from vfurman-gh/master
Show rssi/snr in the user info
This commit is contained in:
6 files changed
+50
-18
No files matched your search
@@ -61,11 +61,9 @@ import com.google.android.material.tabs.TabLayoutMediator
|
|||||||
import com.google.protobuf.InvalidProtocolBufferException
|
import com.google.protobuf.InvalidProtocolBufferException
|
||||||
import com.vorlonsoft.android.rate.AppRate
|
import com.vorlonsoft.android.rate.AppRate
|
||||||
import com.vorlonsoft.android.rate.StoreType
|
import com.vorlonsoft.android.rate.StoreType
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
|
import java.lang.Runnable
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -556,10 +554,16 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||||||
CREATE_CSV_FILE -> {
|
CREATE_CSV_FILE -> {
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
data?.data?.let { file_uri ->
|
data?.data?.let { file_uri ->
|
||||||
|
// model.allPackets is a result of a query, so we need to use observer for
|
||||||
|
// the query to materialize
|
||||||
model.allPackets.observe(this, { packets ->
|
model.allPackets.observe(this, { packets ->
|
||||||
if (packets != null) {
|
if (packets != null) {
|
||||||
saveMessagesCSV(file_uri, packets)
|
// no need for observer once got non-null list
|
||||||
model.allPackets.removeObservers(this)
|
model.allPackets.removeObservers(this)
|
||||||
|
// execute on the default thread pool to not block the main thread
|
||||||
|
CoroutineScope(Dispatchers.Default + Job()).handledLaunch {
|
||||||
|
saveMessagesCSV(file_uri, packets)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1086,7 +1090,7 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||||||
applicationContext.contentResolver.openFileDescriptor(file_uri, "w")?.use {
|
applicationContext.contentResolver.openFileDescriptor(file_uri, "w")?.use {
|
||||||
FileOutputStream(it.fileDescriptor).use { fs ->
|
FileOutputStream(it.fileDescriptor).use { fs ->
|
||||||
// Write header
|
// Write header
|
||||||
fs.write(("from,snr,time,dist\n").toByteArray());
|
fs.write(("from,rssi,snr,time,dist\n").toByteArray());
|
||||||
// Packets are ordered by time, we keep most recent position of
|
// Packets are ordered by time, we keep most recent position of
|
||||||
// our device in my_position.
|
// our device in my_position.
|
||||||
var my_position: MeshProtos.Position? = null
|
var my_position: MeshProtos.Position? = null
|
||||||
@@ -1096,13 +1100,9 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||||||
if (packet_proto.from == myNodeNum) {
|
if (packet_proto.from == myNodeNum) {
|
||||||
my_position = position
|
my_position = position
|
||||||
} else if (my_position != null) {
|
} else if (my_position != null) {
|
||||||
val dist: Int =
|
val dist = positionToMeter(my_position!!, position).roundToInt()
|
||||||
positionToMeter(my_position!!, position).roundToInt()
|
fs.write("%x,%d,%f,%d,%d\n".format(packet_proto.from,packet_proto.rxRssi,
|
||||||
fs.write(
|
packet_proto.rxSnr, packet_proto.rxTime, dist).toByteArray())
|
||||||
("${packet_proto.from.toUInt().toString(16)}," +
|
|
||||||
"${packet_proto.rxSnr},${packet_proto.rxTime},$dist\n")
|
|
||||||
.toByteArray()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,9 @@ data class Position(
|
|||||||
data class NodeInfo(
|
data class NodeInfo(
|
||||||
val num: Int, // This is immutable, and used as a key
|
val num: Int, // This is immutable, and used as a key
|
||||||
var user: MeshUser? = null,
|
var user: MeshUser? = null,
|
||||||
var position: Position? = null
|
var position: Position? = null,
|
||||||
|
var snr: Float = Float.MAX_VALUE,
|
||||||
|
var rssi: Int = Int.MAX_VALUE
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
/// Return the last time we've seen this node in secs since 1970
|
/// Return the last time we've seen this node in secs since 1970
|
||||||
|
|||||||
@@ -717,6 +717,7 @@ class MeshService : Service(), Logging {
|
|||||||
// Handle new style position info
|
// Handle new style position info
|
||||||
Portnums.PortNum.POSITION_APP_VALUE -> {
|
Portnums.PortNum.POSITION_APP_VALUE -> {
|
||||||
val u = MeshProtos.Position.parseFrom(data.payload)
|
val u = MeshProtos.Position.parseFrom(data.payload)
|
||||||
|
debug("position_app ${packet.from} ${u.toOneLineString()}")
|
||||||
handleReceivedPosition(packet.from, u, dataPacket.time)
|
handleReceivedPosition(packet.from, u, dataPacket.time)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,6 +828,7 @@ class MeshService : Service(), Logging {
|
|||||||
defaultTime: Long = System.currentTimeMillis()
|
defaultTime: Long = System.currentTimeMillis()
|
||||||
) {
|
) {
|
||||||
updateNodeInfo(fromNum) {
|
updateNodeInfo(fromNum) {
|
||||||
|
debug("update ${it.user?.longName} with ${p.toOneLineString()}")
|
||||||
it.position = Position(p)
|
it.position = Position(p)
|
||||||
updateNodeInfoTime(it, (defaultTime / 1000).toInt())
|
updateNodeInfoTime(it, (defaultTime / 1000).toInt())
|
||||||
}
|
}
|
||||||
@@ -923,6 +925,8 @@ class MeshService : Service(), Logging {
|
|||||||
updateNodeInfo(fromNum) {
|
updateNodeInfo(fromNum) {
|
||||||
// Update our last seen based on any valid timestamps. If the device didn't provide a timestamp make one
|
// Update our last seen based on any valid timestamps. If the device didn't provide a timestamp make one
|
||||||
updateNodeInfoTime(it, rxTime)
|
updateNodeInfoTime(it, rxTime)
|
||||||
|
it.snr = packet.rxSnr
|
||||||
|
it.rssi = packet.rxRssi
|
||||||
}
|
}
|
||||||
|
|
||||||
handleReceivedData(packet)
|
handleReceivedData(packet)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.geeksville.mesh.databinding.NodelistFragmentBinding
|
|||||||
import com.geeksville.mesh.model.UIViewModel
|
import com.geeksville.mesh.model.UIViewModel
|
||||||
import com.geeksville.util.formatAgo
|
import com.geeksville.util.formatAgo
|
||||||
import java.net.URLEncoder
|
import java.net.URLEncoder
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
|
||||||
class UsersFragment : ScreenFragment("Users"), Logging {
|
class UsersFragment : ScreenFragment("Users"), Logging {
|
||||||
@@ -41,6 +42,7 @@ class UsersFragment : ScreenFragment("Users"), Logging {
|
|||||||
val batteryPctView = itemView.batteryPercentageView
|
val batteryPctView = itemView.batteryPercentageView
|
||||||
val lastTime = itemView.lastConnectionView
|
val lastTime = itemView.lastConnectionView
|
||||||
val powerIcon = itemView.batteryIcon
|
val powerIcon = itemView.batteryIcon
|
||||||
|
val signalView = itemView.signalView
|
||||||
}
|
}
|
||||||
|
|
||||||
private val nodesAdapter = object : RecyclerView.Adapter<ViewHolder>() {
|
private val nodesAdapter = object : RecyclerView.Adapter<ViewHolder>() {
|
||||||
@@ -137,10 +139,22 @@ class UsersFragment : ScreenFragment("Users"), Logging {
|
|||||||
} else {
|
} else {
|
||||||
holder.distanceView.visibility = View.INVISIBLE
|
holder.distanceView.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBattery(n.batteryPctLevel, holder)
|
renderBattery(n.batteryPctLevel, holder)
|
||||||
|
|
||||||
holder.lastTime.text = formatAgo(n.lastSeen);
|
holder.lastTime.text = formatAgo(n.lastSeen);
|
||||||
|
|
||||||
|
if ((n.num == ourNodeInfo?.num) || (n.snr > 100f)) {
|
||||||
|
holder.signalView.visibility = View.INVISIBLE
|
||||||
|
} else {
|
||||||
|
val text = if (n.rssi < 0) {
|
||||||
|
"rssi:${n.rssi} snr:${n.snr.roundToInt()}"
|
||||||
|
} else {
|
||||||
|
// Older devices do not send rssi. Remove this branch once upgraded past 1.2.1
|
||||||
|
"snr:${n.snr.roundToInt()}"
|
||||||
|
}
|
||||||
|
holder.signalView.text = text
|
||||||
|
holder.signalView.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var nodes = arrayOf<NodeInfo>()
|
private var nodes = arrayOf<NodeInfo>()
|
||||||
|
|||||||
+1
-1
Submodule app/src/main/proto updated: ac26ffdc71...820fa497df.
@@ -60,7 +60,7 @@
|
|||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:text="@string/sample_coords"
|
android:text="@string/sample_coords"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/distance_view"
|
app:layout_constraintStart_toEndOf="@+id/distance_view"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/imageView"
|
app:layout_constraintTop_toBottomOf="@+id/imageView"
|
||||||
app:layout_constraintVertical_bias="0.0" />
|
app:layout_constraintVertical_bias="0.0" />
|
||||||
@@ -92,7 +92,8 @@
|
|||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:visibility="visible"
|
android:visibility="visible"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintTop_toBottomOf="@id/batteryIcon"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/signalView"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/lastConnectionView"
|
app:layout_constraintEnd_toStartOf="@+id/lastConnectionView"
|
||||||
app:srcCompat="@drawable/ic_antenna_24" />
|
app:srcCompat="@drawable/ic_antenna_24" />
|
||||||
|
|
||||||
@@ -106,6 +107,17 @@
|
|||||||
app:layout_constraintBottom_toBottomOf="@+id/lastCommIcon"
|
app:layout_constraintBottom_toBottomOf="@+id/lastCommIcon"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@+id/lastCommIcon" />
|
app:layout_constraintTop_toTopOf="@+id/lastCommIcon" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/signalView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="rssi:-40 snr:-8"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/lastConnectionView"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
Reference in new issue
Block a user