Commit Graph

2845 Commits

Author SHA1 Message Date
Jakub
02fd79d567 docs: update README with reply feature and screen lock
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 22:33:04 +02:00
Jakub
0f5740f6b6 fix: remove redundant slen clamp and update stale comment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 18:20:42 +02:00
Jakub
34cfd27b8a fix: use @[nick] format for replies and fix fullscreen message display
- Reply prefix changed to "@[nick] " format — bracket delimiter handles
  nicks with spaces unambiguously
- FullscreenMsgView: parse "@[nick] body" to show "To: nick" header;
  fall back gracefully if format not matched
- Reduce FS_CHARS 21→20 to prevent scroll arrows overlapping last char
- Transliterate nick before displaying in "To:" header and "RE:" title
  so non-ASCII characters render correctly on the OLED font

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 18:18:45 +02:00
Jakub
b21bcb5ca4 fix: render reply popup in CHANNEL_HIST and DM_HIST phases
_ctx_menu.render() was only called in CONTACT_PICK and CHANNEL_PICK,
so the reply popup was active but invisible in history views. Added
render calls for list view and fullscreen view in both DM_HIST and
CHANNEL_HIST phases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 16:11:25 +02:00
Jakub
6f7de3ed20 feat: add reply action to channel and DM message history
Long-press Enter (KEY_CONTEXT_MENU) on a selected message shows an
'Options / Reply' popup in both list and fullscreen views. Confirming
opens MSG_PICK with 'RE: nick' title — the reply can be sent via
keyboard or quick message templates, both automatically prefixed with
'@nick '.

- Channel: reply prefix extracted from 'sender: message' format
- DM: reply available only on incoming messages, uses contact name
- FullscreenMsgView: REPLY added to Result enum, KEY_CONTEXT_MENU handled
- MSG_PICK: _reply_mode flag routes prefix through keyboard and templates
- Guard: prevent sending empty reply (prefix-only keyboard input ignored)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 15:12:11 +02:00
Jakub
8f566732ed feat: show @recipient as 'To: nick' bar in fullscreen message view
When a message starts with @nick, the fullscreen view expands the header
to show a second row 'To: nick' below the sender name, and displays the
message body without the @nick prefix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 15:00:01 +02:00
Jakub
9b61bc3028 fix: increase quick-message expansion buffer from 80 to 140 bytes
custom_msgs templates are up to 140 chars; the 80-byte msg[] buffer
silently truncated any message longer than 79 characters before sending.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:53:36 +02:00
Jakub
584ef33b3e fix: channel bot respects bot_enabled flag
tryBotReplyChannel checked bot_channel_enabled but not bot_enabled,
so disabling the bot via the main Enable toggle had no effect on
channel replies. Added bot_enabled to the guard condition.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:41:56 +02:00
Jakub
4df97ae5ed fix: persist auto_lock setting across reboots
auto_lock was defined in NodePrefs but missing from both loadPrefsInt
and savePrefs in DataStore.cpp. Added at the end of the serialization
chain (inside if(file.available())) for backwards compatibility with
existing saved files — old files default to auto_lock=0 (disabled).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:39:10 +02:00
Jakub
a5a32530f0 Update Discord link in README.md 2026-05-17 18:55:21 +02:00
Jakub
44122565f6 perf: query sensors once for both lock screen dashboard fields
Previously each LPP sensor field called querySensors() separately.
Now a single querySensors() call fills a shared buffer used by both fields.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 18:52:40 +02:00
Jakub
28d69f88f4 Add Discord discussion link to README
Added a link to the discussion channel on Discord.
2026-05-17 18:51:48 +02:00
Jakub
360d5d10f7 feat: add 30s minimum interval option to auto-advert screen
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 14:33:58 +02:00
Jakub
a2856b7a48 fix: lock screen wake window no longer extends on repeated key presses
Previously every key press while locked reset _lock_wake_until to now+5s,
so multiple presses (or spurious button events) kept extending the window.
Now the 5s timer is set only when the display first wakes from dark.
The unlock sequence still extends the window on each Back+Enter step.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 14:30:53 +02:00
Jakub
3fb0a55aef fix: auto-reset _lock_seq_used after 5s in case Back release event is missed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:17:02 +02:00
Jakub
2bc6dae78e feat: add Icelandic and Romanian legacy cedilla transliteration
Adds ð/Ð (eth), þ/Þ (thorn) for Icelandic, and ţ/Ţ (t with cedilla)
for legacy-encoded Romanian text.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:11:42 +02:00
Jakub
b0552e246a feat: extend UTF-8 transliteration to cover all major European languages
Adds Scandinavian (å ø æ), Hungarian (ő ű), Romanian (ă ș ț),
Croatian (đ), Turkish (ğ ş ı), and Baltic/Lithuanian/Latvian
(ā ē ī ū ģ ķ ļ ņ ŗ ų ė į) diacritics.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:08:20 +02:00
Jakub
6492fd490e feat: add Czech and Slovak diacritic transliteration
Adds háček and other Czech/Slovak characters (č š ž ř ě ů ď ť ň ľ ĺ ŕ)
to the UTF-8 transliteration table so they display as ASCII letters
instead of █ blocks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:01:51 +02:00
Jakub
20e88443b4 fix: polish lock screen sequence — hints update instantly, screen stays on, triple-Back blocked
- Turn display on at first Back+Enter press so hints are visible even when screen was dark
- Extend _lock_wake_until on every sequence step to prevent screen blanking mid-press
- Set _next_refresh=0 on every Enter press (not just on completion) for immediate hint redraw
- Add _lock_seq_used flag to suppress the Back CLICK that fires on release after unlock
- Block triple-Back (buzzer toggle) when screen is locked

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 11:17:59 +02:00
Jakub
43f3621fdc fix: replace long-press lock trigger with back_btn.isPressed() check
Long press detection on back_btn was unreliable — the release generated
a spurious CLICK that cancelled the sequence. Now the Enter click handler
checks back_btn.isPressed() directly: holding Back and clicking Enter 3×
within 3 seconds locks/unlocks the screen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 10:09:54 +02:00
Jakub
ef0241b5f3 feat: show two dashboard sensor values on lock screen
Reuses dashboard_fields[0] and [1] from NodePrefs — left-aligned and
right-aligned in one row under the clock, no labels to save space.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 10:04:28 +02:00
Jakub
9ff42a9296 feat: screen lock — hold Back + 3×Enter to lock/unlock
- Long press Back starts lock sequence; 3 Enter presses within 3s toggle lock
- Locked screen wakes for 5 seconds on any key, showing clock and unlock hint
- Incoming messages do not wake the display while locked
- Auto Lock setting in Display section: locks automatically when screen turns off
- Lock state persisted in UITask; NodePrefs gains auto_lock flag

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 09:55:51 +02:00
Jakub
b068318bc5 refactor: extract SettingsScreen and QuickMsgScreen to separate header files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wio-tracker-v1.15-plus.1.5
2026-05-17 00:12:40 +02:00
Jakub
a60ec376d7 perf: increase render interval on static screens from 300ms to 2000ms
Static screens (SettingsScreen, BotScreen, FullscreenMsgView, message
list, contact picker) were re-rendering every 300ms with no visible
benefit. New messages still trigger immediate refresh via newMsg() →
_next_refresh=100, so responsiveness is unchanged. Reduces unnecessary
SPI transfers and CPU wakeups ~6x on idle static screens.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 23:42:52 +02:00
Jakub
c4b152fd6a fix: clear arrow background in FullscreenMsgView to prevent text overlap
Text lines fill the full display width, causing the last chars to bleed
into the scroll arrow area. Draw a DARK fillRect behind each arrow before
rendering it, so the arrow appears on a clean black background without
truncating the text width.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 23:28:18 +02:00
Jakub
5d41812784 fix: separate DM and channel bot reply cooldown timers
Single shared _bot_last_reply_ms caused a DM reply to block the
channel bot for 10s and vice versa. Split into _bot_last_dm_reply_ms
and _bot_last_ch_reply_ms so each cooldown is independent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 23:26:31 +02:00
Jakub
44b2519df4 fix: with_sender buffer too small and FS_LINE_H mismatch
- with_sender[160] could hold only ~160 chars but node_name(32) +
  expanded(200) needs up to 234; snprintf would silently truncate
  the UI display entry. Increased to 240.
- FS_LINE_H was 9 but Adafruit 5x7 font line height is 8, wasting
  1px per line and showing 5 lines instead of 6.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 23:23:20 +02:00
Jakub
1b9dc42250 fix: bot trigger matched against message body only, not sender name
Channel messages have the format "sender_name: body". The trigger was
being searched across the whole string, so a nick containing the trigger
word would fire a reply even with an unrelated message. Now the match
skips past the ": " separator and only checks the message body.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 23:19:12 +02:00
Jakub
5bc250888f fix: apply saved display brightness before UI task starts
Loading... screen was always shown at full brightness because prefs
are not yet loaded at that point. Apply setBrightness() in the first
common code path after the_mesh.begin() loads prefs, so at least the
tail of the loading screen and the entire splash screen respect the
saved brightness level.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 23:15:29 +02:00
Jakub
b91afa05b9 fix: reduce low battery shutdown text size to fit 128px OLED
Size 2 rendered text wider than display width. Switched to size 1
and adjusted y-positions to keep both lines visible.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 17:47:22 +02:00
Jakub
6a7f8b7ca7 fix: transliterate message text in FullscreenMsgView before wrapping
Raw UTF-8 message body was passed directly to display.print(), rendering
Polish and other accented chars as garbage on the Adafruit font.
Transliterating before wrapLines also fixes byte-count wrapping for
multi-byte UTF-8 characters.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:24:36 +02:00
Jakub
31962726ec fix: apply UTF-8 transliteration in drawTextEllipsized
Names printed via drawTextEllipsized (contacts, senders) bypassed
translateUTF8ToBlocks, causing raw UTF-8 bytes to render as garbage
on the Adafruit font. Now transliteration happens inside the method.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:11:12 +02:00
Jakub
f6b13c5cab fix: use block char █ fallback for unknown codepoints in transliteration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:05:53 +02:00
Jakub
8d3b955da1 feat: transliterate accented/diacritic characters to ASCII in translateUTF8ToBlocks
Replaces the block-character fallback with proper transliteration for
Polish (ą→a, ć→c, ę→e, ł→l, ń→n, ó→o, ś→s, ź→z, ż→z), German (ä ö ü ß),
and common French/Spanish/Portuguese accents. Unknown codepoints fall back
to '?' instead of █.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 14:46:53 +02:00
Jakub
2978b0ffc4 Merge remote-tracking branch 'upstream/main' into wio-tracker-l1-improvements 2026-05-16 10:51:42 +02:00
ripplebiz
c940ea5f30 Merge pull request #2567 from recrof/patch-4
Change MeshCore intro video link to The Comms Channel's MC intro playlist
2026-05-16 13:03:00 +10:00
Jakub
fbe636a05a feat: show plus version number on splash screen
Splash screen bar changes from "Plus for Wio" to "Plus 1.4 for Wio"
by extracting the suffix after "plus." from FIRMWARE_VERSION.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wio-tracker-v1.15-plus.1.4
2026-05-16 00:33:13 +02:00
Jakub
9c40a253e2 update README and fix quick message / melody naming collision
- Expand README: ringtone editor now documents two melody slots, full
  note spec, and melody assignment to DM/channel notifications; settings
  section lists DM Melody and Channel Melody options; context menu
  description updated with melody override detail
- Rename quick reply template labels from M1-M10 to Q1-Q10 to avoid
  ambiguity with melody slot identifiers M1/M2
- Increase DM message history buffer from 32 to 64 entries

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 00:09:57 +02:00
Jakub
e0e79b725d Merge branch 'meshcore-dev:main' into wio-tracker-l1-improvements 2026-05-16 00:02:22 +02:00
Rastislav Vysoky
d4c99dec65 Change MeshCore intro video link to The Comms Channel's MC intro playlist 2026-05-15 16:42:29 +02:00
Jakub
1d04930c1e quick fix 2026-05-15 16:33:19 +02:00
Jakub
ec601ef118 fix: renderBar always shows slot outlines regardless of value
Previously empty slots used drawRect and filled slots used fillRect,
so at max value (e.g. volume=4) no drawRect was called and no slot
borders were visible when selected (inverted colors). Brightness at
default (2/5) always had visible outlines, making the two bars look
inconsistent.

Now drawRect is called for every slot, with fillRect(+1,+1,w-2,h-2)
on top for filled ones. All 5 slots are always visually distinct.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 15:48:05 +02:00
Jakub
484f0891b1 fix: three bugs found in code review
- DataStore: validate ringtone2_len <= 32 after loading from flash
  (same guard as ringtone_len on line 252; we introduced this field
  but forgot the validation)
- UITask: fix shutdown buzzer timeout to conventional unsigned form
  (millis() - start) < timeout to avoid unsigned underflow if called
  within first 2.5s of boot
- UITask: guard _last_notif_ch_idx < 64 before 1ULL shift in notify()
  (defensive; MAX_GROUP_CHANNELS=40 so currently unreachable, but
  prevents UB if the value is ever unexpectedly out of range)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 15:34:10 +02:00
Jakub
a819b05ed0 fix: correct UF2 artifact name for wio-tracker tags with hyphenated versions
##*- strips to the last hyphen, so wio-tracker-v1.15-plus.1.3 yielded
"plus.1.3" instead of "v1.15-plus.1.3". Switch to #*-v (shortest prefix
ending with -v) which preserves hyphens inside the version string.

Also remove the -Plus suffix appended in build_wio_tracker_l1_firmwares()
since the version scheme already encodes "plus" in the tag/version string,
making the suffix redundant and producing doubled output like "plus.1.3-Plus".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 15:24:54 +02:00
Jakub
bf05a13549 fix: implement nRF52 RTTTL player using direct NRF_PWM2 control for working volume
tone() dynamically computes seq_refresh so the DMA repeats 50% duty for
~13-30ms per note before re-reading its buffer — volume cannot take effect
until that delay passes, producing a staircase artifact.

Replace tone()/NonBlockingRtttl with a custom RTTTL parser that drives
NRF_PWM2 directly using REFRESH=0. DMA now re-reads _duty_buf every
PWM period so:
- Duty is set before SEQSTART fires → no initial full-volume burst
- applyVolume() writes to _duty_buf and takes effect within one period (<2.3ms at A4)
- setVolume() during playback adjusts loudness immediately and smoothly

Non-nRF52 platforms continue to use NonBlockingRtttl + analogWrite.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 13:09:38 +02:00
Jakub
d02c1cf098 feat: play preview tone when buzzer volume changes in settings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 11:46:48 +02:00
Jakub
b3c6416874 feat: melody assignment per channel/DM, dual ringtone slots, volume cleanup
Add second ringtone slot (ringtone2_*) to NodePrefs and DataStore.
Add per-channel and per-DM melody assignment (built-in / melody 1 / 2)
stored in NodePrefs bitmasks and DmMelodyEntry table.
Settings screen exposes DM/CH sound items; RingtoneEditorScreen supports
switching between slots. notify() uses buildMelodyFromPrefs() to select
the correct RTTTL string per contact.

Remove broken nRF52 volume control from buzzer.cpp: tone() uses
NRF_PWM2 with DECODER.MODE=Auto so TASKS_NEXTSTEP has no effect and
duty cannot be changed before the first DMA read without patching the
Arduino core. applyVolume() is now a no-op on nRF52.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 11:43:38 +02:00
Jakub
39731bb7fa docs: update README for v1.15-plus.1.3
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 09:21:32 +02:00
ripplebiz
181a54e718 Merge pull request #2532 from swaits/fix/trace-offset-widening
fix(mesh): widen TRACE offset to uint16 to avoid narrowing
2026-05-15 13:17:03 +10:00
Jakub
c86e6c803e fix: reverse fullscreen message nav order and remove channel # prefix
- Swap left/right navigation in fullscreen view: left=newer, right=older
- Update arrow indicators to match new direction
- Remove # prefix from channel name in message and compose view titles

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wio-tracker-v1.15-plus.1.3
2026-05-14 20:21:13 +02:00