kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
IPC implementation is more real
rodzic
b6166fbd33
commit
75d35b87be
2
TODO.md
2
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).
|
* 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
|
Don't leave device discoverable. Don't let unpaired users do thing with device
|
||||||
* remove example code boilerplate from the service
|
* 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
|
# Low priority
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,8 @@ protobuf {
|
||||||
all().each { task ->
|
all().each { task ->
|
||||||
task.builtins {
|
task.builtins {
|
||||||
java {
|
java {
|
||||||
option "lite"
|
// turned off for now so I can use json printing
|
||||||
|
// option "lite"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +63,7 @@ protobuf {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
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.appcompat:appcompat:1.1.0'
|
||||||
implementation 'androidx.core:core-ktx:1.1.0'
|
implementation 'androidx.core:core-ktx:1.1.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
|
@ -72,7 +73,10 @@ dependencies {
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||||
|
|
||||||
// You need to depend on the lite runtime library, not protobuf-java
|
// 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.
|
// You also need to include the following Compose toolkit dependencies.
|
||||||
implementation("androidx.compose:compose-runtime:$compose_version")
|
implementation("androidx.compose:compose-runtime:$compose_version")
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
<!-- This is a private service which just does direct communication to the radio -->
|
<!-- This is a private service which just does direct communication to the radio -->
|
||||||
<service
|
<service
|
||||||
android:name="com.geeksville.mesh.RadioInterfaceService"
|
android:name="com.geeksville.mesh.RadioInterfaceService"
|
||||||
|
android:permission="android.permission.BIND_JOB_SERVICE"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import com.geeksville.android.Logging
|
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
|
* Handles all the communication with android apps. Also keeps an internal model
|
||||||
|
@ -43,6 +45,11 @@ class MeshService : Service(), Logging {
|
||||||
sendBroadcast(intent)
|
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 {
|
override fun onBind(intent: Intent): IBinder {
|
||||||
// Return the interface
|
// Return the interface
|
||||||
return binder
|
return binder
|
||||||
|
@ -53,6 +60,13 @@ class MeshService : Service(), Logging {
|
||||||
|
|
||||||
val filter = IntentFilter(RadioInterfaceService.RECEIVE_FROMRADIO_ACTION)
|
val filter = IntentFilter(RadioInterfaceService.RECEIVE_FROMRADIO_ACTION)
|
||||||
registerReceiver(radioInterfaceReceiver, filter)
|
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() {
|
override fun onDestroy() {
|
||||||
|
@ -60,6 +74,43 @@ class MeshService : Service(), Logging {
|
||||||
super.onDestroy()
|
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<Int, NodeInfo>()
|
||||||
|
|
||||||
|
/// The database of active nodes, index is the node user ID string
|
||||||
|
private val nodeDBbyID = mutableMapOf<String, NodeInfo>()
|
||||||
|
|
||||||
|
/// 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
|
* Receives messages from our BT radio service and processes them to update our model
|
||||||
* and send to clients as needed.
|
* and send to clients as needed.
|
||||||
|
@ -72,23 +123,40 @@ class MeshService : Service(), Logging {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private val binder = object : IMeshService.Stub() {
|
private val binder = object : IMeshService.Stub() {
|
||||||
override fun setOwner(myId: String, longName: String, shortName: String) {
|
override fun setOwner(myId: String, longName: String, shortName: String) {
|
||||||
error("TODO setOwner $myId : $longName : $shortName")
|
error("TODO setOwner $myId : $longName : $shortName")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sendOpaque(destId: String, payload: ByteArray) {
|
override fun sendOpaque(destId: String, payloadIn: ByteArray) {
|
||||||
error("TODO sendOpaque $destId <- ${payload.size}")
|
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<String> {
|
override fun getOnline(): Array<String> {
|
||||||
error("TODO getOnline")
|
info("getOnline")
|
||||||
return arrayOf("+16508675309")
|
// return arrayOf("+16508675309")
|
||||||
|
return nodeDBbyID.keys.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isConnected(): Boolean {
|
override fun isConnected(): Boolean {
|
||||||
error("TODO isConnected")
|
info("isConnected")
|
||||||
return true
|
return isConnected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ import android.content.Intent
|
||||||
import androidx.core.app.JobIntentService
|
import androidx.core.app.JobIntentService
|
||||||
import com.geeksville.android.DebugLogFile
|
import com.geeksville.android.DebugLogFile
|
||||||
import com.geeksville.android.Logging
|
import com.geeksville.android.Logging
|
||||||
|
import com.google.protobuf.util.JsonFormat
|
||||||
|
|
||||||
const val EXTRA_CONNECTED = "$prefix.Connected"
|
const val EXTRA_CONNECTED = "$prefix.Connected"
|
||||||
const val EXTRA_PAYLOAD = "$prefix.Payload"
|
const val EXTRA_PAYLOAD = "$prefix.Payload"
|
||||||
|
@ -58,9 +59,12 @@ class RadioInterfaceService : JobIntentService(), Logging {
|
||||||
i.putExtra(EXTRA_PAYLOAD, a)
|
i.putExtra(EXTRA_PAYLOAD, a)
|
||||||
enqueueWork(context, i)
|
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) {
|
private fun broadcastReceivedFromRadio(payload: ByteArray) {
|
||||||
val intent = Intent(RECEIVE_FROMRADIO_ACTION)
|
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
|
// For debugging/logging purposes ONLY we convert back into a protobuf for readability
|
||||||
val proto = MeshProtos.ToRadio.parseFrom(p)
|
val proto = MeshProtos.ToRadio.parseFrom(p)
|
||||||
info("TODO sending to radio: $proto")
|
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
|
// Handle an incoming packet from the radio, broadcasts it as an android intent
|
||||||
|
@ -88,6 +93,12 @@ class RadioInterfaceService : JobIntentService(), Logging {
|
||||||
broadcastReceivedFromRadio(p)
|
broadcastReceivedFromRadio(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
|
||||||
|
sentPacketsLog = DebugLogFile(this, "sent_log.json")
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
sentPacketsLog.close()
|
sentPacketsLog.close()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
|
Ładowanie…
Reference in New Issue