Cover lost cumulative BLE acknowledgements with full duplex windows
This commit is contained in:
1 parent
f4bcc6eae9
commit
008bafc18a
2 files changed
+15
-2
No files matched your search
@@ -4,6 +4,7 @@
|
||||
* Один сервис обслуживает независимые соединения; данные — непрозрачные кадры 1..1500 байт.
|
||||
* Целые кадры находятся в ll_queue. DATA: Write Without Response/Notification; INVITE: Request/Indication.
|
||||
* DATA имеет накопительный ACK GATT-фрагментов: ограничивает очередь ОС, без собственных ретрансляций.
|
||||
* ACK: Without Response/Notification; последний ID повторяется, чтобы потеря ACK не запирала окно.
|
||||
* Доставку целых DATA подтверждает потребитель (ETCP); ACK не является подтверждением приложения.
|
||||
* Диагностика: discovery (BLE-префикс). NULL validate разрешает запрос, как и начальная политика GUI. */
|
||||
#ifndef VIBECHAT_BLE_TRANSPORT_H
|
||||
@@ -24,6 +25,7 @@ extern "C" {
|
||||
#define BLE_TX_WINDOW_MS 50u
|
||||
#define BLE_TX_WINDOW_BYTES (BLE_TX_RATE_BITS / 8u * BLE_TX_WINDOW_MS / 1000u)
|
||||
#define BLE_ACK_INTERVAL_US 15000u
|
||||
#define BLE_ACK_REPEAT_US 100000u /* Повтор последнего ACK при отсутствии нового DATA. */
|
||||
struct ble_transport;
|
||||
struct UASYNC;
|
||||
typedef uint64_t ble_link_id;
|
||||
|
||||
@@ -19,6 +19,7 @@ static int hold_ack;
|
||||
static unsigned ack_delay_us;
|
||||
static unsigned ack_timeouts;
|
||||
static unsigned closed_count;
|
||||
static unsigned drop_acks[3]; /* Потери ACK в эфире независимы от успешного локального completion. */
|
||||
static uint64_t data_wire_bytes[3];
|
||||
static ble_link_id incoming_ids[3];
|
||||
static void run(void* arg);
|
||||
@@ -81,6 +82,7 @@ static void run(void* arg) {
|
||||
if (!f->delivered) {
|
||||
uint8_t data[512]; size_t len = f->len; memcpy(data, f->data, len); f->delivered = 1;
|
||||
int dropped = f->channel != BLE_WIRE_ACK && data[f->channel == BLE_WIRE_DATA ? 2 : 0] == 3 && drop && --drop == 0;
|
||||
if (f->channel == BLE_WIRE_ACK && drop_acks[b->index]) { drop_acks[b->index]--; dropped = 1; }
|
||||
if (hold_ack && f->channel == BLE_WIRE_ACK) f->ack_held = 1;
|
||||
else if (!dropped && peer && slot(peer, other)) {
|
||||
if (f->channel == BLE_WIRE_ACK) f->ack_delivered = f->ack_id;
|
||||
@@ -229,7 +231,12 @@ static void exercise_flow(void) {
|
||||
ble_backend_received(a, id, BLE_WIRE_ACK, duplicate, 2);
|
||||
for (unsigned i = 0; i < 1000; i++) uasync_poll(ua, 0);
|
||||
CHECK(data_wire_bytes[0] == paused && !ble_tx_ready(a, id));
|
||||
hold_ack = 0; schedule(backends[0]); schedule(backends[1]);
|
||||
/* Последний ACK потерян в обоих направлениях, а новый DATA уже не помещается в окно. */
|
||||
hold_ack = 0;
|
||||
slot(backends[0], id)->ack_held = receiver->ack_held = 0;
|
||||
drop_acks[0] = drop_acks[1] = 3;
|
||||
uint64_t recovery_started = get_time_us();
|
||||
schedule(backends[0]); schedule(backends[1]);
|
||||
uint64_t deadline = get_time_us() + 5000000;
|
||||
while ((received[0] < BLE_QUEUE_MAX || received[1] < BLE_QUEUE_MAX) && get_time_us() < deadline) {
|
||||
uasync_poll(ua, 10);
|
||||
@@ -241,7 +248,11 @@ static void exercise_flow(void) {
|
||||
}
|
||||
}
|
||||
}
|
||||
CHECK(received[0] == BLE_QUEUE_MAX && received[1] == BLE_QUEUE_MAX); drain(ua);
|
||||
CHECK(received[0] == BLE_QUEUE_MAX && received[1] == BLE_QUEUE_MAX);
|
||||
CHECK(!drop_acks[0] && !drop_acks[1] && get_time_us() - recovery_started >= 3 * BLE_ACK_REPEAT_US);
|
||||
printf("BLE lost ACK recovery PASS (3 losses per direction, both windows full, elapsed_us=%llu)\n",
|
||||
(unsigned long long)(get_time_us() - recovery_started));
|
||||
drain(ua);
|
||||
/* Больше полного оборота wire ID; новые данные действительно приходят, старые ACK не открывают окно. */
|
||||
unsigned sent = 0, delivered = 0; deadline = get_time_us() + 10000000;
|
||||
while (delivered < 70000 && get_time_us() < deadline) {
|
||||
|
||||
Reference in new issue
Block a user