diff --git a/TODO.md b/TODO.md
index c6cd45c6d..6d463fca6 100644
--- a/TODO.md
+++ b/TODO.md
@@ -29,7 +29,7 @@ nanopb binaries available here: https://jpa.kapsi.fi/nanopb/download/ use nanopb
* require user auth to pair with the device (i.e. press button on device to allow a new phone to pair with it).
Don't leave device discoverable. Don't let unpaired users do thing with device
* remove example code boilerplate from the service
-
+* switch from protobuf-java to protobuf-javalite - much faster and smaller, just no JSON debug printing
# Low priority
diff --git a/app/build.gradle b/app/build.gradle
index 92fa3ff64..3b1125e73 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -53,7 +53,8 @@ protobuf {
all().each { task ->
task.builtins {
java {
- option "lite"
+ // turned off for now so I can use json printing
+ // option "lite"
}
}
}
@@ -62,7 +63,7 @@ protobuf {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
@@ -72,7 +73,10 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// You need to depend on the lite runtime library, not protobuf-java
- implementation 'com.google.protobuf:protobuf-javalite:3.8.0'
+ // For now I'm not using javalite, because I want JSON printing
+ implementation 'com.google.protobuf:protobuf-java:3.11.1'
+ implementation 'com.google.protobuf:protobuf-java-util:3.11.1'
+ // implementation 'com.google.protobuf:protobuf-javalite:3.11.1'
// You also need to include the following Compose toolkit dependencies.
implementation("androidx.compose:compose-runtime:$compose_version")
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e14921688..978e0c377 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,7 @@
diff --git a/app/src/main/java/com/geeksville/mesh/MeshService.kt b/app/src/main/java/com/geeksville/mesh/MeshService.kt
index 9f540f9c2..476dcbe1b 100644
--- a/app/src/main/java/com/geeksville/mesh/MeshService.kt
+++ b/app/src/main/java/com/geeksville/mesh/MeshService.kt
@@ -7,7 +7,9 @@ import android.content.Intent
import android.content.IntentFilter
import android.os.IBinder
import com.geeksville.android.Logging
-
+import com.geeksville.mesh.MeshProtos.MeshPacket
+import com.geeksville.mesh.MeshProtos.ToRadio
+import com.google.protobuf.ByteString
/**
* Handles all the communication with android apps. Also keeps an internal model
@@ -43,6 +45,11 @@ class MeshService : Service(), Logging {
sendBroadcast(intent)
}
+ /// Send a command/packet to our radio
+ private fun sendToRadio(p: ToRadio.Builder) {
+ RadioInterfaceService.sendToRadio(this, p.build().toByteArray())
+ }
+
override fun onBind(intent: Intent): IBinder {
// Return the interface
return binder
@@ -53,6 +60,13 @@ class MeshService : Service(), Logging {
val filter = IntentFilter(RadioInterfaceService.RECEIVE_FROMRADIO_ACTION)
registerReceiver(radioInterfaceReceiver, filter)
+
+ // FIXME - don't do this until after we see that the radio is connected to the phone
+ // Ask for the current node DB
+ sendToRadio(ToRadio.newBuilder().apply {
+ wantNodes = ToRadio.WantNodes.newBuilder().build()
+ })
+
}
override fun onDestroy() {
@@ -60,6 +74,43 @@ class MeshService : Service(), Logging {
super.onDestroy()
}
+ /// Is our radio connected to the phone?
+ private var isConnected = false
+
+ /// We learn this from the node db sent by the device - it is stable for the entire session
+ private var ourNodeNum = -1
+
+ // model objects that directly map to the corresponding protobufs
+ data class MeshUser(val id: String, val longName: String, val shortName: String)
+
+ data class Position(val latitude: Double, val longitude: Double, val altitude: Int)
+ data class NodeInfo(
+ val num: Int,
+ val user: MeshUser,
+ val position: Position,
+ val lastSeen: Long
+ )
+
+ // The database of active nodes, index is the node number
+ private val nodeDBbyNodeNum = mutableMapOf()
+
+ /// The database of active nodes, index is the node user ID string
+ private val nodeDBbyID = mutableMapOf()
+
+ /// Map a userid to a node num, or throw an exception if not found
+ private fun idToNodeNum(id: String) = nodeDBbyID.getValue(id).num
+
+ /// Generate a new mesh packet builder with our node as the sender, and the specified node num
+ private
+
+ fun newMeshPacketTo(idNum: Int) = MeshPacket.newBuilder().apply {
+ from = ourNodeNum
+ to = idNum
+ }
+
+ /// Generate a new mesh packet builder with our node as the sender, and the specified recipient
+ private fun newMeshPacketTo(id: String) = newMeshPacketTo(idToNodeNum(id))
+
/**
* Receives messages from our BT radio service and processes them to update our model
* and send to clients as needed.
@@ -72,23 +123,40 @@ 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")
}
- override fun sendOpaque(destId: String, payload: ByteArray) {
- error("TODO sendOpaque $destId <- ${payload.size}")
+ override fun sendOpaque(destId: String, payloadIn: ByteArray) {
+ info("sendOpaque $destId <- ${payloadIn.size}")
+
+ // 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 {
+ opaque = MeshProtos.Opaque.newBuilder().apply {
+ payload = ByteString.copyFrom(payloadIn)
+ }.build()
+ }.build())
+ }.build()
+ }.build()
+
+ sendToRadio(ToRadio.newBuilder().apply {
+ this.packet = packet
+ })
}
override fun getOnline(): Array {
- error("TODO getOnline")
- return arrayOf("+16508675309")
+ info("getOnline")
+ // return arrayOf("+16508675309")
+ return nodeDBbyID.keys.toTypedArray()
}
override fun isConnected(): Boolean {
- error("TODO isConnected")
- return true
+ info("isConnected")
+ return isConnected
}
}
}
\ 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 8124090de..e4dc8d8db 100644
--- a/app/src/main/java/com/geeksville/mesh/RadioInterfaceService.kt
+++ b/app/src/main/java/com/geeksville/mesh/RadioInterfaceService.kt
@@ -5,6 +5,7 @@ import android.content.Intent
import androidx.core.app.JobIntentService
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"
@@ -58,9 +59,12 @@ class RadioInterfaceService : JobIntentService(), Logging {
i.putExtra(EXTRA_PAYLOAD, a)
enqueueWork(context, i)
}
+
+ // for debug logging only
+ private val jsonPrinter = JsonFormat.printer()
}
- val sentPacketsLog = DebugLogFile(this, "sent_log.json")
+ lateinit var sentPacketsLog: DebugLogFile // inited in onCreate
private fun broadcastReceivedFromRadio(payload: ByteArray) {
val intent = Intent(RECEIVE_FROMRADIO_ACTION)
@@ -80,7 +84,8 @@ class RadioInterfaceService : JobIntentService(), Logging {
// For debugging/logging purposes ONLY we convert back into a protobuf for readability
val proto = MeshProtos.ToRadio.parseFrom(p)
info("TODO sending to radio: $proto")
- sentPacketsLog.log("FIXME JSON")
+ val json = jsonPrinter.print(proto).replace('\n', ' ')
+ sentPacketsLog.log(json)
}
// Handle an incoming packet from the radio, broadcasts it as an android intent
@@ -88,6 +93,12 @@ class RadioInterfaceService : JobIntentService(), Logging {
broadcastReceivedFromRadio(p)
}
+ override fun onCreate() {
+ super.onCreate()
+
+ sentPacketsLog = DebugLogFile(this, "sent_log.json")
+ }
+
override fun onDestroy() {
sentPacketsLog.close()
super.onDestroy()