treat disabiling bluetooth as loss of connection

pull/8/head
geeksville 2020-02-04 17:27:10 -08:00
rodzic 9e83bfd790
commit 8ce5a13cf8
4 zmienionych plików z 59 dodań i 16 usunięć

Wyświetl plik

@ -1,9 +1,8 @@
# High priority
* fix startup race conditions in services, allow reads to block as needed
* if radio disconnects, we need to requeue a new connect attempt in RadioService
* when notified phone should download messages
* have phone use our local node number as its node number (instead of hardwired)
* fix startup race conditions in services, allow reads to block as needed
* investigate the Signal SMS message flow path, see if I could just make Mesh a third peer to signal & sms?
* make signal work when there is no internet up
* make Signal rx path work
@ -69,3 +68,4 @@ Don't leave device discoverable. Don't let unpaired users do things with device
* investigate a 16 bit node number. If possible it would make collisions super rare. Much easier to just pick a nodenum and go.
* remove example code boilerplate from the service
* switch from protobuf-java to protobuf-javalite - much faster and smaller, just no JSON debug printing
* have phone use our local node number as its node number (instead of hardwired)

Wyświetl plik

@ -132,11 +132,12 @@ class RadioInterfaceService : Service(), Logging {
private lateinit var device: BluetoothDevice
private lateinit var safe: SafeBluetooth
val service get() = safe.gatt.services.find { it.uuid == BTM_SERVICE_UUID }!!
val service get() = safe.gatt!!.services.find { it.uuid == BTM_SERVICE_UUID }!!
private lateinit var fromRadio: BluetoothGattCharacteristic
private lateinit var fromNum: BluetoothGattCharacteristic
private val logSends = false
lateinit var sentPacketsLog: BinaryLogFile // inited in onCreate
private var isConnected = false
@ -160,8 +161,10 @@ class RadioInterfaceService : Service(), Logging {
debug("sending to radio")
doWrite(BTM_TORADIO_CHARACTER, p)
sentPacketsLog.write(p)
sentPacketsLog.flush()
if (logSends) {
sentPacketsLog.write(p)
sentPacketsLog.flush()
}
}
// Handle an incoming packet from the radio, broadcasts it as an android intent
@ -239,12 +242,14 @@ class RadioInterfaceService : Service(), Logging {
}
}
sentPacketsLog = BinaryLogFile(this, "sent_log.pb")
if (logSends)
sentPacketsLog = BinaryLogFile(this, "sent_log.pb")
}
override fun onDestroy() {
info("Destroying radio interface service")
sentPacketsLog.close()
if (logSends)
sentPacketsLog.close()
safe.disconnect()
super.onDestroy()
}

Wyświetl plik

@ -1,11 +1,15 @@
package com.geeksville.mesh
import android.bluetooth.*
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import com.geeksville.android.Logging
import com.geeksville.concurrent.CallbackContinuation
import com.geeksville.concurrent.Continuation
import com.geeksville.concurrent.SyncContinuation
import com.geeksville.util.exceptionReporter
import java.io.IOException
@ -25,12 +29,39 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD
var timeoutMsec = 5 * 1000L
/// Users can access the GATT directly as needed
lateinit var gatt: BluetoothGatt
var gatt: BluetoothGatt? = null
var state = BluetoothProfile.STATE_DISCONNECTED
private var currentWork: BluetoothContinuation? = null
private val workQueue = mutableListOf<BluetoothContinuation>()
/// When we see the BT stack getting disabled/renabled we handle that as a connect/disconnect event
private val btStateReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) = exceptionReporter {
if (intent.action == BluetoothAdapter.ACTION_STATE_CHANGED) {
val newstate = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
when (newstate) {
// Simulate a disconnection if the user disables bluetooth entirely
BluetoothAdapter.STATE_OFF -> if (gatt != null) gattCallback.onConnectionStateChange(
gatt!!,
0,
BluetoothProfile.STATE_DISCONNECTED
)
BluetoothAdapter.STATE_ON -> {
warn("FIXME - requeue a connect anytime bluetooth is reenabled")
}
}
}
}
}
init {
context.registerReceiver(
btStateReceiver,
IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
)
}
/**
* a schedulable bit of bluetooth work, includes both the closure to call to start the operation
* and the completion (either async or sync) to call when it completes
@ -48,10 +79,11 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD
}
}
private val gattCallback = object : BluetoothGattCallback() {
override fun onConnectionStateChange(
gatt: BluetoothGatt,
g: BluetoothGatt,
status: Int,
newState: Int
) {
@ -66,6 +98,8 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD
BluetoothProfile.STATE_DISCONNECTED -> {
// cancel any queued ops? for now I think it is best to keep them around
// failAllWork(IOException("Lost connection"))
gatt = null;
}
}
}
@ -167,6 +201,7 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD
// more info.
// Otherwise if you pass in false, it will try to connect now and will timeout and fail in 30 seconds.
private fun queueConnect(autoConnect: Boolean = false, cont: Continuation<Unit>) {
assert(gatt == null);
queueWork("connect", cont) {
val g = device.connectGatt(context, autoConnect, gattCallback)
if (g != null)
@ -185,7 +220,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", cont) { gatt!!.readCharacteristic(c) }
fun asyncReadCharacteristic(
c: BluetoothGattCharacteristic,
@ -197,7 +232,7 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD
private fun queueDiscoverServices(cont: Continuation<Unit>) {
queueWork("discover", cont) {
gatt.discoverServices()
gatt!!.discoverServices()
}
}
@ -211,7 +246,7 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD
private fun queueRequestMtu(
len: Int,
cont: Continuation<Int>
) = queueWork("reqMtu", cont) { gatt.requestMtu(len) }
) = queueWork("reqMtu", cont) { gatt!!.requestMtu(len) }
fun asyncRequestMtu(
len: Int,
@ -227,7 +262,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", cont) { gatt!!.writeCharacteristic(c) }
fun asyncWriteCharacteristic(
c: BluetoothGattCharacteristic,
@ -238,7 +273,10 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD
makeSync { queueWriteCharacteristic(c, it) }
fun disconnect() {
gatt.disconnect()
if (gatt != null)
gatt!!.disconnect()
context.unregisterReceiver(btStateReceiver)
failAllWork(Exception("SafeBluetooth disconnected"))
}
}

Wyświetl plik

@ -53,8 +53,8 @@ class SoftwareUpdateService : JobIntentService(), Logging {
// we begin by setting our MTU size as high as it can go
sync.requestMtu(512)
val service = sync.gatt.services.find { it.uuid == SW_UPDATE_UUID }!!
val service = sync.gatt!!.services.find { it.uuid == SW_UPDATE_UUID }!!
val totalSizeDesc = service.getCharacteristic(SW_UPDATE_TOTALSIZE_CHARACTER)
val dataDesc = service.getCharacteristic(SW_UPDATE_DATA_CHARACTER)