Skip to content

Make telemetry lines atomic with a scoped sink hold - #73

Merged
georgesleen merged 1 commit into
mainfrom
telemetry-line-mutex
Aug 16, 2026
Merged

Make telemetry lines atomic with a scoped sink hold#73
georgesleen merged 1 commit into
mainfrom
telemetry-line-mutex

Conversation

@georgesleen

Copy link
Copy Markdown
Collaborator

About 6% of telemetry lines arrive spliced (114 of ~1900 in a 60 s bench capture). Two causes, both fixed here.

Lines were never atomic

Four tasks write to the one TelemetrySink, and a telemetry line is several Print calls long: a tag, its fields, then the newline. Nothing held the sink across those calls, so another task could cut in mid-line. Locking each write() would not have helped, because the line boundary is above that level. main.cpp and persist_task show the same shape outside the F/I/M/G records, where one message is a print followed by a println.

TelemetrySink now hands out a Line: an RAII hold taken for one line and released at end of scope. It is the only thing that implements Print, so the sink itself can no longer be written to directly and interleaving stops being something a caller has to remember. That matters here because the failure is silent, a spliced line still parses as two damaged ones.

The GNSS task bypassed the sink

gnss_task wrote its # PVT, # AUX and # GNSS diagnostics straight to Serial, so they raced with the sink's own Serial writes and never reached RTT or the bench UART at all. It now takes a TelemetrySink & like the other three tasks and prints through it.

Notes

I2cTransport::scan keeps its plain Print & parameter and the caller opens the line around the whole call, so lib/bno08x_imu gains no dependency on the firmware's sink.

A Line blocks other tasks' telemetry while held, so the hold is scoped to a single line everywhere and never spans a wait.

The mutex is created in the constructor. If the FreeRTOS heap were exhausted there, xSemaphoreCreateMutex returns null and writes fall back to unlocked rather than dereferencing it; on this firmware that case means boot has already failed.

Verification

217 native tests pass and pio run -e pico2 builds. Not yet verified on hardware: the board dropped off USB before the corruption rate could be re-measured. The check to run is the same 60 s capture, expecting the corrupt-line count to go to zero.

Co-Authored-By: Claude <noreply@anthropic.com>
@georgesleen
georgesleen force-pushed the telemetry-line-mutex branch from da96d41 to 5f08fc5 Compare August 16, 2026 20:26
@georgesleen
georgesleen merged commit f1cc83e into main Aug 16, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant