[FL-1161] Input bug fixes and cleanup (#416)
* Input: start/stop timers only from the input thread, adjust long/short/repeat timings, improve timer routines reliability.
This commit is contained in:
		
							parent
							
								
									a9d227c2b7
								
							
						
					
					
						commit
						8ada9b817b
					
				| @ -1,5 +1,4 @@ | |||||||
| #include "input_i.h" | #include "input_i.h" | ||||||
| #include <m-string.h> |  | ||||||
| 
 | 
 | ||||||
| #define GPIO_Read(input_pin)                                                    \ | #define GPIO_Read(input_pin)                                                    \ | ||||||
|     (HAL_GPIO_ReadPin((GPIO_TypeDef*)input_pin.pin->port, input_pin.pin->pin) ^ \ |     (HAL_GPIO_ReadPin((GPIO_TypeDef*)input_pin.pin->port, input_pin.pin->pin) ^ \ | ||||||
| @ -7,19 +6,33 @@ | |||||||
| 
 | 
 | ||||||
| static Input* input = NULL; | static Input* input = NULL; | ||||||
| 
 | 
 | ||||||
|  | inline static void input_timer_start(osTimerId_t timer_id, uint32_t ticks) { | ||||||
|  |     TimerHandle_t hTimer = (TimerHandle_t)timer_id; | ||||||
|  |     furi_check(xTimerChangePeriod(hTimer, ticks, portMAX_DELAY) == pdPASS); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline static void input_timer_stop(osTimerId_t timer_id) { | ||||||
|  |     TimerHandle_t hTimer = (TimerHandle_t)timer_id; | ||||||
|  |     furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS); | ||||||
|  |     // xTimerStop is not actually stopping timer,
 | ||||||
|  |     // Instead it places stop event into timer queue
 | ||||||
|  |     // This code ensures that timer is stopped
 | ||||||
|  |     while(xTimerIsTimerActive(hTimer) == pdTRUE) osDelay(1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void input_press_timer_callback(void* arg) { | void input_press_timer_callback(void* arg) { | ||||||
|     InputPinState* input_pin = arg; |     InputPinState* input_pin = arg; | ||||||
|     InputEvent event; |     InputEvent event; | ||||||
|     event.key = input_pin->pin->key; |     event.key = input_pin->pin->key; | ||||||
|     if(!input_pin->repeat_event) { |     input_pin->press_counter++; | ||||||
|  |     if(input_pin->press_counter == INPUT_LONG_PRESS_COUNTS) { | ||||||
|         event.type = InputTypeLong; |         event.type = InputTypeLong; | ||||||
|         notify_pubsub(&input->event_pubsub, &event); |         notify_pubsub(&input->event_pubsub, &event); | ||||||
|         input_pin->repeat_event = true; |     } else if(input_pin->press_counter > INPUT_LONG_PRESS_COUNTS) { | ||||||
|     } else { |         input_pin->press_counter--; | ||||||
|         event.type = InputTypeRepeat; |         event.type = InputTypeRepeat; | ||||||
|         notify_pubsub(&input->event_pubsub, &event); |         notify_pubsub(&input->event_pubsub, &event); | ||||||
|     } |     } | ||||||
|     osTimerStart(input_pin->press_timer, INPUT_REPEATE_PRESS_TICKS); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void input_isr(void* _pin, void* _ctx) { | void input_isr(void* _pin, void* _ctx) { | ||||||
| @ -34,7 +47,7 @@ void input_cli_send(string_t args, void* context) { | |||||||
|     string_init(key_name); |     string_init(key_name); | ||||||
|     size_t ws = string_search_char(args, ' '); |     size_t ws = string_search_char(args, ' '); | ||||||
|     if(ws == STRING_FAILURE) { |     if(ws == STRING_FAILURE) { | ||||||
|         printf("Wrong input"); |         printf("Invalid arguments. Use `input_send KEY TYPE`."); | ||||||
|         string_clear(key_name); |         string_clear(key_name); | ||||||
|         return; |         return; | ||||||
|     } else { |     } else { | ||||||
| @ -56,7 +69,7 @@ void input_cli_send(string_t args, void* context) { | |||||||
|     } else if(!string_cmp(key_name, "back")) { |     } else if(!string_cmp(key_name, "back")) { | ||||||
|         event.key = InputKeyBack; |         event.key = InputKeyBack; | ||||||
|     } else { |     } else { | ||||||
|         printf("Wrong argument"); |         printf("Invalid key name. Valid keys: `up`, `down`, `left`, `right`, `back`, `ok`."); | ||||||
|         string_clear(key_name); |         string_clear(key_name); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| @ -71,7 +84,7 @@ void input_cli_send(string_t args, void* context) { | |||||||
|     } else if(!string_cmp(args, "long")) { |     } else if(!string_cmp(args, "long")) { | ||||||
|         event.type = InputTypeLong; |         event.type = InputTypeLong; | ||||||
|     } else { |     } else { | ||||||
|         printf("Wrong argument"); |         printf("Ivalid type. Valid types: `press`, `release`, `short`, `long`."); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     // Publish input event
 |     // Publish input event
 | ||||||
| @ -97,10 +110,10 @@ int32_t input_task() { | |||||||
|     for(size_t i = 0; i < pin_count; i++) { |     for(size_t i = 0; i < pin_count; i++) { | ||||||
|         input->pin_states[i].pin = &input_pins[i]; |         input->pin_states[i].pin = &input_pins[i]; | ||||||
|         input->pin_states[i].state = GPIO_Read(input->pin_states[i]); |         input->pin_states[i].state = GPIO_Read(input->pin_states[i]); | ||||||
|         input->pin_states[i].repeat_event = false; |  | ||||||
|         input->pin_states[i].debounce = INPUT_DEBOUNCE_TICKS_HALF; |         input->pin_states[i].debounce = INPUT_DEBOUNCE_TICKS_HALF; | ||||||
|         input->pin_states[i].press_timer = |         input->pin_states[i].press_timer = | ||||||
|             osTimerNew(input_press_timer_callback, osTimerOnce, &input->pin_states[i], NULL); |             osTimerNew(input_press_timer_callback, osTimerPeriodic, &input->pin_states[i], NULL); | ||||||
|  |         input->pin_states[i].press_counter = 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     while(1) { |     while(1) { | ||||||
| @ -113,22 +126,25 @@ int32_t input_task() { | |||||||
|                 input->pin_states[i].debounce += (state ? 1 : -1); |                 input->pin_states[i].debounce += (state ? 1 : -1); | ||||||
|             } else if(input->pin_states[i].state != state) { |             } else if(input->pin_states[i].state != state) { | ||||||
|                 input->pin_states[i].state = state; |                 input->pin_states[i].state = state; | ||||||
|  | 
 | ||||||
|                 // Common state info
 |                 // Common state info
 | ||||||
|                 InputEvent event; |                 InputEvent event; | ||||||
|                 event.type = input->pin_states[i].state ? InputTypePress : InputTypeRelease; |  | ||||||
|                 event.key = input->pin_states[i].pin->key; |                 event.key = input->pin_states[i].pin->key; | ||||||
|  |                 event.type = input->pin_states[i].state ? InputTypePress : InputTypeRelease; | ||||||
|                 // Send Press/Release event
 |                 // Send Press/Release event
 | ||||||
|                 notify_pubsub(&input->event_pubsub, &event); |                 notify_pubsub(&input->event_pubsub, &event); | ||||||
|                 // Short/Long press logic
 | 
 | ||||||
|  |                 // Short / Long / Repeat timer routine
 | ||||||
|                 if(state) { |                 if(state) { | ||||||
|                     osTimerStart(input->pin_states[i].press_timer, INPUT_LONG_PRESS_TICKS); |                     input_timer_start(input->pin_states[i].press_timer, INPUT_PRESS_TICKS); | ||||||
|                 } else if(input->pin_states[i].repeat_event) { |                 } else { | ||||||
|                     osTimerStop(input->pin_states[i].press_timer); |                     input_timer_stop(input->pin_states[i].press_timer); | ||||||
|                     input->pin_states[i].repeat_event = false; |                     if(input->pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) { | ||||||
|                 } else if(osTimerStop(input->pin_states[i].press_timer) == osOK) { |  | ||||||
|                         event.type = InputTypeShort; |                         event.type = InputTypeShort; | ||||||
|                         notify_pubsub(&input->event_pubsub, &event); |                         notify_pubsub(&input->event_pubsub, &event); | ||||||
|                     } |                     } | ||||||
|  |                     input->pin_states[i].press_counter = 0; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,16 +1,18 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "input.h" | #include "input.h" | ||||||
| 
 | #include <FreeRTOS.h> | ||||||
|  | #include <timers.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <cli/cli.h> | #include <cli/cli.h> | ||||||
|  | #include <m-string.h> | ||||||
| 
 | 
 | ||||||
| #define INPUT_DEBOUNCE_TICKS_HALF (INPUT_DEBOUNCE_TICKS / 2) | #define INPUT_DEBOUNCE_TICKS_HALF (INPUT_DEBOUNCE_TICKS / 2) | ||||||
| #define INPUT_LONG_PRESS_TICKS 2048 | #define INPUT_PRESS_TICKS 200 | ||||||
| #define INPUT_REPEATE_PRESS_TICKS 256 | #define INPUT_LONG_PRESS_COUNTS 4 | ||||||
| #define INPUT_THREAD_FLAG_ISR 0x00000001 | #define INPUT_THREAD_FLAG_ISR 0x00000001 | ||||||
| 
 | 
 | ||||||
| /* Input pin state */ | /* Input pin state */ | ||||||
| @ -18,9 +20,9 @@ typedef struct { | |||||||
|     const InputPin* pin; |     const InputPin* pin; | ||||||
|     // State
 |     // State
 | ||||||
|     volatile bool state; |     volatile bool state; | ||||||
|     volatile bool repeat_event; |  | ||||||
|     volatile uint8_t debounce; |     volatile uint8_t debounce; | ||||||
|     volatile osTimerId_t press_timer; |     volatile osTimerId_t press_timer; | ||||||
|  |     volatile uint8_t press_counter; | ||||||
| } InputPinState; | } InputPinState; | ||||||
| 
 | 
 | ||||||
| /* Input state */ | /* Input state */ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく