Fix: ESP32 KISS modem becomes permanently unresponsive under TX backpressure#2646
Draft
agessaman wants to merge 2 commits into
Draft
Fix: ESP32 KISS modem becomes permanently unresponsive under TX backpressure#2646agessaman wants to merge 2 commits into
agessaman wants to merge 2 commits into
Conversation
…fer stalls. Introduce frame write management and update related methods for improved handling of serial communication. Adjust platform configurations for USB-CDC to enhance reliability on ESP32.
…nd timeout handling for USB-CDC. Enhance documentation for better understanding of frame management and serial communication flow.
ripplebiz
reviewed
May 31, 2026
| } | ||
| } | ||
|
|
||
| void KissModem::writeFrame(uint8_t type, const uint8_t* data, uint16_t len) { |
Member
There was a problem hiding this comment.
Just wondering if a better approach is to pre-calc the total frame length, then introduce a new method like:
bool canWriteFrame(size_t len);
And for logic to be:
writeFrame( ... ) {
size_t total_len = ... ;
if (!canWriteFrame(total_len)) return; // bail, all or nothing
_serial.write( ... ); ...
}
Contributor
There was a problem hiding this comment.
I was thinking about the same, but looks like those buffers are quite small (like 64 bytes in some cases). Need some sleep first, but its an interesting one to look into.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On ESP32-S3 boards (Heltec V4, Station G2), the KISS modem would stop responding after a while and stay dead—
SetHardwarePING (0x17) timed out and the condition survived a host service restart, forcing the pyMC_repeater client into no-radio mode. nRF52 (RAK4361) on identical firmware was unaffected.Root cause
The ESP32 modem ran over Arduino TinyUSB
USBCDC(ARDUINO_USB_MODE=0), which wedges under TX backpressure:USBCDC::write()busy-spins indefinitely while "connected" (itstx_timeout_msonly guards the lock acquire, not the send loop), and RX events post to a 5-deep queue withportMAX_DELAY. Sinceloop()is single-threaded and the ESP32-S3 has no DTR/RTS→EN reset, nothing recovers it. nRF52 is immune (hardware UART, non-blocking FIFO writes).Confirmed by a deterministic repro (flood the modem while never reading replies → permanent wedge) and a heartbeat LED that kept blinking while the data path was frozen, isolating the hang to the TinyUSB layer, below app code.
Fix
Switch the ESP32 KISS envs to the ESP32-S3 USB-Serial-JTAG peripheral (
HWCDC,ARDUINO_USB_MODE=1), whosewrite()is bounded (tries/timeout countdown, not an infinite spin) and which posts RX from ISR.variants/{heltec_v4,station_g2}/platformio.ini:build_unflagsthe board default=0, set=1(a bare-Uis reordered after the-Dby SCons).examples/kiss_modem/: transport-neutral hardening—non-blocking writes that drop a frame instead of stallingloop()when the TX buffer is full, plussetTxTimeoutMs(). A dropped reply is harmless; the host retries.Validation
heltec_v4_kiss_modem,Station_G2_kiss_modem,RAK_4631_kiss_modem.nm:HWCDClinked, zero TinyUSB symbols.A Wrinkle
ARDUINO_USB_MODE=1changes the USB descriptor, so the/dev/serial/by-id/path becomesusb-Espressif_USB_JTAG_serial_debug_unit_<MAC>-if00.