From a0160cadf9e082de6cea055ba8f7711ba0b30dab Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 1 Feb 2021 10:31:39 +0800 Subject: [PATCH] WIP to improve simulator --- .../mesh/service/BluetoothInterface.kt | 2 + .../mesh/service/IRadioInterface.kt | 8 -- .../geeksville/mesh/service/MeshService.kt | 2 +- .../geeksville/mesh/service/MockInterface.kt | 95 +++++++++++++++++++ .../geeksville/mesh/service/NopInterface.kt | 10 ++ .../mesh/service/RadioInterfaceService.kt | 9 +- .../geeksville/mesh/ui/SettingsFragment.kt | 1 + 7 files changed, 117 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/com/geeksville/mesh/service/MockInterface.kt create mode 100644 app/src/main/java/com/geeksville/mesh/service/NopInterface.kt diff --git a/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt b/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt index a1e1eda6..a424f864 100644 --- a/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt +++ b/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt @@ -97,6 +97,8 @@ class BluetoothInterface(val service: RadioInterfaceService, val address: String return bluetoothManager.adapter } + fun toInterfaceName(deviceName: String) = "x$deviceName" + /** Return true if this address is still acceptable. For BLE that means, still bonded */ fun addressValid(context: Context, address: String): Boolean { val allPaired = diff --git a/app/src/main/java/com/geeksville/mesh/service/IRadioInterface.kt b/app/src/main/java/com/geeksville/mesh/service/IRadioInterface.kt index c8d5f1b7..a45d0aa9 100644 --- a/app/src/main/java/com/geeksville/mesh/service/IRadioInterface.kt +++ b/app/src/main/java/com/geeksville/mesh/service/IRadioInterface.kt @@ -6,11 +6,3 @@ interface IRadioInterface : Closeable { fun handleSendToRadio(p: ByteArray) } -class NopInterface : IRadioInterface { - override fun handleSendToRadio(p: ByteArray) { - } - - override fun close() { - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt index c8ba1f98..47e05df4 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -1196,8 +1196,8 @@ class MeshService : Service(), Logging { if (newMyNodeInfo == null || newNodes.isEmpty()) errormsg("Did not receive a valid config") else { - debug("Installing new node DB") discardNodeDB() + debug("Installing new node DB") myNodeInfo = newMyNodeInfo newNodes.forEach(::installNodeInfo) diff --git a/app/src/main/java/com/geeksville/mesh/service/MockInterface.kt b/app/src/main/java/com/geeksville/mesh/service/MockInterface.kt new file mode 100644 index 00000000..df59052a --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/service/MockInterface.kt @@ -0,0 +1,95 @@ +package com.geeksville.mesh.service + +import com.geeksville.android.Logging +import com.geeksville.mesh.MeshProtos +import com.geeksville.mesh.R + +/** A simulated interface that is used for testing in the simulator */ +class MockInterface(private val service: RadioInterfaceService) : Logging, IRadioInterface { + companion object : Logging { + + val interfaceName = "m" + } + + init { + info("Starting the mock interface") + service.onConnect() // Tell clients they can use the API + } + + override fun handleSendToRadio(b: ByteArray) { + val p = MeshProtos.ToRadio.parseFrom(b) + + if (p.wantConfigId != 0) + sendConfigResponse(p.wantConfigId) + else + info("Ignoring data sent to mock interface $p") + } + + override fun close() { + info("Closing the mock interface") + } + + private fun sendConfigResponse(configId: Int) { + debug("Sending mock config response") + + // Simulated network data to feed to our app + val MY_NODE = 0x42424242 + val packets = arrayOf( + // MyNodeInfo + MeshProtos.FromRadio.newBuilder().apply { + myInfo = MeshProtos.MyNodeInfo.newBuilder().apply { + myNodeNum = MY_NODE + region = "TW" + numChannels = 7 + hwModel = "Sim" + packetIdBits = 32 + nodeNumBits = 32 + currentPacketId = 1 + messageTimeoutMsec = 5 * 60 * 1000 + firmwareVersion = service.getString(R.string.cur_firmware_version) + }.build() + }, + + // RadioConfig + MeshProtos.FromRadio.newBuilder().apply { + radio = MeshProtos.RadioConfig.newBuilder().apply { + + preferences = MeshProtos.RadioConfig.UserPreferences.newBuilder().apply { + region = MeshProtos.RegionCode.TW + // FIXME set critical times + }.build() + + channel = MeshProtos.ChannelSettings.newBuilder().apply { + // fixme() // fix channel display + // fix testlab // (application as GeeksvilleApplication).isInTestLab + }.build() + }.build() + }, + + // Fake NodeDB + MeshProtos.FromRadio.newBuilder().apply { + nodeInfo = MeshProtos.NodeInfo.newBuilder().apply { + num = MY_NODE + user = MeshProtos.User.newBuilder().apply { + id = "!0x42424242" + longName = "Sim User" + shortName = "SU" + }.build() + position = MeshProtos.Position.newBuilder().apply { + latitudeI = 42 + longitudeI = 42 // FIXME + time = 42 // FIXME + }.build() + }.build() + }, + + MeshProtos.FromRadio.newBuilder().apply { + configCompleteId = configId + } + ) + + packets.forEach { p -> + service.handleFromRadio(p.build().toByteArray()) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/service/NopInterface.kt b/app/src/main/java/com/geeksville/mesh/service/NopInterface.kt new file mode 100644 index 00000000..f4e46234 --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/service/NopInterface.kt @@ -0,0 +1,10 @@ +package com.geeksville.mesh.service + +class NopInterface : IRadioInterface { + override fun handleSendToRadio(p: ByteArray) { + } + + override fun close() { + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt b/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt index ece6f66e..9117bde4 100644 --- a/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt @@ -8,6 +8,7 @@ import android.content.SharedPreferences import android.os.IBinder import androidx.core.content.edit import com.geeksville.android.BinaryLogFile +import com.geeksville.android.BuildUtils.isEmulator import com.geeksville.android.GeeksvilleApplication import com.geeksville.android.Logging import com.geeksville.concurrent.handledLaunch @@ -81,9 +82,13 @@ class RadioInterfaceService : Service(), Logging { rest = null if (rest != null) - address = "x$rest" // Add the bluetooth prefix + address = BluetoothInterface.toInterfaceName(rest) // Add the bluetooth prefix } + // If we are running on the emulator we default to the mock interface, so we can have some data to show to the user + if(address == null && isEmulator) + address = MockInterface.interfaceName + return address } @@ -108,6 +113,7 @@ class RadioInterfaceService : Service(), Logging { 'x' -> BluetoothInterface.addressValid(context, rest) 's' -> SerialInterface.addressValid(context, rest) 'n' -> true + 'm' -> true else -> TODO("Unexpected interface type $c") } if (!isValid) @@ -236,6 +242,7 @@ class RadioInterfaceService : Service(), Logging { radioIf = when (c) { 'x' -> BluetoothInterface(this, rest) 's' -> SerialInterface(this, rest) + 'm' -> MockInterface(this) 'n' -> nopIf else -> { errormsg("Unexpected radio interface type") diff --git a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt index ec8f2ac5..0399cc03 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt @@ -269,6 +269,7 @@ class BTScanModel(app: Application) : AndroidViewModel(app), Logging { warn("No bluetooth adapter. Running under emulation?") val testnodes = listOf( + DeviceListEntry("Simulated interface", "m", true), DeviceListEntry("Meshtastic_ab12", "xaa", false), DeviceListEntry("Meshtastic_32ac", "xbb", true) )