- RepeaterScreen: drop the redundant "Rpt " prefix on the profile fields
(Preset/Freq/SF/BW/CR), matching Settings > Radio's own terminology --
the screen is already dedicated to the repeater's own profile, so the
prefix disambiguated nothing.
- Channel context menu: "Fav: yes/no" -> "Fav: ON/OFF", matching every
other toggle in the app.
- Settings (System tab): six labels left as raw concatenated identifiers
(AutoOff/AutoLock/TimeZone/LowBat/BattDisp/BzrVol) now read like their
space-separated neighbours (Auto pwr/Pwr save/DM sound/GPS pwr), and
BzrVol no longer clashes with "Buzzer" one row above it for the same
feature. Three value-label arrays also had one mismatched-case entry
fixed to match its siblings: Auto-off's "never" -> "OFF", Batt display's
"icon" -> "Icon", Sound's "built-in" -> "Built-in".
- ToolsScreen: re-enabled the mini-icons next to each tool, which had
been commented out ("don't fit visually"). Root cause: the screen's own
drawIcon() centred against lineStep() (line height + inter-row gap)
instead of getLineHeight() alone, 2px too generous for a near-full-
height icon -- now delegates to the already-correct miniIconDraw() used
elsewhere (e.g. the message-list ack checkmark). Also gave Admin and
GPIO their own icons (padlock, 3-pin header) instead of both sharing
System's cog.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The plain ✓ on your own channel post only said "at least one repeater
heard it" -- now it shows how many distinct repeaters echoed it back,
drawn as tiny 3x5 digit icons (icons.h) rather than the normal font,
since the slot next to the sender name is icon-sized, not text-row-
sized. DM delivery ticks are untouched (no repeater-count concept
there, so they keep the plain checkmark).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
An app-originated channel send (mirrored into the on-device history)
bumped that channel's unread badge whenever the device's own UI
wasn't already showing that exact channel -- unlike an on-device
compose, which sidesteps this by forcing itself into that channel's
view right before sending. Adds an explicit own_message flag through
addChannelMsg (MessageHistory -> AbstractUITask -> UITask ->
MessagesScreen) so an own post is never counted unread regardless of
what's on screen when it's sent.
Found the same bug in MyMeshBot.h's three auto-reply-into-channel call
sites (Remote Bot's own reply showing as unread on itself) and fixed
those with the same mechanism.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Extends the existing single-boolean channel relay-echo marker into a
full count + list of distinct confirming repeaters, since each
repeater retransmit already appends its own identity hash to the
packet's path and the echo-matching hash deliberately ignores that
mutable path -- so every distinct repeater's echo of one send now
matches the same tracking slot instead of only the first.
Symmetrically captures the hop path a received DM/channel message
actually took, so a new "Path"/"Relayed by" row in the existing
Hold-Enter Options popup can show the resolved sequence of repeaters
(by contact name, or a hex fallback for an unknown one).
Also fixes a real bug caught during testing: the popup row's own
label ("Path (N hops)"/"Relayed by (N)") was built into a stack-local
buffer handed to PopupMenu, which only stores the pointer -- it
rendered as garbage once the building function returned. Moved to a
persistent member buffer.
Bumps the dev-build fallback version and adds release notes/docs
for this plus the two other 1.27 features already on this branch
(BLE retry backoff, marquee-scroll for selected long text).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CMD_SEND_TXT_MSG and CMD_SEND_CHANNEL_TXT_MSG (the phone app's send path)
transmitted over the mesh but never touched the device's own MessagesScreen
history, unlike a message composed on-device (MessagesScreen::afterSend) --
so a DM/channel post sent from the app was invisible if that same
conversation was later opened on the device's own screen. Both handlers now
also call into the same history-store entry points incoming messages use.
Also wires up delivery-status parity with an on-device send, not just the
raw text:
- Channels: arms the existing "relayed into mesh" repeater-echo tracker
(trackRelaySend()/armChannelRelay()) on the new entry -- sendGroupMessage
already runs that tracker regardless of who originated the send, this
just attaches it to the right history entry. Required threading a ring
position back out through AbstractUITask::addChannelMsg (now returns int)
and a new armChannelRelay() passthrough.
- DMs: addDMMsg gained ack_tag/ack_deadline_ms/resends params (threaded
through MessageHistory -> MessagesScreen -> AbstractUITask/UITask) so an
app-sent DM gets the same pending -> \xe2\x9c\x93/\xe2\x9c\x97 status the on-device compose
path shows. resends stays 0 deliberately: the app owns its own retry
decision, so this only drives the on-screen status, never a second,
independent auto-resend from the device itself.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
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>
release-notes.md's v1.25 section already documents "Updated upstream
base to companion-v1.17.1", and that merge (68527e7b) is confirmed in
main's history -- but every MESHCORE_VERSION string, including
UITask.cpp's fallback default for boards that don't set it explicitly
(Heltec v3/v4, ThinkNode, Mesh Pocket, T-Echo), was still hardcoded to
the pre-bump "1.17". Bumped every occurrence to "1.17.1" to match what
actually shipped.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Scope/repeater-scope filtering, magnetic Hall-sensor screen lock,
solo build configs restructured into their own solo/<board>/ folder
(one _solo_dual build per board), ProMicro + CardKB support (PR #31,
tchellow), new Build Flags reference doc, book-order fullscreen message
paging, and a confirmed "Start OTA" admin action -- plus a full
pre-merge documentation audit.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Full documentation audit before merging 1.26 into main turned up:
- README's Supported Devices table was missing GAT562 Mesh Watch13
(a CI-built, shipping firmware with zero end-user docs -- pre-existing
gap, not introduced by this branch) and ProMicro (added to the build
table by an earlier commit but never to the device list up top).
Building-from-source's env table was also missing Watch13.
- settings_screen.md's Keyboard table never documented the Ext. KB
(Full/Compact) setting, despite external_keyboard.md already
describing it in detail.
- nrf52_power_management.md's board-support table only listed 5 of the
13 boards that actually have a PowerMgtConfig implementation wired up
(grep-verified against every variants/*/*.cpp defining `power_config`)
-- added the other 8, and fixed one board's listed name (RAK 3401,
not "RAK WisMesh Tag") to match its actual getManufacturerName().
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
start ota was already sendable via Admin's Custom-command row (and
CLI-reachable directly), but had no dedicated menu entry. Adds a row to
the Actions tab that confirms first (Start/Cancel, defaulting to
Cancel) before sending -- unlike Reboot, OTA parks the remote in BLE
DFU mode for the duration of the update, disruptive enough to warrant
the extra step.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PR #31 (ProMicro CardKB support) landed a few commits back but the
Contributors list was never updated.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- README's env table and external_keyboard.md's device-support table both
get a ProMicro row -- missed when the PR #31 merge landed since neither
was in scope for that commit.
- external_keyboard.md and build_flags.md now cover CARDKB_I2C alongside
ENV_PIN_SDA/ENV_PIN_SCL: the PR generalised CardKB bus selection to a
single macro after build_flags.md was first written, so the doc only had
the older (still valid, but no longer the only) form.
- release-notes.md: added the ProMicro solo build and the new Build Flags
reference page to v1.26's What's New.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Merged after the fact, so it followed the old convention (solo env inside
variants/promicro/platformio.ini alongside the shared board configs). Moved
to match every other board post-restructuring -- extends still points at
Promicro, defined in variants/promicro/platformio.ini.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
pollHallSensor() acted on the raw pin reading immediately, unlike every other
physical-input path in this file (MomentaryButton, pollCardKB()'s own
last-raw edge check). A cheap mechanical reed switch -- one of the two
sensor types the docs explicitly recommend wiring here, alongside a
solid-state Hall IC -- can chatter for a few ms while the magnet crosses the
trigger distance, so a poll every loop() tick during that window could flip
_locked and fire _display->turnOff()/turnOn() repeatedly in that short span:
wasted work on any panel, and a real cost on e-ink where each is a slow
full-panel operation.
A raw reading now has to hold steady for HALL_DEBOUNCE_MS (25ms, same
threshold as MomentaryButton's ISR_DEBOUNCE_MS) before it replaces
_hall_magnet_present and triggers the lock/unlock actions.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Solo's `_solo_dual` env for each board lived inside variants/<board>/, mixed
in with the shared upstream board configs (repeater, room server, plain
companion) that every MeshCore fork carries. Split them out into their own
top-level solo/<board>/ folder -- each still `extends` the board base defined
in its original variants/<board>/platformio.ini, just no longer interleaved
with it file-wise.
- platformio.ini: extra_configs picks up solo/*/platformio.ini alongside
variants/*/platformio.ini.
- build-solo-firmwares.yml: env-discovery grep now scans solo/ instead of
variants/ (the release matrix is unchanged -- same 8 envs, same names).
- pr-build-check.yml: solo/** added to the trigger paths.
- GAT562 30S Mesh Kit: dropped the separate solo_ble env -- solo_dual is a
strict superset (BLE still works, plus USB), and every other board only
ever had one solo build to begin with.
- GAT562 Mesh Watch13: renamed solo_ble -> solo_dual (added DUAL_SERIAL=1) to
match. No comment anywhere recorded whether this board's USB data lines
are actually broken out to a connector -- DUAL_SERIAL compiles and works
over BLE regardless, so worst case the USB half goes unused.
- Removed a dead AUTO_SHUTDOWN_MILLIVOLTS from the three solo envs that set
it (Heltec V3/V4, T-Echo Lite+KeyShield): that macro is only ever read in
the old ui-tiny UITask, never ui-new, which every solo build (these
included) uses -- it did nothing on any of them. Left alone everywhere
else it's set (non-solo companion envs elsewhere use ui-tiny/ui-orig, or
the flag is legitimately read); out of scope here.
- Added docs/solo_features/build_flags.md: every optional -D flag a solo
build understands (GPIO, CardKB/joystick, Hall-sensor cover lock, buzzer/
vibration, GPS switch, display/battery tuning), verified against the code
rather than the existing per-board comments, with what's already baked
into every solo build kept separate from what's opt-in.
- README: doc index + Building from source section link to the new page;
path references to the moved solo files updated to solo/<board>/.
All 8 solo_dual envs rebuilt clean after the move; native test suite (40
cases) unaffected.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
No board in this repo has one built in, and no default pin is assumed
anywhere -- whoever wires a Hall-effect or reed sensor to a free GPIO sets
PIN_HALL_SENSOR (and HALL_ACTIVE_HIGH, for a sensor that pulls the pin high
rather than low on presence) as a build_flag on their own env. Entirely
opt-in and a no-op elsewhere, same pattern as PIN_GPIO1..4/ADC_MULTIPLIER/
CARDKB_ENABLE.
Level-triggered polling (like pollCardKB()) rather than an edge interrupt --
a magnet held near the sensor reads the same way every tick, so the new
pollHallSensor() only acts on the two transitions. Closing locks and blanks
the display with no wake grace (the cover is physically over the screen, so
there's nothing to show); opening unlocks and wakes it, with no key combo
either way. Both are independent of the Auto-lock setting, which is a
timeout, not a physical event.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The T1 has an ICM-42607-P IMU with the same address as a DS3231 RTC.
This completely breaks the clock on the T1. Reading the time results in
a garbage value, causing all sorts of strange issues. The time never
advances, which breaks logging in to repeaters (due to their time-based
replay protection).
This simply disables the probe on the I2C line. The DS3231 doesn't have
a WHO_AM_I register that could be used to prevent misidentifying it, so
this simpler fix is used.
LEFT went to the newer message and RIGHT to the older one, which reads
backwards against the page metaphor the "<" / ">" markers set up. Swap it:
LEFT turns back to the older message, RIGHT forward to the newer one, and
the markers follow (they were keyed to the opposite flags).
PREV/NEXT are named in message order, not screen order -- MessagesScreen's
_hist_sel counts newest-first, so PREV is the older message -- so only the
key mapping and the two marker conditions change; the caller side is
untouched. Applies to both the DM and channel fullscreen views, which share
handleInput(). AdminScreen's reply view treats every non-NONE result as
"close", so it is unaffected.
Docs and release notes updated to match.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>