diff --git a/TODO.md b/TODO.md
index 684e72d80..43d3ac85b 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,5 +1,5 @@
-
+* test mesh service from activity
* use android service from Signal
* DONE handle failures in onCharWrite, instead of logAssert - because they can happen if device goes away
* make test implementation of android service (doesn't use bluetooth)
@@ -11,6 +11,7 @@
* connect to bluetooth device automatically using minimum power
* have signal declare receivers: https://developer.android.com/guide/components/broadcasts#manifest-declared-receivers
* fix BT device scanning
+* call crashlytics from exceptionReporter!!! currently not logging failures caught there
protobuf notes
protoc -I=. --java_out /tmp mesh.proto
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 978e0c377..515aa6c2a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -44,6 +44,10 @@
android:name="com.mixpanel.android.MPConfig.DisableViewCrawler"
android:value="true" />
+
+
NodeInfo(n) }
/// Map a userid to a node/ node num, or throw an exception if not found
- private fun toNodeInfo(id: String) = nodeDBbyID.getValue(id)
+ private fun toNodeInfo(id: String) = nodeDBbyID[id] ?: throw IdNotFoundException(id)
private fun toNodeNum(id: String) = toNodeInfo(id).num
@@ -141,6 +150,18 @@ class MeshService : Service(), Logging {
/// Generate a new mesh packet builder with our node as the sender, and the specified recipient
private fun newMeshPacketTo(id: String) = newMeshPacketTo(toNodeNum(id))
+ // Helper to make it easy to build a subpacket in the proper protobufs
+ private fun buildMeshPacket(
+ destId: String,
+ initFn: MeshProtos.SubPacket.Builder.() -> Unit
+ ): MeshPacket = newMeshPacketTo(destId).apply {
+ payload = MeshProtos.MeshPayload.newBuilder().apply {
+ addSubPackets(MeshProtos.SubPacket.newBuilder().also {
+ initFn(it)
+ }.build())
+ }.build()
+ }.build()
+
/// Update our model and resend as needed for a MeshPacket we just received from the radio
private fun handleReceivedData(fromNum: Int, data: MeshProtos.Data) {
val bytes = data.payload.toByteArray()
@@ -173,6 +194,16 @@ class MeshService : Service(), Logging {
}
}
+ /// Update our DB of users based on someone sending out a User subpacket
+ private fun handleReceivedUser(fromNum: Int, p: MeshProtos.User) {
+ updateNodeInfo(fromNum) {
+ it.user = MeshUser(p.id, p.longName, p.shortName)
+
+ // This might have been the first time we know an ID for this node, so also update the by ID map
+ nodeDBbyID[p.id] = it
+ }
+ }
+
/// Update our model and resend as needed for a MeshPacket we just received from the radio
private fun handleReceivedMeshPacket(packet: MeshPacket) {
val fromNum = packet.from
@@ -200,12 +231,7 @@ class MeshService : Service(), Logging {
handleReceivedData(fromNum, p.data)
MeshProtos.SubPacket.USER_FIELD_NUMBER ->
- updateNodeInfo(fromNum) {
- it.user = MeshUser(p.user.id, p.user.longName, p.user.shortName)
-
- // This might have been the first time we know an ID for this node, so also update the by ID map
- nodeDBbyID.set(p.user.id, it)
- }
+ handleReceivedUser(fromNum, p.user)
MeshProtos.SubPacket.WANT_NODE_FIELD_NUMBER -> {
// This is managed by the radio on its own
debug("Ignoring WANT_NODE from $fromNum")
@@ -241,41 +267,57 @@ class MeshService : Service(), Logging {
}
private val binder = object : IMeshService.Stub() {
- override fun setOwner(myId: String, longName: String, shortName: String) {
- error("TODO setOwner $myId : $longName : $shortName")
- }
+ // Note: bound methods don't get properly exception caught/logged, so do that with a wrapper
+ // per https://blog.classycode.com/dealing-with-exceptions-in-aidl-9ba904c6d63
- override fun sendOpaque(destId: String, payloadIn: ByteArray, typ: Int) {
- info("sendOpaque $destId <- ${payloadIn.size}")
+ override fun setOwner(myId: String, longName: String, shortName: String) =
+ exceptionsToStrings {
+ error("TODO setOwner $myId : $longName : $shortName")
- // encapsulate our payload in the proper protobufs and fire it off
- val packet = newMeshPacketTo(destId).apply {
- payload = MeshProtos.MeshPayload.newBuilder().apply {
- addSubPackets(MeshProtos.SubPacket.newBuilder().apply {
- data = MeshProtos.Data.newBuilder().also {
- it.typ = MeshProtos.Data.Type.SIGNAL_OPAQUE
- it.payload = ByteString.copyFrom(payloadIn)
- }.build()
- }.build())
+ val user = MeshProtos.User.newBuilder().also {
+ it.id = myId
+ it.longName = longName
+ it.shortName = shortName
}.build()
- }.build()
- sendToRadio(ToRadio.newBuilder().apply {
- this.packet = packet
- })
- }
+ // Also update our own map for our nodenum, by handling the packet just like packets from other users
+ if (ourNodeNum != -1) {
+ handleReceivedUser(ourNodeNum, user)
+ }
- override fun getOnline(): Array {
+ sendToRadio(ToRadio.newBuilder().apply {
+ this.setOwner = user
+ })
+ }
+
+ override fun sendData(destId: String, payloadIn: ByteArray, typ: Int) =
+ exceptionsToStrings {
+ info("sendData $destId <- ${payloadIn.size} bytes")
+
+ // encapsulate our payload in the proper protobufs and fire it off
+ val packet = buildMeshPacket(destId) {
+ data = MeshProtos.Data.newBuilder().also {
+ it.typ = MeshProtos.Data.Type.SIGNAL_OPAQUE
+ it.payload = ByteString.copyFrom(payloadIn)
+ }.build()
+ }
+
+ sendToRadio(ToRadio.newBuilder().apply {
+ this.packet = packet
+ })
+ }
+
+ override fun getOnline(): Array = exceptionReporter {
val r = nodeDBbyID.keys.toTypedArray()
info("in getOnline, count=${r.size}")
// return arrayOf("+16508675309")
- return r
+ r
}
- override fun isConnected(): Boolean {
+ override fun isConnected(): Boolean = exceptionReporter {
val r = this@MeshService.isConnected
info("in isConnected=r")
- return r
+ r
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geeksville/mesh/MeshUtilApplication.kt b/app/src/main/java/com/geeksville/mesh/MeshUtilApplication.kt
index 5f418d76d..36fff96a5 100644
--- a/app/src/main/java/com/geeksville/mesh/MeshUtilApplication.kt
+++ b/app/src/main/java/com/geeksville/mesh/MeshUtilApplication.kt
@@ -2,7 +2,6 @@ package com.geeksville.mesh
import com.geeksville.android.GeeksvilleApplication
-const val prefix = "com.geeksville.mesh"
class MeshUtilApplication : GeeksvilleApplication(null, "58e72ccc361883ea502510baa46580e3") {
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geeksville/mesh/RadioInterfaceService.kt b/app/src/main/java/com/geeksville/mesh/RadioInterfaceService.kt
index 9f97fbfda..37a881c60 100644
--- a/app/src/main/java/com/geeksville/mesh/RadioInterfaceService.kt
+++ b/app/src/main/java/com/geeksville/mesh/RadioInterfaceService.kt
@@ -7,13 +7,6 @@ import com.geeksville.android.DebugLogFile
import com.geeksville.android.Logging
import com.google.protobuf.util.JsonFormat
-const val EXTRA_CONNECTED = "$prefix.Connected"
-const val EXTRA_PAYLOAD = "$prefix.Payload"
-const val EXTRA_SENDER = "$prefix.Sender"
-const val EXTRA_ID = "$prefix.Id"
-const val EXTRA_ONLINE = "$prefix.Online"
-const val EXTRA_TYP = "$prefix.Typ"
-
/**
* Handles the bluetooth link with a mesh radio device. Does not cache any device state,
* just does bluetooth comms etc...
@@ -42,8 +35,7 @@ class RadioInterfaceService : JobIntentService(), Logging {
* Payload will be the raw bytes which were contained within a MeshProtos.FromRadio protobuf
*/
const val RECEIVE_FROMRADIO_ACTION = "$prefix.RECEIVE_FROMRADIO"
-
-
+
/**
* Convenience method for enqueuing work in to this service.
*/
@@ -80,7 +72,7 @@ class RadioInterfaceService : JobIntentService(), Logging {
}
/// Send a packet/command out the radio link
- private fun sendToRadio(p: ByteArray) {
+ private fun handleSendToRadio(p: ByteArray) {
// For debugging/logging purposes ONLY we convert back into a protobuf for readability
val proto = MeshProtos.ToRadio.parseFrom(p)
@@ -109,7 +101,7 @@ class RadioInterfaceService : JobIntentService(), Logging {
// holding a wake lock for us at this point, so we can just go.
debug("Executing work: $intent")
when (intent.action) {
- SEND_TORADIO_ACTION -> sendToRadio(intent.getByteArrayExtra(EXTRA_PAYLOAD)!!)
+ SEND_TORADIO_ACTION -> handleSendToRadio(intent.getByteArrayExtra(EXTRA_PAYLOAD)!!)
else -> TODO("Unhandled case")
}
}
diff --git a/app/src/main/proto/mesh.proto b/app/src/main/proto/mesh.proto
index 8a08184c1..fa259cf38 100644
--- a/app/src/main/proto/mesh.proto
+++ b/app/src/main/proto/mesh.proto
@@ -11,7 +11,7 @@ MESH RADIO PROTOCOL
Old TODO notes on the mesh radio protocol, merge into real docs below...
-for each named group we have a preshared key known by all group members and wrapped around the device.
+for each named group we have a pre-shared key known by all group members and wrapped around the device.
you can only be in one group at a time (FIXME?!)
To join the group we read a qr code with the preshared key and ParamsCodeEnum. that gets sent via
bluetooth to the device. ParamsCodeEnum maps to a set of various radio params (regulatory region,
@@ -63,11 +63,11 @@ message Data {
/// eventually in some circumstances even signal might send messages in this form (see below)
CLEAR_TEXT = 1;
- /// a message receive acknowledgement, sent in cleartext - allows radio to show user that a message has been read by the recpient, optional
+ /// a message receive acknowledgement, sent in cleartext - allows radio to show user that a message has been read by the recipient, optional
CLEAR_READACK = 2;
/// Not yet used but eventually:
- /// SIGNAL_CLEAR_OPAQUE = 3; // Unencrypted at the signal level, relying on the radio crypt only (to keep size small), but contains Signal control data radios don't care about (or non ascii text)
+ /// SIGNAL_CLEAR_DATA = 3; // Unencrypted at the signal level, relying on the radio crypt only (to keep size small), but contains Signal control data radios don't care about (ie non text)
}
Type typ = 1; // required
@@ -85,7 +85,7 @@ message User {
// Broadcast when a newly powered mesh node wants to find a node num it can use (see document for more
// details)
message WantNodeNum {
- // No payload, just its existence is sufficent (desired node num will be in the from field)
+ // No payload, just its existence is sufficient (desired node num will be in the from field)
}
// Sent to a node which has requested a nodenum when it is told it can't have it
@@ -118,7 +118,7 @@ message MeshPacket {
MeshPayload payload = 3;
}
-// Full settings (center freq, spread factor, preshared secret key etc...) needed to configure a radio
+// Full settings (center freq, spread factor, pre-shared secret key etc...) needed to configure a radio
message RadioConfig {
// FIXME
}
@@ -129,7 +129,7 @@ The bluetooth to device link:
Old BTLE protocol docs from TODO, merge in above and make real docs...
-use protocol buffers, and nanopb
+use protocol buffers, and NanoPB
messages from device to phone:
POSITION_UPDATE (..., time)