diff options
author | Peter Johanson <peter@peterjohanson.com> | 2021-08-12 03:44:38 +0000 |
---|---|---|
committer | Pete Johanson <peter@peterjohanson.com> | 2021-09-25 17:17:04 -0400 |
commit | 2128b2b55f85a6190194d83696f7419eb53c6642 (patch) | |
tree | 9ed0a99a5646d6e1b911be6dc3dca1ac58832fdb /app/include/zmk/display.h | |
parent | 063d98e3dfa8e0089aa0039b24489d29b062cf5e (diff) |
refactor(display): Output/layer/battery thread safety.
* Submit widget updates to display queue.
* Use mutex to control access to shared state for widgets.
Diffstat (limited to 'app/include/zmk/display.h')
-rw-r--r-- | app/include/zmk/display.h | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/app/include/zmk/display.h b/app/include/zmk/display.h index d3bd042..45a4bee 100644 --- a/app/include/zmk/display.h +++ b/app/include/zmk/display.h @@ -4,8 +4,57 @@ * SPDX-License-Identifier: MIT */ +/** @file display.h + * @brief Display functions and macros. + */ + #pragma once struct k_work_q *zmk_display_work_q(); -int zmk_display_init();
\ No newline at end of file +bool zmk_display_is_initialized(); +int zmk_display_init(); + +/** + * @brief Macro to define a ZMK event listener that handles the thread safety of fetching + * the necessary state from the system work queue context, invoking a work callback + * in the display queue context, and properly accessing that state safely when performing + * display/LVGL updates. + * + * @param listener THe ZMK Event manager listener name. + * @param state_type The struct/enum type used to store/transfer state. + * @param cb The callback to invoke in the dispaly queue context to update the UI. Should be `void + * func(state_type)` signature. + * @param state_func The callback function to invoke to fetch the updated state from ZMK core. + * Should be `state type func(const zmk_event_t *eh)` signature. + * @retval listner##_init Generates a function `listener##_init` that should be called by the widget + * once ready to be updated. + **/ +#define ZMK_DISPLAY_WIDGET_LISTENER(listener, state_type, cb, state_func) \ + K_MUTEX_DEFINE(listener##_mutex); \ + static state_type __##listener##_state; \ + static state_type listener##_get_local_state() { \ + k_mutex_lock(&listener##_mutex, K_FOREVER); \ + state_type copy = __##listener##_state; \ + k_mutex_unlock(&listener##_mutex); \ + return copy; \ + }; \ + static void listener##_work_cb(struct k_work *work) { cb(listener##_get_local_state()); }; \ + K_WORK_DEFINE(listener##_work, listener##_work_cb); \ + static void listener##_refresh_state(const zmk_event_t *eh) { \ + k_mutex_lock(&listener##_mutex, K_FOREVER); \ + __##listener##_state = state_func(eh); \ + k_mutex_unlock(&listener##_mutex); \ + }; \ + static void listener##_init() { \ + listener##_refresh_state(NULL); \ + listener##_work_cb(NULL); \ + } \ + static int listener##_cb(const zmk_event_t *eh) { \ + if (zmk_display_is_initialized()) { \ + listener##_refresh_state(eh); \ + k_work_submit_to_queue(zmk_display_work_q(), &listener##_work); \ + } \ + return ZMK_EV_EVENT_BUBBLE; \ + } \ + ZMK_LISTENER(listener, listener##_cb); |