more test cases pass - standard startup packets work

This commit is contained in:
geeksville 2020-01-25 12:24:53 -08:00
parent b02a460c38
commit 38119a61f6
5 changed files with 100 additions and 63 deletions

View file

@ -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

View file

@ -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)
}

View file

@ -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() {

View 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())
}
}
}

View file

@ -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
}
}