Add flow control to the companion USB interface

The contact sync streams up to MAX_CONTACTS frames back to back, but
ArduinoSerialInterface never checked whether the stream could take
them: isWriteBusy() returned false unconditionally, so MyMesh's pacing
gate had no effect, and writeFrame() called write() without looking at
availableForWrite(). On ESP32 (HWCDC, 256 byte TX ring) a host that
stalls for a moment makes the driver drop queued bytes silently, which
tears a frame in half - and since the framing is length prefixed with
no checksum and no resync marker, the client stays desynchronised for
the rest of the session. Reported as 'the app disconnects while
syncing contacts' on devices with a large contact list.

Add opt-in flow control: report busy until a whole frame fits, and
drop frames as a unit instead of tearing them. Enable it for the
companion USB interface and give HWCDC a bigger TX buffer with a short
write timeout, mirroring what kiss_modem already does.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Fable 5 committed 2026-08-14 20:16:20 +02:00
1 parent ab492ba187
commit a7724b9ec6
3 files changed
+31 -1

No files matched your search

+8 -1
View File
@@ -10,6 +10,7 @@ public:
private:
bool _isEnabled;
bool _flow_ctl;
uint8_t _state;
uint16_t _frame_len;
uint16_t rx_len;
@@ -19,7 +20,7 @@ private:
uint8_t rx_buf[MAX_FRAME_SIZE];
public:
ArduinoSerialInterface() { _isEnabled = false; _state = 0; _last_frame_ms = 0; _conn_check = NULL; }
ArduinoSerialInterface() { _isEnabled = false; _flow_ctl = false; _state = 0; _last_frame_ms = 0; _conn_check = NULL; }
void begin(Stream& serial) {
_serial = &serial;
@@ -36,6 +37,12 @@ public:
// Useful as an activity-based connection check where no DTR state exists.
uint32_t getLastFrameMillis() const { return _last_frame_ms; }
// Optional: only hand a frame to the stream when it fits into the TX buffer
// as a whole, and report busy while it does not, so bulk streams get paced.
// Only enable this for streams which really implement availableForWrite()
// (USB-CDC does, the Print default returns 0).
void enableFlowControl(bool enable) { _flow_ctl = enable; }
// BaseSerialInterface methods
void enable() override;
void disable() override;