From 054c7ddba269582d8aee4e55b6672bc68b61335f Mon Sep 17 00:00:00 2001 From: diffwireauto <330573775+diffwireauto@users.noreply.github.com> Date: Sun, 25 Oct 2026 11:46:28 -0400 Subject: [PATCH] docs(#976): record the approved tones and screen parity mockup Owner-approved 2026-10-25 with four decisions: Screen and Battery under Node Settings, a separate play button, no way back to radio default, and the Menus and lists / Messages labels. Built against meshcore-firmware 3e788e2a. Covers #970, #971, #986, #987. Co-Authored-By: Claude Opus 5.5 --- .../tones-screen-parity-mockups.html | 362 ++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 docs/initiatives/standalone/975-settings-restructure/tones-screen-parity-mockups.html diff --git a/docs/initiatives/standalone/975-settings-restructure/tones-screen-parity-mockups.html b/docs/initiatives/standalone/975-settings-restructure/tones-screen-parity-mockups.html new file mode 100644 index 00000000..98773cfb --- /dev/null +++ b/docs/initiatives/standalone/975-settings-restructure/tones-screen-parity-mockups.html @@ -0,0 +1,362 @@ + + + + +Badge settings parity mockups + + + + + + +

Badge settings, reachable from the app (client #970, #971, #975)

+

Material 3 blue seed, light, drawn at 390×844 against the real widgets. Wire: 0xC5 as of meshcore-firmware 3e788e2a (#1801, branch epic/1788-client-settings, running on QCC2), read 2026-10-25 in OffbandConfigProtocol.h; badge screens read in BadgeScreens.cpp, BadgeLayout.h, TimeZones.h, BatteryGauge.h at the same commit. Supersedes the #970 slot mockup sent 2026-10-24. Values are examples; the bullets are the behavior to build. Built under #970, #971, #986 and #987. APPROVED 2026-10-25

+ +

The badge's screens against the app

+ + + + + + + + + + + + + + + +
Badge screen and rowWire (0xC5 sub-code, caps byte 2)App beforeApp after this
Tones › Sound (All, Self, None)0x01/0x02, 0x01Buzzer and tonesunchanged (frame 2)
Tones › DM, Channel, Room, New contact, Ack, Sent0x0F/0x10 EVTONE, 0x10missingsix rows + picker (frames 2, 4)
Each picker: Silent, Chime, Kerplop, Tick, Bloop, Drop, Knock, filled slotssame "picker's rule" on every setmissingone shared picker (frames 4, 7)
Picker plays each tune as you move0x11 TUNE_PLAY, 0x10missingplay button per row (frames 3, 4, 5)
Tones › Custom: all eight slots, named or "(empty)"0x09 SLOT_GET, 0x10missingslot list (frame 3)
Custom › edit a slot (keyboard)0x12 SLOT_READ + 0x0A SLOT_SET, 0x10missingeditor, prefilled (frame 6)
Channel's own tone, with Default0x0B/0x0C CHTUNE, 0x10codec built, no screen"Radio tone" in the channel sheet (frame 7)
Settings › Nav text, Message text0x13 GET, 0x14 TEXT_SET, 0x40missingScreen page (frame 8)
Settings › Screen off (15 s, 30 s, 1 m, 2 m, 5 m)0x15 SCROFF_SET, 0x40missingScreen page (frame 8)
Settings › Time zone (45 zones, "not set" shows ages)0x16 TZ_SET, 0x40missingzone list (frame 9)
Settings › Battery: 100% point, Set 100% here, Back to auto0x17 BATT_SET, 0x40missingBattery page (frames 10, 11)
Settings › GPS0x0D/0x0E, 0x20Location (#977)unchanged
Settings › Hibernate, Device pagesnot settings (AmberForge 1350): an action and a navigationn/an/a
+

One caps change to carry into the code already written: 0x10 is now TUNES (slots, channel tone, event tones, preview), not channel tone alone, and the slot sub-codes moved from the buzzer bit to it. A radio with a buzzer but no tune engine advertises 0x01 without 0x10 and keeps today's scope-only screen.

+ +

Buzzer and tones

+ +

1Node Settings gains Screen and Battery

The badge's own hardware settings sit with Button actions, gated on 0x40. A radio without it shows today's card.

+
+
Node Settings
+
+
Node name
QCC2
+
+
Button actions
Assign what the button does
+
+
Screen
Text size, screen off, time zone
+
+
Battery
100% at 4150 mV, learned
+
+
Public key
a1f3 07c2 9e44 … 5b10
+
+
+
  • Both rows appear only on a radio advertising caps byte 2 0x40. Today that means firmware built with the Offband screen set; a display fitted to a pyramid badge with that firmware gets them.
  • Battery's subtitle is the SCREEN_GET reply: the 100% point and where it came from, in the badge's words (default, learned, set).
  • Placement: owner decision 1.
+ +

2The scope, then the six tones

The badge's Tones screen, in its order: Sound first, because nothing below can sound while it says None.

+
+
Buzzer and tones
+
Device notification scope
+
All
Beep for any received message
+
Self
Beep only for direct messages and @[mentions]
+
None
Never beep
+
Tones
+
What this radio plays for each event.
+
DM
Chime (radio default)
+
Channel
Kerplop (radio default)
+
Room
Mario
+
New contact
Bloop
+
Ack
Silent
+
Sent
Silent (radio default)
+
+
  • Labels are the badge's own (kToneEventRows): DM, Channel, Room, New contact, Ack, Sent. DM is one tone for every direct message; there is no per-contact choice (#983 withdrawn).
  • Each subtitle is the effective byte from EVTONE_GET. When stored is 0xFF it adds "(radio default)", so a choice and a default never look alike.
  • The tones section exists only with caps 0x10. With 0x01 alone the screen is today's scope rows.
+ +

3Custom tunes, every slot

Scrolled down. All eight slots are rows, as on the badge: an empty slot is where you go to fill one.

+
+
Buzzer and tones
+
Sent
Silent (radio default)
+
Custom tunes
+
Eight tunes stored on this radio, in RTTTL. A saved tune can be picked for any event or channel.
+
1 Mario
142 characters
+
2 Zelda
96 characters
+
3 (empty)
Tap to add a tune
+
4 (empty)
Tap to add a tune
+
5 Nokia
58 characters
+
6 (empty)
Tap to add a tune
+
7 (empty)
Tap to add a tune
+
8 (empty)
Tap to add a tune
+
+
  • "1 Mario" / "3 (empty)" is the badge's own label shape. Names and lengths are SLOT_GET replies, one per slot, read when the screen opens.
  • The play button sends TUNE_PLAY with the slot's id (8 + slot). Empty slots have none: there is nothing to hear.
  • Tap a row to edit it (frame 6).
+ +

4Pick a tone, hear it first

One picker for all six events, with the badge's list. Play auditions on the radio; tapping the name chooses it.

+
+
Buzzer and tones
+
+
+
DM tone
+
Plays for every direct message.
+
Silent
+
Chime
Now playing for DMs
+
Kerplop
+
Tick
+
Bloop
+
Drop
+
Knock
+
Your tunes
+
Mario
+
Zelda
+
Nokia
+
Cancel
+
+
+
  • The list is exactly what firmware accepts: the named built-ins (ids 0 to 6) and filled slots only. Empty slots are not offered, so a set is never refused for that.
  • Tapping a name sends EVTONE_SET; the dialog closes and the row changes only on the radio's reply, which carries stored and effective.
  • No Default row. Firmware refuses 0xFF on an event, as the badge's own picker offers none (owner decision 3).
  • "Now playing" marks the effective tune, as the badge marks it "now".
+ +

5Why a preview made no sound

The radio says why it refused. The app says it in words, as the badge does with "Buzzer: OFF".

+
+
Buzzer and tones
+
Device notification scope
+
All
Beep for any received message
+
Self
Beep only for direct messages and @[mentions]
+
None
Never beep
+
Custom tunes
+
1 Mario
142 characters
+
Sound is off on this radio. Set the scope to All or Self to hear it.OK
+
+
  • TUNE_PLAY result 2 (sound off): this message, which stays until OK.
  • Result 1 (something more important is sounding): "The radio is playing a notification. Try again in a moment."
  • Result 0: nothing shown. The sound is the confirmation.
+ +

6Edit a slot, starting from what is there

The editor reads the stored tune back first, so a filled slot opens with its text and can be changed, not only replaced.

+
+
Slot 1
+
+
RTTTL
Mario:d=4,o=5,b=100:16e6,16e6,32p,8e6,16c6,8e6,8g6,8p,8g,8p,8c6,16p,8g,16p,8e,16p,8a,8b,16a#,8a,16g.,16e6,16g6,8a6,16f6,8g6,8e6,16c6,16d6,8b
+
Plays as "Mario"142 / 240
+
Clear slotPlay savedSave
+
+
Read from the radio: 142 of 142 characters
+
+
  • Opening sends SLOT_READ at offset 0, then again at offset + bytes while more is 1. The field is read-only and shows this bar until the read completes.
  • Typing is checked live with firmware's own rtttlProblem() and its words ("b= must be 1 or more"); Save stays disabled while there is a problem. Saving is the chunked SLOT_SET, then a re-read.
  • Play saved plays what is on the radio, not unsaved typing: there is no command to play text that has not been saved. It is disabled while the text differs from the saved tune.
  • Clear sends the empty commit, after a confirm.
+ +

7A channel's tone names its Default

The channel sheet's "Radio tone" picker (#971), now able to say what Default plays, the way the badge shows "Default Kerplop".

+
+
Channels
+
+
+
Radio tone
+
#okimesh
+
Default
Kerplop, the radio's channel tone
+
+
Silent
+
Chime
+
Kerplop
+
Tick
+
Bloop
+
Drop
+
Knock
+
Your tunes
+
Mario
+
Zelda
+
+
+
  • Same picker as frame 4 plus the Default row a conversation needs. Default writes stored 0; it is the only way to un-set a channel's tone.
  • Default's subtitle is the Channel event's effective tune from EVTONE_GET ev 1, so it names a real tune rather than "follows the radio".
  • Empty slots are hidden here too: firmware now refuses an empty slot for a channel (3e788e2a), which settles the first #971 question.
  • The row also sits in the channel chat screen's menu, from the same widget.
+ +
+ +

Screen and Battery

+ +

8Screen

The badge's Nav text, Message text and Screen off rows, with the same choices and no others.

+
+
Screen
+
Text size
+
Menus and lists
+
LargeMediumSmall
+
Messages
+
LargeMediumSmall
+
Screen off
+
How long the screen stays on after the last key press.
+
15 s30 s1 m2 m5 m
+
Time zone
+
Eastern
UTC-4 now. Message times show as clock times.
+
+
  • Every control is the SCREEN_GET reply; each change sends its SET and the controls redraw from the 14-byte re-read reply, never from the tap.
  • "Menus and lists" is the badge's Nav text, "Messages" its Message text (owner decision 4).
  • Screen off offers exactly the five steps firmware accepts. When scr_stored is 0 (compiled default), no segment is selected and the line reads "Board default: 1 m" from scr_secs; picking a step replaces it and there is no way back to 0, on the badge or here.
+ +

9Time zone

The badge's 45 zones, its "not set", and a suggestion: the badge suggests from GPS, the app from the phone.

+
+
Time zone
+
Search zones
+
Eastern
Matches this phone
UTC-4
+
+
not set
Messages show their age
+
UTC
UTC+0
+
Eastern
Current
UTC-4
+
Central
UTC-5
+
Mountain
UTC-6
+
Arizona
UTC-7
+
Pacific
UTC-7
+
+
  • The list is a copy of TimeZones.h kZones, in its order. AmberForge confirms it is append-only, so the index is stable; an index the app does not know is shown by number.
  • Offsets are computed with the zone's own daylight rule (US, EU, or none), as the badge's picker shows them.
  • "Matches this phone" picks the named zone whose rule and offset equal the phone's, else the fixed UTC offset, else nothing. It is a suggestion; tapping it sends TZ_SET like any row.
  • "not set" is storable (index 0), as on the badge.
+ +

10Battery

The badge's Battery screen: where 100% is, how it got there, and its two actions.

+
+
Battery
+
96%
+
Reading 4120 mV
+
+
100% at 4150 mV
Learned after a full charge
+
+
The radio learns where full is after a complete charge. Set it by hand only if the bar never reaches 100% when charged.
+
Set 100% hereBack to auto
+
+
  • The 100% point and its source (default, learned, set by hand) are the batt_stored, batt_full and batt_pinned bytes; the reading and percent are the battery report the app already receives.
  • Set 100% here sends BATT_SET 1: the radio pins its own current reading, as the badge does. A confirm says "Only do this with the radio fully charged."
  • Back to auto sends BATT_SET 0, shown only when something is learned or pinned.
+ +

11Refused, with the radio's reason

The radio refuses a reading that is not a plausible full cell, and says which way it is wrong.

+
+
Battery
+
Not charged yet. Charge the radio fully, then set 100% again. Nothing was changed.
+
71%
+
Reading 3890 mV
+
+
100% at 4200 mV
Default for this board
+
+
Set 100% here
+
+
  • ERR_BATT_NOT_CHARGED (9): this message. ERR_BATT_TOO_HIGH (8): "The reading is higher than a full cell, so it was not used."
  • The existing persistent _ErrorBanner: it stays until dismissed.
  • Back to auto is absent: nothing is learned or pinned, matching the badge, which hides it then.
+ +
+ +

Owner decisions, 2026-10-25

+
+

1. Screen and Battery under Node Settings

They are this radio's own hardware settings, beside Button actions, and they appear only on radios that have them. The rejected alternative was a new top-level "Device display" category, which would be empty on most radios.

+

2. Play is a separate button

The badge auditions as you move because moving and choosing are separate keys. On a phone, a tap is the choice, so play is its own button and the name chooses. A preview never changes the setting.

+

3. No way back to "radio default"

Firmware refuses 0xFF on an event because the badge's picker has no Default row for events, and Screen off accepts only its five steps. The app matches that. A way back would be a firmware change.

+

4. "Menus and lists" and "Messages"

The badge says "Nav text" and "Message text", which fit 21 columns. The app has room to say what each governs.

+
+ +

Why these choices

+
+

The radio is the record, everywhere

Every reply on this list re-reads after the write: EVTONE and CHTUNE carry stored and effective, SCREEN carries the whole set. The app draws only from replies, stores none of it, and so has nothing per radio to isolate (#853) or to drift.

+

The app offers exactly what the badge offers

Firmware refuses anything its own screens would not offer. Building each list from the same rule (named built-ins plus filled slots, five Screen off steps, three sizes, the zone table) means the app never offers a choice the radio will reject.

+
+ +