Compare commits
2 Commits
e501895e56
...
15d13cc52f
| Author | SHA1 | Date | |
|---|---|---|---|
| 15d13cc52f | |||
| d2934690a5 |
@@ -12,6 +12,7 @@ import android.os.ParcelUuid
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.TimeoutCancellationException
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import org.json.JSONObject
|
||||
@@ -36,19 +37,35 @@ class BleClient(private val context: Context) {
|
||||
private val writes = ArrayDeque<ByteArray>()
|
||||
private var writeInProgress = false
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val reconnect: Runnable = Runnable { connect() }
|
||||
private val restartScan: Runnable = Runnable {
|
||||
if (!stopped && state.value == ConnectionState.SCANNING) {
|
||||
bluetoothManager.adapter?.bluetoothLeScanner?.stopScan(scanCallback)
|
||||
scheduleReconnect(1_000)
|
||||
}
|
||||
}
|
||||
private var stopped = true
|
||||
|
||||
fun connect() {
|
||||
stopped = false
|
||||
val adapter = bluetoothManager.adapter ?: return
|
||||
handler.removeCallbacks(reconnect)
|
||||
handler.removeCallbacks(restartScan)
|
||||
val adapter = bluetoothManager.adapter ?: run {
|
||||
state.value = ConnectionState.DISCONNECTED
|
||||
scheduleReconnect()
|
||||
return
|
||||
}
|
||||
adapter.bluetoothLeScanner?.stopScan(scanCallback)
|
||||
state.value = ConnectionState.SCANNING
|
||||
val filter = ScanFilter.Builder().setServiceUuid(ParcelUuid(SERVICE_UUID)).build()
|
||||
adapter.bluetoothLeScanner?.startScan(listOf(filter), ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(), scanCallback)
|
||||
handler.postDelayed(restartScan, 15_000)
|
||||
}
|
||||
|
||||
fun disconnect() {
|
||||
stopped = true
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
handler.removeCallbacks(reconnect)
|
||||
handler.removeCallbacks(restartScan)
|
||||
bluetoothManager.adapter?.bluetoothLeScanner?.stopScan(scanCallback)
|
||||
gatt?.close(); gatt = null; rx = null
|
||||
resetWrites()
|
||||
@@ -64,21 +81,30 @@ class BleClient(private val context: Context) {
|
||||
enqueue((message.toString() + "\n").toByteArray())
|
||||
return try {
|
||||
withTimeout(20_000) { deferred.await() }
|
||||
} catch (error: TimeoutCancellationException) {
|
||||
handler.post { gatt?.disconnect() }
|
||||
throw error
|
||||
} finally {
|
||||
pending.remove(id)
|
||||
}
|
||||
}
|
||||
|
||||
private val scanCallback = object : ScanCallback() {
|
||||
private val scanCallback: ScanCallback = object : ScanCallback() {
|
||||
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
||||
handler.removeCallbacks(restartScan)
|
||||
bluetoothManager.adapter.bluetoothLeScanner?.stopScan(this)
|
||||
state.value = ConnectionState.CONNECTING
|
||||
gatt?.close()
|
||||
gatt = result.device.connectGatt(context, false, gattCallback, BluetoothDevice.TRANSPORT_LE)
|
||||
}
|
||||
override fun onScanFailed(errorCode: Int) { state.value = ConnectionState.DISCONNECTED }
|
||||
override fun onScanFailed(errorCode: Int) {
|
||||
handler.removeCallbacks(restartScan)
|
||||
state.value = ConnectionState.DISCONNECTED
|
||||
scheduleReconnect()
|
||||
}
|
||||
}
|
||||
|
||||
private val gattCallback = object : BluetoothGattCallback() {
|
||||
private val gattCallback: BluetoothGattCallback = object : BluetoothGattCallback() {
|
||||
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
this@BleClient.gatt = gatt
|
||||
@@ -88,8 +114,10 @@ class BleClient(private val context: Context) {
|
||||
if (!gatt.requestMtu(247)) gatt.discoverServices()
|
||||
}
|
||||
else {
|
||||
rx = null; gatt.close(); resetWrites(); state.value = ConnectionState.DISCONNECTED
|
||||
if (!stopped) handler.postDelayed({ connect() }, 3_000)
|
||||
rx = null; gatt.close()
|
||||
if (this@BleClient.gatt === gatt) this@BleClient.gatt = null
|
||||
resetWrites(); state.value = ConnectionState.DISCONNECTED
|
||||
scheduleReconnect()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,4 +223,10 @@ class BleClient(private val context: Context) {
|
||||
writes.clear()
|
||||
writeInProgress = false
|
||||
}
|
||||
|
||||
private fun scheduleReconnect(delayMillis: Long = 3_000) {
|
||||
if (stopped) return
|
||||
handler.removeCallbacks(reconnect)
|
||||
handler.postDelayed(reconnect, delayMillis)
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -7,7 +7,7 @@ Wants=pi-car-companion.service
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/libexec/pi-car-companion-bluetooth
|
||||
ExecStartPost=-/usr/bin/timeout 10 /usr/bin/btmgmt add-adv -c -u 6c7a0001-7c6d-4f74-9bb0-c5a4e5efc001 1
|
||||
ExecStartPost=/usr/bin/timeout 5 /usr/bin/script -qec '/usr/bin/btmgmt add-adv -c -u 6c7a0001-7c6d-4f74-9bb0-c5a4e5efc001 1' /dev/null
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
NoNewPrivileges=true
|
||||
|
||||
Reference in New Issue
Block a user