diff --git a/app/src/main/java/com/geeksville/mesh/service/MockInterface.kt b/app/src/main/java/com/geeksville/mesh/service/MockInterface.kt
index 84d3aab53..c83b0b00d 100644
--- a/app/src/main/java/com/geeksville/mesh/service/MockInterface.kt
+++ b/app/src/main/java/com/geeksville/mesh/service/MockInterface.kt
@@ -26,13 +26,40 @@ class MockInterface(private val service: RadioInterfaceService) : Logging, IRadi
override fun handleSendToRadio(p: ByteArray) {
val pr = MeshProtos.ToRadio.parseFrom(p)
+ val data = if (pr.hasPacket()) pr.packet.decoded else null
+
when {
pr.wantConfigId != 0 -> sendConfigResponse(pr.wantConfigId)
+ data != null && data.portnum == Portnums.PortNum.ADMIN_APP -> handleAdminPacket(
+ pr,
+ AdminProtos.AdminMessage.parseFrom(data.payload)
+ )
pr.hasPacket() && pr.packet.wantAck -> sendFakeAck(pr)
else -> info("Ignoring data sent to mock interface $pr")
}
}
+ private fun handleAdminPacket(pr: MeshProtos.ToRadio, d: AdminProtos.AdminMessage) {
+ if (d.getRadioRequest)
+ sendAdmin(pr.packet.to, pr.packet.from, pr.packet.id) {
+ getRadioResponse = RadioConfigProtos.RadioConfig.newBuilder().apply {
+
+ preferences = RadioConfigProtos.RadioConfig.UserPreferences.newBuilder().apply {
+ region = RadioConfigProtos.RegionCode.TW
+ // FIXME set critical times?
+ }.build()
+ }.build()
+ }
+
+ if (d.getChannelRequest != 0)
+ sendAdmin(pr.packet.to, pr.packet.from, pr.packet.id) {
+ getChannelResponse = ChannelProtos.Channel.newBuilder().apply {
+ index = d.getChannelRequest - 1 // 0 based on the response
+ role = if(d.getChannelRequest == 1) ChannelProtos.Channel.Role.PRIMARY else ChannelProtos.Channel.Role.DISABLED
+ }.build()
+ }
+ }
+
override fun close() {
info("Closing the mock interface")
}
@@ -53,8 +80,7 @@ class MockInterface(private val service: RadioInterfaceService) : Logging, IRadi
}.build()
}
-
- private fun makeAck(fromIn: Int, toIn: Int, msgId: Int) =
+ private fun makeDataPacket(fromIn: Int, toIn: Int, data: MeshProtos.Data.Builder) =
MeshProtos.FromRadio.newBuilder().apply {
packet = MeshProtos.MeshPacket.newBuilder().apply {
id = messageNumSequence.next()
@@ -62,15 +88,34 @@ class MockInterface(private val service: RadioInterfaceService) : Logging, IRadi
to = toIn
rxTime = (System.currentTimeMillis() / 1000).toInt()
rxSnr = 1.5f
- decoded = MeshProtos.Data.newBuilder().apply {
- portnum = Portnums.PortNum.ROUTING_APP
- payload = MeshProtos.Routing.newBuilder().apply {
- }.build().toByteString()
- requestId = msgId
- }.build()
+ decoded = data.build()
}.build()
}
+ private fun makeAck(fromIn: Int, toIn: Int, msgId: Int) =
+ makeDataPacket(fromIn, toIn, MeshProtos.Data.newBuilder().apply {
+ portnum = Portnums.PortNum.ROUTING_APP
+ payload = MeshProtos.Routing.newBuilder().apply {
+ }.build().toByteString()
+ requestId = msgId
+ })
+
+ private fun sendAdmin(
+ fromIn: Int,
+ toIn: Int,
+ reqId: Int,
+ initFn: AdminProtos.AdminMessage.Builder.() -> Unit
+ ) {
+ val p = makeDataPacket(fromIn, toIn, MeshProtos.Data.newBuilder().apply {
+ portnum = Portnums.PortNum.ADMIN_APP
+ payload = AdminProtos.AdminMessage.newBuilder().also {
+ initFn(it)
+ }.build().toByteString()
+ requestId = reqId
+ })
+ service.handleFromRadio(p.build().toByteArray())
+ }
+
/// Send a fake ack packet back if the sender asked for want_ack
private fun sendFakeAck(pr: MeshProtos.ToRadio) {
service.handleFromRadio(
diff --git a/app/src/main/java/com/geeksville/mesh/service/SimRadio.kt b/app/src/main/java/com/geeksville/mesh/service/SimRadio.kt
deleted file mode 100644
index 36b87b40d..000000000
--- a/app/src/main/java/com/geeksville/mesh/service/SimRadio.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.geeksville.mesh
-
-import android.content.Context
-import com.geeksville.mesh.service.RadioInterfaceService
-
-class SimRadio(private val context: Context) {
-
- /**
- * 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": { "user": { "id": "+16508675310", "longName": "Bob One", "shortName": "BO" }}} """,
- """ { "from": 10, "to": 9, "payload": { "data": { "payload": "aGVsbG8gd29ybGQ=", "typ": 0 }}} """, // SIGNAL_OPAQUE
- """ { "from": 10, "to": 9, "payload": { "data": { "payload": "aGVsbG8gd29ybGQ=", "typ": 1 }}} """, // CLEAR_TEXT
- """ { "from": 10, "to": 9, "payload": { "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
- /* FIXME - change to use new radio info message
- RadioInterfaceService.broadcastReceivedFromRadio(
- context,
- MeshProtos.FromRadio.newBuilder().apply {
- myNodeNum = 9
- }.build().toByteArray()
- ) */
-
- simInitPackets.forEach { _ ->
- val fromRadio = MeshProtos.FromRadio.newBuilder().apply {
- packet = MeshProtos.MeshPacket.newBuilder().apply {
- // jsonParser.merge(json, this)
- }.build()
- }.build()
-
- RadioInterfaceService.broadcastReceivedFromRadio(context, fromRadio.toByteArray())
- }
- }
-}
\ No newline at end of file
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 ae77be60c..86c20fc2c 100644
--- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt
+++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt
@@ -590,7 +590,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
val spinner = binding.regionSpinner
val regionAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, regions)
regionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
- spinner.adapter = regionAdapter
+ // spinner.adapter = regionAdapter
model.ownerName.observe(viewLifecycleOwner, { name ->
binding.usernameEditText.setText(name)
diff --git a/app/src/main/res/layout/settings_fragment.xml b/app/src/main/res/layout/settings_fragment.xml
index 80c7a6714..e34fb6518 100644
--- a/app/src/main/res/layout/settings_fragment.xml
+++ b/app/src/main/res/layout/settings_fragment.xml
@@ -62,8 +62,10 @@
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp"
+ android:theme="@style/AppTheme.Spinner"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/usernameView"
+ android:entries="@array/regions"
app:layout_constraintTop_toTopOf="parent" />
diff --git a/app/src/main/res/values/protobufs.xml b/app/src/main/res/values/protobufs.xml
new file mode 100644
index 000000000..190471fc4
--- /dev/null
+++ b/app/src/main/res/values/protobufs.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ - Unset
+ - US
+ - EU433
+ - EU865
+ - CN
+ - JP
+ - ANZ
+ - KR
+ - TW
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 691680617..e36ac68c6 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -13,6 +13,20 @@
- @style/menu_item_color
+
+
+
+
+