mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
more test cases pass - standard startup packets work
This commit is contained in:
parent
b02a460c38
commit
38119a61f6
5 changed files with 100 additions and 63 deletions
8
TODO.md
8
TODO.md
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
* receive fake packets at power on to built initial state (for debugging, pretend there are a couple of nodes out there)
|
||||
* learn our node number
|
||||
* 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)
|
||||
|
|
@ -52,4 +50,6 @@ Don't leave device discoverable. Don't let unpaired users do thing with device
|
|||
* change bluetooth mtu length to 512 (default is only 20)
|
||||
* DONE get signal running under debugger
|
||||
* Find good Signal hooks
|
||||
|
||||
* receive fake packets at power on to built initial state (for debugging, pretend there are a couple of nodes out there)
|
||||
* learn our node number
|
||||
* test mesh service from activity
|
||||
|
|
|
|||
|
|
@ -26,6 +26,14 @@ class MeshService : Service(), Logging {
|
|||
companion object {
|
||||
class IdNotFoundException(id: String) : Exception("ID not found $id")
|
||||
class NodeNumNotFoundException(id: Int) : Exception("NodeNum not found $id")
|
||||
class NotInMeshException() : Exception("We are not yet in a mesh")
|
||||
class RadioNotConnectedException() : Exception("Can't find radio")
|
||||
|
||||
/// If we haven't yet received a node number from the radio
|
||||
private const val NODE_NUM_UNKNOWN = -2
|
||||
|
||||
/// If the radio hasn't yet joined a mesh (i.e. no nodenum assigned)
|
||||
private const val NODE_NUM_NO_MESH = -1
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -74,6 +82,9 @@ class MeshService : Service(), Logging {
|
|||
registerReceiver(radioInterfaceReceiver, filter)
|
||||
|
||||
// FIXME - don't do this until after we see that the radio is connected to the phone
|
||||
val sim = SimRadio(this)
|
||||
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 {
|
||||
wantNodes = ToRadio.WantNodes.newBuilder().build()
|
||||
|
|
@ -106,7 +117,7 @@ class MeshService : Service(), Logging {
|
|||
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
|
||||
private var ourNodeNum = NODE_NUM_UNKNOWN
|
||||
|
||||
// The database of active nodes, index is the node number
|
||||
private val nodeDBbyNodeNum = mutableMapOf<Int, NodeInfo>()
|
||||
|
|
@ -147,6 +158,12 @@ class MeshService : Service(), Logging {
|
|||
/// 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
|
||||
|
||||
if (from == NODE_NUM_NO_MESH)
|
||||
throw NotInMeshException()
|
||||
else if (from == NODE_NUM_UNKNOWN)
|
||||
throw RadioNotConnectedException()
|
||||
|
||||
to = idNum
|
||||
}
|
||||
|
||||
|
|
@ -264,6 +281,7 @@ class MeshService : Service(), Logging {
|
|||
when (proto.variantCase.number) {
|
||||
MeshProtos.FromRadio.PACKET_FIELD_NUMBER -> handleReceivedMeshPacket(proto.packet)
|
||||
MeshProtos.FromRadio.NODE_INFO_FIELD_NUMBER -> handleReceivedNodeInfo(proto.nodeInfo)
|
||||
MeshProtos.FromRadio.MY_NODE_NUM_FIELD_NUMBER -> ourNodeNum = proto.myNodeNum
|
||||
else -> TODO("Unexpected FromRadio variant")
|
||||
}
|
||||
}
|
||||
|
|
@ -284,7 +302,7 @@ class MeshService : Service(), Logging {
|
|||
}.build()
|
||||
|
||||
// Also update our own map for our nodenum, by handling the packet just like packets from other users
|
||||
if (ourNodeNum != -1) {
|
||||
if (ourNodeNum >= 0) {
|
||||
handleReceivedUser(ourNodeNum, user)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,52 +55,17 @@ class RadioInterfaceService : JobIntentService(), Logging {
|
|||
|
||||
// for debug logging only
|
||||
private val jsonPrinter = JsonFormat.printer()
|
||||
private val jsonParser = JsonFormat.parser()
|
||||
|
||||
/**
|
||||
* When simulating we parse these MeshPackets as if they arrived at startup
|
||||
* Send broadcast them after we receive a ToRadio.WantNodes message.
|
||||
*
|
||||
* Our fake net has three nodes
|
||||
*
|
||||
* +16508675309, nodenum 9 - our node
|
||||
* +16508675310, nodenum 10 - some other node, name Bob One/BO
|
||||
* (eventually) +16508675311, nodenum 11 - some other node
|
||||
*/
|
||||
/*
|
||||
|
||||
2020-01-25 11:02:05.279 1162-1280/com.geeksville.mesh D/com.geeksville.mesh.RadioInterfaceService: Executing work: Intent { act=com.geeksville.mesh.SEND_TORADIO (has extras) }
|
||||
2020-01-25 11:02:05.282 1162-1273/com.geeksville.mesh D/EGL_emulation: eglMakeCurrent: 0xebb2b500: ver 2 0 (tinfo 0xc9748bc0)
|
||||
2020-01-25 11:02:05.449 1162-1280/com.geeksville.mesh I/com.geeksville.mesh.RadioInterfaceService: TODO sending to radio: { "wantNodes": { } }
|
||||
2020-01-25 11:02:05.452 1162-1280/com.geeksville.mesh D/com.geeksville.mesh.RadioInterfaceService: Executing work: Intent { act=com.geeksville.mesh.SEND_TORADIO (has extras) }
|
||||
2020-01-25 11:02:05.479 1162-1280/com.geeksville.mesh I/com.geeksville.mesh.RadioInterfaceService: TODO sending to radio: { "setOwner": { "id": "+16508675309", "longName": "Kevin Xter", "shortName": "kx" } }
|
||||
2020-01-25 11:02:05.480 1162-1280/com.geeksville.mesh D/com.geeksville.mesh.RadioInterfaceService: Executing work: Intent { act=com.geeksville.mesh.SEND_TORADIO (has extras) }
|
||||
2020-01-25 11:02:05.504 1162-1280/com.geeksville.mesh I/com.geeksville.mesh.RadioInterfaceService: TODO sending to radio: { "packet": { "from": -1, "to": 10, "payload": { "subPackets": [{ "data": { "payload": "aGVsbG8gd29ybGQ=" } }] } } }
|
||||
2020-01-25 11:02:05.505 1162-1280/com.geeksville.mesh D/com.geeksville.mesh.RadioInterfaceService: Executing work: Intent { act=com.geeksville.mesh.SEND_TORADIO (has extras) }
|
||||
2020-01-25 11:02:05.510 1162-1280/com.geeksville.mesh I/com.geeksville.mesh.RadioInterfaceService: TODO sending to radio: { "packet": { "from": -1, "to": 10, "payload": { "subPackets": [{ "data": { "payload": "aGVsbG8gd29ybGQ=" } }] } } }
|
||||
2020-01-25 11:02:08.232 1162-1273/com.geeksville.mesh D/EGL_emulation: eglMakeCurrent: 0xebb2b500: ver 2 0 (tinfo 0xc9748bc0)
|
||||
|
||||
*/
|
||||
val simInitPackets =
|
||||
arrayOf(
|
||||
""" { "from": 10, "to": 9, "payload": { "subPackets": [{ "user": { "id": "+16508675310", "longName": "Bob One", "shortName": "BO" }}]}} """,
|
||||
""" { "from": 10, "to": 9, "payload": { "subPackets": [{ "data": { "payload": "aGVsbG8gd29ybGQ=", "typ": 0 }}]}} """, // SIGNAL_OPAQUE
|
||||
""" { "from": 10, "to": 9, "payload": { "subPackets": [{ "data": { "payload": "aGVsbG8gd29ybGQ=", "typ": 1 }}]}} """, // CLEAR_TEXT
|
||||
""" { "from": 10, "to": 9, "payload": { "subPackets": [{ "data": { "payload": "", "typ": 2 }}]}} """ // CLEAR_READACK
|
||||
)
|
||||
|
||||
// FIXME, move into a subclass?
|
||||
val isSimulating = true
|
||||
/// This is public only so that SimRadio can bootstrap our message flow
|
||||
fun broadcastReceivedFromRadio(context: Context, payload: ByteArray) {
|
||||
val intent = Intent(RECEIVE_FROMRADIO_ACTION)
|
||||
intent.putExtra(EXTRA_PAYLOAD, payload)
|
||||
context.sendBroadcast(intent)
|
||||
}
|
||||
}
|
||||
|
||||
lateinit var sentPacketsLog: DebugLogFile // inited in onCreate
|
||||
|
||||
private fun broadcastReceivedFromRadio(payload: ByteArray) {
|
||||
val intent = Intent(RECEIVE_FROMRADIO_ACTION)
|
||||
intent.putExtra("$prefix.Payload", payload)
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
|
||||
fun broadcastConnectionChanged(isConnected: Boolean) {
|
||||
val intent = Intent("$prefix.CONNECTION_CHANGED")
|
||||
intent.putExtra(EXTRA_CONNECTED, isConnected)
|
||||
|
|
@ -116,22 +81,11 @@ class RadioInterfaceService : JobIntentService(), Logging {
|
|||
val json = jsonPrinter.print(proto).replace('\n', ' ')
|
||||
info("TODO sending to radio: $json")
|
||||
sentPacketsLog.log(json)
|
||||
|
||||
if (isSimulating)
|
||||
simInitPackets.forEach { json ->
|
||||
val fromRadio = MeshProtos.FromRadio.newBuilder().apply {
|
||||
packet = MeshProtos.MeshPacket.newBuilder().apply {
|
||||
jsonParser.merge(json, this)
|
||||
}.build()
|
||||
}.build()
|
||||
|
||||
broadcastReceivedFromRadio(fromRadio.toByteArray())
|
||||
}
|
||||
}
|
||||
|
||||
// Handle an incoming packet from the radio, broadcasts it as an android intent
|
||||
private fun handleFromRadio(p: ByteArray) {
|
||||
broadcastReceivedFromRadio(p)
|
||||
broadcastReceivedFromRadio(this, p)
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
|
|
|
|||
51
app/src/main/java/com/geeksville/mesh/SimRadio.kt
Normal file
51
app/src/main/java/com/geeksville/mesh/SimRadio.kt
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package com.geeksville.mesh
|
||||
|
||||
import android.content.Context
|
||||
import com.google.protobuf.util.JsonFormat
|
||||
|
||||
class SimRadio(private val context: Context) {
|
||||
private val jsonParser = JsonFormat.parser()
|
||||
|
||||
/**
|
||||
* When simulating we parse these MeshPackets as if they arrived at startup
|
||||
* Send broadcast them after we receive a ToRadio.WantNodes message.
|
||||
*
|
||||
* Our fake net has three nodes
|
||||
*
|
||||
* +16508675309, nodenum 9 - our node
|
||||
* +16508675310, nodenum 10 - some other node, name Bob One/BO
|
||||
* (eventually) +16508675311, nodenum 11 - some other node
|
||||
*/
|
||||
private val simInitPackets =
|
||||
arrayOf(
|
||||
""" { "from": 10, "to": 9, "payload": { "subPackets": [{ "user": { "id": "+16508675310", "longName": "Bob One", "shortName": "BO" }}]}} """,
|
||||
""" { "from": 10, "to": 9, "payload": { "subPackets": [{ "data": { "payload": "aGVsbG8gd29ybGQ=", "typ": 0 }}]}} """, // SIGNAL_OPAQUE
|
||||
""" { "from": 10, "to": 9, "payload": { "subPackets": [{ "data": { "payload": "aGVsbG8gd29ybGQ=", "typ": 1 }}]}} """, // CLEAR_TEXT
|
||||
""" { "from": 10, "to": 9, "payload": { "subPackets": [{ "data": { "payload": "", "typ": 2 }}]}} """ // CLEAR_READACK
|
||||
)
|
||||
|
||||
fun start() {
|
||||
// FIXME, do this sim startup elsewhere, because waiting for a packet from MeshService
|
||||
// isn't right, because that service can't successfully send radio packets until it knows
|
||||
// our node num
|
||||
// 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
|
||||
RadioInterfaceService.broadcastReceivedFromRadio(
|
||||
context,
|
||||
MeshProtos.FromRadio.newBuilder().apply {
|
||||
myNodeNum = 9
|
||||
}.build().toByteArray()
|
||||
)
|
||||
|
||||
simInitPackets.forEach { json ->
|
||||
val fromRadio = MeshProtos.FromRadio.newBuilder().apply {
|
||||
packet = MeshProtos.MeshPacket.newBuilder().apply {
|
||||
jsonParser.merge(json, this)
|
||||
}.build()
|
||||
}.build()
|
||||
|
||||
RadioInterfaceService.broadcastReceivedFromRadio(context, fromRadio.toByteArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -161,7 +161,12 @@ message NodeInfo {
|
|||
message FromRadio {
|
||||
oneof variant {
|
||||
MeshPacket packet = 1;
|
||||
NodeInfo node_info = 2;
|
||||
|
||||
/// Tells the phone what our node number is, can be -1 if we've not yet joined a mesh.
|
||||
sint32 my_node_num = 2;
|
||||
|
||||
/// One packet is sent for each node in the on radio DB
|
||||
NodeInfo node_info = 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -177,9 +182,18 @@ message ToRadio {
|
|||
|
||||
oneof variant {
|
||||
MeshPacket packet = 1; // send this packet on the mesh
|
||||
RadioConfig set_radio = 2; // set the radio provisioning for this node
|
||||
User set_owner = 3; // Set the owner for this node
|
||||
WantNodes want_nodes = 4; // phone wants radio to send full node db to the phone
|
||||
|
||||
//
|
||||
// Rare operations
|
||||
//
|
||||
|
||||
/// phone wants radio to send full node db to the phone, This is typically the first packet sent
|
||||
/// to the radio when the phone gets a bluetooth connection.
|
||||
/// The radio will respond by sending back a FromRadio.my_node_num and a series of FromRadio.node_info
|
||||
WantNodes want_nodes = 100;
|
||||
|
||||
RadioConfig set_radio = 101; // set the radio provisioning for this node
|
||||
User set_owner = 102; // Set the owner for this node
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue