Repository navigation
suunto_nautic: step aside for another app on the shared link and resume - #16
trustthegoose wants to merge 7 commits into
Conversation
…Data stream The Suunto app on the same phone holds subscriptions whose pushed values arrive as 0x01 notifications with sequence number 0, like our stream chunks (one seen on handle F0 BF 06 with a 4-byte payload). The stream loop took them as chunks and failed the stream with "Unexpected chunk size". Skip notifications whose handle isn't the stream's, comparing without the slot byte (chunks carry slot F0, the GET reply slot 00).
When the Suunto app opens its own session on the phone's shared BLE link, the watch answers its hello and ends our /Data stream: a torn chunk (the hello reply is usually swallowed with it) or UNSUBSCRIBE_REPLY with a non-200 status. Until now that truncated the dive or failed the download. On any of those during a stream, mark the link contended and, instead of unsubscribing into the other app's session, step aside: emit DC_EVENT_WAITING, read and discard packets until the link has been quiet for 15 s (longer than the Suunto app's ~10.6 s hello retry, so it gets in; capped at an hour, cancellable), then stop and release the old stream (or the restart is refused with 423) and restart the dive from the beginning. No new hello on resume: the Suunto app answers a hello by re-opening its own session, which would end our stream again. A 423 after a pause means the other app is still streaming, so pause again. Pauses don't use up retries; at most 5 per dive. A hello reply seen during an ordinary request just keeps us waiting for our own reply, as before. Before our own hello, listen 1.5 s and wait for quiet if another app is mid-sync. Part 2 of deepsealabs/libdc-swift#78.
… handle The watch has one handle for streaming a dive's /Data, shared by every client on the link. Another app's GET of a dive's /Data re-points it, so our subscription then carries that app's dive, and its UNSUBSCRIBE ends our stream. Seen with a second client streaming dives back to back: one dive came out truncated with the other client's data in it, caught only by the listed-size check. While streaming, treat another client's GET or SUBSCRIBE reply on our stream's handle (ignoring the slot byte) as a takeover. After a pause, a size mismatch also means the other app's traffic got into our stream: pause again and redo the dive instead of keeping it truncated.
When another app re-points the shared /Data stream handle, it is downloading dives itself. Wait that out without counting it toward the pause cap, so an app fetching many dives in a row is waited out in full. Every other pause (a fresh hello, a 423, a torn stream) still counts, so an app stuck reconnecting still ends the download after 5 pauses.
|
Two commits added after more testing, plus results with Auto download. What this is built for. The main case is the Suunto app running in the background on the same phone: its hourly sync (weather and settings, no logbook access), the values it gets pushed, and the occasional reconnect, which sends a fresh hello. #15 and this PR cover all of those. If the user deliberately opens the Suunto app and it starts downloading dives, DC Tester should stand aside until it's done and then carry on; downloading from both apps at once is never a good idea, and the first new commit is what stops it. 1. The shared 2. Waiting out a deliberate download ( Results:
One UI note to add to the Explorer ones on deepsealabs/libdc-swift#78: the driver's pause and resume only show in the debug console, not in Auto download's live log, which is where a user would look. |
Back-to-back frames share no flag: one frame's closing 0x7E is followed by the next one's opening 0x7E. A reader that starts in the middle of a frame takes the closing flag as an opening one, returns an empty frame at the next flag, and then starts each later read inside a frame again. It stays out of sync for as long as the frames keep coming back to back, so every read returns an empty frame and every packet is lost. Seen on the Suunto Nautic when another client is streaming a dive on the shared link: our reader sees nothing for the whole stream, including any reply meant for us. Treat two flags in a row as the start of the next frame, as HDLC readers usually do; an empty frame carries nothing.
Before the hello, send a GET without one. The watch answers it only when another client already has a session on the link; on a fresh link it stays silent, and then we say hello as before. With an existing session, skip our hello: it would take that session over, and a Suunto app that doesn't answer it with a hello of its own keeps sending requests but stops getting their replies. It then reports the sync done without the new dives until it is restarted. Seen on both watches with the app mid-sync; on one of them the listen before the hello heard nothing, so only a request can tell. The watch doesn't answer a client without a session of its own while another client's stream is running, so if other traffic arrived while waiting for the reply, wait for quiet and ask again.
… a takeover
Another client's UNSUBSCRIBE (status 200) and FETCH on the shared /Data
handle also end or disturb our stream, not only its GET and SUBSCRIBE.
Seen with the Suunto app on an Ocean: its UNSUBSCRIBE reply ended our
stream silently ('ended without an end marker'), and the dive was only
saved because the immediate retry happened to land after the app was done.
|
Three more commits, from a real-case test with the Suunto app. One of them touches shared code ( What went wrong. Phone + Ocean and iPad + Nautic, DC Tester Auto download on, Suunto app in the background on each, a bucket dive on both watches. DC Tester got both dives, but both Suunto apps stopped working: each kept sending one request about every 10 s, the watch answered every one (we can see the replies on the shared link), and the app never followed up. It reported the sync done without the new dive, and stayed that way until it was force-quit and reopened. Both times it started right after a hello from DC Tester that the app didn't answer with a hello of its own; DC Tester hellos that the app did answer within a second left it fine. In both bad cases the app was in the middle of its sync, in a quiet gap between requests. Versions: Suunto app 3.15.0 (build 23972) on iOS 27.0.1, both devices (iPhone 16 Pro, iPad Pro M5); Ocean firmware 2.51.28, Nautic firmware 2.55.46; DC Tester build 22 with #15 and this PR. The Suunto app's side of this depends on its version, so the behaviour may change with app updates. The commits:
Results:
One thing left: on the phone the Suunto app asked for the new dive while DC Tester was streaming it, got no reply, showed "last sync failed", and retried on its own about 3.5 minutes later, successfully. No data lost, but a user sees a failure message. Avoiding it would mean DC Tester holding back whenever it sees the app working; I've left that for later. |
Part 2 of deepsealabs/libdc-swift#78. Stacked on #15: this branch contains #15's commit too, so please merge #15 first; after that only the second commit (
d5746ba) is new here.Problem
On the same phone, DC Tester and the Suunto app share one BLE link to the watch. When the Suunto app opens a session (a fresh launch, a reconnect), the watch answers its hello on that link and ends our
/Datastream: either a chunk is cut off mid-frame (the hello reply is usually swallowed with it inhdlc.c) orUNSUBSCRIBE_REPLYarrives with status 404. Today that truncates the dive or fails the download, which is why testers are told to block the Suunto app's Bluetooth.What this does
UNSUBSCRIBE_REPLYbefore we unsubscribed, or a torn / CRC-bad packet. Ordinary requests that see another app's hello reply just keep waiting for their own reply, as before.DC_EVENT_WAITING(hosts can show "paused, the Suunto app is syncing"), then reads and discards packets until the link has been quiet for 15 s. That's longer than the Suunto app's ~10.6 s hello retry, so the app gets in and syncs while we wait. The pause lasts as long as the app's traffic keeps flowing, up to an hour, and is cancellable.Testing
-Wall -Wextra).Logs, timelines and the four problems found along the way are in deepsealabs/libdc-swift#78.
Not covered yet
Happy to restructure or split further if you'd prefer.