Load-testing the restored token bucket at 'set dutycycle 1' showed MQTT
capture dropping to exactly the TX rate. Queued retransmissions hold static-
pool packets with no expiry, so throttling parks the whole pool in the send
queue; Dispatcher::checkRecv() then discards received packets before logRx()
ever feeds the bridge — each completed TX frees exactly one packet for
exactly one more RX.
Observer builds now use RxReservePacketManager (fork-owned header): once the
free pool drops below a quarter of the pool, outbound packets are refused and
freed, so RX allocation and MQTT capture continue at full rate while the node
sheds repeat load it has no TX budget for anyway. Non-observer builds keep
upstream pool behavior via the same factory; StaticPoolPacketManager stays
byte-identical to upstream.
companion_radio has its own NodePrefs without radio_fem_rxgain (matching
upstream, which doesn't wire companion either), so the startup call added in
e905451d broke every companion build:
MyMesh.cpp:973: error: 'struct NodePrefs' has no member named 'radio_fem_rxgain'
It went unnoticed behind the pre-existing companion build failures.
Also port upstream's FEM LNA overrides for heltec_t096 and heltec_tracker_v2
verbatim (board overrides + isLNAEnabled/const getters), so all three boards
upstream wires now match instead of reporting unsupported. Both variant files
compile; those targets still fail overall on the pre-existing non-observer
MQTT-source build-config issue (unchanged with this work stashed).
Completes the FEM RX-gain restoration begun in the CAD/prefs change, which
persisted radio_fem_rxgain but didn't yet drive the hardware. Also dropped
by the 22eb9b87 revert; restored to match upstream.
- MainBoard: setLoRaFemLnaEnabled()/canControlLoRaFemLna()/isLoRaFemLnaEnabled()
virtuals (default: can't control — non-FEM boards report unsupported)
- heltec_v4: board overrides driving loRaFEMControl; LoRaFEMControl gains the
isLNAEnabled() getter (it already tracked lna_enabled and drove the FEM)
- CLI: `set radio.fem.rxgain on/off` / `get radio.fem.rxgain` (guarded by
canControlLoRaFemLna, so it reports "unsupported" on non-FEM boards)
- app startup applies the persisted pref: board.setLoRaFemLnaEnabled(
_prefs.radio_fem_rxgain), beside setRxBoostedGainMode
Default is ON (upstream), so on FEM boards the LNA is enabled after upgrade —
a real reception behavior change to confirm on hardware. The other FEM
variants (heltec_t096/tower_v2/tracker_v2) need the same small board-override
addition; until then `radio.fem.rxgain` reports unsupported there (no
regression — status quo).
Builds: heltec_v4 repeater-observer + room-observer (FEM board), Heltec_v3
repeater (non-FEM, base virtuals no-op). NEEDS on-device validation on a
Heltec V4.
Continues restoring features dropped by the 22eb9b87 revert. Both were
upstream-tested code, not intentional fork removals.
CAD (hardware Channel Activity Detection / listen-before-talk before TX),
fully restored and functional:
- NodePrefs.cad_enabled + `set cad on/off` / `get cad` CLI (default off)
- RadioLibWrapper: _cad_enabled + setCADEnabled() + the scanChannel()/CAD
branch in isChannelActive() (Phase 1 already restored the Dispatcher hook)
- getCADEnabled() overrides in the repeater/room/sensor apps (return the
pref) and companion (always on, matching upstream)
radio_fem_rxgain: the NodePrefs field + /com_prefs persistence are restored
here at upstream's exact offsets (293 fem, 294 cad), which makes /com_prefs
byte-identical to upstream through the tail. The field is persisted and
defaults on (upstream default), but the per-board LNA *driving* + the
`radio.fem.rxgain` CLI are deferred to the FEM-hardware change (they depend
on board methods and want per-board bench testing).
The new-format /com_prefs tail grows from 3 to 5 bytes; the old-format
detection threshold and the host migration harness are updated accordingly
(all scenarios pass, incl. the non-MQTT-build variant).
Builds: Heltec_v3 repeater, repeater-observer, room-observer. (sensor /
plain-room / companion fail only on the pre-existing Timezone.h include
issue, unrelated to these changes.)
Refactored the handling of observer-related settings by moving them from
NodePrefs to a new MQTTPrefs structure. This change centralizes MQTT,
WiFi, timezone, SNMP, and alert configurations, improving code organization
and maintainability. The new structure allows for better separation of
concerns and prepares the codebase for future enhancements.
Implemented new commands for configuring and diagnosing NTP server
settings in the MQTT bridge. Users can now set a custom NTP server
and probe connectivity to configured servers. This enhancement
improves time synchronization reliability for JWT authentication
and provides better diagnostics for NTP connectivity issues.
Implemented functionality to generate and compare partition-table
signatures during OTA updates. This enhancement ensures that the
target build's partition layout matches the device's actual layout,
improving the reliability of OTA updates and preventing issues
related to partition changes.
Enhanced the firmware versioning system by appending a build number
suffix when available, allowing for better tracking of published builds.
This change improves the OTA update process by providing clearer
versioning information in the embedded firmware string.
Added support for deferred OTA updates in the MyMesh class, allowing
the system to schedule firmware updates to occur after a confirmation
reply is sent. This change improves the user experience by ensuring
that the update process does not block the main application loop,
allowing for smoother operation during firmware updates.
Before this commit, there was no way to set a different max hop count
for unscoped messages.
Now with this change, by defaul it tracks the flood.max setting, until
a user provides a flood.max.unscoped value, which tax precidence for
packets if ROUTE_TYPE_FLOOD is true.
AUTO_OFF_MILLIS is a power-save feature aimed at battery use. When the
board reports isExternalPowered() == true (USB or other DC source),
blanking the screen serves no purpose — there's nothing to conserve.
But OLEDs are vulnerable to burn-in with static content, so this
behaviour is gated behind a new build flag KEEP_DISPLAY_ON_USB. Default
is unchanged from upstream — the display blanks after AUTO_OFF_MILLIS
on USB or battery. Variants that ship with an LCD instead of an OLED
(e.g. heltec_t096) can opt in by adding -D KEEP_DISPLAY_ON_USB to
their env, gaining always-on-while-powered without exposing OLED users
to burn-in risk.
When the flag is enabled, the implementation refreshes _auto_off every
loop iteration while externally powered, so the timer naturally counts
a fresh AUTO_OFF_MILLIS window from the moment power is removed —
no instantaneous-blank-on-unplug.
Applied to all three companion_radio UI flavours (ui-new, ui-tiny,
ui-orig). Boards without an isExternalPowered() override use the
base-class default in MeshCore.h (returns false), so battery-powered
behaviour is unchanged everywhere.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Framework for upcoming variant-specific PRs that add LED feedback during boot. The hook gives users visual cues that the device is busy and
shouldn't be interacted with until startup completes.
- Introduced two new MQTT presets: `meshcore-ca-1` and `meshcore-ca-2`.
- Updated documentation to reflect compile-time configuration options for MQTT defaults, including slot presets, IATA, and timezone settings.
- Removed legacy default MQTT settings from the code, now relying on the new configuration approach.