kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
Merge branch 'master' into url-fix
commit
a6fe6b2bbf
|
@ -61,11 +61,9 @@ import com.google.android.material.tabs.TabLayoutMediator
|
|||
import com.google.protobuf.InvalidProtocolBufferException
|
||||
import com.vorlonsoft.android.rate.AppRate
|
||||
import com.vorlonsoft.android.rate.StoreType
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.*
|
||||
import java.io.FileOutputStream
|
||||
import java.lang.Runnable
|
||||
import java.nio.charset.Charset
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
|
@ -556,10 +554,16 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||
CREATE_CSV_FILE -> {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
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 ->
|
||||
if (packets != null) {
|
||||
saveMessagesCSV(file_uri, packets)
|
||||
// no need for observer once got non-null list
|
||||
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 {
|
||||
FileOutputStream(it.fileDescriptor).use { fs ->
|
||||
// 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
|
||||
// our device in my_position.
|
||||
var my_position: MeshProtos.Position? = null
|
||||
|
@ -1096,13 +1100,9 @@ class MainActivity : AppCompatActivity(), Logging,
|
|||
if (packet_proto.from == myNodeNum) {
|
||||
my_position = position
|
||||
} else if (my_position != null) {
|
||||
val dist: Int =
|
||||
positionToMeter(my_position!!, position).roundToInt()
|
||||
fs.write(
|
||||
("${packet_proto.from.toUInt().toString(16)}," +
|
||||
"${packet_proto.rxSnr},${packet_proto.rxTime},$dist\n")
|
||||
.toByteArray()
|
||||
)
|
||||
val dist = positionToMeter(my_position!!, position).roundToInt()
|
||||
fs.write("%x,%d,%f,%d,%d\n".format(packet_proto.from,packet_proto.rxRssi,
|
||||
packet_proto.rxSnr, packet_proto.rxTime, dist).toByteArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,9 @@ data class Position(
|
|||
data class NodeInfo(
|
||||
val num: Int, // This is immutable, and used as a key
|
||||
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 {
|
||||
|
||||
/// 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
|
||||
Portnums.PortNum.POSITION_APP_VALUE -> {
|
||||
val u = MeshProtos.Position.parseFrom(data.payload)
|
||||
debug("position_app ${packet.from} ${u.toOneLineString()}")
|
||||
handleReceivedPosition(packet.from, u, dataPacket.time)
|
||||
}
|
||||
|
||||
|
@ -827,6 +828,7 @@ class MeshService : Service(), Logging {
|
|||
defaultTime: Long = System.currentTimeMillis()
|
||||
) {
|
||||
updateNodeInfo(fromNum) {
|
||||
debug("update ${it.user?.longName} with ${p.toOneLineString()}")
|
||||
it.position = Position(p)
|
||||
updateNodeInfoTime(it, (defaultTime / 1000).toInt())
|
||||
}
|
||||
|
@ -923,6 +925,8 @@ class MeshService : Service(), Logging {
|
|||
updateNodeInfo(fromNum) {
|
||||
// Update our last seen based on any valid timestamps. If the device didn't provide a timestamp make one
|
||||
updateNodeInfoTime(it, rxTime)
|
||||
it.snr = packet.rxSnr
|
||||
it.rssi = packet.rxRssi
|
||||
}
|
||||
|
||||
handleReceivedData(packet)
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.geeksville.mesh.databinding.NodelistFragmentBinding
|
|||
import com.geeksville.mesh.model.UIViewModel
|
||||
import com.geeksville.util.formatAgo
|
||||
import java.net.URLEncoder
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
class UsersFragment : ScreenFragment("Users"), Logging {
|
||||
|
@ -41,6 +42,7 @@ class UsersFragment : ScreenFragment("Users"), Logging {
|
|||
val batteryPctView = itemView.batteryPercentageView
|
||||
val lastTime = itemView.lastConnectionView
|
||||
val powerIcon = itemView.batteryIcon
|
||||
val signalView = itemView.signalView
|
||||
}
|
||||
|
||||
private val nodesAdapter = object : RecyclerView.Adapter<ViewHolder>() {
|
||||
|
@ -137,10 +139,22 @@ class UsersFragment : ScreenFragment("Users"), Logging {
|
|||
} else {
|
||||
holder.distanceView.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
renderBattery(n.batteryPctLevel, holder)
|
||||
|
||||
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>()
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit ac26ffdc71dad5765124186df5ec38771a0e5240
|
||||
Subproject commit 820fa497dfde07e129cad6955bf2f4b2b9cecebc
|
|
@ -60,7 +60,7 @@
|
|||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/sample_coords"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
||||
app:layout_constraintStart_toEndOf="@+id/distance_view"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageView"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
|
@ -92,7 +92,8 @@
|
|||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
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:srcCompat="@drawable/ic_antenna_24" />
|
||||
|
||||
|
@ -106,6 +107,17 @@
|
|||
app:layout_constraintBottom_toBottomOf="@+id/lastCommIcon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
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>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</LinearLayout>
|
Ładowanie…
Reference in New Issue