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