diff --git a/app/src/behaviors/behavior_turbo_key.c b/app/src/behaviors/behavior_turbo_key.c index cd4c2435..96238032 100644 --- a/app/src/behaviors/behavior_turbo_key.c +++ b/app/src/behaviors/behavior_turbo_key.c @@ -25,16 +25,17 @@ struct behavior_turbo_config { const struct zmk_behavior_binding binding; }; -#define ZMK_BHV_TURBO_MAX_ACTIVE 5 - -struct active_turbo { - const struct behavior_turbo_config *config; +struct behavior_turbo_data { uint32_t position; bool is_active; bool is_pressed; int32_t press_time; + int tap_ms; + int wait_ms; + struct zmk_behavior_binding binding; + // Timer Data bool timer_started; bool timer_cancelled; @@ -43,107 +44,67 @@ struct active_turbo { struct k_work_delayable release_timer; }; -struct active_turbo active_turbos[ZMK_BHV_TURBO_MAX_ACTIVE] = {}; +static int behavior_turbo_key_init(const struct device *dev) { return 0; }; -static struct active_turbo *find_active_turbo(uint32_t position) { - for (int i = 0; i < ZMK_BHV_TURBO_MAX_ACTIVE; i++) { - if (active_turbos[i].is_active) { - return &active_turbos[i]; - } - } - return NULL; -} - -static int new_turbo(uint32_t position, const struct behavior_turbo_config *config, - struct active_turbo **turbo) { - for (int i = 0; i < ZMK_BHV_TURBO_MAX_ACTIVE; i++) { - struct active_turbo *const ref_turbo = &active_turbos[i]; - if (!ref_turbo->is_active) { - ref_turbo->is_active = true; - ref_turbo->position = position; - ref_turbo->config = config; - ref_turbo->is_pressed = true; - ref_turbo->press_time = k_uptime_get(); - ref_turbo->release_at = 0; - ref_turbo->timer_started = true; - ref_turbo->timer_cancelled = false; - *turbo = ref_turbo; - return 0; - } - } - return -ENOMEM; -}; - -static int stop_timer(struct active_turbo *turbo) { - int timer_cancel_result = k_work_cancel_delayable(&turbo->release_timer); +static int stop_timer(struct behavior_turbo_data *data) { + int timer_cancel_result = k_work_cancel_delayable(&data->release_timer); if (timer_cancel_result == -EINPROGRESS) { // too late to cancel, we'll let the timer handler clear up. - turbo->timer_cancelled = true; + data->timer_cancelled = true; } return timer_cancel_result; } -static void clear_turbo(struct active_turbo *turbo) { +static void clear_turbo(struct behavior_turbo_data *data) { LOG_DBG("Turbo deactivated"); - turbo->is_active = false; - stop_timer(turbo); + data->is_active = false; + stop_timer(data); } -static void reset_timer(struct active_turbo *turbo, struct zmk_behavior_binding_event event) { - turbo->release_at = event.timestamp + turbo->config->wait_ms; - int32_t ms_left = turbo->release_at - k_uptime_get(); +static void reset_timer(struct behavior_turbo_data *data, struct zmk_behavior_binding_event event) { + data->release_at = event.timestamp + data->wait_ms; + LOG_DBG("Resetting turbo timer: %d + %d = %d", event.timestamp, data->wait_ms, + data->release_at); + int32_t ms_left = data->release_at - k_uptime_get(); if (ms_left > 0) { - k_work_schedule(&turbo->release_timer, K_MSEC(ms_left)); - LOG_DBG("Successfully reset turbo timer at position %d", turbo->position); + k_work_schedule(&data->release_timer, K_MSEC(ms_left)); + LOG_DBG("Successfully reset turbo timer at position %d", data->position); } } static void behavior_turbo_timer_handler(struct k_work *item) { - struct active_turbo *turbo = CONTAINER_OF(item, struct active_turbo, release_timer); - if (!turbo->is_active) { + struct behavior_turbo_data *data = + CONTAINER_OF(item, struct behavior_turbo_data, release_timer); + if (!data->is_active) { return; } - if (turbo->timer_cancelled) { + if (data->timer_cancelled) { return; } LOG_DBG("Turbo timer reached."); - struct zmk_behavior_binding_event event = {.position = turbo->position, + struct zmk_behavior_binding_event event = {.position = data->position, .timestamp = k_uptime_get()}; - zmk_behavior_queue_add(event.position, turbo->config->binding, true, turbo->config->tap_ms); - zmk_behavior_queue_add(event.position, turbo->config->binding, false, 0); - reset_timer(turbo, event); + zmk_behavior_queue_add(event.position, data->binding, true, data->tap_ms); + zmk_behavior_queue_add(event.position, data->binding, false, 0); + reset_timer(data, event); } -static int behavior_turbo_key_init(const struct device *dev) { - static bool init_first_run = true; - if (init_first_run) { - for (int i = 0; i < ZMK_BHV_TURBO_MAX_ACTIVE; i++) { - k_work_init_delayable(&active_turbos[i].release_timer, behavior_turbo_timer_handler); - clear_turbo(&active_turbos[i]); - } - } - init_first_run = false; - return 0; -}; - static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { const struct device *dev = device_get_binding(binding->behavior_dev); const struct behavior_turbo_config *cfg = dev->config; + struct behavior_turbo_data *data = dev->data; - struct active_turbo *turbo; - turbo = find_active_turbo(event.position); - if (turbo == NULL) { - if (new_turbo(event.position, cfg, &turbo) == -ENOMEM) { - LOG_ERR("Unable to create new turbo. Insufficient space in active_turbos[]."); - return ZMK_BEHAVIOR_OPAQUE; - } - LOG_DBG("%d created new turbo", event.position); - zmk_behavior_queue_add(event.position, turbo->config->binding, true, turbo->config->tap_ms); - zmk_behavior_queue_add(event.position, turbo->config->binding, false, 0); - reset_timer(turbo, event); + if (!data->is_active) { + data->is_active = true; + + LOG_DBG("%d started new turbo", event.position); + k_work_init_delayable(&data->release_timer, behavior_turbo_timer_handler); + zmk_behavior_queue_add(event.position, cfg->binding, true, cfg->tap_ms); + zmk_behavior_queue_add(event.position, cfg->binding, false, 0); + reset_timer(data, event); } else { - clear_turbo(turbo); + clear_turbo(data); } return ZMK_BEHAVIOR_OPAQUE; } @@ -152,15 +113,14 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { const struct device *dev = device_get_binding(binding->behavior_dev); const struct behavior_turbo_config *cfg = dev->config; + struct behavior_turbo_data *data = dev->data; - struct active_turbo *turbo; - turbo = find_active_turbo(event.position); - if (turbo != NULL) { - turbo->is_pressed = false; - int32_t elapsedTime = k_uptime_get() - turbo->press_time; + if (&data->is_active == false) { + data->is_pressed = false; + int32_t elapsedTime = k_uptime_get() - data->press_time; LOG_DBG("turbo elapsed time: %d", elapsedTime); if (elapsedTime > cfg->toggle_term_ms) { - clear_turbo(turbo); + clear_turbo(data); } } return 0; @@ -186,8 +146,12 @@ static const struct behavior_driver_api behavior_turbo_key_driver_api = { .wait_ms = DT_INST_PROP(n, wait_ms), \ .toggle_term_ms = DT_INST_PROP(n, toggle_term_ms), \ .binding = _TRANSFORM_ENTRY(0, n)}; \ - DEVICE_DT_INST_DEFINE(n, behavior_turbo_key_init, NULL, NULL, &behavior_turbo_config_##n, \ - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ - &behavior_turbo_key_driver_api); + static struct behavior_turbo_data behavior_turbo_data_##n = { \ + .tap_ms = DT_INST_PROP(n, tap_ms), \ + .wait_ms = DT_INST_PROP(n, wait_ms), \ + .binding = _TRANSFORM_ENTRY(0, n)}; \ + DEVICE_DT_INST_DEFINE(n, behavior_turbo_key_init, NULL, &behavior_turbo_data_##n, \ + &behavior_turbo_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_turbo_key_driver_api); DT_INST_FOREACH_STATUS_OKAY(TURBO_INST) diff --git a/app/tests/turbo/behavior_keymap.dtsi b/app/tests/turbo/behavior_keymap.dtsi index b7ad1f91..e37d4f75 100644 --- a/app/tests/turbo/behavior_keymap.dtsi +++ b/app/tests/turbo/behavior_keymap.dtsi @@ -14,7 +14,7 @@ }; t2: turbo2 { compatible = "zmk,behavior-turbo-key"; - label = "turbo"; + label = "turbo2"; #binding-cells = <0>; tap-ms = <5>; wait-ms = <300>;