fix: per-write timeouts + reduced inter-write delay #10

Merged
schwifty merged 1 commit from schwifty/per-write-timeout-and-mtu into main 2026-03-22 02:17:19 +00:00
Collaborator

Summary

  • Per-write timeout (5s): iOS had no per-write timeout — if a BLE write callback never came back, the operation hung until the 30s global timeout. Android uses withTimeoutOrNull(5000L) per write. Now iOS does the same: 5s timeout per command, retry once, then skip (non-fatal) or fail (critical).
  • Reduced inter-write delay: 200ms → 150ms between commands (Android uses 100ms). Saves ~1.2s across 24 commands and reduces the disconnect window.
  • MTU logging: Logs the negotiated max write length on connect to diagnose packet size issues.
  • SaveConfig timeout = success: If SaveConfig write times out (beacon reboots before callback), treat as success instead of waiting for global timeout.

What was happening

The beacon disconnect during the write phase was likely caused by:

  1. A write callback getting lost (no ATT response from beacon firmware)
  2. iOS waiting the full 30 seconds before giving up
  3. By then the BLE connection is long dead

With per-write timeouts, we detect the stall in 5 seconds and can retry or reconnect.

Test plan

  • Provision a DX-Smart CP28 beacon and verify all 24 commands complete
  • Check debug log for MTU and write timing messages
  • Intentionally test with beacon that drops writes (if available)
  • Verify SaveConfig still treated as success on reboot

🤖 Generated with Claude Code

## Summary - **Per-write timeout (5s)**: iOS had no per-write timeout — if a BLE write callback never came back, the operation hung until the 30s global timeout. Android uses `withTimeoutOrNull(5000L)` per write. Now iOS does the same: 5s timeout per command, retry once, then skip (non-fatal) or fail (critical). - **Reduced inter-write delay**: 200ms → 150ms between commands (Android uses 100ms). Saves ~1.2s across 24 commands and reduces the disconnect window. - **MTU logging**: Logs the negotiated max write length on connect to diagnose packet size issues. - **SaveConfig timeout = success**: If SaveConfig write times out (beacon reboots before callback), treat as success instead of waiting for global timeout. ## What was happening The beacon disconnect during the **write phase** was likely caused by: 1. A write callback getting lost (no ATT response from beacon firmware) 2. iOS waiting the full 30 seconds before giving up 3. By then the BLE connection is long dead With per-write timeouts, we detect the stall in 5 seconds and can retry or reconnect. ## Test plan - [ ] Provision a DX-Smart CP28 beacon and verify all 24 commands complete - [ ] Check debug log for MTU and write timing messages - [ ] Intentionally test with beacon that drops writes (if available) - [ ] Verify SaveConfig still treated as success on reboot 🤖 Generated with [Claude Code](https://claude.com/claude-code)
schwifty added 1 commit 2026-03-22 02:14:50 +00:00
The iOS provisioner had no per-write timeout — if a BLE write callback
never came back, the operation hung until the 30s global timeout, by
which point the connection was likely dead. Android uses a 5-second
per-write timeout with withTimeoutOrNull(5000L).

Changes:
- Add 5-second per-write timeout with retry (1 retry per command)
- On timeout: retry once, skip if non-fatal (steps 1-6), or fail
- SaveConfig timeout treated as success (beacon reboots = no callback)
- Reduce inter-write delay from 200ms to 150ms (Android uses 100ms)
- Log negotiated MTU on connect to diagnose packet size issues
- Cancel write timeout on cleanup/succeed/fail to prevent stale timers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
schwifty merged commit cabb2825d8 into main 2026-03-22 02:17:19 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: payfrit/payfrit-beacon-ios#10
No description provided.