Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba1667b4d1 | ||
|
|
c106d47b9b | ||
|
|
1aa4496530 | ||
|
|
37aac2736c | ||
|
|
6160184531 | ||
|
|
6ee33990a3 | ||
|
|
8b75132f07 | ||
|
|
03d05d7e57 | ||
|
|
a4dc077d80 | ||
|
|
74594d3d54 | ||
|
|
c18916835a | ||
|
|
7352a58701 | ||
|
|
96ba457984 | ||
|
|
f1f12fb30f | ||
|
|
5c3a7a5d46 | ||
|
|
530b539957 | ||
|
|
7f20ebe522 | ||
|
|
565eb7d954 | ||
|
|
28fb57ef4c | ||
|
|
b692fa403c |
No files matched your search
@@ -71,6 +71,18 @@ field, so you're never stuck. Enter sends (toggleable under Settings), Back
|
||||
leaves the field. In the Terminal, Enter runs the command; in the text editor
|
||||
it inserts a newline.
|
||||
|
||||
Channels, direct messages, and room conversations place **#** and emoji to the
|
||||
right of the message input. Press Right to move from the input to **#**, and
|
||||
Right again to move to emoji. Press **OK** on either button to open its picker.
|
||||
|
||||
In the symbol grid, use all four arrows to move the highlight and **OK** to
|
||||
insert the selected character.
|
||||
|
||||
The Create/Join channel forms use the same **#** action beside every text
|
||||
field. Right moves from the field to **#**; Left returns to editing the field.
|
||||
Password fields use the same control, including Wi-Fi, MQTT, and repeater login.
|
||||
After inserting a symbol, focus returns to the originating text field.
|
||||
|
||||
## Lock screen
|
||||
|
||||
**Hold OK** to unlock — the keyboard's hardware long-press stands in for the
|
||||
|
||||
@@ -17,9 +17,9 @@ on both.
|
||||
(press the knob) to select. It's your only pointing device, so almost
|
||||
every screen is navigable with turn + click alone.
|
||||
|
||||
Everything below only fires while you're **not** actively typing into a text
|
||||
field — if a field is focused and you're typing into it, letters type
|
||||
normally and these combos step out of the way.
|
||||
Unless a row explicitly says it applies to a text field, the shortcuts below
|
||||
only fire while you're **not** actively typing. Letters continue to type
|
||||
normally while a field is active.
|
||||
|
||||
## Bottom menu shortcuts
|
||||
|
||||
@@ -45,6 +45,7 @@ while editing a text field, where the keys type normally.
|
||||
| Hold ~1 s, then release | **Back**: closes a popup → closes an open chat → goes Home → Esc (whichever applies first) | **Backspace held ~1 s** |
|
||||
| **Fn (Alt) + turn**, on a main tab | Move between the 5 main tabs (Mail / Contacts / Home / Map / Settings) | **M / C / H / A / S** jumps directly |
|
||||
| **Fn (Alt) + turn**, inside a settings page or chat | Scroll the page up/down | none — encoder only |
|
||||
| **Fn (Alt) + short click**, with a text field focused | Open the special-character picker | none — encoder only |
|
||||
| Turn, with a dropdown open | Scroll through the dropdown's options | none — encoder only |
|
||||
| Turn, with the accent picker open | Cycle through the accent variants (see below) | none — encoder only (Fn+Space to enter is shared) |
|
||||
| Turn, with the @-mention list open | Cycle through matching contacts (see below) | none — encoder only |
|
||||
@@ -129,6 +130,15 @@ return to letters.
|
||||
[Space]
|
||||
```
|
||||
|
||||
### Symbols not on the keyboard
|
||||
|
||||
While any text field is focused, including a Wi-Fi or repeater password:
|
||||
|
||||
1. Hold **Fn (Alt)** and short-click the encoder to open **Special characters**.
|
||||
2. Turn the encoder to highlight a symbol such as `%`, `<`, `>`, or `€`.
|
||||
3. Short-click the encoder or press **Enter** to insert it.
|
||||
4. Hold the encoder for about one second to close the picker without inserting.
|
||||
|
||||
### Shift and Caps Lock
|
||||
|
||||
- **Hold Shift + a letter**: that letter (or letters, for as long as you
|
||||
@@ -247,6 +257,7 @@ that changes keyboard language.
|
||||
| Hold encoder ~1s (or hold Backspace ~1s) | Back |
|
||||
| Fn + turn (main tab) | Switch tabs |
|
||||
| Fn + turn (page/chat) | Scroll |
|
||||
| Fn + encoder click (text field focused) | Open special-character picker |
|
||||
| Fn tap alone | Use the symbol layer for the next key |
|
||||
| Fn double-tap | Lock the symbol layer; tap Fn again to unlock |
|
||||
| Hold Shift + letter | Momentary uppercase |
|
||||
|
||||
@@ -1162,3 +1162,13 @@ Upload files or download screenshots from a browser on the same Wi-Fi. Upload fi
|
||||
Waiting for browser Waiting for browser
|
||||
Download mode (wait for USB flash) Download mode (wait for USB flash)
|
||||
Download mode… reflash over USB,\nor press RESET to cancel Download mode… reflash over USB,\nor press RESET to cancel
|
||||
1 km 1 km
|
||||
100 m 100 m
|
||||
250 m 250 m
|
||||
Location privacy Location privacy
|
||||
position others see is shifted; your own map keeps the real fix position others see is shifted; your own map keeps the real fix
|
||||
Arrows • OK Arrows • OK
|
||||
Direct message color Direct message color
|
||||
Incoming message blink Incoming message blink
|
||||
Notifications Notifications
|
||||
Room / channel color Room / channel color
|
||||
@@ -1158,3 +1158,13 @@ Upload files or download screenshots from a browser on the same Wi-Fi. Upload fi
|
||||
Waiting for browser Waiting for browser
|
||||
Download mode (wait for USB flash) Download mode (wait for USB flash)
|
||||
Download mode… reflash over USB,\nor press RESET to cancel Download mode… reflash over USB,\nor press RESET to cancel
|
||||
1 km 1 km
|
||||
100 m 100 m
|
||||
250 m 250 m
|
||||
Location privacy Location privacy
|
||||
position others see is shifted; your own map keeps the real fix position others see is shifted; your own map keeps the real fix
|
||||
Arrows • OK Arrows • OK
|
||||
Direct message color Direct message color
|
||||
Incoming message blink Incoming message blink
|
||||
Notifications Notifications
|
||||
Room / channel color Room / channel color
|
||||
@@ -1162,3 +1162,13 @@ Upload files or download screenshots from a browser on the same Wi-Fi. Upload fi
|
||||
Waiting for browser Waiting for browser
|
||||
Download mode (wait for USB flash) Download mode (wait for USB flash)
|
||||
Download mode… reflash over USB,\nor press RESET to cancel Download mode… reflash over USB,\nor press RESET to cancel
|
||||
1 km 1 km
|
||||
100 m 100 m
|
||||
250 m 250 m
|
||||
Location privacy Location privacy
|
||||
position others see is shifted; your own map keeps the real fix position others see is shifted; your own map keeps the real fix
|
||||
Arrows • OK Arrows • OK
|
||||
Direct message color Direct message color
|
||||
Incoming message blink Incoming message blink
|
||||
Notifications Notifications
|
||||
Room / channel color Room / channel color
|
||||
@@ -1162,3 +1162,13 @@ Upload files or download screenshots from a browser on the same Wi-Fi. Upload fi
|
||||
Waiting for browser Waiting for browser
|
||||
Download mode (wait for USB flash) Download mode (wait for USB flash)
|
||||
Download mode… reflash over USB,\nor press RESET to cancel Download mode… reflash over USB,\nor press RESET to cancel
|
||||
1 km 1 km
|
||||
100 m 100 m
|
||||
250 m 250 m
|
||||
Location privacy Location privacy
|
||||
position others see is shifted; your own map keeps the real fix position others see is shifted; your own map keeps the real fix
|
||||
Arrows • OK Arrows • OK
|
||||
Direct message color Direct message color
|
||||
Incoming message blink Incoming message blink
|
||||
Notifications Notifications
|
||||
Room / channel color Room / channel color
|
||||
@@ -1161,3 +1161,13 @@ Upload files or download screenshots from a browser on the same Wi-Fi. Upload fi
|
||||
Waiting for browser Waiting for browser
|
||||
Download mode (wait for USB flash) Download mode (wait for USB flash)
|
||||
Download mode… reflash over USB,\nor press RESET to cancel Download mode… reflash over USB,\nor press RESET to cancel
|
||||
1 km 1 km
|
||||
100 m 100 m
|
||||
250 m 250 m
|
||||
Location privacy Location privacy
|
||||
position others see is shifted; your own map keeps the real fix position others see is shifted; your own map keeps the real fix
|
||||
Arrows • OK Arrows • OK
|
||||
Direct message color Direct message color
|
||||
Incoming message blink Incoming message blink
|
||||
Notifications Notifications
|
||||
Room / channel color Room / channel color
|
||||
@@ -1179,3 +1179,13 @@ Upload files or download screenshots from a browser on the same Wi-Fi. Upload fi
|
||||
Waiting for browser Waiting for browser
|
||||
Download mode (wait for USB flash) Download mode (wait for USB flash)
|
||||
Download mode… reflash over USB,\nor press RESET to cancel Download mode… reflash over USB,\nor press RESET to cancel
|
||||
1 km 1 km
|
||||
100 m 100 m
|
||||
250 m 250 m
|
||||
Location privacy Location privacy
|
||||
position others see is shifted; your own map keeps the real fix position others see is shifted; your own map keeps the real fix
|
||||
Arrows • OK Arrows • OK
|
||||
Direct message color Direct message color
|
||||
Incoming message blink Incoming message blink
|
||||
Notifications Notifications
|
||||
Room / channel color Room / channel color
|
||||
@@ -1161,3 +1161,13 @@ Upload files or download screenshots from a browser on the same Wi-Fi. Upload fi
|
||||
Waiting for browser Waiting for browser
|
||||
Download mode (wait for USB flash) Download mode (wait for USB flash)
|
||||
Download mode… reflash over USB,\nor press RESET to cancel Download mode… reflash over USB,\nor press RESET to cancel
|
||||
1 km 1 km
|
||||
100 m 100 m
|
||||
250 m 250 m
|
||||
Location privacy Location privacy
|
||||
position others see is shifted; your own map keeps the real fix position others see is shifted; your own map keeps the real fix
|
||||
Arrows • OK Arrows • OK
|
||||
Direct message color Direct message color
|
||||
Incoming message blink Incoming message blink
|
||||
Notifications Notifications
|
||||
Room / channel color Room / channel color
|
||||
@@ -1159,3 +1159,13 @@ Upload files or download screenshots from a browser on the same Wi-Fi. Upload fi
|
||||
Waiting for browser Waiting for browser
|
||||
Download mode (wait for USB flash) Download mode (wait for USB flash)
|
||||
Download mode… reflash over USB,\nor press RESET to cancel Download mode… reflash over USB,\nor press RESET to cancel
|
||||
1 km 1 km
|
||||
100 m 100 m
|
||||
250 m 250 m
|
||||
Location privacy Location privacy
|
||||
position others see is shifted; your own map keeps the real fix position others see is shifted; your own map keeps the real fix
|
||||
Arrows • OK Arrows • OK
|
||||
Direct message color Direct message color
|
||||
Incoming message blink Incoming message blink
|
||||
Notifications Notifications
|
||||
Room / channel color Room / channel color
|
||||
@@ -1161,3 +1161,13 @@ Upload files or download screenshots from a browser on the same Wi-Fi. Upload fi
|
||||
Waiting for browser Waiting for browser
|
||||
Download mode (wait for USB flash) Download mode (wait for USB flash)
|
||||
Download mode… reflash over USB,\nor press RESET to cancel Download mode… reflash over USB,\nor press RESET to cancel
|
||||
1 km 1 km
|
||||
100 m 100 m
|
||||
250 m 250 m
|
||||
Location privacy Location privacy
|
||||
position others see is shifted; your own map keeps the real fix position others see is shifted; your own map keeps the real fix
|
||||
Arrows • OK Arrows • OK
|
||||
Direct message color Direct message color
|
||||
Incoming message blink Incoming message blink
|
||||
Notifications Notifications
|
||||
Room / channel color Room / channel color
|
||||
@@ -1163,3 +1163,13 @@ Upload files or download screenshots from a browser on the same Wi-Fi. Upload fi
|
||||
Waiting for browser Waiting for browser
|
||||
Download mode (wait for USB flash) Download mode (wait for USB flash)
|
||||
Download mode… reflash over USB,\nor press RESET to cancel Download mode… reflash over USB,\nor press RESET to cancel
|
||||
1 km 1 km
|
||||
100 m 100 m
|
||||
250 m 250 m
|
||||
Location privacy Location privacy
|
||||
position others see is shifted; your own map keeps the real fix position others see is shifted; your own map keeps the real fix
|
||||
Arrows • OK Arrows • OK
|
||||
Direct message color Direct message color
|
||||
Incoming message blink Incoming message blink
|
||||
Notifications Notifications
|
||||
Room / channel color Room / channel color
|
||||
@@ -1162,3 +1162,13 @@ Upload files or download screenshots from a browser on the same Wi-Fi. Upload fi
|
||||
Waiting for browser Waiting for browser
|
||||
Download mode (wait for USB flash) Download mode (wait for USB flash)
|
||||
Download mode… reflash over USB,\nor press RESET to cancel Download mode… reflash over USB,\nor press RESET to cancel
|
||||
1 km 1 km
|
||||
100 m 100 m
|
||||
250 m 250 m
|
||||
Location privacy Location privacy
|
||||
position others see is shifted; your own map keeps the real fix position others see is shifted; your own map keeps the real fix
|
||||
Arrows • OK Arrows • OK
|
||||
Direct message color Direct message color
|
||||
Incoming message blink Incoming message blink
|
||||
Notifications Notifications
|
||||
Room / channel color Room / channel color
|
||||
@@ -1162,3 +1162,13 @@ Upload files or download screenshots from a browser on the same Wi-Fi. Upload fi
|
||||
Waiting for browser Waiting for browser
|
||||
Download mode (wait for USB flash) Download mode (wait for USB flash)
|
||||
Download mode… reflash over USB,\nor press RESET to cancel Download mode… reflash over USB,\nor press RESET to cancel
|
||||
1 km 1 km
|
||||
100 m 100 m
|
||||
250 m 250 m
|
||||
Location privacy Location privacy
|
||||
position others see is shifted; your own map keeps the real fix position others see is shifted; your own map keeps the real fix
|
||||
Arrows • OK Arrows • OK
|
||||
Direct message color Direct message color
|
||||
Incoming message blink Incoming message blink
|
||||
Notifications Notifications
|
||||
Room / channel color Room / channel color
|
||||
@@ -1162,3 +1162,13 @@ Upload files or download screenshots from a browser on the same Wi-Fi. Upload fi
|
||||
Waiting for browser Waiting for browser
|
||||
Download mode (wait for USB flash) Download mode (wait for USB flash)
|
||||
Download mode… reflash over USB,\nor press RESET to cancel Download mode… reflash over USB,\nor press RESET to cancel
|
||||
1 km 1 km
|
||||
100 m 100 m
|
||||
250 m 250 m
|
||||
Location privacy Location privacy
|
||||
position others see is shifted; your own map keeps the real fix position others see is shifted; your own map keeps the real fix
|
||||
Arrows • OK Arrows • OK
|
||||
Direct message color Direct message color
|
||||
Incoming message blink Incoming message blink
|
||||
Notifications Notifications
|
||||
Room / channel color Room / channel color
|
||||
@@ -1506,6 +1506,10 @@ build_flags =
|
||||
-D UI_LVGL=1
|
||||
-D HAS_TOUCH_UI=1
|
||||
-D FIRMWARE_OTA_ENV='"ThinkNode_M9_companion_radio_touch"'
|
||||
; 20px Montserrat for the at-a-glance body (atGlanceEnsureFont). 28px filled
|
||||
; this 240x320 panel and crowded out the message (#446); the T-Deck already
|
||||
; dropped to 20 for the same reason. Only 20px is forced, nothing else.
|
||||
-D LV_FONT_MONTSERRAT_20=1
|
||||
-D ENABLE_ADVERT_ON_BOOT=0
|
||||
-D LV_CONF_PATH=lv_conf_m9.h
|
||||
-D LV_CONF_INCLUDE_SIMPLE=1
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# beta_78 - test build. Stable stays beta_65.
|
||||
# One user-facing note per non-blank, non-# line; # lines are section comments.
|
||||
|
||||
# --- A crash at startup ---------------------------------------------------------------------
|
||||
A device could crash while starting up, before it finished booting, and on an unlucky unit that means it never comes up at all. Found by decoding a crash dump from a Heltec V4-R8.
|
||||
The cause was a race inside the Wi-Fi stack: the firmware was adding its Wi-Fi event handlers after the radio had already started, and a disconnect arriving in that moment could be handled while the list of handlers was being rebuilt underneath. The handlers are now all registered before the radio starts, which closes the window rather than narrowing it. A failed first connection is ordinary, which is why this could happen at all.
|
||||
|
||||
# --- The location privacy setting was on the wrong page --------------------------------------
|
||||
beta_77 added an option to advertise a position near you rather than your exact one, and put it on a settings page most devices do not show. Two people went looking for it and correctly concluded it was not there. It is now in Settings, GPS, at the bottom.
|
||||
It is also easier to recognise: it is called "Location privacy" rather than "Position in adverts", and it shows four buttons, Exact, 100 m, 250 m and 1 km, so every choice and the current one are visible without tapping anything.
|
||||
|
||||
# --- Lock screen notifications ----------------------------------------------------------------
|
||||
A message arriving on the lock screen now says who sent it and how far away they are, not just which conversation it was in. A channel post shows the channel, the sender and the hop count; a direct message shows the contact and "direct" when they are one hop away.
|
||||
Messages in a muted channel no longer light the screen. Muting silenced the sound but still woke the display and printed the message in large type, which was the louder half of the notification rather than the quieter one. Mentions are separate, so a channel muted for chatter still shows an @-mention.
|
||||
|
||||
# --- ThinkNode M9 -------------------------------------------------------------------------------
|
||||
Special characters can be selected. Contact search navigation, the contacts menu delay, and the composer being focused when a chat opens are all fixed, and the battery saver now shows in the status icons. All by Michael A. Cojocari, from reports by Buko84.
|
||||
The colour picker in Display settings no longer turns the swatch you are on white, which hid the colour you were choosing. Reported by Buko84.
|
||||
The notification text on a dark screen is smaller, so the message has room. It was sized to be readable from across a room, which crowded a 240x320 panel. Requested by Buko84.
|
||||
|
||||
# --- Also ----------------------------------------------------------------------------------------
|
||||
The T-Lora Pager has a shortcut to the special-character picker, and several Attaky usability problems are fixed. Both by Michael A. Cojocari.
|
||||
|
||||
# --- For testers ---------------------------------------------------------------------------------
|
||||
If you use the lock screen notification, the two things worth confirming are that a muted channel stays dark and that an @-mention in that same channel still comes through.
|
||||
Still not verified on hardware, both off by default and unchanged: the DS3231 clock module support, written from the datasheet with nobody having wired one up, and the louder chime, whose pitch has not been measured on an M9.
|
||||
Still open and not fixed here: a reboot when pressing down past the bottom of a chat on the M9, which needs a crash dump to place; a screen that will not stay dark after a manual lock; and the web flasher hanging at "wrapping up" on the T-Display P4.
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace TouchPrefsSchema {
|
||||
|
||||
static constexpr uint16_t MAGIC = 0x5743; // 'WC' (WadaCfg)
|
||||
static constexpr uint8_t CURRENT_VERSION = 57; // v49: fem_lna default flip on the V4-R8; v50: map tile z/x/y line off by default (no new fields); v51: console_mode (boot into the text console; new trailing field, default OFF); v52: console_monitor (show incoming messages in the console, default ON); v54: boot_wifi_time + boot_wifi_open (cold-boot saved-Wi-Fi time sync, #383; both OFF); v55: loud_alerts (resonant-pitch chime, #388; OFF); v56: theme_mode (Day/Night firmware theme, #296; default Night); v57: gps_fuzz_m (displace the advertised position, #399; 0 = off)
|
||||
static constexpr uint8_t CURRENT_VERSION = 58; // v49: fem_lna default flip on the V4-R8; v50: map tile z/x/y line off by default (no new fields); v51: console_mode (boot into the text console; new trailing field, default OFF); v52: console_monitor (show incoming messages in the console, default ON); v54: boot_wifi_time + boot_wifi_open (cold-boot saved-Wi-Fi time sync, #383; both OFF); v55: loud_alerts (resonant-pitch chime, #388; OFF); v56: theme_mode (Day/Night firmware theme, #296; default Night); v57: gps_fuzz_m (displace the advertised position, #399; 0 = off); v58: Attaky notification blink enable + room/DM color indexes (#423)
|
||||
static constexpr uint8_t BROKEN_MID_INSERT_VERSION = 44;
|
||||
|
||||
// Persisted byte layout. New fields must be appended at the end: older blobs
|
||||
@@ -109,6 +109,9 @@ struct __attribute__((packed)) Config {
|
||||
// advert: a fresh random offset each time would let anyone averaging a night
|
||||
// of adverts recover the true centre, which is the opposite of the intent.
|
||||
uint16_t gps_fuzz_m;
|
||||
uint8_t attaky_notify_enabled; // v58: blink both keyboard indicators for incoming messages
|
||||
uint8_t attaky_notify_room_color; // v58: seven-color palette index for rooms/channels
|
||||
uint8_t attaky_notify_dm_color; // v58: seven-color palette index for direct messages
|
||||
};
|
||||
|
||||
static constexpr size_t HEADER_SIZE = offsetof(Config, bright);
|
||||
@@ -121,10 +124,10 @@ static_assert(offsetof(Config, web_mirror) == offsetof(Config, rx_queue) + sizeo
|
||||
// rejection is silent: cfgFlush just returns false and every preference stops
|
||||
// persisting, with nothing in the log to say why. The struct grows most releases,
|
||||
// so guard the ceiling here rather than discover it as "settings do not save" on
|
||||
// whichever board is using the file backend. 114 bytes today.
|
||||
// whichever board is using the file backend. 117 bytes today.
|
||||
static_assert(sizeof(Config) <= 2048,
|
||||
"Config exceeds the SdNvsPrefs value cap; prefs would silently stop saving");
|
||||
static_assert(offsetof(Config, gps_fuzz_m) + sizeof(Config::gps_fuzz_m) == sizeof(Config),
|
||||
static_assert(offsetof(Config, attaky_notify_dm_color) + sizeof(Config::attaky_notify_dm_color) == sizeof(Config),
|
||||
"new preference fields must remain trailing");
|
||||
// lang_file must stay immediately before the tail, or a v48-era blob overlays
|
||||
// onto the wrong bytes. Checking both ends means the next person to append is
|
||||
@@ -150,6 +153,15 @@ static_assert(offsetof(Config, theme_mode) ==
|
||||
static_assert(offsetof(Config, gps_fuzz_m) ==
|
||||
offsetof(Config, theme_mode) + sizeof(Config::theme_mode),
|
||||
"gps_fuzz_m must follow theme_mode");
|
||||
static_assert(offsetof(Config, attaky_notify_enabled) ==
|
||||
offsetof(Config, gps_fuzz_m) + sizeof(Config::gps_fuzz_m),
|
||||
"attaky_notify_enabled must follow gps_fuzz_m");
|
||||
static_assert(offsetof(Config, attaky_notify_room_color) ==
|
||||
offsetof(Config, attaky_notify_enabled) + sizeof(Config::attaky_notify_enabled),
|
||||
"attaky_notify_room_color must follow attaky_notify_enabled");
|
||||
static_assert(offsetof(Config, attaky_notify_dm_color) ==
|
||||
offsetof(Config, attaky_notify_room_color) + sizeof(Config::attaky_notify_room_color),
|
||||
"attaky_notify_dm_color must follow attaky_notify_room_color");
|
||||
|
||||
// Overlay a persisted blob on caller-provided defaults. Beta 57 wrote v44 with
|
||||
// retry_echo inserted before web_mirror, shifting every later value. That blob
|
||||
|
||||
@@ -144,6 +144,9 @@ static void cfgSetDefaults(TouchCfg& c) {
|
||||
c.loud_alerts = 0; // OFF: the standard chime pitch unless asked for
|
||||
c.theme_mode = 0; // Night: preserves the existing firmware appearance
|
||||
c.gps_fuzz_m = 0; // OFF: advertise the real position unless asked otherwise
|
||||
c.attaky_notify_enabled = 0; // OFF: incoming messages do not blink the keyboard indicators
|
||||
c.attaky_notify_room_color = 0; // red
|
||||
c.attaky_notify_dm_color = 1; // green
|
||||
c.compact_chat = 0; // OFF: bubble chat layout (opt-in IRC-style dense rows)
|
||||
c.clock_floor = 0; // no persisted send-timestamp floor yet
|
||||
c.rx_queue = 1; // ON: buffered receive (test-channel default; opt-out toggle in Radio & Mesh)
|
||||
@@ -259,6 +262,11 @@ static void cfgLoadOrMigrate() {
|
||||
if (stored_version < 55) { s_cfg.loud_alerts = 0; }
|
||||
if (stored_version < 56) { s_cfg.theme_mode = 0; } // Night: unchanged appearance
|
||||
if (stored_version < 57) { s_cfg.gps_fuzz_m = 0; } // OFF: real position
|
||||
if (stored_version < 58) {
|
||||
s_cfg.attaky_notify_enabled = 0;
|
||||
s_cfg.attaky_notify_room_color = 0;
|
||||
s_cfg.attaky_notify_dm_color = 1;
|
||||
}
|
||||
if (stored_version < 31) s_cfg.compact_chat = 0; // new trailing field: compact chat rows off by default
|
||||
if (stored_version < 32) s_cfg.clock_floor = 0; // new trailing field: no send-timestamp floor persisted yet (#89)
|
||||
if (stored_version < 33) s_cfg.rx_queue = 1; // buffered LoRa receive ON for the test channel (opt-out toggle in Radio & Mesh)
|
||||
@@ -1130,6 +1138,38 @@ bool touchPrefsSetMsgFlash(bool on) {
|
||||
return cfgFlush();
|
||||
}
|
||||
|
||||
bool touchPrefsGetAttakyNotifyEnabled() {
|
||||
if (!s_begun) touchPrefsBegin();
|
||||
return s_cfg.attaky_notify_enabled != 0;
|
||||
}
|
||||
bool touchPrefsSetAttakyNotifyEnabled(bool on) {
|
||||
if (!s_begun) touchPrefsBegin();
|
||||
s_cfg.attaky_notify_enabled = on ? 1 : 0;
|
||||
return cfgFlush();
|
||||
}
|
||||
uint8_t touchPrefsGetAttakyNotifyRoomColor() {
|
||||
if (!s_begun) touchPrefsBegin();
|
||||
return s_cfg.attaky_notify_room_color < TOUCH_ATTAKY_NOTIFY_COLOR_COUNT
|
||||
? s_cfg.attaky_notify_room_color : 0;
|
||||
}
|
||||
bool touchPrefsSetAttakyNotifyRoomColor(uint8_t color) {
|
||||
if (color >= TOUCH_ATTAKY_NOTIFY_COLOR_COUNT) return false;
|
||||
if (!s_begun) touchPrefsBegin();
|
||||
s_cfg.attaky_notify_room_color = color;
|
||||
return cfgFlush();
|
||||
}
|
||||
uint8_t touchPrefsGetAttakyNotifyDmColor() {
|
||||
if (!s_begun) touchPrefsBegin();
|
||||
return s_cfg.attaky_notify_dm_color < TOUCH_ATTAKY_NOTIFY_COLOR_COUNT
|
||||
? s_cfg.attaky_notify_dm_color : 1;
|
||||
}
|
||||
bool touchPrefsSetAttakyNotifyDmColor(uint8_t color) {
|
||||
if (color >= TOUCH_ATTAKY_NOTIFY_COLOR_COUNT) return false;
|
||||
if (!s_begun) touchPrefsBegin();
|
||||
s_cfg.attaky_notify_dm_color = color;
|
||||
return cfgFlush();
|
||||
}
|
||||
|
||||
// Console mode is a BOOT mode, so this is read before the UI is built. It fails
|
||||
// safe by construction: the only value that means console is exactly 1, so a
|
||||
// corrupt or unreadable pref boots the graphical UI, which is the mode everyone
|
||||
|
||||
@@ -196,6 +196,14 @@ bool touchPrefsSetFemLna(bool on);
|
||||
bool touchPrefsGetMsgFlash();
|
||||
bool touchPrefsSetMsgFlash(bool on);
|
||||
|
||||
static constexpr uint8_t TOUCH_ATTAKY_NOTIFY_COLOR_COUNT = 7;
|
||||
bool touchPrefsGetAttakyNotifyEnabled();
|
||||
bool touchPrefsSetAttakyNotifyEnabled(bool on);
|
||||
uint8_t touchPrefsGetAttakyNotifyRoomColor();
|
||||
bool touchPrefsSetAttakyNotifyRoomColor(uint8_t color);
|
||||
uint8_t touchPrefsGetAttakyNotifyDmColor();
|
||||
bool touchPrefsSetAttakyNotifyDmColor(uint8_t color);
|
||||
|
||||
/* Advertise on boot (#76): fire one flood self-advert ~6s after boot so peers with auto-add on
|
||||
* refresh our pubkey (useful after a reflash wiped storage). Opt-in, default off. All boards. */
|
||||
bool touchPrefsGetConsoleMode(); // boot into the LVGL-free console (CONSOLE_MODE.md)
|
||||
|
||||
+30
-16
@@ -1435,6 +1435,36 @@ void setup() {
|
||||
* contiguous DMA block, so let it claim memory before BLE. (Association
|
||||
* happens later in loop(); this just inits the stack.) */
|
||||
if (want_wifi) {
|
||||
// Register every Wi-Fi event handler BEFORE the stack is started, never
|
||||
// after. WiFi.onEvent() push_backs into a std::vector that the Arduino core
|
||||
// iterates from its own event task, with no lock on either side: a
|
||||
// registration that reallocates the vector while an event is being
|
||||
// dispatched frees the buffer the event task is walking, and it then calls
|
||||
// through a dangling function pointer. That is a real crash we have a dump
|
||||
// of, on a Heltec V4-R8 on beta_77: the event task was inside
|
||||
// _eventCallback copying a WiFiEventCbList entry while setup() was inside
|
||||
// _M_realloc_insert growing that same vector, and it jumped to a garbage PC.
|
||||
//
|
||||
// The bug is in the Arduino core rather than here, and we cannot lock its
|
||||
// vector, but we can make the race impossible: with nothing registered
|
||||
// after the stack can emit events, the vector is never mutated while it is
|
||||
// being read. Both handlers used to be added afterwards, one of them after
|
||||
// WiFi.begin(), which is where the window came from.
|
||||
//
|
||||
// Records WHY every STA disconnect happened, surfaced by the UI's Wi-Fi
|
||||
// status string as "auth failed (rNN)", so failures are diagnosable on a
|
||||
// device with no serial console.
|
||||
WiFi.onEvent([](WiFiEvent_t, WiFiEventInfo_t info){
|
||||
g_wifi_last_disc_reason = info.wifi_sta_disconnected.reason;
|
||||
}, ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
|
||||
// Without the WIFI_DEBUG_PRINTLN tracing the old copy had: that macro comes
|
||||
// from SerialWifiInterface.h, which is not in scope this early in setup().
|
||||
// The prints were debug-only and compile to nothing in a release build; the
|
||||
// flag is the handler's actual job and is unchanged.
|
||||
WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t){
|
||||
if (event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) wifi_needs_reconnect = true;
|
||||
else if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP) wifi_needs_reconnect = false;
|
||||
});
|
||||
const bool wifi_mode_ready = WiFi.mode(WIFI_STA);
|
||||
#if defined(TLORA_PAGER)
|
||||
if (!wifi_mode_ready) {
|
||||
@@ -1448,12 +1478,6 @@ void setup() {
|
||||
// exists so a later WPA re-auth cannot bypass Wi-Fi-first ordering
|
||||
#endif
|
||||
WiFi.persistent(false);
|
||||
// Record WHY every STA disconnect happened — surfaced by the UI's Wi-Fi
|
||||
// status string as "auth failed (rNN)" so failures are diagnosable on a
|
||||
// device with no serial console. Additive: multiple onEvent handlers coexist.
|
||||
WiFi.onEvent([](WiFiEvent_t, WiFiEventInfo_t info){
|
||||
g_wifi_last_disc_reason = info.wifi_sta_disconnected.reason;
|
||||
}, ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
|
||||
// NOTE: do NOT enable modem-sleep here. On a fresh, *unassociated* STA (the
|
||||
// setup wizard, no creds yet) DTIM modem-sleep naps the radio through the
|
||||
// scan dwell, so WiFi.scanNetworks() comes back empty ("no networks found").
|
||||
@@ -1562,16 +1586,6 @@ void setup() {
|
||||
board.setInhibitSleep(true); // prevent sleep when WiFi is active
|
||||
WiFi.setAutoReconnect(true);
|
||||
|
||||
WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info){
|
||||
if (event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) {
|
||||
WIFI_DEBUG_PRINTLN("WiFi disconnected. Flagging for reconnect...");
|
||||
wifi_needs_reconnect = true;
|
||||
} else if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP) {
|
||||
WIFI_DEBUG_PRINTLN("WiFi connected successfully!");
|
||||
wifi_needs_reconnect = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (wifiConfigHasRuntime()) {
|
||||
char ssid[WIFI_CONFIG_SSID_MAX];
|
||||
char pwd[WIFI_CONFIG_PWD_MAX];
|
||||
|
||||
+675
-116
File diff suppressed because it is too large.
Load diff
@@ -3,7 +3,7 @@
|
||||
// now also builds this for the "at a glance" notification's 20 px message body
|
||||
// (see atGlanceEnsureFont() in UITask.cpp) -- an experiment to see whether a
|
||||
// smaller-than-28px glance body is still legible on that panel.
|
||||
#if defined(HAS_TANMATSU) || defined(HAS_TDECK_GT911)
|
||||
#if defined(HAS_TANMATSU) || defined(HAS_TDECK_GT911) || defined(HAS_THINKNODE_M9)
|
||||
|
||||
/*******************************************************************************
|
||||
* Size: 20 px
|
||||
|
||||
@@ -27,6 +27,9 @@ static Config safeDefaults() {
|
||||
c.boot_wifi_open = 0;
|
||||
c.theme_mode = 0;
|
||||
c.gps_fuzz_m = 0;
|
||||
c.attaky_notify_enabled = 0;
|
||||
c.attaky_notify_room_color = 0;
|
||||
c.attaky_notify_dm_color = 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -85,6 +88,9 @@ int main() {
|
||||
assert(migrated.loud_alerts == 0);
|
||||
assert(migrated.theme_mode == 0);
|
||||
assert(migrated.gps_fuzz_m == 0);
|
||||
assert(migrated.attaky_notify_enabled == 0);
|
||||
assert(migrated.attaky_notify_room_color == 0);
|
||||
assert(migrated.attaky_notify_dm_color == 1);
|
||||
|
||||
// Reproduce beta 57 exactly: retry was inserted before the old suffix, then
|
||||
// the v43 bytes were copied and the full shifted v44 structure was written.
|
||||
@@ -116,7 +122,9 @@ int main() {
|
||||
constexpr size_t v53_size = offsetof(Config, boot_wifi_time);
|
||||
static_assert(v53_size + sizeof(Config::boot_wifi_time) + sizeof(Config::boot_wifi_open)
|
||||
+ sizeof(Config::loud_alerts) + sizeof(Config::theme_mode)
|
||||
+ sizeof(Config::gps_fuzz_m) == sizeof(Config),
|
||||
+ sizeof(Config::gps_fuzz_m) + sizeof(Config::attaky_notify_enabled)
|
||||
+ sizeof(Config::attaky_notify_room_color)
|
||||
+ sizeof(Config::attaky_notify_dm_color) == sizeof(Config),
|
||||
"v53 is the current layout minus every byte appended since");
|
||||
|
||||
Config v53 = safeDefaults();
|
||||
@@ -155,6 +163,9 @@ int main() {
|
||||
current.loud_alerts = 1;
|
||||
current.theme_mode = 1;
|
||||
current.gps_fuzz_m = 150;
|
||||
current.attaky_notify_enabled = 1;
|
||||
current.attaky_notify_room_color = 6;
|
||||
current.attaky_notify_dm_color = 4;
|
||||
migrated = safeDefaults();
|
||||
assert(TouchPrefsSchema::overlayStored(migrated, ¤t, sizeof(current), &stored_version));
|
||||
assert(stored_version == TouchPrefsSchema::CURRENT_VERSION);
|
||||
@@ -177,15 +188,16 @@ int main() {
|
||||
assert(migrated.app_hide == safeDefaults().app_hide);
|
||||
assert(migrated.theme_mode == 0);
|
||||
|
||||
// v56 appends only theme_mode. It was written as v54 on the contributing
|
||||
// v56 appended only theme_mode. It was written as v54 on the contributing
|
||||
// branch, but v54 and v55 were taken by boot_wifi_* and loud_alerts before it
|
||||
// merged, so the field sits behind those and the blob one version short of
|
||||
// current is the one that must leave it at the Night default.
|
||||
// merged, so the field sits behind those and a historical v55 blob must leave
|
||||
// it at the Night default.
|
||||
constexpr size_t v55_size = offsetof(Config, theme_mode);
|
||||
static_assert(offsetof(Config, gps_fuzz_m) + sizeof(Config::gps_fuzz_m) == sizeof(Config),
|
||||
"gps_fuzz_m must remain last");
|
||||
static_assert(v55_size + sizeof(Config::theme_mode) + sizeof(Config::gps_fuzz_m) == sizeof(Config),
|
||||
"v55 is the current layout minus theme_mode and gps_fuzz_m");
|
||||
static_assert(v55_size + sizeof(Config::theme_mode) + sizeof(Config::gps_fuzz_m)
|
||||
+ sizeof(Config::attaky_notify_enabled)
|
||||
+ sizeof(Config::attaky_notify_room_color)
|
||||
+ sizeof(Config::attaky_notify_dm_color) == sizeof(Config),
|
||||
"v55 is the current layout minus every byte appended since");
|
||||
Config v55 = safeDefaults();
|
||||
v55.ver = 55;
|
||||
v55.kb_force_legacy = 1;
|
||||
@@ -198,6 +210,28 @@ int main() {
|
||||
assert(migrated.loud_alerts == 1);
|
||||
assert(migrated.theme_mode == 0);
|
||||
assert(migrated.gps_fuzz_m == 0);
|
||||
assert(migrated.attaky_notify_enabled == 0);
|
||||
assert(migrated.attaky_notify_room_color == 0);
|
||||
assert(migrated.attaky_notify_dm_color == 1);
|
||||
|
||||
constexpr size_t v57_size = offsetof(Config, attaky_notify_enabled);
|
||||
static_assert(v57_size + sizeof(Config::attaky_notify_enabled)
|
||||
+ sizeof(Config::attaky_notify_room_color)
|
||||
+ sizeof(Config::attaky_notify_dm_color) == sizeof(Config),
|
||||
"v57 is the current layout minus the Attaky notification fields");
|
||||
Config v57 = safeDefaults();
|
||||
v57.ver = 57;
|
||||
v57.gps_fuzz_m = 250;
|
||||
v57.attaky_notify_enabled = 1; // outside the stored v57 extent
|
||||
v57.attaky_notify_room_color = 6;
|
||||
v57.attaky_notify_dm_color = 5;
|
||||
migrated = safeDefaults();
|
||||
assert(TouchPrefsSchema::overlayStored(migrated, &v57, v57_size, &stored_version));
|
||||
assert(stored_version == 57);
|
||||
assert(migrated.gps_fuzz_m == 250);
|
||||
assert(migrated.attaky_notify_enabled == 0);
|
||||
assert(migrated.attaky_notify_room_color == 0);
|
||||
assert(migrated.attaky_notify_dm_color == 1);
|
||||
|
||||
Config invalid = safeDefaults();
|
||||
uint8_t garbage[sizeof(Config)] = {};
|
||||
|
||||
@@ -46,6 +46,7 @@ static const uint8_t SHIFT_HALF = 0, SHIFT_ROW = 3, SHIFT_COL = 0;
|
||||
|
||||
static bool s_inited = false;
|
||||
static bool s_present[2] = { false, false };
|
||||
static uint8_t s_notify_color = ATTAKY_NOTIFY_OFF;
|
||||
static uint8_t s_prev[2][5] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
|
||||
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } };
|
||||
|
||||
@@ -72,6 +73,11 @@ static uint8_t awRead(uint8_t addr, uint8_t reg) {
|
||||
return (uint8_t)Wire.read();
|
||||
}
|
||||
|
||||
static uint8_t p1Value(uint8_t row_bits) {
|
||||
const uint8_t led_bits = (uint8_t)((~s_notify_color & 0x07u) << 5);
|
||||
return (uint8_t)((row_bits & 0x1Fu) | led_bits);
|
||||
}
|
||||
|
||||
static bool initHalf(uint8_t addr) {
|
||||
bool ok = true;
|
||||
ok &= awWrite(addr, AW_REG_SWRST, 0x00);
|
||||
@@ -81,7 +87,7 @@ static bool initHalf(uint8_t addr) {
|
||||
ok &= awWrite(addr, AW_REG_CFG_P0, 0xFF);
|
||||
ok &= awWrite(addr, AW_REG_CFG_P1, 0x00);
|
||||
ok &= awWrite(addr, AW_REG_OUT_P0, 0x00);
|
||||
ok &= awWrite(addr, AW_REG_OUT_P1, P1_IDLE);
|
||||
ok &= awWrite(addr, AW_REG_OUT_P1, p1Value(P1_IDLE));
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -97,11 +103,11 @@ static void ensureInit() {
|
||||
|
||||
static void scanHalf(uint8_t addr, uint8_t cols[5]) {
|
||||
for (uint8_t row = 0; row < 5; row++) {
|
||||
awWrite(addr, AW_REG_OUT_P1, (uint8_t)(ROW_DRIVE[row] | 0xE0));
|
||||
awWrite(addr, AW_REG_OUT_P1, p1Value(ROW_DRIVE[row]));
|
||||
delayMicroseconds(50);
|
||||
cols[row] = (uint8_t)(awRead(addr, AW_REG_IN_P0) & 0x1F);
|
||||
}
|
||||
awWrite(addr, AW_REG_OUT_P1, P1_IDLE);
|
||||
awWrite(addr, AW_REG_OUT_P1, p1Value(P1_IDLE));
|
||||
}
|
||||
|
||||
void attakyKeyboardPoll(bool active) {
|
||||
@@ -155,4 +161,20 @@ int attakyKeyboardReadKey() {
|
||||
|
||||
bool attakyKeyboardPresent() { return s_present[0] || s_present[1]; }
|
||||
|
||||
bool attakyKeyboardSetNotificationColor(uint8_t color_mask) {
|
||||
s_notify_color = color_mask & 0x07u;
|
||||
ensureInit();
|
||||
if (!attakyI2cLock(20)) return false;
|
||||
|
||||
bool wrote = false;
|
||||
bool ok = true;
|
||||
for (int h = 0; h < 2; ++h) {
|
||||
if (!s_present[h]) continue;
|
||||
wrote = true;
|
||||
if (!awWrite(KB_ADDR[h], AW_REG_OUT_P1, p1Value(P1_IDLE))) ok = false;
|
||||
}
|
||||
attakyI2cUnlock();
|
||||
return wrote && ok;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -5,8 +5,16 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum : uint8_t {
|
||||
ATTAKY_NOTIFY_OFF = 0,
|
||||
ATTAKY_NOTIFY_BLUE = 1u << 0,
|
||||
ATTAKY_NOTIFY_GREEN = 1u << 1,
|
||||
ATTAKY_NOTIFY_RED = 1u << 2,
|
||||
};
|
||||
|
||||
void attakyKeyboardPoll(bool active);
|
||||
int attakyKeyboardReadKey();
|
||||
bool attakyKeyboardPresent();
|
||||
bool attakyKeyboardSetNotificationColor(uint8_t color_mask);
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user