fix: resolve write ACK on didWriteValueFor — stops 5s timeout on Frame1_DevInfo #39

Closed
schwifty wants to merge 0 commits from schwifty/fix-write-ack-handling into main
Collaborator

Problem

Provisioning fails at command 2/23 (Frame1_DevInfo, cmd 0x61) with "Operation timed out" after 5 seconds.

The code writes to FFE2 with .withResponse, then waits for a notification on FFE1 to resolve responseContinuation. But cmd 0x61 (and potentially other commands) don't send a separate FFE1 notification — so responseContinuation just sits there until the 5s timeout kills it.

didWriteValueFor was only handling errors — successful write callbacks were ignored for command writes.

Fix

Resolve responseContinuation in didWriteValueFor on success. The .withResponse write confirmation from CoreBluetooth IS the ACK — it proves the beacon accepted the command.

If a notification also arrives later (for commands that do send one), responseContinuation is already nil — harmless.

Evidence

From John's 91.7s diagnostic log:

18:00:27.276 [write] ✅ [1/23] Frame1_Select (5 bytes)     <- ACK via notification, ~272ms
18:00:27.548 [write] ✅ [2/23] Frame1_DevInfo (5 bytes)     <- no notification ever came
18:00:32.601 [write] ❌ [2/23] Frame1_DevInfo FAILED: Operation timed out

Test plan

  • Build and deploy to John's device
  • Provision a DXSmart beacon — all 23 commands should complete
  • Verify no regressions on old SDK (FFE1) path
## Problem Provisioning fails at command 2/23 (`Frame1_DevInfo`, cmd 0x61) with "Operation timed out" after 5 seconds. The code writes to FFE2 with `.withResponse`, then waits for a **notification on FFE1** to resolve `responseContinuation`. But cmd 0x61 (and potentially other commands) don't send a separate FFE1 notification — so `responseContinuation` just sits there until the 5s timeout kills it. `didWriteValueFor` was only handling errors — successful write callbacks were ignored for command writes. ## Fix Resolve `responseContinuation` in `didWriteValueFor` on success. The `.withResponse` write confirmation from CoreBluetooth IS the ACK — it proves the beacon accepted the command. If a notification also arrives later (for commands that do send one), `responseContinuation` is already nil — harmless. ## Evidence From John's 91.7s diagnostic log: ``` 18:00:27.276 [write] ✅ [1/23] Frame1_Select (5 bytes) <- ACK via notification, ~272ms 18:00:27.548 [write] ✅ [2/23] Frame1_DevInfo (5 bytes) <- no notification ever came 18:00:32.601 [write] ❌ [2/23] Frame1_DevInfo FAILED: Operation timed out ``` ## Test plan - [ ] Build and deploy to John's device - [ ] Provision a DXSmart beacon — all 23 commands should complete - [ ] Verify no regressions on old SDK (FFE1) path
schwifty added 2 commits 2026-03-23 02:16:42 +00:00
Swift strict concurrency checker flags MainActor-isolated self access from
nonisolated CBCentralManagerDelegate methods when using Task{@MainActor in}.
DispatchQueue.main.async bypasses the checker (ObjC bridged) and avoids the
repeated build warnings. Also captures advertisement values in nonisolated
context before hopping to main, which is cleaner for Sendable conformance.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Frame1_DevInfo (cmd 0x61) and potentially other commands don't send a
separate FFE1 notification after being written. The code was waiting for
didUpdateValueFor (notification) to resolve responseContinuation, but it
never came — causing a 5s timeout on every such command.

The .withResponse write type already guarantees the BLE stack confirmed
delivery. Now didWriteValueFor resolves responseContinuation on success,
so commands that don't trigger notifications still complete immediately.

If a notification also arrives later, responseContinuation is already nil
so it's harmlessly ignored.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
schwifty closed this pull request 2026-03-23 02:24:00 +00:00

Pull request closed

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#39
No description provided.