Commit Graph
1287 Commits
Author SHA1 Message Date
JakubandClaude Opus 5.5 1620df6c10 fix: move FEAT_RX_POWERSAVE to Features.h; no extra [LOC] on "Stop after" change
- FEAT_RX_POWERSAVE lived in MyMesh.h, but SettingsScreen.h only pulls
  Features.h -- it saw the flag only via include order, and an undefined
  macro in `#if` silently reads as 0, which would split the build the day
  it's flipped to 1. Now defined in Features.h (the home of FEAT_* flags),
  which MyMesh.h includes; comment/doc pointers updated.
- Changing Live Share's "Stop after" restarted the whole session, forcing
  an immediate re-announce [LOC] although the position hadn't changed. It
  now restarts only the duration clock (restartLocShareClock()).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 15:50:37 +02:00
JakubandClaude Opus 5.5 22eba3c244 fix(radio): keep the radio serviced while an e-ink refresh blocks the loop
GxEPD2 polls the panel's BUSY pin for the whole refresh (up to ~1-2s),
stalling the main loop. A TX finishing in that window left the SX126x in
standby -- deaf -- until the refresh ended; packets received meanwhile could
be lost (only the latest is readable, and a later CRC failure rejects a good
one still pending). Hook GxEPD2's busy callback to finish TX / drain RX into
a small staging queue and re-arm right away, without touching dispatch/UI.
Wired only where the display driver supports it (GxEPD2: the two e-ink Solo
boards); OLED and sim builds are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 15:21:38 +02:00
JakubandClaude Sonnet 5 81cee3846f feat(ui): flag unread counts understated by a full history ring
DM and channel history each live in a fixed-size ring (32 DM / 48
channel entries). A conversation that outpaces reading can fill its
ring, evicting the oldest entries — including unread ones that were
never opened — so the unread badge silently caps at ring capacity
instead of reflecting how many messages actually arrived.

MessageHistory now tracks a sticky per-channel overflow flag, set at
the exact point an unread channel entry gets evicted (mirroring the
existing unread-decrement logic) and cleared once the count reads back
down to 0. DMUnreadEntry gains the same bit for DM contacts, detected
by comparing the raw per-contact counter against actual ring occupancy
on each new message (the DM ring, unlike the channel ring, doesn't
proactively decrement on eviction).

DisplayDriver::drawUnreadBadge/unreadBadgeWidth/fmtBadgeCount take an
optional overflow flag (default false, existing call sites unchanged)
that appends "+" to the badge. Wired into every place an unread count
is shown: DM/favourites and channel lists, the DM/Channels/Rooms
mode-select screen, favourite tiles, and the aggregate "Msgs" field on
the clock and lock dashboards plus the Messages home-carousel page.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 13:45:07 +02:00
JakubandClaude Sonnet 5 26e6bc877a fix(radio): disable Pwr save (RX duty-cycle) — unsafe across mixed firmware
Field report: a user on the stock SF8 "EU/UK (Narrow)" preset saw reception
drop from ~1-5 msg/min to ~1/3h with Pwr save on, unaffected by a better
antenna. Root cause, confirmed against the SX1262 datasheet and RadioLib's
own maintainers (jgromes/RadioLib#1597, closed as inherent chip behaviour):
the SX126x's duty-cycle preamble detection needs the sender's actual
preamble to closely match what we've configured our receiver to expect.
A mismatch — e.g. a repeater still on pre-v1.16 firmware sending 16 symbols
against our 32 — doesn't cost a little sensitivity, it silently drops every
packet from that sender regardless of signal strength. There's no local
parameter fix: shortening minSymbols to tolerate shorter preambles directly
shortens the wake-window's correlator dwell time, trading the preamble
mismatch failure mode for a marginal-signal one instead. Checked whether
IoTThinks' MeshCore fork solved this differently — it doesn't hit the
problem at all, because its "power saving" only light-sleeps the MCU on the
radio's own GPIO interrupt and never touches RX duty-cycle.

examples/companion_radio/MyMesh.h now defines FEAT_RX_POWERSAVE 0, gating
out the Settings row, the Diagnostics RXPS watchdog row, and every call site
that would apply rx_powersave to the radio or CAD auto-enable — including
forcing setPowerSaving(false) unconditionally so a stale rx_powersave=1 byte
from before this change can't do anything either. The real duty-cycle
implementation in RadioLibWrapper/CustomSX1262Wrapper is left in place,
unneutered, for if a network-wide compatibility mechanism (e.g. the
still-unused ADV_FEAT1/FEAT2 advert bits) is ever built to make it safe.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 20:04:42 +02:00
JakubandClaude Sonnet 5 745aefcee1 fix(radio): init SX1262 at a safe power on boards with an external-PA curve
95e3cf26 raised LORA_TX_POWER to 30 for the GAT562 30S, but CustomSX1262 passed
it straight to RadioLib's begin(), whose setOutputPower() rejects anything over
22 dBm (ERR_INVALID_OUTPUT_POWER) -- so radio init would fail on that board.
With NUM_PA_POINTS/TX_GAIN_LORA defined, LORA_TX_POWER is a radiated power, not
a chip register value: init at register 0 and let RadioLibWrapper::setTxPower()
apply the real power through the curve right after (companion applyApc(),
repeater setTxPower at begin). Other boards are unchanged.

Verified by build (GAT562 30S companion + repeater, Heltec V3 repeater) and by
reading RadioLib's SX1262::checkOutputPower(); not tested on hardware.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 13:19:46 +02:00
JakubandClaude Sonnet 5 95e3cf2618 feat(radio): honest TX power for GAT562 30S external PA
gat562_30s_mesh_kit has an always-on external PA rated at +30dBm, but the
firmware wrote tx_power_dbm straight to the SX1262 register (capped at 22),
so the app/CLI/UI never matched the real radiated power and couldn't ask
for more than 22 even though the hardware supports it.

Add a generic, macro-gated PA gain-curve resolution in
RadioLibWrapper::setTxPower() (the single choke point every TX-power path
already funnels through), reusable by any future board with a similar PA.
For this board, reuse the vendor-measured 869MHz curve from the open
upstream Meshtastic PR that added it for the same physical module
(meshtastic/firmware#11212): pick the lowest SX1262 setting whose measured
output reaches the requested dBm, clamped at the PA's saturation knee.
Bump LORA_TX_POWER/MAX_LORA_TX_POWER to 30 for this variant only -- the
other three GAT562 boards use the SX1262's own PA_BOOST (22dBm, no
external PA) and are unaffected.

Since a request below the PA's floor gain (14dBm) still radiates at that
floor, also make CommonCLICallbacks::setTxPower() return what was actually
applied, and have every setter (BLE CMD_SET_RADIO_TX_POWER, CLI "tx",
simple_repeater/room_server/sensor) persist and report that value instead
of the raw request -- so tx_power_dbm never silently disagrees with the
physical output in either direction.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 12:54:48 +02:00
Jakub 333d739103 Revert "fix(ui): marquee's hold no longer dominates a barely-overflowing label"
This reverts commit e300db7908.
2026-09-08 11:38:31 +02:00
JakubandClaude Sonnet 5 e300db7908 fix(ui): marquee's hold no longer dominates a barely-overflowing label
User report: a repeater path popup's short "?A1B2C3D4"-style hop tags
(often just a couple pixels over the box width) felt stuck rather than
scrolling, while longer names (Nodes list) already felt right after the
recent marqueeHoldMs() speedup.

Root cause: the swing marquee's hold applies uniformly regardless of how
much text is actually hidden. When only 1-2 codepoints overflow, the full
cycle is hold + a single, barely-there step + hold + step back -- nearly
all hold, for almost no new information revealed each side. New
marqueeHoldForSkip(skip_cp) scales the hold down (to 1/3 or 1/2) when the
computed reveal distance is small; longer overflows keep the full hold,
since there's real text worth pausing to read.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 11:12:23 +02:00
JakubandClaude Sonnet 5 1f41b3a1b8 docs(release-notes): catch up v1.27 with missing entries; tune(ui): faster marquee hold
release-notes.md was missing three shipped changes: the Msg-wake toggle +
all-home-pages default, the repeater advert-interval default (2min->6min),
and three Fixes (settings-persist-on-reboot, RTC bootstrap floor-not-
rollback, ESP32 diagnostics heap/stack).

marqueeHoldMs() reverted 1500/2500 -> 700/1200 (OLED/e-ink) -- the longer
hold made the swing-marquee's full reveal cycle too slow for long message
previews.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 10:12:58 +02:00
JakubandClaude Opus 5 c7d0cd23b6 fix(rtc): bootstrap from contacts is a floor, never a rollback
BaseChatMesh::bootstrapRTCfromContacts() called setCurrentTime(latest+1)
unconditionally. The newest contact's lastmod proves the clock must be at
*least* that late -- it says nothing about it being any earlier -- so on
any node that already has a better time source (a board with a real RTC,
or the Emscripten sim whose SimRTCClock is backed by the host's wall
clock) this dragged a correct clock backwards to whatever timestamp
happened to be persisted alongside the contact list. Measured in the
sim: ~9s behind real time after every reboot, growing with how long the
previous session ran.

Also adds sim_test_sync_time(epoch_secs) next to the other
SIM_PLATFORM/__EMSCRIPTEN__ test hooks, so a host page can re-anchor the
RTC on every (re)boot. The clock is live state the real mesh writes to at
runtime -- a peer whose own clock runs ahead pushes ours forward, which
is right on a node with no better source and, with meshcore-solo-site's
cross-visitor relay, means one skewed visitor can drag everyone. On a
demo running on someone's computer, "reset the device" should also mean
"the clock is correct again".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018iubftDmKNWmkNnhJRz8UH
2026-09-04 20:34:36 +02:00
JakubandClaude Sonnet 5 f61d6832a7 feat(sim): real buzzer/RTTTL sound via Web Audio
genericBuzzer (src/helpers/ui/buzzer.h/.cpp) gets a third platform branch,
#elif defined(SIM_PLATFORM), alongside the existing NRF52 (direct PWM) and
NonBlockingRtttl paths -- purely additive, no changes to either real-hardware
branch. It reuses the NRF52 branch's already hardware-free RTTTL parser
(_parseHeader/_parseNext/_noteFreq, now shared via a widened guard) but
tracks (current frequency, note-end-time) instead of touching real PWM/timer
registers, advancing on plain millis() polling from loop() -- same
non-blocking shape UITask already drives every tick.

Wired into the sim build the same way every real board sets its buzzer pin
(-D PIN_BUZZER=<n> in build_flags/DEFINES; here it's a dummy sentinel since
there's no real pin, just something to activate the existing #ifdef
PIN_BUZZER guards in UITask.h/.cpp/SoundNotifier.h unchanged), plus two new
small UITask accessors (isBuzzerPlaying/buzzerFreqHz/buzzerVolume) and three
EMSCRIPTEN_KEEPALIVE exports so a host page can poll the buzzer's state.

Browser side: one Web Audio oscillator+gain per companion instance (index.html
single-instance; mesh.html per A/B, not R which is headless), created lazily
on the first real user gesture (AudioContext autoplay policy), polled every
20ms and mapped to the oscillator frequency/gain -- so every notification
sound, ringtone, alarm, and volume-blip that already worked on real hardware
now actually produces audio in the browser, unchanged at the call-site level.

Verified end-to-end with real RTTTL playback traces (not just "no errors"):
the startup jingle's exact note frequencies (C6/E6/G6) and a real DM-received
notification triggering the receiving instance's Web Audio gain node from 0
to its mapped volume and back, matching the actual "MsgRcv3" melody's notes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 13:59:26 +02:00
JakubandClaude Sonnet 5 9cfb58a60b feat(sim): two-device messaging + repeater relay over a JS ether
Ports examples/simple_repeater to variants/sim/ (new sim_simple_repeater
native env + build_wasm_repeater.sh) and adds a JS "ether"
(variants/sim/web/mesh.html) that bridges two real companion_radio WASM
instances through a real simple_repeater instance in a strict A<->R<->B
topology (no direct A-B link), proving genuine relay routing rather than
a shortcut.

Also fixes multi-instance issues Phase 2's single-instance design never
surfaced: SimDisplayDriver's canvas context/id caching was keyed on a
single global instead of per-instance, and both wasm builds were missing
_malloc/_free/HEAPU8 runtime exports needed for the ether to poke bytes
into an instance's memory.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 09:14:15 +02:00
Jakub 8f4c92a217 feat(sim): add variants/sim/ — real companion_radio firmware on native + Emscripten
New board variant compiling the unmodified MyMesh/UITask/DataStore app
logic against real mesh::Radio/MainBoard/RTCClock/RNG interfaces, for
running the actual firmware outside embedded hardware:

- Native (plain g++, platform = native): ASCII-art display over stdout,
  stdin-driven input, local-disk-backed DataStore/IdentityStore.
- Emscripten/WASM (variants/sim/build_wasm.sh, since PlatformIO's native
  platform force-overrides any CC/CXX toolchain override back to system
  clang++): canvas-backed display, IDBFS-backed persistence across page
  reloads, JS-callable input via sim_enqueue_key(), emscripten_set_main_loop.

Real rweather/Crypto (AES128/SHA256/Ed25519) vendored unmodified and
proven working on both targets. variants/sim/web/index.html is a bare
verification harness, not the polished website embed.
2026-09-03 00:46:47 +02:00
JakubandClaude Sonnet 5 19b8d96ffe fix(diag): report real heap/stack stats on ESP32, not just nRF52
DeviceDiag::getHeapStats()/getStackFreeBytes() only had an implementation
for NRF52_PLATFORM; every other platform fell through to the 0/0 stub, so
Diagnostics > Live showed "N/A" for Heap free and Stack free on ESP32
boards (Heltec v3/v4) -- exactly the boards where that number is most
useful to see. Added an ESP32 branch using heap_caps_get_free_size()/
heap_caps_get_total_size() (MALLOC_CAP_8BIT, matching the general-purpose
heap `new`/malloc() actually draw from) and the same
uxTaskGetStackHighWaterMark() call nRF52 already uses, since Arduino-ESP32
runs on FreeRTOS too.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 09:02:53 +02:00
Jakub 8ceb420b43 fix(ui): marquee-scroll never advances past 63 characters
The animated marquee that lets a selected row scroll into view instead of
truncating behind an ellipsis uses a small "is this the same text as last
frame" buffer, _marquee_text[64], compared against the current frame's
temp_str[256] via strcmp(). For any text at or past that 64-byte cutoff,
temp_str simply has more bytes than _marquee_text can hold, so strcmp
always finds a difference at the truncation point -- is_new evaluates true
on every single call, which resets _marquee_skip_cp and _marquee_phase back
to the start every frame. Short labels and names (what this was written
for) stayed under the cutoff and animated fine; a longer message-body
preview -- letting a message be read from the list without opening
fullscreen, an emergent use of the same feature -- got stuck holding at its
first frame forever.

Bumped _marquee_text to 256 to match temp_str/window's own cap in the same
function, so the comparison is exact instead of silently truncated. Static
+192 bytes on the one global DisplayDriver instance; verified against RAM
usage on all four build targets (all comfortably under headroom).

This lives in src/helpers/ui/, shared with upstream, unlike the rest of
this session's ui-new/-only work -- kept as its own commit.
2026-08-31 20:10:09 +02:00
JakubandClaude Sonnet 5 1bb28296c2 feat(ui): marquee-scroll selected long names/labels instead of static ellipsis
Selecting a row whose ellipsized text overflows now animates a "swing"
marquee: holds at the start, scrolls to reveal the full tail, holds
there, then scrolls back and repeats. Unselected/non-overflowing text
is unchanged (still a static "..."). E-ink gets slower, coarser steps
(fewer, cheaper partial refreshes) than OLED; unchanged frames are
already skipped by the display's CRC diff, so idle holds are free.

Wired into every screen with a selectable row: home favourites, DM/
channel lists and message bodies, Settings, popup menus, Bot, Admin,
Nearby, Waypoints, Locator, Live Share, and the alarm screen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 17:17:55 +02:00
JakubandClaude Sonnet 5 12cf81b13f fix(ble): back off BLE send retries instead of hammering a marginal link
At the edge of BLE range the phone repeatedly drops and reconnects, and
each queued outgoing frame's write can block the main loop up to 100ms
(Bluefruit's notify() waits on a free HVN packet slot). The fixed 250ms
retry throttle re-triggered that blocking wait constantly during a bad
link, making the device feel almost unresponsive. Retries now back off
exponentially (250ms -> 2s cap) on repeated failure and reset on the
next successful send.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 15:39:57 +02:00
JakubandClaude Sonnet 5 f589b9b2d1 feat(companion): on-device scope + repeater scope filtering; fix CAD, UTF-8 truncation, Public channel, Nodes list, keyboard cursor
- Settings > Radio > Scope: type a community/region name on-device (derives
  the shared key the same "#name" -> SHA256 way as DEFAULT_FLOOD_SCOPE_NAME),
  previously only settable from a connected app.
- Tools > Repeater > Scope only + Extra scopes: only relay flood traffic
  matching the device's own scope or a comma-separated list of additional
  scopes, without changing what scope the device's own messages send under.
  No-op while unconfigured.
- getCADEnabled()/getInterferenceThreshold() were hardcoded off on
  companion_radio; CAD now auto-enables whenever RX power-save (duty-cycle)
  is active, since the noise floor isn't kept fresh during duty-cycle sleep.
- Message truncation to fit the send frame could split a multi-byte UTF-8
  character in half; now stops at the last complete character.
- The default "Public" channel was unconditionally re-added at every boot
  before the saved channel list was loaded, so deleting it never stuck.
  Only seeded now on a genuinely fresh device (no channel file yet).
- Tools > Nodes read contacts from the wrong starting offset, landing on
  internally-reserved bookkeeping slots instead of real contacts -- showed
  as blank "Unknown" rows and silently dropped that many real contacts off
  the end of the list.
- resetContacts() only cleared the first few reserved slots, not the whole
  contact table, contrary to its own comment; only reachable today via
  private-key import, fixed to match stated intent regardless.
- Keyboard's multi-line text preview could render the cursor on an empty
  line below short typed text instead of right after it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 10:40:50 +02:00
MarekZegare4 68527e7ba0 Merge upstream companion-v1.17.1 into power-saving
Pulls in real fixes: scoped-reply routing, RX boosted-gain restored
correctly after AGC reset, T-Echo Lite/Card SPI pin corrections
(unused pins now map to NRFX_SPIM_PIN_NOT_USED via 0 instead of -1)
and TCXO voltage fix, Heltec T096/T1 and MeshPocket pin fixes,
T-beam Supreme S3 display fix, LR2021 preamble/IRQ timeout handling.

None of the touched variants overlap with our active Heltec V3/V4,
Cardputer ADV, GAT562, or WioTracker builds.

# Conflicts:
#	examples/companion_radio/MyMesh.cpp
#	examples/companion_radio/MyMesh.h
#	examples/companion_radio/NodePrefs.h
#	src/helpers/radiolib/CustomSX1262Wrapper.h
#	src/helpers/radiolib/RadioLibWrappers.cpp
#	src/helpers/ui/SH1106Display.cpp
#	variants/lilygo_techo_lite/platformio.ini
#	variants/lilygo_techo_lite/variant.h
2026-08-14 15:58:23 +02:00
Scott Powell fcb9bdf209 * combine radio's entropy with CC310 RNG 2026-08-14 17:46:43 +10:00
MarekZegare4 64d4b2982b fix(ui): wake display on T-Echo KeyShield Home key, drop dead code
Home key toggles the keyboard backlight but wasn't going through
checkDisplayOn() like every other TCA8418 key, so it couldn't wake a
sleeping display or extend the auto-off timer.

Also: removed a no-op #elif branch in ST7789Display.cpp (same values as
the #else it duplicated), and ENABLE_SCREENSHOT on the Cardputer ADV
solo env, which does nothing since ST7789Display has no getBuffer().
2026-08-14 01:07:06 +02:00
ripplebizandGitHub b09cb27a1f Merge pull request #3106 from ViezeVingertjes/fix/scoped-reply-routing
Fix replies dropped when flood.max.unscoped is low
2026-08-13 15:00:37 +10:00
MarekZegare4andClaude Sonnet 5 c045df1da5 fix(power): stop GPS duty-cycling from starving !gps fix and fighting manual toggles
Two races between the new GPS duty-cycle scheduler and code that changes
GPS state independently of it:

- gpsDutyCycleLoop() capped every "GPS on" phase at a fixed 60s and would
  stop_gps() as soon as a fix went valid, with no awareness of an
  in-flight "!gps fix" bot request -- so a fix's own up-to-300s acquire
  window (and its 10s averaging phase) could get cut short by the
  scheduler shutting GPS off mid-request. MyMesh::isGpsFixPending() now
  feeds into UITask's existing "is anything live using GPS right now"
  hold, alongside trail/live-share/locator/nearby.

- setSettingValue("gps", ...) (Settings toggle, bot !gps on/off, CLI)
  starts/stops GPS directly without resetting the scheduler's own phase
  timer, so a manual toggle could land on a stale, already-expired
  deadline left over from before -- immediately re-stopping GPS a tick
  after turning it on. The phase timer now resets on every external
  change, so the next duty-cycle tick re-arms fresh.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 22:08:13 +02:00
ripplebizandGitHub e9edfc8e1a Merge pull request #3188 from oltaco/heltec-t096-pin-fix
Fix Heltec T096 Tx issue
2026-08-12 23:00:31 +10:00
taco f43e1cde89 Revert "t096 compiler layout workaround"
This reverts commit 9c60f9696e.
2026-08-12 22:28:36 +10:00
ripplebizandGitHub a4ab7f0e59 Merge pull request #3137 from agessaman/feat/station-g3-fem-prefs
Station G3: Expose, persist, and apply FEM gain preferences
2026-08-12 16:11:23 +10:00
ripplebizandGitHub 1cb308b694 Merge pull request #3182 from oltaco/t096-tx-workaround
Workaround for Heltec T096 transmit issue
2026-08-12 14:49:32 +10:00
taco 9c60f9696e t096 compiler layout workaround
see https://github.com/meshcore-dev/MeshCore/issues/3151
2026-08-12 14:04:50 +10:00
ripplebizandGitHub e027263d1e Merge pull request #3154 from fdlamotte/nrf52_hwcrypto_init
nrf52: call nRFCrypto.begin()/end() only once
2026-08-12 12:14:21 +10:00
JakubandClaude Sonnet 5 7699d8ffad Merge upstream companion-v1.17.0 (CAD) into power-saving
Adopts hardware Channel Activity Detection (wired into
RadioLibWrapper::isChannelActive() alongside our RSSI-threshold check
and RX duty-cycle power-save), MCU temperature telemetry, LR2021
standby workaround, DISPLAY_SCALE/FLIP overrides, NRF52Board
shutdownPeripherals() refactor, and misc upstream fixes.

Declines upstream's ConfigSerializer-based NodePrefs rewrite,
MultiSerialInterface/interface_manager, and UIColor palette system —
each would have broken large parts of the Solo-specific feature set
(NodePrefs fields, per-variant single serial_interface, enum-based
DisplayDriver::Color). Flagged as candidate follow-up migrations, not
permanent no's.

Also fixes several pre-existing bugs surfaced while chasing silent
merge breaks (stale newMsg() override signature in ui-tiny/ui-orig,
dead UIEventType::newContactMessage case, missing ContactsIterator
init), bumps FIRMWARE_VERSION/MESHCORE_VERSION to 1.17, and fixes a
missing <cstdlib> include that broke the native ConfigSerializer unit
tests.

Verified via 13+ pio run builds across ESP32/nRF52, all 3 companion UI
variants, and 7 display drivers, plus the full native unit test suite
(33/33 passing).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 17:25:35 +02:00
ripplebizandGitHub fbef2ff0dc Merge pull request #3164 from weebl2000/fix-tbeam-s3-display
Fix display issues on T-beam Supreme S3
2026-08-11 14:39:39 +10:00
agessaman e2aa7b98f9 feat(companion_radio): add external FEM gain preferences for RX and TX for companions
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.
2026-08-10 11:59:26 -07:00
Rastislav Vysoky 3138ad99ba move RadioLibWrapper noise_floor level message under special debug flag 2026-08-10 16:56:56 +02:00
Wessel Nieboer 32bd6d48d6 Fix T-beam Supreme S3 display 2026-08-10 13:39:16 +02:00
Huw DuddyandGitHub f6c25e6a25 Merge pull request #3158 from mepholic/bug/fix-rxgain-setting-post-agc-reset
Fix RX Boosted Gain setting after AGC reset is triggered
2026-08-10 17:31:38 +10:00
Dan Theisen 6f491f3033 RX Boosted Gain was set back to the compiled in value rather than the current/flash value set by the user when the ACG reset is triggered. This commit fixes this. 2026-08-09 18:11:35 -07:00
Florent ecb8c94560 nrf52: call nRFCrypto.begin()/end() only once 2026-08-09 14:46:23 -04:00
taco ce62c8b5d7 LR2021: add PREAMBLE_DETECTED bit and IRQ timeout logic 2026-08-09 21:41:22 +10:00
JakubandClaude Opus 5 05e57357d3 feat(boards): add M5Stack Cardputer ADV and LilyGO T-Echo Lite KeyShield
New M5Stack Cardputer ADV variant (ESP32-S3, ST7789 TFT, built-in TCA8418
QWERTY keyboard, PI4IOE5V6408 LoRa-cap IO-expander autodetect), and a
KeyShield accessory variant for the existing LilyGO T-Echo Lite (external
TCA8418 T9 keypad + AW21009 backlight driver). Both keyboards share one
ENV_USE_TCA8418 polling block in UITask.cpp::loop(), coexisting with the
unrelated CardKB support (different chip/address/flag).

Fixes carried in from the contributed T-Echo Lite code: swapped GPS RX/TX
pins, TX-LED hooks, TCXO voltage, missing GxEPD2_122_T61 panel include.
Fixed during integration: I2C bus was probed for an RTC before Wire.begin()
configured its pins on Cardputer ADV (silent RTC autodetect failure).

Added dedicated *_solo_dual release envs for both boards (auto-picked up by
the solo-firmware release workflow). Gave the T-Echo Lite KeyShield solo
build -Os/-Ofast-unflag like every other nRF52 solo build (was missing,
cut flash usage from 90.7% to 61.4%).

Ported the shared misc-fixed 6x9 font (full Latin/Greek/Cyrillic, opt-in via
OLED_MISC_FIXED_FONT) to ST7789Display for the Cardputer's on-screen
keyboard. ST7789Spi isn't Adafruit_GFX-based like the other single-font
drivers, and this panel's logical->physical scale is non-integer, so glyphs
are re-packed to XBM and blitted through the existing drawXbm(), which
already does correct fractional-scale boundary math, rather than
duplicating that logic.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 01:06:24 +02:00
JakubandClaude Opus 5 73744175b0 feat(power): RX duty-cycle watchdog, noise-floor recal, GPS duty-cycling
Three power-saving additions, prompted by comparing this fork's existing
RX duty-cycle support against IoTThinks/EasySkyMesh:

- RX duty-cycle watchdog: the SX126x's hardware RX<->sleep sequencer runs
  with no MCU polling, so a desync (a known failure mode) previously had
  nothing watching for it. A new watchdog samples the BUSY pin every tick;
  no transition for too long triggers a soft re-arm, then a full chip
  reset (with cached radio params reapplied, since std_init() resets to
  compiled firmware defaults) if that doesn't clear it. Soft/hard recovery
  counts surface on Tools > Diagnostics > Live as "RXPS wd s/h".

- Noise-floor recalibration during power-save: sampling was previously
  skipped entirely while duty-cycling, freezing int.thresh interference
  detection at whatever the floor was when power-save turned on. Now
  borrows a brief continuous-RX window once a minute to take a fresh
  reading before re-arming duty-cycle.

- GPS duty-cycling (Settings > System > "GPS pwr"): cycles GPS off between
  fixes instead of running it continuously. Each wake waits for a fix
  (capped at 60s) before sleeping again for the configured interval.
  Repurposes the long-dead NodePrefs::gps_interval byte rather than adding
  a new persisted field. A "is anything live using GPS right now" hold in
  UITask keeps GPS continuously on whenever trail recording, live-share,
  an armed Locator, or the Compass/Nearby-navigate view actually need a
  live fix, so none of those features degrade. Locator crossing-state is
  reset on each wake so a still-settling first fix can't read as a false
  geofence crossing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 22:14:19 +02:00
agessaman 23066573e5 fix(station-g3): expose FEM gain preferences 2026-08-06 15:29:14 -07:00
JakubandClaude Sonnet 5 2bde84a573 feat(heltec): solo dual-transport builds for Heltec V3/V4
Port the Wio Tracker L1 solo firmware (full on-device UI, dual BLE/USB
companion transport) to Heltec V3 and V4 OLED boards. Neither board has
a joystick or CardKB on-board, so each new env wires up both as optional
peripherals with default pins from what the board leaves free, gated
behind the existing UI_HAS_JOYSTICK/ENV_PIN_SDA+SCL flags.

DUAL_SERIAL was nRF52-only; added an ESP32 helpers/esp32/DualSerialInterface.h
counterpart so the flag isn't silently ignored on these boards. On V4's
native USB CDC, isClientConnected() also honours (bool)Serial (real DTR),
same as the nRF52 version; V3 has no native CDC so it stays BLE-only there.

Screen (SDA 17/SCL 18) and CardKB (SDA 3/SCL 4) confirmed working on real
V4 hardware.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 20:08:31 +02:00
Hacuchino-hash 3abe415cf7 Add RGB LED and haptic notifications for SenseCAP MeshTracker X1 2026-08-06 07:27:05 -05:00
ripplebizandGitHub 84e3a67bd7 Merge pull request #3115 from oltaco/meshnology_w12
Add support for Meshnology W12 and LR2021 Wrapper
2026-08-05 15:04:00 +10:00
taco 9d4f93806d LR2021: auto-LDRO for side detectors 2026-08-05 14:23:32 +10:00
taco 36e77671a2 LR2021: fix for hardware cad and side detectors 2026-08-05 14:23:32 +10:00
taco 696a82d7c2 LR2021 multi-SF support (side detectors) 2026-08-05 14:23:32 +10:00
taco 7cc16366cb add Meshnology W12 support and LR2021 wrapper 2026-08-05 14:23:29 +10:00
ViezeVingertjes b155081882 Merge remote-tracking branch 'upstream/dev' into fix/scoped-reply-routing
# Conflicts:
#	examples/simple_repeater/MyMesh.cpp
2026-08-04 11:49:58 +02:00
ViezeVingertjes fad11c90f3 Fix replies dropped when flood.max.unscoped is low 2026-08-03 22:57:12 +02:00