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>
ArduinoSerialInterface::isConnected() always returned true, so any
companion build with a USB interface believes a client is attached from
boot onwards. Two user visible effects:
- new message notifications never fire, because MyMesh only notifies
the UI (display, buzzer) while no client is connected
- on builds that also expose BLE the home screen shows '< Connected >'
instead of the BLE pairing PIN, so a freshly flashed device cannot be
paired at all
Add an optional connection check callback and wire it up per platform:
native USB-CDC (TinyUSB on nRF52/RP2040/ESP32 with USB_MODE=0) exposes
real DTR through (bool)Serial. The ESP32 USB-Serial-JTAG peripheral has
no DTR concept - it reports 'connected' as soon as the host enumerated
the device - so fall back to frame activity there. Plain UARTs keep the
previous assume-connected behaviour.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Introduced consistent preferences for external LoRa FEM RX and TX gain settings in NodePrefs. Updated companion MyMesh to apply these settings during initialization and transmission. Added unit tests to verify the round-trip serialization of these new preferences.
CustomLR1110::startReceive() passed RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED
(1<<4 = 16) as RadioLib's first argument, which is the RX *timeout*, not an
IRQ mask. At the LR11x0's 30.52us tick that armed the receiver for ~488us, so
it dropped out of RX before any packet could arrive and the node received
nothing at all -- while transmitting normally.
Symptoms on a SenseCAP T1000-E: tx_air_secs rising, rx_air_secs stuck at 0,
recv_errors 0, and the noise floor pinned at the -120 clamp because
getCurrentRSSI() never sampled a live receiver.
Pass RADIOLIB_LR11X0_RX_TIMEOUT_INF (continuous RX), which is what
LR11x0::startReceive() itself uses, keeping the PREAMBLE_DETECTED flag in the
reported IRQ flags as intended.
Introduced in ea5d7c8b ("LR1110: add PREAMBLE_DETECTED to reported irq flags").
Verified on two T1000-E units: with only the repeater fixed it began receiving
(last_rssi -29, SNR 17.0) while the unfixed companion stayed deaf; fixing both
brought up the link in each direction.
If Bluefruit.begin fails, BLE OTA mode won't actually start and the board might require a reboot to reattempt.
Fixes:
- Bluefruit.begin returns false in NRF52Board.startOTAUpdate if OTA mode fails to start. User is notified of the fault through existing error message in CommonCLI and can reattempt "start ota" command.