mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-26 14:58:12 +00:00
feat(clock,keyboard): alarm repeat + non-Latin keyboard alphabets
Alarm repeat (Clock Tools): - NodePrefs::alarm_repeat_mask (weekday bitmask, struct tm::tm_wday convention) — new Repeat row cycles Off/Daily/Weekdays/Weekends. computeAlarmNextFire() scans the next 7 days for a matching weekday when set; evaluateAlarm() only clears alarm_on (one-shot) when the mask is empty, otherwise re-arms. mask==0 is byte-for-byte the original one-shot behaviour, so existing users see no change. On-screen keyboard alphabets (Settings > Keyboard > Alphabet): - KeyboardWidget reworked from single-byte ASCII cells to UTF-8 codepoints (insertion, backspace and T9 in-place cycling all codepoint-aware now, so a multi-byte character is never split) — see kbApplyCapsUtf8/kbUtf8Len/ kbUtf8CharAt/kbUtf8LastCharBytes. - Cyrillic, Greek and an Extended Latin set (Polish/Czech/Slovak/German/ French/Spanish/Nordic diacritics) join the keyboard's existing #@/abc page cycle (Latin -> alt alphabet -> Symbols -> Latin) — no new key needed. NodePrefs::keyboard_alt_alphabet picks which one, if any, is active. - Lemon font is forced on transiently inside KeyboardWidget::render() (saved and restored every call) whenever the alt-alphabet page is showing or already-typed text has non-ASCII bytes, so composing is visible even if Font is set to Default. - Each script's caps-shift rule is distinct and documented in kbApplyCapsUtf8: flat -0x20 for ASCII/Cyrillic/Greek (with the ё/ς exceptions), flat -0x20 for Latin-1 (à-þ), and an adjacent-pair -1 for Latin Extended-A (verified against every character actually used, not a blanket rule for that whole Unicode block). NodePrefs schema: two tail-appended fields this session (alarm_repeat_mask, keyboard_alt_alphabet), SCHEMA_SENTINEL 0xC0DE001B -> 0xC0DE001D, sizeof(NodePrefs) 2496 -> 2504 (verified via a standalone host compile). Docs: Clock Tools' Repeat row, Settings > Keyboard > Alphabet, and the Rooms keyboard note (no longer ASCII-only once an alphabet is enabled). Not build-verified — no PlatformIO toolchain available this session. Caps mappings cross-checked against Python's Unicode case tables; UTF-8 literal bytes verified at the byte level.
This commit is contained in:
@@ -1496,14 +1496,30 @@ void UITask::wakeForAlarm() {
|
||||
|
||||
// Next absolute wall instant matching alarm_hour:alarm_min in local time,
|
||||
// strictly after now_wall (an alarm set to the current minute waits a day).
|
||||
// With alarm_repeat_mask == 0 that's just tomorrow's occurrence (one-shot).
|
||||
// With a repeat mask set, scan today..+6 days for the next weekday whose bit
|
||||
// is set (struct tm's tm_wday convention, same as the mask) — today counts
|
||||
// only if its time hasn't already passed.
|
||||
uint32_t UITask::computeAlarmNextFire(uint32_t now_wall) const {
|
||||
int tz = _node_prefs ? _node_prefs->tz_offset_hours : 0;
|
||||
int64_t now_local = (int64_t)now_wall + (int64_t)tz * 3600;
|
||||
time_t t = (time_t)now_local;
|
||||
struct tm* ti = gmtime(&t);
|
||||
int64_t sod = ti->tm_hour * 3600 + ti->tm_min * 60 + ti->tm_sec; // secs since local midnight
|
||||
int64_t target = (now_local - sod)
|
||||
+ (int64_t)_node_prefs->alarm_hour * 3600 + (int64_t)_node_prefs->alarm_min * 60;
|
||||
int64_t midnight = now_local - sod;
|
||||
int64_t time_of_day = (int64_t)_node_prefs->alarm_hour * 3600 + (int64_t)_node_prefs->alarm_min * 60;
|
||||
uint8_t mask = _node_prefs->alarm_repeat_mask;
|
||||
if (mask != 0) {
|
||||
for (int d = 0; d < 7; d++) {
|
||||
if (mask & (1 << ((ti->tm_wday + d) % 7))) {
|
||||
int64_t target = midnight + (int64_t)d * 86400 + time_of_day;
|
||||
if (target > now_local) return (uint32_t)(target - (int64_t)tz * 3600);
|
||||
}
|
||||
}
|
||||
// Mask had no bit set (shouldn't happen — the UI only offers non-empty
|
||||
// presets) — fall through to the one-shot calculation so it still fires.
|
||||
}
|
||||
int64_t target = midnight + time_of_day;
|
||||
if (target <= now_local) target += 86400;
|
||||
return (uint32_t)(target - (int64_t)tz * 3600);
|
||||
}
|
||||
@@ -1529,8 +1545,12 @@ void UITask::evaluateAlarm() {
|
||||
if (now_wall - _alarm_next_fire < CLOCK_ALARM_CATCHUP_SECS) {
|
||||
char lbl[20];
|
||||
snprintf(lbl, sizeof(lbl), "Alarm %02d:%02d", _node_prefs->alarm_hour, _node_prefs->alarm_min);
|
||||
_node_prefs->alarm_on = 0; // one-shot
|
||||
bool dirty = true; savePrefsIfDirty(dirty);
|
||||
if (_node_prefs->alarm_repeat_mask == 0) {
|
||||
_node_prefs->alarm_on = 0; // one-shot
|
||||
bool dirty = true; savePrefsIfDirty(dirty);
|
||||
}
|
||||
// Repeating: alarm_on stays set: computeAlarmNextFire() re-arms it for the
|
||||
// next matching weekday below.
|
||||
_alarm_next_fire = 0;
|
||||
fireClockAlert(lbl);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user