kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
we now fetch any new rxmessages when they arrive at the radio
rodzic
6244556f8b
commit
10ad07e136
|
@ -53,14 +53,14 @@
|
|||
|
||||
<!-- we need bind job service for oreo -->
|
||||
<service
|
||||
android:name="com.geeksville.mesh.SoftwareUpdateService"
|
||||
android:name="com.geeksville.mesh.service.SoftwareUpdateService"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE"></service>
|
||||
|
||||
<!-- This is the public API for doing mesh radio operations from android apps -->
|
||||
<service
|
||||
android:name="com.geeksville.mesh.MeshService"
|
||||
android:name="com.geeksville.mesh.service.MeshService"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
|
@ -70,7 +70,7 @@
|
|||
|
||||
<!-- This is a private service which just does direct communication to the radio -->
|
||||
<service
|
||||
android:name="com.geeksville.mesh.RadioInterfaceService"
|
||||
android:name="com.geeksville.mesh.service.RadioInterfaceService"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
|
@ -85,7 +85,7 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<receiver android:name="com.geeksville.mesh.BootCompleteReceiver">
|
||||
<receiver android:name="com.geeksville.mesh.service.BootCompleteReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
|
|
|
@ -17,6 +17,7 @@ import androidx.core.app.ActivityCompat
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.ui.core.setContent
|
||||
import com.geeksville.android.Logging
|
||||
import com.geeksville.mesh.service.*
|
||||
import com.geeksville.mesh.ui.MeshApp
|
||||
import com.geeksville.mesh.ui.TextMessage
|
||||
import com.geeksville.mesh.ui.UIState
|
||||
|
@ -175,7 +176,7 @@ class MainActivity : AppCompatActivity(), Logging {
|
|||
else -> TODO()
|
||||
}
|
||||
}
|
||||
RadioInterfaceService.CONNECTCHANGED_ACTION -> {
|
||||
MeshService.ACTION_MESH_CONNECTED -> {
|
||||
UIState.isConnected.value = intent.getBooleanExtra(EXTRA_CONNECTED, false)
|
||||
debug("connchange ${UIState.isConnected.value}")
|
||||
}
|
||||
|
@ -200,7 +201,12 @@ class MainActivity : AppCompatActivity(), Logging {
|
|||
|
||||
// make some placeholder nodeinfos
|
||||
UIState.nodes.value =
|
||||
m.online.toList().map { it to NodeInfo(0, MeshUser(it, "unknown", "unk")) }.toMap()
|
||||
m.online.toList().map {
|
||||
it to NodeInfo(
|
||||
0,
|
||||
MeshUser(it, "unknown", "unk")
|
||||
)
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(name: ComponentName) {
|
||||
|
@ -218,7 +224,7 @@ class MainActivity : AppCompatActivity(), Logging {
|
|||
//val intent = Intent(this, MeshService::class.java)
|
||||
//intent.action = IMeshService::class.java.name
|
||||
val intent = Intent()
|
||||
intent.setClassName("com.geeksville.mesh", "com.geeksville.mesh.MeshService")
|
||||
intent.setClassName("com.geeksville.mesh", "com.geeksville.mesh.service.MeshService")
|
||||
|
||||
// Before binding we want to explicitly create - so the service stays alive forever (so it can keep
|
||||
// listening for the bluetooth packets arriving from the radio. And when they arrive forward them
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.geeksville.mesh
|
||||
package com.geeksville.mesh.service
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
|
@ -1,4 +1,4 @@
|
|||
package com.geeksville.mesh
|
||||
package com.geeksville.mesh.service
|
||||
|
||||
const val prefix = "com.geeksville.mesh"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.geeksville.mesh
|
||||
package com.geeksville.mesh.service
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
|
@ -13,6 +13,9 @@ import androidx.annotation.RequiresApi
|
|||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationCompat.PRIORITY_MIN
|
||||
import com.geeksville.android.Logging
|
||||
import com.geeksville.mesh.IMeshService
|
||||
import com.geeksville.mesh.IRadioInterfaceService
|
||||
import com.geeksville.mesh.MeshProtos
|
||||
import com.geeksville.mesh.MeshProtos.MeshPacket
|
||||
import com.geeksville.mesh.MeshProtos.ToRadio
|
||||
import com.geeksville.util.exceptionReporter
|
||||
|
@ -55,6 +58,7 @@ class MeshService : Service(), Logging {
|
|||
/// Intents broadcast by MeshService
|
||||
const val ACTION_RECEIVED_DATA = "$prefix.RECEIVED_DATA"
|
||||
const val ACTION_NODE_CHANGE = "$prefix.NODE_CHANGE"
|
||||
const val ACTION_MESH_CONNECTED = "$prefix.MESH_CONNECTED"
|
||||
|
||||
class IdNotFoundException(id: String) : Exception("ID not found $id")
|
||||
class NodeNumNotFoundException(id: Int) : Exception("NodeNum not found $id")
|
||||
|
@ -78,7 +82,9 @@ class MeshService : Service(), Logging {
|
|||
see com.geeksville.mesh broadcast intents
|
||||
// RECEIVED_OPAQUE for data received from other nodes
|
||||
// NODE_CHANGE for new IDs appearing or disappearing
|
||||
// CONNECTION_CHANGED for losing/gaining connection to the packet radio
|
||||
// ACTION_MESH_CONNECTED for losing/gaining connection to the packet radio (note, this is not
|
||||
the same as RadioInterfaceService.RADIO_CONNECTED_ACTION, because it implies we have assembled a valid
|
||||
node db.
|
||||
*/
|
||||
|
||||
private fun explicitBroadcast(intent: Intent) {
|
||||
|
@ -89,6 +95,7 @@ class MeshService : Service(), Logging {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The RECEIVED_OPAQUE:
|
||||
* Payload will be the raw bytes which were contained within a MeshPacket.Opaque field
|
||||
|
@ -134,7 +141,9 @@ class MeshService : Service(), Logging {
|
|||
|
||||
private val radioConnection = object : ServiceConnection {
|
||||
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||
val m = IRadioInterfaceService.Stub.asInterface(service)
|
||||
val m = IRadioInterfaceService.Stub.asInterface(
|
||||
service
|
||||
)
|
||||
radioService = m
|
||||
}
|
||||
|
||||
|
@ -210,7 +219,7 @@ class MeshService : Service(), Logging {
|
|||
// we listen for messages from the radio receiver _before_ trying to create the service
|
||||
val filter = IntentFilter()
|
||||
filter.addAction(RadioInterfaceService.RECEIVE_FROMRADIO_ACTION)
|
||||
filter.addAction(RadioInterfaceService.CONNECTCHANGED_ACTION)
|
||||
filter.addAction(RadioInterfaceService.RADIO_CONNECTED_ACTION)
|
||||
registerReceiver(radioInterfaceReceiver, filter)
|
||||
|
||||
// We in turn need to use the radiointerface service
|
||||
|
@ -239,7 +248,8 @@ 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 = NODE_NUM_UNKNOWN
|
||||
private var ourNodeNum =
|
||||
NODE_NUM_UNKNOWN
|
||||
|
||||
// The database of active nodes, index is the node number
|
||||
private val nodeDBbyNodeNum = mutableMapOf<Int, NodeInfo>()
|
||||
|
@ -255,7 +265,9 @@ class MeshService : Service(), Logging {
|
|||
///
|
||||
|
||||
/// Map a nodenum to a node, or throw an exception if not found
|
||||
private fun toNodeInfo(n: Int) = nodeDBbyNodeNum[n] ?: throw NodeNumNotFoundException(n)
|
||||
private fun toNodeInfo(n: Int) = nodeDBbyNodeNum[n] ?: throw NodeNumNotFoundException(
|
||||
n
|
||||
)
|
||||
|
||||
/// Map a nodenum to the nodeid string, or throw an exception if not present
|
||||
private fun toNodeID(n: Int) = toNodeInfo(n).user?.id
|
||||
|
@ -267,7 +279,9 @@ class MeshService : Service(), Logging {
|
|||
/// Map a userid to a node/ node num, or throw an exception if not found
|
||||
private fun toNodeInfo(id: String) =
|
||||
nodeDBbyID[id]
|
||||
?: throw IdNotFoundException(id)
|
||||
?: throw IdNotFoundException(
|
||||
id
|
||||
)
|
||||
|
||||
// ?: getOrCreateNodeInfo(10) // FIXME hack for now - throw IdNotFoundException(id)
|
||||
|
||||
|
@ -354,7 +368,11 @@ class MeshService : Service(), Logging {
|
|||
/// Update our DB of users based on someone sending out a User subpacket
|
||||
private fun handleReceivedUser(fromNum: Int, p: MeshProtos.User) {
|
||||
updateNodeInfo(fromNum) {
|
||||
it.user = MeshUser(p.id, p.longName, p.shortName)
|
||||
it.user = MeshUser(
|
||||
p.id,
|
||||
p.longName,
|
||||
p.shortName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,7 +423,9 @@ class MeshService : Service(), Logging {
|
|||
//val sim = SimRadio(this@MeshService)
|
||||
//sim.start() // Fake up our node id info and some past packets from other nodes
|
||||
|
||||
val myInfo = MeshProtos.MyNodeInfo.parseFrom(connectedRadio.readMyNode())
|
||||
val myInfo = MeshProtos.MyNodeInfo.parseFrom(
|
||||
connectedRadio.readMyNode()
|
||||
)
|
||||
ourNodeNum = myInfo.myNodeNum
|
||||
|
||||
// Ask for the current node DB
|
||||
|
@ -414,14 +434,19 @@ class MeshService : Service(), Logging {
|
|||
// read all the infos until we get back null
|
||||
var infoBytes = connectedRadio.readNodeInfo()
|
||||
while (infoBytes != null) {
|
||||
val info = MeshProtos.NodeInfo.parseFrom(infoBytes)
|
||||
val info =
|
||||
MeshProtos.NodeInfo.parseFrom(infoBytes)
|
||||
debug("Received initial nodeinfo $info")
|
||||
|
||||
// Just replace/add any entry
|
||||
updateNodeInfo(info.num) {
|
||||
if (info.hasUser())
|
||||
it.user =
|
||||
MeshUser(info.user.id, info.user.longName, info.user.shortName)
|
||||
MeshUser(
|
||||
info.user.id,
|
||||
info.user.longName,
|
||||
info.user.shortName
|
||||
)
|
||||
|
||||
if (info.hasPosition())
|
||||
it.position = Position(
|
||||
|
@ -450,14 +475,22 @@ class MeshService : Service(), Logging {
|
|||
|
||||
debug("Received broadcast ${intent.action}")
|
||||
when (intent.action) {
|
||||
RadioInterfaceService.CONNECTCHANGED_ACTION -> {
|
||||
RadioInterfaceService.RADIO_CONNECTED_ACTION -> {
|
||||
onConnectionChanged(intent.getBooleanExtra(EXTRA_CONNECTED, false))
|
||||
explicitBroadcast(intent) // forward the connection change message to anyone who is listening to us
|
||||
|
||||
// forward the connection change message to anyone who is listening to us. but change the action
|
||||
// to prevent an infinite loop from us receiving our own broadcast. ;-)
|
||||
intent.action = ACTION_MESH_CONNECTED
|
||||
explicitBroadcast(intent)
|
||||
}
|
||||
|
||||
RadioInterfaceService.RECEIVE_FROMRADIO_ACTION -> {
|
||||
val proto =
|
||||
MeshProtos.FromRadio.parseFrom(intent.getByteArrayExtra(EXTRA_PAYLOAD)!!)
|
||||
MeshProtos.FromRadio.parseFrom(
|
||||
intent.getByteArrayExtra(
|
||||
EXTRA_PAYLOAD
|
||||
)!!
|
||||
)
|
||||
info("Received from radio service: ${proto.toOneLineString()}")
|
||||
when (proto.variantCase.number) {
|
||||
MeshProtos.FromRadio.PACKET_FIELD_NUMBER -> handleReceivedMeshPacket(
|
||||
|
@ -507,7 +540,8 @@ class MeshService : Service(), Logging {
|
|||
// encapsulate our payload in the proper protobufs and fire it off
|
||||
val packet = buildMeshPacket(destId) {
|
||||
data = MeshProtos.Data.newBuilder().also {
|
||||
it.typ = MeshProtos.Data.Type.SIGNAL_OPAQUE
|
||||
it.typ =
|
||||
MeshProtos.Data.Type.SIGNAL_OPAQUE
|
||||
it.payload = ByteString.copyFrom(payloadIn)
|
||||
}.build()
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.geeksville.mesh
|
||||
package com.geeksville.mesh.service
|
||||
|
||||
import android.app.Service
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
|
@ -10,6 +10,7 @@ import android.os.IBinder
|
|||
import com.geeksville.android.BinaryLogFile
|
||||
import com.geeksville.android.Logging
|
||||
import com.geeksville.concurrent.DeferredExecution
|
||||
import com.geeksville.mesh.IRadioInterfaceService
|
||||
import com.geeksville.util.toRemoteExceptions
|
||||
import java.util.*
|
||||
|
||||
|
@ -91,9 +92,9 @@ class RadioInterfaceService : Service(), Logging {
|
|||
const val RECEIVE_FROMRADIO_ACTION = "$prefix.RECEIVE_FROMRADIO"
|
||||
|
||||
/**
|
||||
* This is broadcast when connection state changed (it is also rebroadcast by the MeshService)
|
||||
* This is broadcast when connection state changed
|
||||
*/
|
||||
const val CONNECTCHANGED_ACTION = "$prefix.CONNECT_CHANGED"
|
||||
const val RADIO_CONNECTED_ACTION = "$prefix.CONNECT_CHANGED"
|
||||
|
||||
private val BTM_SERVICE_UUID = UUID.fromString("6ba1b218-15a8-461f-9fa8-5dcae273eafd")
|
||||
private val BTM_FROMRADIO_CHARACTER =
|
||||
|
@ -150,7 +151,7 @@ class RadioInterfaceService : Service(), Logging {
|
|||
|
||||
private fun broadcastConnectionChanged(isConnected: Boolean) {
|
||||
debug("Broadcasting connection=$isConnected")
|
||||
val intent = Intent(CONNECTCHANGED_ACTION)
|
||||
val intent = Intent(RADIO_CONNECTED_ACTION)
|
||||
intent.putExtra(EXTRA_CONNECTED, isConnected)
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
|
@ -171,7 +172,10 @@ class RadioInterfaceService : Service(), Logging {
|
|||
|
||||
// Handle an incoming packet from the radio, broadcasts it as an android intent
|
||||
private fun handleFromRadio(p: ByteArray) {
|
||||
broadcastReceivedFromRadio(this, p)
|
||||
broadcastReceivedFromRadio(
|
||||
this,
|
||||
p
|
||||
)
|
||||
}
|
||||
|
||||
/// Attempt to read from the fromRadio mailbox, if data is found broadcast it to android apps
|
|
@ -1,4 +1,4 @@
|
|||
package com.geeksville.mesh
|
||||
package com.geeksville.mesh.service
|
||||
|
||||
import android.bluetooth.*
|
||||
import android.content.BroadcastReceiver
|
||||
|
@ -244,7 +244,12 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD
|
|||
}
|
||||
|
||||
private fun <T> queueWork(tag: String, cont: Continuation<T>, initFn: () -> Boolean) {
|
||||
val btCont = BluetoothContinuation(tag, cont, initFn)
|
||||
val btCont =
|
||||
BluetoothContinuation(
|
||||
tag,
|
||||
cont,
|
||||
initFn
|
||||
)
|
||||
|
||||
synchronized(workQueue) {
|
||||
debug("Enqueuing work: ${btCont.tag}")
|
||||
|
@ -341,7 +346,7 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD
|
|||
private fun queueReadCharacteristic(
|
||||
c: BluetoothGattCharacteristic,
|
||||
cont: Continuation<BluetoothGattCharacteristic>
|
||||
) = queueWork("readc", cont) { gatt!!.readCharacteristic(c) }
|
||||
) = queueWork("readC ${c.uuid}", cont) { gatt!!.readCharacteristic(c) }
|
||||
|
||||
fun asyncReadCharacteristic(
|
||||
c: BluetoothGattCharacteristic,
|
||||
|
@ -383,7 +388,7 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD
|
|||
private fun queueWriteCharacteristic(
|
||||
c: BluetoothGattCharacteristic,
|
||||
cont: Continuation<BluetoothGattCharacteristic>
|
||||
) = queueWork("writeC", cont) { gatt!!.writeCharacteristic(c) }
|
||||
) = queueWork("writeC ${c.uuid}", cont) { gatt!!.writeCharacteristic(c) }
|
||||
|
||||
fun asyncWriteCharacteristic(
|
||||
c: BluetoothGattCharacteristic,
|
|
@ -1,4 +1,4 @@
|
|||
package com.geeksville.mesh
|
||||
package com.geeksville.mesh.service
|
||||
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothDevice
|
||||
|
@ -13,6 +13,7 @@ import android.content.Intent
|
|||
import android.os.ParcelUuid
|
||||
import androidx.core.app.JobIntentService
|
||||
import com.geeksville.android.Logging
|
||||
import com.geeksville.mesh.MainActivity
|
||||
import java.util.*
|
||||
import java.util.zip.CRC32
|
||||
|
||||
|
@ -40,7 +41,11 @@ class SoftwareUpdateService : JobIntentService(), Logging {
|
|||
fun startUpdate() {
|
||||
info("starting update")
|
||||
|
||||
val sync = SafeBluetooth(this@SoftwareUpdateService, device)
|
||||
val sync =
|
||||
SafeBluetooth(
|
||||
this@SoftwareUpdateService,
|
||||
device
|
||||
)
|
||||
|
||||
val firmwareStream = assets.open("firmware.bin")
|
||||
val firmwareCrc = CRC32()
|
||||
|
@ -216,7 +221,8 @@ class SoftwareUpdateService : JobIntentService(), Logging {
|
|||
fun enqueueWork(context: Context, work: Intent) {
|
||||
enqueueWork(
|
||||
context,
|
||||
SoftwareUpdateService::class.java, JOB_ID, work
|
||||
SoftwareUpdateService::class.java,
|
||||
JOB_ID, work
|
||||
)
|
||||
}
|
||||
}
|
|
@ -9,8 +9,8 @@ import androidx.ui.material.MaterialTheme
|
|||
import androidx.ui.material.ProvideEmphasis
|
||||
import androidx.ui.tooling.preview.Preview
|
||||
import androidx.ui.unit.dp
|
||||
import com.geeksville.mesh.NodeInfo
|
||||
import com.geeksville.mesh.R
|
||||
import com.geeksville.mesh.service.NodeInfo
|
||||
|
||||
|
||||
@Composable
|
||||
|
|
|
@ -2,9 +2,9 @@ package com.geeksville.mesh.ui
|
|||
|
||||
import androidx.compose.Model
|
||||
import androidx.compose.mutableStateOf
|
||||
import com.geeksville.mesh.MeshUser
|
||||
import com.geeksville.mesh.NodeInfo
|
||||
import com.geeksville.mesh.Position
|
||||
import com.geeksville.mesh.service.MeshUser
|
||||
import com.geeksville.mesh.service.NodeInfo
|
||||
import com.geeksville.mesh.service.Position
|
||||
import java.util.*
|
||||
|
||||
// defines the screens we have in the app
|
||||
|
@ -26,12 +26,20 @@ object UIState {
|
|||
private val testPositions = arrayOf(
|
||||
Position(32.776665, -96.796989, 35), // dallas
|
||||
Position(32.960758, -96.733521, 35), // richardson
|
||||
Position(32.912901, -96.781776, 35) // north dallas
|
||||
Position(
|
||||
32.912901,
|
||||
-96.781776,
|
||||
35
|
||||
) // north dallas
|
||||
)
|
||||
|
||||
val testNodeNoPosition = NodeInfo(
|
||||
8,
|
||||
MeshUser("+6508765308".format(8), "Kevin MesterNoLoc", "KLO"),
|
||||
MeshUser(
|
||||
"+6508765308".format(8),
|
||||
"Kevin MesterNoLoc",
|
||||
"KLO"
|
||||
),
|
||||
null,
|
||||
12345
|
||||
)
|
||||
|
@ -39,7 +47,11 @@ object UIState {
|
|||
val testNodes = testPositions.mapIndexed { index, it ->
|
||||
NodeInfo(
|
||||
9 + index,
|
||||
MeshUser("+65087653%02d".format(9 + index), "Kevin Mester$index", "KM$index"),
|
||||
MeshUser(
|
||||
"+65087653%02d".format(9 + index),
|
||||
"Kevin Mester$index",
|
||||
"KM$index"
|
||||
),
|
||||
it,
|
||||
12345
|
||||
)
|
||||
|
|
Ładowanie…
Reference in New Issue