Request high BLE priority for incoming Android links on the shared ACL
This commit is contained in:
1 parent
7dab663b93
commit
8ab25c1389
2 files changed
+45
-5
No files matched your search
@@ -1,5 +1,5 @@
|
||||
/* Реальное Android↔desktop радио. Android instrumentation включает только тестовый echo.
|
||||
* ble_peer_probe [connect|listen] [seconds]; 96 пакетов, TX saturation, побайтовая сверка. */
|
||||
* ble_peer_probe [connect|listen] [seconds] [peer_hex]; 96 пакетов, TX saturation, побайтовая сверка. */
|
||||
#include "ble_transport.h"
|
||||
#include "ble_identity.h"
|
||||
#include "u_async.h"
|
||||
@@ -7,11 +7,12 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
static struct ble_transport* transport;
|
||||
static ble_link_id session;
|
||||
static unsigned sent, received_count, blocked;
|
||||
static int failed, dial, seen, radio_ready;
|
||||
static uint64_t peer, started, verified_bytes;
|
||||
static uint64_t peer, expected_peer, started, verified_bytes;
|
||||
static const unsigned lengths[] = {1,13,14,20,244,512,1499,1500};
|
||||
static unsigned length(unsigned n) { return lengths[n % 8]; }
|
||||
static uint8_t probe_byte(unsigned n, unsigned i) { return (uint8_t)(n + i * 37); }
|
||||
@@ -58,6 +59,7 @@ static void status(void* arg, enum ble_state state, const char* reason) {
|
||||
static void broadcast(void* arg, const struct ble_endpoint* ep, const uint8_t* data, size_t len, int rssi) {
|
||||
(void)arg; struct ble_identity identity;
|
||||
if (ble_identity_decode(&identity, data, len) < 0) return;
|
||||
if (expected_peer && identity.node_id != expected_peer) return;
|
||||
if (!seen) printf("DISCOVER node=%016llx name=%s rssi=%d endpoint=%s\n",
|
||||
(unsigned long long)identity.node_id, identity.name, rssi, ep->id);
|
||||
seen = 1;
|
||||
@@ -66,7 +68,12 @@ static void broadcast(void* arg, const struct ble_endpoint* ep, const uint8_t* d
|
||||
int main(int argc, char** argv) {
|
||||
dial = argc < 2 || !strcmp(argv[1], "connect");
|
||||
int seconds = argc > 2 ? atoi(argv[2]) : 90;
|
||||
if (argc > 3) {
|
||||
char* end; errno = 0; expected_peer = strtoull(argv[3], &end, 16);
|
||||
if (errno || !expected_peer || !argv[3][0] || *end) { fprintf(stderr, "Invalid peer_hex\n"); return 2; }
|
||||
}
|
||||
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO); debug_set_category_level(DEBUG_CATEGORY_DISCOVERY, DEBUG_LEVEL_DEBUG);
|
||||
if (getenv("UTUN_TEST_DEBUG")) debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_TRACE);
|
||||
struct UASYNC* ua = uasync_create(); struct ble_config cfg = {0};
|
||||
cfg.node_id = 0x5643424c45544553ULL; cfg.company_id = 0xffff;
|
||||
cfg.callbacks.status = status; cfg.callbacks.broadcast = broadcast; cfg.callbacks.connection = connected;
|
||||
|
||||
@@ -52,7 +52,8 @@ object BleRadio {
|
||||
var gatt: BluetoothGatt? = null, var rx: BluetoothGattCharacteristic? = null,
|
||||
var invite: BluetoothGattCharacteristic? = null, var subscriptions: Int = 0, var channel: Int = 0,
|
||||
var mtu: Int = 23, var opened: Boolean = false, var pending: ByteArray? = null, var writing: Boolean = false,
|
||||
var busySince: Long = 0)
|
||||
var busySince: Long = 0,
|
||||
var priorityGatt: BluetoothGatt? = null) // Клиентский handle того же ACL: server API не имеет requestConnectionPriority.
|
||||
@JvmStatic external fun nativeInstall()
|
||||
@JvmStatic external fun nativeConfigure(flags: Int): Boolean
|
||||
@JvmStatic private external fun nativeEvent(gen: Long, token: Long, type: Int, arg: Int, text: String, bytes: ByteArray)
|
||||
@@ -169,6 +170,7 @@ object BleRadio {
|
||||
links[link.token] = link
|
||||
emit(9, link.token, text = device.address) // Core ограничивает время ожидания обеих CCC.
|
||||
preferFastPhy(device, null)
|
||||
tuneIncomingPriority(link)
|
||||
} else if (!accepted) {
|
||||
log("WARN", "Subscription rejected address=${device.address} characteristic=${descriptor.characteristic.uuid} " +
|
||||
"descriptor=${descriptor.uuid} incoming=$incoming prepared=$preparedWrite response=$responseNeeded " +
|
||||
@@ -301,6 +303,34 @@ object BleRadio {
|
||||
if (gatt != null) gatt.readPhy() else checkNotNull(server).readPhy(device)
|
||||
} catch (e: RuntimeException) { log("WARN", "PHY tuning unavailable address=${device.address}: ${e.message}") }
|
||||
}
|
||||
private fun requestHighPriority(link: Link, gatt: BluetoothGatt) {
|
||||
val accepted = gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH)
|
||||
log(if (accepted) "INFO" else "WARN", "Connection priority HIGH requested link=${link.token} outgoing=${link.outgoing} accepted=$accepted")
|
||||
}
|
||||
// GATT client/server — роли API. Клиентский handle использует уже открытый физический ACL, без discovery/DATA.
|
||||
private fun tuneIncomingPriority(link: Link) {
|
||||
val gen = generation
|
||||
try {
|
||||
val callback = object : BluetoothGattCallback() {
|
||||
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
|
||||
if (generation != gen || links[link.token] !== link || link.priorityGatt !== gatt) return
|
||||
guarded {
|
||||
log(if (status == 0) "DEBUG" else "WARN", "Priority GATT link=${link.token} status=$status state=$newState")
|
||||
if (status == 0 && newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
try { requestHighPriority(link, gatt) }
|
||||
catch (e: RuntimeException) { log("WARN", "Priority tuning failed link=${link.token}: $e") }
|
||||
} else if (status != 0 || newState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||
link.priorityGatt = null
|
||||
cleanup.retain(gatt, "priority GATT link=${link.token}") { gatt.close() }; drainCleanup()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
link.priorityGatt = link.device.connectGatt(context, false, callback, BluetoothDevice.TRANSPORT_LE,
|
||||
BluetoothDevice.PHY_LE_1M_MASK, worker)
|
||||
if (link.priorityGatt == null) log("WARN", "Priority GATT unavailable link=${link.token}")
|
||||
} catch (e: RuntimeException) { log("WARN", "Incoming priority tuning unavailable link=${link.token}: $e") }
|
||||
}
|
||||
private fun connect(token: Long, address: String) {
|
||||
check(cleanup.isEmpty) { "Previous BLE cleanup pending" }
|
||||
check(links.size < 16) { "link limit" }
|
||||
@@ -314,8 +344,7 @@ object BleRadio {
|
||||
log(if (status == 0) "INFO" else "WARN", "Client link=$token status=$status state=$newState")
|
||||
if (status != 0 || newState != BluetoothProfile.STATE_CONNECTED) close(link, "client status=$status state=$newState")
|
||||
else {
|
||||
val priority = gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH)
|
||||
log(if (priority) "INFO" else "WARN", "Connection priority HIGH requested link=$token accepted=$priority")
|
||||
requestHighPriority(link, gatt)
|
||||
preferFastPhy(link.device, gatt)
|
||||
if (!gatt.requestMtu(517)) close(link, "requestMtu refused")
|
||||
}
|
||||
@@ -454,6 +483,10 @@ object BleRadio {
|
||||
links.remove(link.token)
|
||||
log(if (report) "WARN" else "INFO", "Closed link=${link.token} address=${link.device.address} outgoing=${link.outgoing} " +
|
||||
"opened=${link.opened} channel=${link.channel} pending=${link.pending?.size} writing=${link.writing} reason=$reason")
|
||||
link.priorityGatt?.let { gatt ->
|
||||
link.priorityGatt = null
|
||||
cleanup.retain(gatt, "priority GATT link=${link.token}") { gatt.close() }
|
||||
}
|
||||
if (link.outgoing) link.gatt?.let { gatt ->
|
||||
try { gatt.disconnect() } catch (e: RuntimeException) { log("WARN", "Disconnect failed link=${link.token}: $e") }
|
||||
cleanup.retain(gatt, "client GATT link=${link.token}") { gatt.close() }
|
||||
|
||||
Reference in new issue
Block a user