From cc28333ff7572ab90f215d0d7ded23107458fdf7 Mon Sep 17 00:00:00 2001 From: geeksville Date: Tue, 4 Feb 2020 09:41:38 -0800 Subject: [PATCH] prepare for WIP of sync api --- TODO.md | 1 + .../java/com/geeksville/mesh/MeshService.kt | 14 +++- .../geeksville/mesh/RadioInterfaceService.kt | 82 ++++++++++++++++--- .../main/java/com/geeksville/mesh/SimRadio.kt | 3 +- 4 files changed, 82 insertions(+), 18 deletions(-) diff --git a/TODO.md b/TODO.md index ec7eb6b9a..d5d6c0005 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,6 @@ # High priority +* fix startup race conditions in services, allow reads to block as needed * when notified phone should download messages * have phone use our local node number as its node number (instead of hardwired) * investigate the Signal SMS message flow path, see if I could just make Mesh a third peer to signal & sms? diff --git a/app/src/main/java/com/geeksville/mesh/MeshService.kt b/app/src/main/java/com/geeksville/mesh/MeshService.kt index b04f9ba18..c2ecc04da 100644 --- a/app/src/main/java/com/geeksville/mesh/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/MeshService.kt @@ -105,10 +105,10 @@ class MeshService : Service(), Logging { val sim = SimRadio(this@MeshService) sim.start() // Fake up our node id info and some past packets from other nodes - // Ask for the current node DB - sendToRadio(ToRadio.newBuilder().apply { + // Ask for the current node DB FIXME + /* sendToRadio(ToRadio.newBuilder().apply { wantNodes = ToRadio.WantNodes.newBuilder().build() - }) + }) */ // Now send any packets which had previously been queued for clients toRadioDeferred.run() @@ -290,7 +290,7 @@ class MeshService : Service(), Logging { } MeshProtos.SubPacket.TIME_FIELD_NUMBER -> updateNodeInfo(fromNum) { - it.lastSeen = p.time.msecs + it.lastSeen = p.time } MeshProtos.SubPacket.DATA_FIELD_NUMBER -> handleReceivedData(fromNum, p.data) @@ -324,8 +324,12 @@ class MeshService : Service(), Logging { info("Received from radio service: ${proto.toOneLineString()}") when (proto.variantCase.number) { MeshProtos.FromRadio.PACKET_FIELD_NUMBER -> handleReceivedMeshPacket(proto.packet) + /* + FIXME - handle node info and setting my protonum MeshProtos.FromRadio.NODE_INFO_FIELD_NUMBER -> handleReceivedNodeInfo(proto.nodeInfo) MeshProtos.FromRadio.MY_NODE_NUM_FIELD_NUMBER -> ourNodeNum = proto.myNodeNum + + */ else -> TODO("Unexpected FromRadio variant") } } @@ -354,9 +358,11 @@ class MeshService : Service(), Logging { handleReceivedUser(ourNodeNum, user) } + /* FIXME - set my owner info sendToRadio(ToRadio.newBuilder().apply { this.setOwner = user }) + */ } override fun sendData(destId: String, payloadIn: ByteArray, typ: Int) = diff --git a/app/src/main/java/com/geeksville/mesh/RadioInterfaceService.kt b/app/src/main/java/com/geeksville/mesh/RadioInterfaceService.kt index eae23e69f..30a59b302 100644 --- a/app/src/main/java/com/geeksville/mesh/RadioInterfaceService.kt +++ b/app/src/main/java/com/geeksville/mesh/RadioInterfaceService.kt @@ -51,6 +51,18 @@ callback was called, but before it arrives at the phone. If the phone writes to When the esp32 advances fromnum, it will delay doing the notify by 100ms, in the hopes that the notify will never actally need to be sent if the phone is already pulling from fromradio. Note: that if the phone ever sees this number decrease, it means the esp32 has rebooted. +meshMyNodeCharacteristic("ea9f3f82-8dc4-4733-9452-1f6da28892a2", BLECharacteristic::PROPERTY_READ) +mynode - read/write this to access a MyNodeInfo protobuf + +meshNodeInfoCharacteristic("d31e02e0-c8ab-4d3f-9cc9-0b8466bdabe8", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ), +nodeinfo - read this to get a series of node infos (ending with a null empty record), write to this to restart the read statemachine that returns all the node infos + +meshRadioCharacteristic("b56786c8-839a-44a1-b98e-a1724c4a0262", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ), +radio - read/write this to access a RadioConfig protobuf + +meshOwnerCharacteristic("6ff1d8b6-e2de-41e3-8c0b-8fa384f64eb6", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ) +owner - read/write this to access a User protobuf + Re: queue management Not all messages are kept in the fromradio queue (filtered based on SubPacket): * only the most recent Position and User messages for a particular node are kept @@ -86,6 +98,22 @@ class RadioInterfaceService : Service(), Logging { private val BTM_FROMNUM_CHARACTER = UUID.fromString("ed9da18c-a800-4f66-a670-aa7547e34453") + /// mynode - read/write this to access a MyNodeInfo protobuf + private val BTM_MYNODE_CHARACTER = + UUID.fromString("ea9f3f82-8dc4-4733-9452-1f6da28892a2") + + /// nodeinfo - read this to get a series of node infos (ending with a null empty record), write to this to restart the read statemachine that returns all the node infos + private val BTM_NODEINFO_CHARACTER = + UUID.fromString("d31e02e0-c8ab-4d3f-9cc9-0b8466bdabe8") + + /// radio - read/write this to access a RadioConfig protobuf + private val BTM_RADIO_CHARACTER = + UUID.fromString("b56786c8-839a-44a1-b98e-a1724c4a0262") + + /// owner - read/write this to access a User protobuf + private val BTM_OWNER_CHARACTER = + UUID.fromString("6ff1d8b6-e2de-41e3-8c0b-8fa384f64eb6") + /// This is public only so that SimRadio can bootstrap our message flow fun broadcastReceivedFromRadio(context: Context, payload: ByteArray) { val intent = Intent(RECEIVE_FROMRADIO_ACTION) @@ -226,23 +254,51 @@ class RadioInterfaceService : Service(), Logging { return binder; } - private val binder = object : IRadioInterfaceService.Stub() { - override fun sendToRadio(a: ByteArray) { - debug("queuing ${a.size} bytes to radio") + /** + * We allow writes to bluetooth characteristics to be queued up until our init is completed. + */ + private fun doAsyncWrite(uuid: UUID, a: ByteArray) { + debug("queuing ${a.size} bytes to $uuid") - clientOperations.add { - // Note: we generate a new characteristic each time, because we are about to - // change the data and we want the data stored in the closure - val toRadio = service.getCharacteristic(BTM_TORADIO_CHARACTER) - toRadio.value = a + clientOperations.add { + // Note: we generate a new characteristic each time, because we are about to + // change the data and we want the data stored in the closure + val toRadio = service.getCharacteristic(uuid) + toRadio.value = a - safe.asyncWriteCharacteristic(toRadio) { - it.getOrThrow() // FIXME, handle the error better - debug("ToRadio write of ${a.size} bytes completed") - } + safe.asyncWriteCharacteristic(toRadio) { + it.getOrThrow() // FIXME, handle the error better + debug("ToRadio write of ${a.size} bytes completed") } + } - doClientOperations() + doClientOperations() + } + + private val binder = object : IRadioInterfaceService.Stub() { + // A write of any size to nodeinfo means restart reading + override fun restartNodeInfo() = doAsyncWrite(BTM_NODEINFO_CHARACTER, ByteArray(0)) + + override fun readMyNode(): ByteArray { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun sendToRadio(a: ByteArray) = doAsyncWrite(BTM_TORADIO_CHARACTER, a) + + override fun readRadioConfig(): ByteArray { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun readOwner(): ByteArray { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun writeOwner(owner: ByteArray) = doAsyncWrite(BTM_OWNER_CHARACTER, owner) + + override fun writeRadioConfig(config: ByteArray) = doAsyncWrite(BTM_RADIO_CHARACTER, config) + + override fun readNodeInfo(): ByteArray { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } } } \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/SimRadio.kt b/app/src/main/java/com/geeksville/mesh/SimRadio.kt index 4cff6fcaf..96822be0d 100644 --- a/app/src/main/java/com/geeksville/mesh/SimRadio.kt +++ b/app/src/main/java/com/geeksville/mesh/SimRadio.kt @@ -31,12 +31,13 @@ class SimRadio(private val context: Context) { // Instead a separate sim radio thing can come in at startup and force these broadcasts to happen // at the right time // Send a fake my_node_num response + /* FIXME - change to use new radio info message RadioInterfaceService.broadcastReceivedFromRadio( context, MeshProtos.FromRadio.newBuilder().apply { myNodeNum = 9 }.build().toByteArray() - ) + ) */ simInitPackets.forEach { json -> val fromRadio = MeshProtos.FromRadio.newBuilder().apply {