fix(logs): open log files from the UI task (#7513)#7523
Conversation
Log files were opened lazily from logsWrite(), which runs on the FreeRTOS timer daemon task (priority 2). Telemetry frame polling is dispatched to that same task via async_call_isr(). When the LOGS directory is large (thousands of files), f_open() with FA_OPEN_ALWAYS has to scan the whole FAT directory and blocks the timer task long enough to starve telemetry polling, producing a brief "Telemetry lost" / "Telemetry recovered" at log start. Move the file open/close into the new logsHandle(), called cyclically from perMain() on the menus/UI task (priority 1). logsWrite() now only appends a line to an already-open file and never blocks on f_open(). Because the timer/telemetry task is higher priority, it preempts the directory scan running on the UI task, so telemetry keeps flowing while the log file is being created. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughRefactors SD card logging so the UI task owns log file lifecycle and timer control, while the timer task only appends to an already-open file. Adds shared one-time error display handling and updates the caller and header declarations. ChangesLog lifecycle refactor
Estimated code review effort: 3 (Moderate) | ~25 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@radio/src/logs.cpp`:
- Around line 104-110: The sticky error_displayed state is preventing
logsWrite() from resuming while logging remains enabled, and logsHandle() is not
closing the open file after write-side failures. Update the logging flow in
logsWrite(), logsHandle(), and the related close/retry paths so any write error
clears or resets the error state, closes g_oLogFile.obj.fs when appropriate, and
allows the timer-driven callback to recover without requiring the user to toggle
logging.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4c9f59a7-dacc-4bda-b2b7-633d0ca7eef7
📒 Files selected for processing (3)
radio/src/logs.cppradio/src/main.cppradio/src/sdcard.h
After logsWrite() reported a read/write error it set error_displayed and then no-op'd on every timer tick, leaving the file open and the timer firing empty callbacks until the user toggled logging off and on. The open-error path in logsHandle() already retried automatically, so the two error paths were inconsistent. Handle a pending error in logsHandle() (UI task): stop the timer, close the file, and retry a fresh open through the existing open path. A successful (re)open clears error_displayed and resumes logging; while the error persists the timer stays stopped and the file closed, and the popup remains deduplicated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The previous change retried the open on every perMain() cycle after any error. For a persistent hard error (bad card / corrupted FS) that means rescanning a potentially huge LOGS directory indefinitely, which is wasteful and cannot succeed. Only a full SD card is treated as recoverable: sdIsFull() is a cheap check (no directory scan) and the condition clears when the user frees space, so logging resumes automatically. Any other error now stops logging until the user re-enables it (which clears error_displayed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Log file write is still done in timer callback so update frequency should be the same. |
Fixes #7513.
Problem
On the X9D+ (and other targets), telemetry briefly drops ("Telemetry lost" / "Telemetry recovered") the moment SD-card logging starts. The reporter traced it to the size of the
LOGS/directory: ~2,250 files caused the glitch every time, while an emptyLOGS/did not. It is a regression from 2.10.6.Root cause
Log files were opened lazily from
logsWrite(), which runs on the FreeRTOS timer daemon task. Telemetry frame polling (_poll_frame) is dispatched to that same task viaasync_call_isr()/xTimerPendFunctionCallFromISR(). WhenLOGS/is large,f_open(..., FA_OPEN_ALWAYS | ...)has to scan the whole FAT directory and blocks the timer task long enough to starve telemetry polling.The
_poll_framecoalescing already present does not help here — coalescing prevents queue flooding, but nothing runs while the daemon task is blocked insidef_open().Fix
Move the log-file open/close into a new
logsHandle(), called cyclically fromperMain()on the menus/UI task (priority 1).logsWrite()now only appends a line to an already-open file and never blocks onf_open().Because the timer/telemetry task (priority 2) is higher priority than the UI task, it preempts the directory scan now running on the UI task, so telemetry keeps flowing while the log file is being created.
Concurrency
The timer task (
configTIMER_TASK_PRIORITY= 2) cannot be preempted by the UI task (MENUS_TASK_PRIO= 1), sologsClose()/error_displayedcannot race an in-flightlogsWrite()on the target. Only the simulator (timer_nativehost thread) is truly concurrent, andFF_FS_REENTRANT = 1covers that.Testing
LOGS/, arm, watch for telemetry drop) — @Fpv191, a test build would help confirm.Backports for 2.11 and 2.12 are prepared in separate PRs.
🤖 Generated with Claude Code
Summary by CodeRabbit