From 8b94888ef5fc9c52aa47ae4dbb51415abb505f28 Mon Sep 17 00:00:00 2001 From: SkorP Date: Tue, 22 Oct 2024 15:20:33 +0400 Subject: [PATCH 1/4] Input_SRV: migration to event_loop --- applications/services/input/input.c | 315 ++++++++++++++++++---------- 1 file changed, 201 insertions(+), 114 deletions(-) diff --git a/applications/services/input/input.c b/applications/services/input/input.c index 6cbafb79583..27666ce0d3f 100644 --- a/applications/services/input/input.c +++ b/applications/services/input/input.c @@ -2,56 +2,53 @@ #include #include -#include #include #include #include -#define INPUT_DEBOUNCE_TICKS_HALF (INPUT_DEBOUNCE_TICKS / 2) -#define INPUT_PRESS_TICKS 150 -#define INPUT_LONG_PRESS_COUNTS 2 -#define INPUT_THREAD_FLAG_ISR 0x00000001 +#define TAG "Input" -/** Input pin state */ -typedef struct { - const InputPin* pin; - // State - volatile bool state; - volatile uint8_t debounce; - FuriTimer* press_timer; - FuriPubSub* event_pubsub; - volatile uint8_t press_counter; - volatile uint32_t counter; -} InputPinState; +#define INPUT_SRV_DEBOUNCE_TIMER_TICKS 1 //ms -/** Input CLI command handler */ -void input_cli(Cli* cli, FuriString* args, void* context); - -// #define INPUT_DEBUG +#define INPUT_SRV_INPUT_LONG_PRESS_TICKS 150 //ms +#define INPUT_SRV_LONG_PRESS_COUNTS 2 #define GPIO_Read(input_pin) (furi_hal_gpio_read(input_pin.pin->gpio) ^ (input_pin.pin->inverted)) -void input_press_timer_callback(void* arg) { - InputPinState* input_pin = arg; - InputEvent event; - event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; - event.sequence_counter = input_pin->counter; - event.key = input_pin->pin->key; - input_pin->press_counter++; - if(input_pin->press_counter == INPUT_LONG_PRESS_COUNTS) { - event.type = InputTypeLong; - furi_pubsub_publish(input_pin->event_pubsub, &event); - } else if(input_pin->press_counter > INPUT_LONG_PRESS_COUNTS) { - input_pin->press_counter--; - event.type = InputTypeRepeat; - furi_pubsub_publish(input_pin->event_pubsub, &event); - } -} +#ifdef INPUT_DEBUG +#define INPUT_LOG(...) FURI_LOG_D(TAG, __VA_ARGS__) +#else +#define INPUT_LOG(...) +#endif +typedef struct { + FuriEventLoopTimer* timer; + FuriPubSub* event_pubsub; + uint32_t sequence_counter; + uint32_t press_counter; + InputType type; + InputKey key; +} InputSrvKeySequence; -void input_isr(void* _ctx) { - FuriThreadId thread_id = (FuriThreadId)_ctx; - furi_thread_flags_set(thread_id, INPUT_THREAD_FLAG_ISR); -} +typedef struct { + const InputPin* pin; + uint16_t debounce_count; + bool state; +} InputSrvKeyState; + +typedef struct { + FuriEventLoop* event_loop; + FuriPubSub* event_pubsub; + FuriSemaphore* input_semaphore; + FuriEventLoopTimer* debounce_timer; + InputSrvKeyState* key_state; + InputSrvKeySequence* key_sequence; + uint32_t sequence_counter; +} InputSrv; + +static void input_key_sequence_run( + InputSrvKeySequence* key_sequence, + InputType type, + uint32_t sequence_counter); const char* input_get_key_name(InputKey key) { for(size_t i = 0; i < input_pins_count; i++) { @@ -59,7 +56,7 @@ const char* input_get_key_name(InputKey key) { return input_pins[i].name; } } - return "Unknown"; + furi_crash(); } const char* input_get_type_name(InputType type) { @@ -75,95 +72,185 @@ const char* input_get_type_name(InputType type) { case InputTypeRepeat: return "Repeat"; default: - return "Unknown"; + furi_crash(); } } -int32_t input_srv(void* p) { - UNUSED(p); - - const FuriThreadId thread_id = furi_thread_get_current_id(); - FuriPubSub* event_pubsub = furi_pubsub_alloc(); - uint32_t counter = 1; - furi_record_create(RECORD_INPUT_EVENTS, event_pubsub); +static void input_isr_key(void* context) { + InputSrv* instance = context; + furi_semaphore_release(instance->input_semaphore); +} -#ifdef INPUT_DEBUG - furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeOutputPushPull); -#endif +static bool input_semaphore_callback(FuriEventLoopObject* object, void* context) { + furi_assert(context); + InputSrv* instance = context; + furi_assert(object == instance->input_semaphore); -#ifdef SRV_CLI - Cli* cli = furi_record_open(RECORD_CLI); - cli_add_command(cli, "input", CliCommandFlagParallelSafe, input_cli, event_pubsub); -#endif + furi_check(furi_semaphore_acquire(instance->input_semaphore, 0) == FuriStatusOk); - InputPinState pin_states[input_pins_count]; + if(!furi_event_loop_timer_is_running(instance->debounce_timer)) { + furi_event_loop_timer_start(instance->debounce_timer, INPUT_SRV_DEBOUNCE_TIMER_TICKS); + } + return true; +} +static void input_debounce_timer_callback(void* context) { + furi_assert(context); + InputSrv* instance = context; + bool is_changing = false; for(size_t i = 0; i < input_pins_count; i++) { - furi_hal_gpio_add_int_callback(input_pins[i].gpio, input_isr, thread_id); - pin_states[i].pin = &input_pins[i]; - pin_states[i].state = GPIO_Read(pin_states[i]); - pin_states[i].debounce = INPUT_DEBOUNCE_TICKS_HALF; - pin_states[i].press_timer = - furi_timer_alloc(input_press_timer_callback, FuriTimerTypePeriodic, &pin_states[i]); - pin_states[i].event_pubsub = event_pubsub; - pin_states[i].press_counter = 0; - } + bool state = GPIO_Read(instance->key_state[i]); - while(1) { - bool is_changing = false; - for(size_t i = 0; i < input_pins_count; i++) { - bool state = GPIO_Read(pin_states[i]); - if(state) { - if(pin_states[i].debounce < INPUT_DEBOUNCE_TICKS) pin_states[i].debounce += 1; - } else { - if(pin_states[i].debounce > 0) pin_states[i].debounce -= 1; + if(state) { + if(instance->key_state[i].debounce_count < INPUT_DEBOUNCE_TICKS) { + instance->key_state[i].debounce_count++; + is_changing = true; } + } else if(instance->key_state[i].debounce_count > 0) { + instance->key_state[i].debounce_count--; + is_changing = true; + } - if(pin_states[i].debounce > 0 && pin_states[i].debounce < INPUT_DEBOUNCE_TICKS) { - is_changing = true; - } else if(pin_states[i].state != state) { - pin_states[i].state = state; - - // Common state info - InputEvent event; - event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; - event.key = pin_states[i].pin->key; - - // Short / Long / Repeat timer routine - if(state) { - pin_states[i].counter = counter++; - event.sequence_counter = pin_states[i].counter; - furi_timer_start(pin_states[i].press_timer, INPUT_PRESS_TICKS); - } else { - event.sequence_counter = pin_states[i].counter; - furi_timer_stop(pin_states[i].press_timer); - while(furi_timer_is_running(pin_states[i].press_timer)) - furi_delay_tick(1); - if(pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) { - event.type = InputTypeShort; - furi_pubsub_publish(event_pubsub, &event); - } - pin_states[i].press_counter = 0; - } - - // Send Press/Release event - event.type = pin_states[i].state ? InputTypePress : InputTypeRelease; - furi_pubsub_publish(event_pubsub, &event); + if(!is_changing && instance->key_state[i].state != state) { + instance->key_state[i].state = state; + + if(state) { + input_key_sequence_run( + &instance->key_sequence[i], InputTypePress, ++instance->sequence_counter); + } else { + input_key_sequence_run( + &instance->key_sequence[i], InputTypeRelease, instance->sequence_counter); } } + } - if(is_changing) { -#ifdef INPUT_DEBUG - furi_hal_gpio_write(&gpio_ext_pa4, 1); -#endif - furi_delay_tick(1); - } else { -#ifdef INPUT_DEBUG - furi_hal_gpio_write(&gpio_ext_pa4, 0); -#endif - furi_thread_flags_wait(INPUT_THREAD_FLAG_ISR, FuriFlagWaitAny, FuriWaitForever); + if(!is_changing) { + furi_event_loop_timer_stop(instance->debounce_timer); + } +} + +static inline void input_send(FuriPubSub* pubsub, InputEvent* event) { + furi_pubsub_publish(pubsub, event); + INPUT_LOG( + "input_send: %s %s %x", + input_get_key_name(event->key), + input_get_type_name(event->type), + event->sequence_counter); +} + +static void input_key_sequence_run( + InputSrvKeySequence* key_sequence, + InputType type, + uint32_t sequence_counter) { + InputEvent event; + + switch(type) { + case InputTypePress: + key_sequence->sequence_counter = sequence_counter; + key_sequence->press_counter = 0; + key_sequence->type = InputTypePress; + + event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; + event.sequence_counter = key_sequence->sequence_counter; + event.key = key_sequence->key; + event.type = InputTypePress; + input_send(key_sequence->event_pubsub, &event); + + furi_check(!furi_event_loop_timer_is_running(key_sequence->timer)); + furi_event_loop_timer_start(key_sequence->timer, INPUT_SRV_INPUT_LONG_PRESS_TICKS); + + key_sequence->type = InputTypeRepeat; + break; + case InputTypeRelease: + if(key_sequence->press_counter < INPUT_SRV_LONG_PRESS_COUNTS) { + event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; + event.sequence_counter = key_sequence->sequence_counter; + event.key = key_sequence->key; + event.type = InputTypeShort; + input_send(key_sequence->event_pubsub, &event); } + event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; + event.sequence_counter = key_sequence->sequence_counter; + event.key = key_sequence->key; + event.type = InputTypeRelease; + input_send(key_sequence->event_pubsub, &event); + + furi_event_loop_timer_stop(key_sequence->timer); + + key_sequence->type = InputTypeRelease; + break; + + default: + break; } +} +static void input_sequence_timer_callback(void* context) { + furi_assert(context); + InputSrvKeySequence* key_sequence = context; + InputEvent event; + + if(key_sequence->press_counter == INPUT_SRV_LONG_PRESS_COUNTS) { + event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; + event.sequence_counter = key_sequence->sequence_counter; + event.key = key_sequence->key; + event.type = InputTypeLong; + input_send(key_sequence->event_pubsub, &event); + } else if(key_sequence->press_counter > INPUT_SRV_LONG_PRESS_COUNTS) { + event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; + event.sequence_counter = key_sequence->sequence_counter; + event.key = key_sequence->key; + event.type = InputTypeRepeat; + input_send(key_sequence->event_pubsub, &event); + } + + key_sequence->press_counter++; +} + +int32_t input_srv(void* p) { + UNUSED(p); + InputSrv* instance = malloc(sizeof(InputSrv)); + instance->event_pubsub = furi_pubsub_alloc(); + furi_record_create(RECORD_INPUT_EVENTS, instance->event_pubsub); + + instance->input_semaphore = furi_semaphore_alloc(1, 0); + instance->event_loop = furi_event_loop_alloc(); + instance->debounce_timer = furi_event_loop_timer_alloc( + instance->event_loop, + input_debounce_timer_callback, + FuriEventLoopTimerTypePeriodic, + instance); + + instance->key_state = malloc(sizeof(InputSrvKeyState) * input_pins_count); + for(size_t i = 0; i < input_pins_count; i++) { + furi_hal_gpio_add_int_callback(input_pins[i].gpio, input_isr_key, instance); + instance->key_state[i].pin = &input_pins[i]; + instance->key_state[i].state = GPIO_Read(instance->key_state[i]); + instance->sequence_counter = 0; + } + + furi_event_loop_subscribe_semaphore( + instance->event_loop, + instance->input_semaphore, + FuriEventLoopEventIn, + input_semaphore_callback, + instance); + + instance->key_sequence = malloc(sizeof(InputSrvKeySequence) * input_pins_count); + for(size_t i = 0; i < input_pins_count; i++) { + instance->key_sequence[i].sequence_counter = 0; + instance->key_sequence[i].press_counter = 0; + instance->key_sequence[i].type = InputTypeRelease; + instance->key_sequence[i].key = input_pins[i].key; + instance->key_sequence[i].timer = furi_event_loop_timer_alloc( + instance->event_loop, + input_sequence_timer_callback, + FuriEventLoopTimerTypePeriodic, + &instance->key_sequence[i]); + instance->key_sequence[i].event_pubsub = instance->event_pubsub; + } + + // Start Input Service + furi_event_loop_run(instance->event_loop); return 0; } From bbc70816f92fe22a877c04d43f3f271c4149875e Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Thu, 31 Oct 2024 14:31:58 +0900 Subject: [PATCH 2/4] Input: update event loop API usage --- applications/services/input/input.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/services/input/input.c b/applications/services/input/input.c index 27666ce0d3f..be270c7f19e 100644 --- a/applications/services/input/input.c +++ b/applications/services/input/input.c @@ -81,7 +81,7 @@ static void input_isr_key(void* context) { furi_semaphore_release(instance->input_semaphore); } -static bool input_semaphore_callback(FuriEventLoopObject* object, void* context) { +static void input_semaphore_callback(FuriEventLoopObject* object, void* context) { furi_assert(context); InputSrv* instance = context; furi_assert(object == instance->input_semaphore); @@ -91,7 +91,6 @@ static bool input_semaphore_callback(FuriEventLoopObject* object, void* context) if(!furi_event_loop_timer_is_running(instance->debounce_timer)) { furi_event_loop_timer_start(instance->debounce_timer, INPUT_SRV_DEBOUNCE_TIMER_TICKS); } - return true; } static void input_debounce_timer_callback(void* context) { From 35ca0acb6384dc4cc66ccad7b3c61eefbe483561 Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Thu, 31 Oct 2024 16:51:26 +0900 Subject: [PATCH 3/4] Input: code cleanup --- applications/services/input/input.c | 89 +++++++++++++++-------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/applications/services/input/input.c b/applications/services/input/input.c index be270c7f19e..ecb2b6934a1 100644 --- a/applications/services/input/input.c +++ b/applications/services/input/input.c @@ -20,12 +20,12 @@ #else #define INPUT_LOG(...) #endif + typedef struct { FuriEventLoopTimer* timer; FuriPubSub* event_pubsub; uint32_t sequence_counter; uint32_t press_counter; - InputType type; InputKey key; } InputSrvKeySequence; @@ -117,8 +117,7 @@ static void input_debounce_timer_callback(void* context) { input_key_sequence_run( &instance->key_sequence[i], InputTypePress, ++instance->sequence_counter); } else { - input_key_sequence_run( - &instance->key_sequence[i], InputTypeRelease, instance->sequence_counter); + input_key_sequence_run(&instance->key_sequence[i], InputTypeRelease, 0); } } } @@ -128,78 +127,83 @@ static void input_debounce_timer_callback(void* context) { } } -static inline void input_send(FuriPubSub* pubsub, InputEvent* event) { - furi_pubsub_publish(pubsub, event); +static inline void + input_send(FuriPubSub* pubsub, InputKey key, InputType type, uint32_t sequence_counter) { + InputEvent event = { + .sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE, + .sequence_counter = sequence_counter, + .key = key, + .type = type, + }; + + furi_pubsub_publish(pubsub, &event); INPUT_LOG( "input_send: %s %s %x", - input_get_key_name(event->key), - input_get_type_name(event->type), - event->sequence_counter); + input_get_key_name(event.key), + input_get_type_name(event.type), + event.sequence_counter); } static void input_key_sequence_run( InputSrvKeySequence* key_sequence, InputType type, uint32_t sequence_counter) { - InputEvent event; - switch(type) { case InputTypePress: key_sequence->sequence_counter = sequence_counter; key_sequence->press_counter = 0; - key_sequence->type = InputTypePress; - - event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; - event.sequence_counter = key_sequence->sequence_counter; - event.key = key_sequence->key; - event.type = InputTypePress; - input_send(key_sequence->event_pubsub, &event); - furi_check(!furi_event_loop_timer_is_running(key_sequence->timer)); + furi_assert(!furi_event_loop_timer_is_running(key_sequence->timer)); furi_event_loop_timer_start(key_sequence->timer, INPUT_SRV_INPUT_LONG_PRESS_TICKS); - key_sequence->type = InputTypeRepeat; + input_send( + key_sequence->event_pubsub, + key_sequence->key, + InputTypePress, + key_sequence->sequence_counter); + break; case InputTypeRelease: if(key_sequence->press_counter < INPUT_SRV_LONG_PRESS_COUNTS) { - event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; - event.sequence_counter = key_sequence->sequence_counter; - event.key = key_sequence->key; - event.type = InputTypeShort; - input_send(key_sequence->event_pubsub, &event); + input_send( + key_sequence->event_pubsub, + key_sequence->key, + InputTypeShort, + key_sequence->sequence_counter); } - event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; - event.sequence_counter = key_sequence->sequence_counter; - event.key = key_sequence->key; - event.type = InputTypeRelease; - input_send(key_sequence->event_pubsub, &event); + furi_assert(furi_event_loop_timer_is_running(key_sequence->timer)); furi_event_loop_timer_stop(key_sequence->timer); - key_sequence->type = InputTypeRelease; - break; + input_send( + key_sequence->event_pubsub, + key_sequence->key, + InputTypeRelease, + key_sequence->sequence_counter); + break; default: + furi_crash(); break; } } + static void input_sequence_timer_callback(void* context) { furi_assert(context); InputSrvKeySequence* key_sequence = context; - InputEvent event; if(key_sequence->press_counter == INPUT_SRV_LONG_PRESS_COUNTS) { - event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; - event.sequence_counter = key_sequence->sequence_counter; - event.key = key_sequence->key; - event.type = InputTypeLong; - input_send(key_sequence->event_pubsub, &event); + input_send( + key_sequence->event_pubsub, + key_sequence->key, + InputTypeLong, + key_sequence->sequence_counter); } else if(key_sequence->press_counter > INPUT_SRV_LONG_PRESS_COUNTS) { - event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; - event.sequence_counter = key_sequence->sequence_counter; - event.key = key_sequence->key; - event.type = InputTypeRepeat; - input_send(key_sequence->event_pubsub, &event); + input_send( + key_sequence->event_pubsub, + key_sequence->key, + InputTypeRepeat, + key_sequence->sequence_counter); } key_sequence->press_counter++; @@ -238,7 +242,6 @@ int32_t input_srv(void* p) { for(size_t i = 0; i < input_pins_count; i++) { instance->key_sequence[i].sequence_counter = 0; instance->key_sequence[i].press_counter = 0; - instance->key_sequence[i].type = InputTypeRelease; instance->key_sequence[i].key = input_pins[i].key; instance->key_sequence[i].timer = furi_event_loop_timer_alloc( instance->event_loop, From a43990cb6413bb4fb15b2274b7bd85ded01015d3 Mon Sep 17 00:00:00 2001 From: Georgii Surkov Date: Thu, 31 Oct 2024 12:42:17 +0000 Subject: [PATCH 4/4] Increment press counter before checks --- applications/services/input/input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/services/input/input.c b/applications/services/input/input.c index ecb2b6934a1..663dc27ec9e 100644 --- a/applications/services/input/input.c +++ b/applications/services/input/input.c @@ -192,6 +192,8 @@ static void input_sequence_timer_callback(void* context) { furi_assert(context); InputSrvKeySequence* key_sequence = context; + key_sequence->press_counter++; + if(key_sequence->press_counter == INPUT_SRV_LONG_PRESS_COUNTS) { input_send( key_sequence->event_pubsub, @@ -205,8 +207,6 @@ static void input_sequence_timer_callback(void* context) { InputTypeRepeat, key_sequence->sequence_counter); } - - key_sequence->press_counter++; } int32_t input_srv(void* p) {