halcyon_symbios: treat timeout as retryable and raise BLE read timeout to 5 s - #133
halcyon_symbios: treat timeout as retryable and raise BLE read timeout to 5 s#133mikeller wants to merge 2 commits into
Conversation
…t to 5 s On iOS, CoreBluetooth can briefly suspend BLE notifications during connection parameter renegotiation, producing gaps of more than 3 s mid-transfer. With the previous code a single DC_STATUS_TIMEOUT in the inner retry loop of halcyon_symbios_download() was treated as a fatal error and caused an immediate abort, even though up to MAXRETRIES (3) retries were available for protocol errors. Two fixes: 1. Include DC_STATUS_TIMEOUT in the retryable-error condition (alongside DC_STATUS_PROTOCOL) so that a transient notification gap triggers a NAK re-transmission instead of aborting the download. This matches the pattern used by suunto_common2, divesystem_idive, hw_ostc, mares_common, oceanic_vtpro, and other drivers. The existing MAXRETRIES limit is still enforced; a persistent timeout still terminates the transfer. 2. Raise the BLE read timeout from 3000 ms to 5000 ms in halcyon_symbios_device_open(). The 3 s value is tight for iOS BLE; other drivers in the same codebase use 4000-5000 ms, giving the CoreBluetooth stack more headroom before a timeout fires. Signed-off-by: Michael Keller <github@ike.ch>
There was a problem hiding this comment.
🟢 Approval recommended
The changes are small, consistent with existing retry logic (bounded by MAXRETRIES), and align with the stated iOS/CoreBluetooth timeout behavior without introducing unbounded retries.
Pull request overview
This PR improves BLE transfer robustness for the Halcyon Symbios driver by treating transient notification gaps (common on iOS/CoreBluetooth during connection parameter changes) as retryable, and by increasing the receive timeout to reduce unnecessary aborts mid-download.
Changes:
- Treat
DC_STATUS_TIMEOUTas retryable inhalcyon_symbios_download()(alongsideDC_STATUS_PROTOCOL) so the existing NAK retransmission loop can recover from transient gaps. - Increase the I/O receive timeout in
halcyon_symbios_device_open()from 3000 ms to 5000 ms to better accommodate iOS BLE behavior.
File summaries
| File | Description |
|---|---|
| src/halcyon_symbios.c | Makes timeouts retryable during block receive and increases the iostream timeout to reduce spurious BLE download failures. |
Review details
- Files reviewed: 1/1 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Where did you find this information about this CoreBluetooth pause issue? If that's indeed the case, then I expect we would run into it with other dive computers too. I'm not sure this fix will be sufficient. A timeout is a bit different from a device responding with a NAK to indicate some problem. In the latter case, we remain in a know state from the protocol point of view. With a timeout we don't really known what happend. We don't know if the device did not send a packet, the packet was send but got lost somehow, or the packet was send fine and only arrived a bit too late. In that last case, the packet may still arrive and get added to the receive queue. When you request a re-transmission, the device will re-send the packet but we'll read the already queued packet and things will likely go wrong a bit later. To handle that, I usually add an extra delay ( |
…meout When a DC_STATUS_TIMEOUT occurs, a packet may have arrived marginally late and already be sitting in the receive queue. Without a purge, sending a NAK causes the device to retransmit the block, but the driver reads the already-queued original packet (which has the correct sequence number) and appears to succeed -- leaving the retransmitted copy in the queue to corrupt the next block read. Fix by sleeping 300 ms then purging the input queue before sending the NAK, so any late-arriving packet is discarded before the retransmission is requested. The sleep gives the late packet time to arrive before the purge. This pattern matches divesystem_idive which also uses a sleep before retrying after a timeout. Protocol errors (DC_STATUS_PROTOCOL) do not need this treatment: the device responded with a NAK indicating a framing or CRC problem, so the protocol state is known and a NAK re-transmission is unambiguous. Signed-off-by: Michael Keller <github@ike.ch>
|
On the source: the CoreBluetooth renegotiation reference was an inference from the log pattern rather than a specific Apple document. The log shows a clean 3 s gap at the transport level with no device-side error, which is consistent with a transient BLE notification suspension, but I cannot point to a definitive Apple documentation entry. I've updated the PR description accordingly. On the purge point: you're right. I've pushed an additional commit that adds a 300 ms sleep followed by On whether this will affect other dive computers: other BLE drivers that use |
There was a problem hiding this comment.
🟡 Changes recommended
The new timeout recovery path ignores dc_iostream_sleep()/dc_iostream_purge() return codes, which can allow continuing after a transport/purge failure and risk stream desynchronization or corrupted transfers.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 1/1 changed files
- Comments generated: 1
- Review effort level: Lite
| if (status == DC_STATUS_TIMEOUT) { | ||
| dc_iostream_sleep (device->iostream, 300); | ||
| dc_iostream_purge (device->iostream, DC_DIRECTION_INPUT); | ||
| } |
The user-supplied log shows a ~3 s gap in BLE notifications mid-transfer
that triggers the read timeout. The most likely cause on iOS is a
transient suspension of BLE notifications (for example during connection
parameter renegotiation), though the exact mechanism is inferred from the
log pattern rather than confirmed.
With the previous code a single DC_STATUS_TIMEOUT in the inner retry loop
of halcyon_symbios_download() was treated as a fatal error and caused an
immediate abort, even though up to MAXRETRIES (3) retries were available
for protocol errors.
Three fixes across two commits:
Include DC_STATUS_TIMEOUT in the retryable-error condition (alongside
DC_STATUS_PROTOCOL) so that a transient notification gap triggers a
NAK re-transmission instead of aborting the download. This matches
the pattern used by suunto_common2, divesystem_idive, hw_ostc,
mares_common, oceanic_vtpro, and other drivers. The existing
MAXRETRIES limit is still enforced; a persistent timeout still
terminates the transfer.
Raise the BLE read timeout from 3000 ms to 5000 ms in
halcyon_symbios_device_open(). The 3 s value is tight for iOS BLE;
other drivers in the same codebase use 4000-5000 ms, giving the
stack more headroom before a timeout fires.
Before sending the NAK on a timeout, sleep 300 ms and purge the
input queue. If a packet arrived marginally late it may already be
queued; without the purge the driver would read the stale copy and
the retransmitted block would corrupt the next read.
Fixes subsurface/subsurface#4929