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.
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.