From 4c3f4844d29561171e04f78661a2342cb8ed99fa Mon Sep 17 00:00:00 2001 From: ReFil <31960031+ReFil@users.noreply.github.com> Date: Sun, 9 Feb 2025 19:52:39 +0000 Subject: [PATCH] feat(core): Allow idle and deep sleep timeouts to be configured at runtime --- app/include/zmk/activity.h | 8 ++++ app/src/activity.c | 87 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 91 insertions(+), 4 deletions(-) diff --git a/app/include/zmk/activity.h b/app/include/zmk/activity.h index 2aad024a8..ea55dd82b 100644 --- a/app/include/zmk/activity.h +++ b/app/include/zmk/activity.h @@ -9,3 +9,11 @@ enum zmk_activity_state { ZMK_ACTIVITY_ACTIVE, ZMK_ACTIVITY_IDLE, ZMK_ACTIVITY_SLEEP }; enum zmk_activity_state zmk_activity_get_state(void); + +uint32_t zmk_activity_get_idle_timeout(void); +void zmk_activity_set_idle_timeout(uint32_t timeout); + +#if IS_ENABLED(CONFIG_ZMK_SLEEP) +uint32_t zmk_activity_get_sleep_timeout(void); +void zmk_activity_set_sleep_timeout(uint32_t timeout); +#endif \ No newline at end of file diff --git a/app/src/activity.c b/app/src/activity.c index b109d46d8..362385001 100644 --- a/app/src/activity.c +++ b/app/src/activity.c @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -42,10 +43,10 @@ static enum zmk_activity_state activity_state; static uint32_t activity_last_uptime; -#define MAX_IDLE_MS CONFIG_ZMK_IDLE_TIMEOUT +static uint32_t idle_timeout_ms = CONFIG_ZMK_IDLE_TIMEOUT; #if IS_ENABLED(CONFIG_ZMK_SLEEP) -#define MAX_SLEEP_MS CONFIG_ZMK_IDLE_SLEEP_TIMEOUT +static uint32_t sleep_timeout_ms = CONFIG_ZMK_IDLE_SLEEP_TIMEOUT; #endif int raise_event(void) { @@ -63,6 +64,39 @@ int set_state(enum zmk_activity_state state) { enum zmk_activity_state zmk_activity_get_state(void) { return activity_state; } +#if IS_ENABLED(CONFIG_SETTINGS) +static void activity_save_timeouts_work(struct k_work *work) { + settings_save_one("activity/idle", &idle_timeout_ms, sizeof(idle_timeout_ms)); +#if IS_ENABLED(CONFIG_ZMK_SLEEP) + settings_save_one("activity/sleep", &sleep_timeout_ms, sizeof(sleep_timeout_ms)); +#endif +} + +static struct k_work_delayable activity_save_work; +#endif + +static int activity_save_timeouts(void) { +#if IS_ENABLED(CONFIG_SETTINGS) + return k_work_reschedule(&activity_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); +#else + return 0; +#endif +} + +uint32_t zmk_activity_get_idle_timeout(void) { return idle_timeout_ms; } +void zmk_activity_set_idle_timeout(uint32_t timeout) { + idle_timeout_ms = timeout; + activity_save_timeouts(); +} + +#if IS_ENABLED(CONFIG_ZMK_SLEEP) +uint32_t zmk_activity_get_sleep_timeout(void) { return sleep_timeout_ms; } +void zmk_activity_set_sleep_timeout(uint32_t timeout) { + sleep_timeout_ms = timeout; + activity_save_timeouts(); +} +#endif + static int note_activity(void) { activity_last_uptime = k_uptime_get(); @@ -75,7 +109,7 @@ void activity_work_handler(struct k_work *work) { int32_t current = k_uptime_get(); int32_t inactive_time = current - activity_last_uptime; #if IS_ENABLED(CONFIG_ZMK_SLEEP) - if (inactive_time > MAX_SLEEP_MS && !is_usb_power_present()) { + if (inactive_time > sleep_timeout_ms && !is_usb_power_present()) { // Put devices in suspend power mode before sleeping set_state(ZMK_ACTIVITY_SLEEP); @@ -88,7 +122,7 @@ void activity_work_handler(struct k_work *work) { sys_poweroff(); } else #endif /* IS_ENABLED(CONFIG_ZMK_SLEEP) */ - if (inactive_time > MAX_IDLE_MS) { + if (inactive_time > idle_timeout_ms) { set_state(ZMK_ACTIVITY_IDLE); } } @@ -99,7 +133,52 @@ void activity_expiry_function(struct k_timer *_timer) { k_work_submit(&activity_ K_TIMER_DEFINE(activity_timer, activity_expiry_function, NULL); +#if IS_ENABLED(CONFIG_SETTINGS) + +static int activity_handle_set(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg) { + LOG_DBG("Setting timeout value %s", name); + + if (settings_name_steq(name, "idle", NULL)) { + if (len != sizeof(idle_timeout_ms)) { + LOG_ERR("Invalid timeout size (got %d expected %d)", len, sizeof(idle_timeout_ms)); + return -EINVAL; + } + + int err = read_cb(cb_arg, &idle_timeout_ms, sizeof(idle_timeout_ms)); + if (err <= 0) { + LOG_ERR("Failed to read idle timeout from settings (err %d)", err); + return err; + } + } +#if IS_ENABLED(CONFIG_ZMK_SLEEP) + else if (settings_name_steq(name, "sleep", NULL)) { + if (len != sizeof(sleep_timeout_ms)) { + LOG_ERR("Invalid timeout size (got %d expected %d)", len, sizeof(sleep_timeout_ms)); + return -EINVAL; + } + + int err = read_cb(cb_arg, &sleep_timeout_ms, sizeof(sleep_timeout_ms)); + if (err <= 0) { + LOG_ERR("Failed to read sleep timeout from settings (err %d)", err); + return err; + } + } +#endif + + return 0; +} + +SETTINGS_STATIC_HANDLER_DEFINE(activity, "activity", NULL, activity_handle_set, NULL, NULL); + +#endif /* IS_ENABLED(CONFIG_SETTINGS) */ + static int activity_init(void) { + +#if IS_ENABLED(CONFIG_SETTINGS) + k_work_init_delayable(&activity_save_work, activity_save_timeouts_work); +#endif + activity_last_uptime = k_uptime_get(); k_timer_start(&activity_timer, K_SECONDS(1), K_SECONDS(1));