Commit Graph
1270 Commits
Author SHA1 Message Date
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
Huw DuddyandGitHub 9d902e634a Merge pull request #3076 from MDamon/fix/lr1110-rx-timeout
LR1110: fix startReceive() passing an IRQ bit as the RX timeout 🤖🤖
2026-08-03 23:02:52 +10:00
Huw DuddyandGitHub 5d940a1dc9 Clean up comments in startReceive method
Removed unnecessary comments regarding RX timeout and IRQ mask.
2026-08-03 22:57:34 +10:00
ripplebizandGitHub 626a82fd30 Merge pull request #2824 from NickDunklee/rak-advert-hw-encryption
feat: use nrf52 hardware crypto where we can
2026-08-02 15:35:33 +10:00
Mike Damon 78723d2565 LR1110: fix startReceive() passing an IRQ bit as the RX timeout
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.
2026-07-30 12:14:39 -04:00
ripplebizandGitHub 57ddada3ba Merge pull request #3004 from axhoff/agent/preserve-utf8-advert-names
Preserve UTF-8 boundaries in advert names
2026-07-30 12:59:59 +10:00
JakubandClaude Opus 5 f8b9e1acb8 feat(oled): misc-fixed 6x9 font on SSD1306 too, for GAT562 30S solo
The misc-fixed font (full Latin/Greek/Cyrillic) had only ever reached
SH1106Display and the e-ink driver. GAT562 30S -- like 24 other variants
-- uses SSD1306Display, which stayed on the built-in 5x7 font, so every
keyboard alphabet beyond ASCII and every accented contact name was
transliterated (Łódź -> Lodz) or drawn as a filled block.

Extract the renderer into MiscFixedRenderer.h rather than copying it:
Adafruit_SH110X and Adafruit_SSD1306 both derive from Adafruit_GFX and
glyph drawing is pure pixel plotting, so one implementation serves both
drivers (-79 lines from SH1106Display.cpp, same flash usage as before).
The header is .cpp-only by contract -- the font tables are static const,
so including it from a driver header would land a copy in every
translation unit.

On SSD1306 the path is opt-in behind OLED_MISC_FIXED_FONT, set only in
the two GAT562 30S solo envs: the font costs ~14 KB of flash and the
other 24 variants' repeater/companion builds have no keyboard to type
those alphabets on. Without the flag that driver is unchanged, verified
by building GAT562_30S_Mesh_Kit_repeater.

Drive-by consistency fix from the extraction: a newline in print() now
advances the cursor by yAdvance * text_size instead of a single yAdvance,
which was half a row short at setTextSize(2). The e-ink driver always
scaled it. No effect at size 1, which is everywhere the UI prints '\n'.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 22:48:06 +02:00
ripplebizandGitHub 6e39cff8a1 Merge pull request #3063 from oltaco/unify-irq-timeout
Unify IRQ timeout logic across all applicable radio types
2026-07-29 23:52:48 +10:00
ripplebizandGitHub 279ac78122 Merge pull request #3049 from liamcottle/feature/ethernet
Refactor Companion Interfaces + Add ThinkNode M7 Ethernet Support
2026-07-29 23:45:51 +10:00
taco 79eb7f5d8d LLCC68: add IRQ timeout logic 2026-07-29 23:34:01 +10:00
taco a3732e1c65 SX1268: add IRQ timeout logic 2026-07-29 23:34:01 +10:00
taco a5c323cc19 STM32WLx: add IRQ timeout logic 2026-07-29 23:33:51 +10:00
taco a7426de0bf LR1110: fix unnecessary IRQ clear 2026-07-29 23:18:15 +10:00
ripplebizandGitHub 9f73fbf870 Merge pull request #3062 from oltaco/fix-irq-clear
Fix unnecessary IRQ clearing
2026-07-29 22:37:30 +10:00
taco 20f55a4f42 fix unnecessary IRQ clear 2026-07-29 21:39:56 +10:00
JakubandClaude Opus 5 de16dbe32a fix(eink): drive the whole panel on every update, not just the changes
The screen faded as the device was used: text went grey a few updates
after it was drawn, while whatever had just changed stayed crisp. Only a
full refresh brought it back, and the next few updates ate it again.

A partial update is differential -- the controller drives only the pixels
that differ between its "current" (0x24) and "previous" (0x26) RAM and
leaves the rest to hold their own charge, which this panel doesn't do
well. Priming the previous-image RAM with the inverse of the incoming
frame makes every pixel a difference, so all of them get driven to their
target, in both directions.

The inverse matters: priming with flat white makes only white->black a
difference, so ink is re-driven but never erased and every screen ever
shown accumulates as a ghost. Confirmed on hardware, both ways round.

Costs one extra full-screen RAM write (a few ms of SPI). The refresh
itself is unchanged -- the waveform clocks the whole panel regardless of
how many pixels it drives -- so nothing got slower. Clearing ghosts is
still the periodic full refresh's job (Settings > Full rfsh), which can
now stay off.

The helper needs GxEPD2_BW's private _buffer/_page_height, so it goes in
the patched copy of the header, which every e-ink build now includes
unconditionally rather than only screenshot-enabled ones. All e-ink
variants pin GxEPD2 1.6.2, the version that copy tracks.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 15:02:28 +02:00
JakubandClaude Opus 5 b36cc7730b fix(ui): honour newlines in message text instead of overdrawing lines
A message containing a line break drew two words on top of each other in
the fullscreen reader. wrapLines() treated '\n' as an ordinary character:
it measured it via getCodepointWidth() -- which reports a full 6px cell
for it, since 0x0A sits below the font's first glyph -- and copied it into
the wrapped line. Both display drivers' print() then acts on '\n' by
resetting the cursor to x=0 and stepping down one row, so the tail of that
line was drawn straight over the following one.

wrapLines() now ends the line at '\n'/'\r' (CRLF counts as one break) and
consumes the byte rather than emitting it, preserving blank lines the
sender typed while still skipping degenerate empty wrap segments so the
loop can't stall. This covers the fullscreen view and the history list's
portrait bubbles, which share the function.

drawTextEllipsized() folds newlines into spaces for the same reason: it
draws one line clipped to max_width, and the compact one-line message
previews in the landscape list feed it raw message bodies. A space keeps
the words apart and measures the same, so the ellipsis maths is unchanged;
for names and labels it's a no-op.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 13:54:34 +02:00
entr0p1 4050b7d526 nRF52840 "start ota" Failure Recovery
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.
2026-07-28 10:14:59 +10:00