Repeat cumulative BLE acknowledgements after unreliable delivery
This commit is contained in:
1 parent
008bafc18a
commit
e0076d5d10
1 file changed
+21
-17
+21
-17
@@ -35,7 +35,7 @@ struct ble_connection {
|
||||
unsigned int capacity;
|
||||
uint16_t pending_bytes;
|
||||
/* ID монотонен по модулю 65536; кольцо хранит только размеры, payload остаётся у ETCP. */
|
||||
uint16_t tx_next, tx_acked, rx_last, flight_head, flight_count, flight_bytes, flight_sizes[FLOW_SLOTS];
|
||||
uint16_t tx_next, tx_acked, rx_last, ack_sent, flight_head, flight_count, flight_bytes, flight_sizes[FLOW_SLOTS];
|
||||
uint64_t flight_deadline, ack_due, ack_completed;
|
||||
void* ack_timer;
|
||||
int rx_flow_seen, ack_dirty, pending_ack;
|
||||
@@ -156,14 +156,18 @@ static void wake_writer(struct ble_transport* t, struct ble_connection* c, enum
|
||||
}
|
||||
static void ack_timer(void* arg) {
|
||||
struct ble_connection* c = arg; c->ack_timer = NULL;
|
||||
c->ack_dirty = 1;
|
||||
pump(c->owner, c);
|
||||
}
|
||||
/* Один отложенный ACK на направление; новые RX заменяют ID, не отодвигая срок. */
|
||||
static int schedule_ack(struct ble_transport* t, struct ble_connection* c) {
|
||||
/* Свежий ID объединяем до 15ms, последний повторяем раз в 100ms даже при полном окне отправителя. */
|
||||
static int schedule_ack(struct ble_transport* t, struct ble_connection* c, int fresh) {
|
||||
if (fresh && c->ack_dirty) return 1;
|
||||
if (fresh) c->ack_dirty = 1;
|
||||
uint64_t now = get_time_us();
|
||||
if (!c->ack_dirty) c->ack_due = c->ack_completed ? c->ack_completed + BLE_ACK_INTERVAL_US : now + BLE_ACK_INTERVAL_US;
|
||||
c->ack_dirty = 1;
|
||||
if (c->ack_timer || (c->pending && now >= c->ack_due)) return 1;
|
||||
c->ack_due = c->ack_completed ? c->ack_completed + (c->ack_dirty ? BLE_ACK_INTERVAL_US : BLE_ACK_REPEAT_US) :
|
||||
now + BLE_ACK_INTERVAL_US;
|
||||
if (c->ack_timer) { uasync_cancel_timeout(t->ua, c->ack_timer); c->ack_timer = NULL; }
|
||||
if (c->pending && now >= c->ack_due) return 1;
|
||||
/* uasync использует усечённые TB: дополнительный TB исключает срабатывание раньше 15ms. */
|
||||
uint64_t delay = c->ack_due > now ? (c->ack_due - now + 199) / 100 : 0;
|
||||
c->ack_timer = uasync_set_timeout(t->ua, (int)delay, c, ack_timer, "ble_ack");
|
||||
@@ -219,7 +223,9 @@ static void pump(struct ble_transport* t, struct ble_connection* c) {
|
||||
if (wire == BLE_WIRE_ACK) {
|
||||
if (c->ack_timer) { uasync_cancel_timeout(t->ua, c->ack_timer); c->ack_timer = NULL; }
|
||||
c->ack_dirty = 0; c->stats.ack_tx++;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "BLE ACK TX link=%llu id=%u", (unsigned long long)c->id, c->rx_last);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "BLE ACK TX link=%llu id=%u repeat=%d",
|
||||
(unsigned long long)c->id, c->rx_last, c->ack_sent == c->rx_last);
|
||||
c->ack_sent = c->rx_last;
|
||||
} else if (wire == BLE_WIRE_DATA) {
|
||||
if (!c->flight_count) c->flight_deadline = c->submitted + DEADLINE_US;
|
||||
c->flight_sizes[(c->flight_head + c->flight_count++) % FLOW_SLOTS] = len;
|
||||
@@ -383,8 +389,9 @@ void ble_backend_opened(struct ble_transport* t, ble_link_id id, unsigned int mt
|
||||
c->opened = 1;
|
||||
DEBUG_INFO(CAT, "BLE GATT open link=%llu mtu=%u fragment_payload=%u outgoing=%d DATA=without_response/notify INVITE=request/indicate tx_limit=%u",
|
||||
(unsigned long long)id, mtu, c->capacity - HEADER - FLOW_HEADER, c->outgoing, t->config.tx_limit);
|
||||
DEBUG_INFO(CAT, "BLE flow configured link=%llu rate_bits=%u window_ms=%u window_bytes=%u ACK_interval_us=%u id_bits=16",
|
||||
(unsigned long long)id, BLE_TX_RATE_BITS, BLE_TX_WINDOW_MS, BLE_TX_WINDOW_BYTES, BLE_ACK_INTERVAL_US);
|
||||
DEBUG_INFO(CAT, "BLE flow configured link=%llu rate_bits=%u window_ms=%u window_bytes=%u "
|
||||
"ACK=without_response/notify ACK_interval_us=%u ACK_repeat_us=%u id_bits=16",
|
||||
(unsigned long long)id, BLE_TX_RATE_BITS, BLE_TX_WINDOW_MS, BLE_TX_WINDOW_BYTES, BLE_ACK_INTERVAL_US, BLE_ACK_REPEAT_US);
|
||||
if (c->outgoing) {
|
||||
c->control[0] = HELLO; write64(c->control + 1, t->config.node_id); write64(c->control + 9, c->peer);
|
||||
c->control_pending = 1;
|
||||
@@ -438,12 +445,12 @@ void ble_backend_received(struct ble_transport* t, ble_link_id id, enum ble_wire
|
||||
(unsigned long long)id, seq, data[FLOW_HEADER], len, c->rx_last, advance);
|
||||
if (!advance || advance >= 0x8000) {
|
||||
DEBUG_WARN(CAT, "BLE duplicate/stale DATA link=%llu id=%u last=%u", (unsigned long long)id, seq, c->rx_last);
|
||||
if (c->rx_flow_seen) schedule_ack(t, c); return;
|
||||
if (c->rx_flow_seen) schedule_ack(t, c, 1); return;
|
||||
}
|
||||
if (advance != 1) DEBUG_WARN(CAT, "BLE DATA flow gap link=%llu expected=%u received=%u missing=%u",
|
||||
(unsigned long long)id, (uint16_t)(c->rx_last + 1), seq, advance - 1);
|
||||
c->rx_last = seq; c->rx_flow_seen = 1;
|
||||
if (!schedule_ack(t, c)) return;
|
||||
if (!schedule_ack(t, c, 1)) return;
|
||||
data += FLOW_HEADER; len -= FLOW_HEADER;
|
||||
}
|
||||
struct ble_channel_state* ch = &c->channels[channel];
|
||||
@@ -530,12 +537,9 @@ void ble_backend_sent(struct ble_transport* t, ble_link_id id, int success) {
|
||||
c->pending = 0;
|
||||
if (c->pending_ack) {
|
||||
c->pending_ack = 0; c->ack_completed = get_time_us();
|
||||
/* Даже при медленном ACK дать DATA/INVITE следующие 15ms, иначе непрерывный RX вытесняет ответы. */
|
||||
if (c->ack_dirty) {
|
||||
if (c->ack_timer) { uasync_cancel_timeout(t->ua, c->ack_timer); c->ack_timer = NULL; }
|
||||
c->ack_due = c->ack_completed + BLE_ACK_INTERVAL_US;
|
||||
if (!schedule_ack(t, c)) return;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "BLE ACK sent link=%llu id=%u elapsed_us=%llu latest=%u dirty=%d",
|
||||
(unsigned long long)id, c->ack_sent, (unsigned long long)waited, c->rx_last, c->ack_dirty);
|
||||
if (!schedule_ack(t, c, 0)) return;
|
||||
pump(t, c); return;
|
||||
}
|
||||
struct ble_channel_state* ch = &c->channels[channel];
|
||||
|
||||
Reference in new issue
Block a user