crosspoint-reader/claude_notes/missing-serial-guards-2026-01-28.md
cottongin 8fa01bc83a
Some checks failed
CI / build (push) Failing after 2m16s
fix: prevent Serial.printf from blocking when USB disconnected
On ESP32-C3 with USB CDC, Serial.printf() blocks indefinitely when USB
is not connected. This caused device freezes when booted without USB.

Solution: Call Serial.setTxTimeoutMs(0) after Serial.begin() to make
all Serial output non-blocking.

Also added if (Serial) guards to high-traffic logging paths in
EpubReaderActivity as belt-and-suspenders protection.

Includes documentation of the debugging process and Serial call inventory.

Also applies clang-format to fix pre-existing formatting issues.
2026-01-28 16:02:13 -05:00

2.9 KiB

Serial.printf Calls Without if (Serial) Guards

Date: 2026-01-28
Status: Informational (not blocking issues)

Summary

The codebase contains 408 Serial print calls across 27 files in src/. Of these, only 16 calls (in 2 files) have explicit if (Serial) guards.

This is not a problem because Serial.setTxTimeoutMs(0) is called in setup() before any activity code runs, making all Serial output non-blocking globally.

Protection Mechanism

In src/main.cpp (lines 467-468):

Serial.begin(115200);
Serial.setTxTimeoutMs(0);  // Non-blocking TX - critical for USB disconnect handling

This ensures that even without if (Serial) guards, Serial.printf calls will return immediately when USB is disconnected instead of blocking indefinitely.

Files with if (Serial) Guards (16 calls)

File Protected Calls
src/activities/reader/EpubReaderActivity.cpp 15
src/main.cpp 1

Files Without Guards (392 calls)

These calls are protected by Serial.setTxTimeoutMs(0) but don't have explicit guards:

File Unguarded Calls
src/network/CrossPointWebServer.cpp 106
src/activities/network/CrossPointWebServerActivity.cpp 49
src/activities/boot_sleep/SleepActivity.cpp 33
src/BookManager.cpp 25
src/activities/reader/TxtReaderActivity.cpp 20
src/activities/home/HomeActivity.cpp 16
src/network/OtaUpdater.cpp 16
src/util/Md5Utils.cpp 15
src/main.cpp 13 (plus 1 guarded)
src/WifiCredentialStore.cpp 12
src/network/HttpDownloader.cpp 12
src/BookListStore.cpp 11
src/activities/network/WifiSelectionActivity.cpp 11
src/activities/settings/OtaUpdateActivity.cpp 9
src/activities/browser/OpdsBookBrowserActivity.cpp 9
src/activities/settings/ClearCacheActivity.cpp 7
src/BookmarkStore.cpp 6
src/RecentBooksStore.cpp 5
src/activities/reader/ReaderActivity.cpp 4
src/activities/Activity.h 3
src/CrossPointSettings.cpp 3
src/activities/network/CalibreConnectActivity.cpp 2
src/activities/home/ListViewActivity.cpp 2
src/activities/home/MyLibraryActivity.cpp 1
src/activities/dictionary/DictionarySearchActivity.cpp 1
src/CrossPointState.cpp 1

Recommendation

No immediate action required. The global Serial.setTxTimeoutMs(0) protection is sufficient.

If desired, if (Serial) guards could be added to high-frequency logging paths for minor performance optimization (skipping format string processing), but this is low priority.

Note on open-x4-sdk

The open-x4-sdk submodule also contains Serial calls (in EInkDisplay.cpp, SDCardManager.cpp). These are also protected by the global timeout setting since Serial.begin() and setTxTimeoutMs() are called before any SDK code executes.