From a031af8037dee7f1489088d71f1ac80c6be78142 Mon Sep 17 00:00:00 2001 From: benblaise Date: Tue, 30 Jun 2026 13:14:47 +0200 Subject: [PATCH 1/4] BENB add direction logic to smooth encoder --- common/src/c/grid_ui_encoder.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/common/src/c/grid_ui_encoder.c b/common/src/c/grid_ui_encoder.c index 1460ad93..8186e1ef 100644 --- a/common/src/c/grid_ui_encoder.c +++ b/common/src/c/grid_ui_encoder.c @@ -148,6 +148,8 @@ void grid_ui_element_encoder_page_change_cb(struct grid_ui_element* ele, uint8_t // } } +#define SIGN(x) (((x) > 0) - ((x) < 0)) + int16_t grid_ui_encoder_rotation_delta(uint8_t old_value, uint8_t new_value, uint8_t detent, int8_t* last_leave_dir) { // lookup table indexed by a combination of old and new encoder output AB @@ -158,18 +160,24 @@ int16_t grid_ui_encoder_rotation_delta(uint8_t old_value, uint8_t new_value, uin // 4-bit state value holding old and new 2-bit encoder quadratures uint8_t combined_state = (old_value & 0b11) << 2 | (new_value & 0b11); + int16_t dir = encoder_heading[combined_state]; + int16_t delta = 0; - // non-detent encoders should produce deltas upon every quadrature change + // non-detent encoders should produce deltas upon every quadrature change, + // when that change agrees with the direction of the previous change if (!detent) { - delta = encoder_heading[combined_state]; + + if (SIGN(dir) == SIGN(*last_leave_dir)) { + delta = *last_leave_dir = dir; + } else { + *last_leave_dir = dir; + } } // detent encoders here should only a produce delta upon entering a detent, // and only if the would-be delta matches the direction lock else { - int16_t dir = encoder_heading[combined_state]; - // leaving a detent into either neighboring quadrature sets direction lock static uint8_t update_lock[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, From 5a1a69bb4b7d614d6362c1ffa05a10da757e62bc Mon Sep 17 00:00:00 2001 From: benblaise Date: Tue, 30 Jun 2026 14:41:14 +0200 Subject: [PATCH 2/4] BENB clear events after init --- common/src/c/grid_ui.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/common/src/c/grid_ui.c b/common/src/c/grid_ui.c index 86ce4879..c8d6e9a7 100644 --- a/common/src/c/grid_ui.c +++ b/common/src/c/grid_ui.c @@ -159,6 +159,13 @@ void grid_ui_event_reset(struct grid_ui_event* eve) { eve->cfg_default_flag = 1; } +void grid_ui_event_clear(struct grid_ui_event* eve) { + + if (eve->parent && eve->parent->event_clear_cb) { + eve->parent->event_clear_cb(eve); + } +} + void grid_ui_event_init(struct grid_ui_element* ele, uint8_t index, uint8_t event_type, char* function_name, const char* default_script) { assert(index < ele->event_list_length); @@ -686,10 +693,7 @@ static void grid_ui_clear_triggered(struct grid_ui_model* ui, struct grid_msg* m grid_ui_event_render_event(eve, msg); grid_ui_event_render_event_view(eve, msg); - if (ele->event_clear_cb) { - ele->event_clear_cb(eve); - } - + grid_ui_event_clear(eve); grid_ui_event_state_set(eve, GRID_EVE_STATE_INIT); } } @@ -915,6 +919,20 @@ static void grid_ui_page_read(struct grid_ui_model* ui, uint8_t page) { grid_lua_semaphore_release(&grid_lua_state); grid_usb_keyboard_enable(&grid_usb_keyboard_state); + + // Clear all events + for (uint8_t i = 0; i < ui->element_list_length; i++) { + + // Handle system element first then all the ui elements in ascending order + uint8_t element_index = (i == 0 ? ui->element_list_length - 1 : i - 1); + + struct grid_ui_element* ele = &ui->element_list[element_index]; + + for (uint8_t j = 0; j < ele->event_list_length; j++) { + + grid_ui_event_clear(&ele->event_list[j]); + } + } } #pragma GCC diagnostic push From effbddfba488cebf46320463ecfa9ec05b248f4f Mon Sep 17 00:00:00 2001 From: benblaise Date: Wed, 1 Jul 2026 12:45:21 +0200 Subject: [PATCH 3/4] BENB refactor encoder logic --- common/src/c/grid_ui_encoder.c | 45 +++++++++++++++------------------- common/src/c/grid_ui_encoder.h | 2 +- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/common/src/c/grid_ui_encoder.c b/common/src/c/grid_ui_encoder.c index 8186e1ef..837c6e6b 100644 --- a/common/src/c/grid_ui_encoder.c +++ b/common/src/c/grid_ui_encoder.c @@ -1,6 +1,7 @@ #include "grid_ui_encoder.h" #include +#include #include #include @@ -192,21 +193,16 @@ int16_t grid_ui_encoder_rotation_delta(uint8_t old_value, uint8_t new_value, uin return delta; } -uint8_t grid_ui_encoder_update_trigger(struct grid_ui_element* ele, uint64_t* last_real_time, int16_t delta) { +void grid_ui_encoder_update_trigger(struct grid_ui_element* ele, uint64_t* last_real_time, int16_t delta) { // limit lastrealtime uint64_t now = grid_platform_rtc_get_micros(); uint64_t elapsed_us = grid_platform_rtc_get_diff(now, *last_real_time); elapsed_us = MIN(elapsed_us, GRID_PARAMETER_ELAPSED_LIMIT * MS_TO_US); - if (delta == 0) { - return 0; // did not trigger - } - - // positive delta means we wish to move closer to max value, megative delta means we wish to move closer to min value - // update lastrealtime *last_real_time = now; + int32_t* template_parameter_list = ele->template_parameter_list; template_parameter_list[GRID_LUA_FNC_E_ENCODER_ELAPSED_index] = elapsed_us / MS_TO_US; @@ -222,14 +218,15 @@ uint8_t grid_ui_encoder_update_trigger(struct grid_ui_element* ele, uint64_t* la double elapsed_ms = clampu32(elapsed_us, 1000, 25000) / MS_TO_US; - double minmaxscale = (max - min) / 128.0; - - double velocityparam = template_parameter_list[GRID_LUA_FNC_E_ENCODER_VELOCITY_index] / 100.0; + double vel_param = template_parameter_list[GRID_LUA_FNC_E_ENCODER_VELOCITY_index] / 100.0; + double sen_param = template_parameter_list[GRID_LUA_FNC_E_ENCODER_SENSITIVITY_index] / 100.0; - // implement configurable velocity parameters here - double velocityfactor = ((25 * 25 - elapsed_ms * elapsed_ms) / 75.0) * minmaxscale * velocityparam + (1.0 * template_parameter_list[GRID_LUA_FNC_E_ENCODER_SENSITIVITY_index] / 100.0); + double vel_comp = (625.0 - elapsed_ms * elapsed_ms) / 75.0 * vel_param; + double sen_comp = sen_param; + double minmaxscale = (max - min) / 128.0; + double factor = vel_comp * minmaxscale + sen_comp; - int32_t delta_velocity = delta * velocityfactor; + int32_t delta_velocity = delta * factor; if (delta_velocity == 0) { return 0; // did not trigger @@ -272,12 +269,16 @@ uint8_t grid_ui_encoder_update_trigger(struct grid_ui_element* ele, uint64_t* la struct grid_ui_event* eve = grid_ui_event_find(ele, GRID_PARAMETER_EVENT_ENCODER); grid_ui_event_state_set(eve, GRID_EVE_STATE_TRIG); - - return 1; // did trigger } void grid_ui_encoder_store_input(struct grid_ui_encoder_state* state, struct grid_ui_encoder_sample sample) { + state->initial_samples += (state->initial_samples <= GRID_UI_ENCODER_INIT_SAMPLES); + + if (state->initial_samples <= GRID_UI_ENCODER_INIT_SAMPLES) { + return; + } + struct grid_ui_element* ele = state->parent; // Handle button input using embedded button state @@ -286,23 +287,17 @@ void grid_ui_encoder_store_input(struct grid_ui_encoder_state* state, struct gri // Reconstruct rotation value from phases uint8_t new_value = sample.phase_a | (sample.phase_b << 1); - // extract old value from state, rewrite state with new + // Extract old value from state, rewrite state with new uint8_t old_value = state->last_nibble; state->last_nibble = new_value; - state->initial_samples += (state->initial_samples <= GRID_UI_ENCODER_INIT_SAMPLES); - if (old_value == new_value) { - // no change since the last time we read the shift register return; } - int16_t delta = grid_ui_encoder_rotation_delta(old_value, new_value, state->detent, &state->encoder_last_leave_dir); // delta can be -1, 0 or 1 - - delta *= state->direction; + int16_t delta = grid_ui_encoder_rotation_delta(old_value, new_value, state->detent, &state->encoder_last_leave_dir); - // Evaluate the results - if (state->initial_samples > GRID_UI_ENCODER_INIT_SAMPLES) { - grid_ui_encoder_update_trigger(ele, &state->encoder_last_real_time, delta); + if (delta) { + grid_ui_encoder_update_trigger(ele, &state->encoder_last_real_time, delta * state->direction); } } diff --git a/common/src/c/grid_ui_encoder.h b/common/src/c/grid_ui_encoder.h index 47bab463..d6046e78 100644 --- a/common/src/c/grid_ui_encoder.h +++ b/common/src/c/grid_ui_encoder.h @@ -47,7 +47,7 @@ void grid_ui_element_encoder_event_clear_cb(struct grid_ui_event* eve); void grid_ui_element_encoder_page_change_cb(struct grid_ui_element* ele, uint8_t page_old, uint8_t page_new); int16_t grid_ui_encoder_rotation_delta(uint8_t old_value, uint8_t new_value, uint8_t detent, int8_t* dir_lock); -uint8_t grid_ui_encoder_update_trigger(struct grid_ui_element* ele, uint64_t* encoder_last_real_time, int16_t delta); +void grid_ui_encoder_update_trigger(struct grid_ui_element* ele, uint64_t* encoder_last_real_time, int16_t delta); static inline struct grid_ui_encoder_state* grid_ui_encoder_get_state(struct grid_ui_element* ele) { return (struct grid_ui_encoder_state*)ele->primary_state; } From 5a3e068c2b6a2e4fa39f4fc2131766bf6b7e9223 Mon Sep 17 00:00:00 2001 From: benblaise Date: Wed, 1 Jul 2026 16:08:15 +0200 Subject: [PATCH 4/4] BENB fix return in grid_ui_encoder_update_trigger --- common/src/c/grid_ui_encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/c/grid_ui_encoder.c b/common/src/c/grid_ui_encoder.c index 837c6e6b..be0e4ae2 100644 --- a/common/src/c/grid_ui_encoder.c +++ b/common/src/c/grid_ui_encoder.c @@ -229,7 +229,7 @@ void grid_ui_encoder_update_trigger(struct grid_ui_element* ele, uint64_t* last_ int32_t delta_velocity = delta * factor; if (delta_velocity == 0) { - return 0; // did not trigger + return; // did not trigger } int32_t old_value = template_parameter_list[GRID_LUA_FNC_E_ENCODER_VALUE_index];