Просмотр исходного кода

Input, Gui: total events complementarity on all levels (#681)

* Cli: add missing const in cli_write.
* Gui, Input: bit fields based key complementarity on all levels, key and type names API.
* Gui: minor cleanup of bit filed usage
あく 4 лет назад
Родитель
Сommit
433025b5c7

+ 1 - 1
applications/cli/cli.c

@@ -46,7 +46,7 @@ void cli_stdout_callback(void* _cookie, const char* data, size_t size) {
     furi_hal_vcp_tx((const uint8_t*)data, size);
 }
 
-void cli_write(Cli* cli, uint8_t* buffer, size_t size) {
+void cli_write(Cli* cli, const uint8_t* buffer, size_t size) {
     return furi_hal_vcp_tx(buffer, size);
 }
 

+ 1 - 1
applications/cli/cli.h

@@ -88,7 +88,7 @@ bool cli_cmd_interrupt_received(Cli* cli);
  * @param size - size of buffer in bytes
  * @return bytes written
  */
-void cli_write(Cli* cli, uint8_t* buffer, size_t size);
+void cli_write(Cli* cli, const uint8_t* buffer, size_t size);
 
 /* Read character
  * @param cli - Cli instance

+ 2 - 38
applications/debug_tools/keypad_test.c

@@ -22,42 +22,6 @@ typedef struct {
     EventType type;
 } KeypadTestEvent;
 
-static const char* keypad_test_get_key_name(InputKey key) {
-    switch(key) {
-    case InputKeyOk:
-        return "Ok";
-    case InputKeyBack:
-        return "Back";
-    case InputKeyLeft:
-        return "Left";
-    case InputKeyRight:
-        return "Right";
-    case InputKeyUp:
-        return "Up";
-    case InputKeyDown:
-        return "Down";
-    default:
-        return "Unknown";
-    }
-}
-
-static const char* keypad_test_get_type_name(InputType type) {
-    switch(type) {
-    case InputTypePress:
-        return "Press";
-    case InputTypeRelease:
-        return "Release";
-    case InputTypeShort:
-        return "Short";
-    case InputTypeLong:
-        return "Long";
-    case InputTypeRepeat:
-        return "Repeat";
-    default:
-        return "Unknown";
-    }
-}
-
 static void keypad_test_reset_state(KeypadTestState* state) {
     state->left = 0;
     state->right = 0;
@@ -139,8 +103,8 @@ int32_t keypad_test_app(void* p) {
                 FURI_LOG_I(
                     "KeypadTest",
                     "key: %s type: %s",
-                    keypad_test_get_key_name(event.input.key),
-                    keypad_test_get_type_name(event.input.type));
+                    input_get_key_name(event.input.key),
+                    input_get_type_name(event.input.type));
 
                 if(event.input.type == InputTypeLong && event.input.key == InputKeyBack) {
                     release_mutex(&state_mutex, state);

+ 13 - 8
applications/dialogs/view_holder.c

@@ -12,7 +12,7 @@ struct ViewHolder {
     BackCallback back_callback;
     void* back_context;
 
-    uint8_t ongoing_input_events_count;
+    uint8_t ongoing_input;
 };
 
 static void view_holder_draw_callback(Canvas* canvas, void* context);
@@ -94,7 +94,7 @@ void view_holder_start(ViewHolder* view_holder) {
 }
 
 void view_holder_stop(ViewHolder* view_holder) {
-    while(view_holder->ongoing_input_events_count > 0) osDelay(1);
+    while(view_holder->ongoing_input) osDelay(1);
     view_port_enabled_set(view_holder->view_port, false);
 }
 
@@ -118,12 +118,17 @@ static void view_holder_draw_callback(Canvas* canvas, void* context) {
 static void view_holder_input_callback(InputEvent* event, void* context) {
     ViewHolder* view_holder = context;
 
-    if(event->type == InputTypeRelease && view_holder->ongoing_input_events_count > 0) {
-        view_holder->ongoing_input_events_count--;
-    } else if(event->type == InputTypePress) {
-        view_holder->ongoing_input_events_count++;
-    } else if(view_holder->ongoing_input_events_count == 0) {
-        FURI_LOG_E("ViewHolder", "non-complementary input, discarding");
+    uint8_t key_bit = (1 << event->key);
+    if(event->type == InputTypePress) {
+        view_holder->ongoing_input |= key_bit;
+    } else if(event->type == InputTypeRelease) {
+        view_holder->ongoing_input &= ~key_bit;
+    } else if(!(view_holder->ongoing_input & key_bit)) {
+        FURI_LOG_W(
+            "ViewHolder",
+            "non-complementary input, discarding key: %s, type: %s",
+            input_get_key_name(event->key),
+            input_get_type_name(event->type));
         return;
     }
 

+ 34 - 8
applications/gui/gui.c

@@ -216,20 +216,46 @@ void gui_input(Gui* gui, InputEvent* input_event) {
     furi_assert(gui);
     furi_assert(input_event);
 
-    gui_lock(gui);
+    // Check input complementarity
+    uint8_t key_bit = (1 << input_event->key);
+    if(input_event->type == InputTypeRelease) {
+        gui->ongoing_input &= ~key_bit;
+    } else if(input_event->type == InputTypePress) {
+        gui->ongoing_input |= key_bit;
+    } else if(!(gui->ongoing_input & key_bit)) {
+        FURI_LOG_W(
+            "Gui",
+            "non-complementary input, discarding key %s type %s",
+            input_get_key_name(input_event->key),
+            input_get_type_name(input_event->type));
+        return;
+    }
 
-    ViewPort* view_port;
+    gui_lock(gui);
 
-    view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]);
+    ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]);
     if(!view_port) view_port = gui_view_port_find_enabled(gui->layers[GuiLayerMain]);
     if(!view_port) view_port = gui_view_port_find_enabled(gui->layers[GuiLayerNone]);
 
+    if(!(gui->ongoing_input & ~key_bit) && input_event->type == InputTypePress) {
+        gui->ongoing_input_view_port = view_port;
+    }
+
     if(view_port) {
-        if(view_port_get_orientation(view_port) == ViewPortOrientationVertical) {
-            gui_rotate_buttons(input_event);
+        if(view_port == gui->ongoing_input_view_port) {
+            if(view_port_get_orientation(view_port) == ViewPortOrientationVertical) {
+                gui_rotate_buttons(input_event);
+            }
+            view_port_input(view_port, input_event);
+        } else {
+            FURI_LOG_W(
+                "Gui",
+                "ViewPort change while key press %x -> %x. Discarding key: %s, type: %s",
+                gui->ongoing_input_view_port,
+                view_port,
+                input_get_key_name(input_event->key),
+                input_get_type_name(input_event->type));
         }
-
-        view_port_input(view_port, input_event);
     }
 
     gui_unlock(gui);
@@ -251,7 +277,7 @@ void gui_cli_screen_stream_callback(uint8_t* data, size_t size, void* context) {
     furi_assert(context);
 
     Gui* gui = context;
-    uint8_t magic[] = {0xF0, 0xE1, 0xD2, 0xC3};
+    const uint8_t magic[] = {0xF0, 0xE1, 0xD2, 0xC3};
     cli_write(gui->cli, magic, sizeof(magic));
     cli_write(gui->cli, data, size);
 }

+ 5 - 0
applications/gui/gui_i.h

@@ -35,14 +35,19 @@ struct Gui {
     // Thread and lock
     osThreadId_t thread;
     osMutexId_t mutex;
+
     // Layers and Canvas
     ViewPortArray_t layers[GuiLayerMAX];
     Canvas* canvas;
     GuiCanvasCommitCallback canvas_callback;
     void* canvas_callback_context;
+
     // Input
     osMessageQueueId_t input_queue;
     PubSub* input_events;
+    uint8_t ongoing_input;
+    ViewPort* ongoing_input_view_port;
+
     // Cli
     Cli* cli;
 };

+ 18 - 12
applications/gui/view_dispatcher.c

@@ -93,13 +93,14 @@ void view_dispatcher_run(ViewDispatcher* view_dispatcher) {
     }
 
     // Wait till all input events delivered
-    while(view_dispatcher->ongoing_input_events_count > 0) {
+    while(view_dispatcher->ongoing_input) {
         osMessageQueueGet(view_dispatcher->queue, &message, NULL, osWaitForever);
         if(message.type == ViewDispatcherMessageTypeInput) {
+            uint8_t key_bit = (1 << message.input.key);
             if(message.input.type == InputTypePress) {
-                view_dispatcher->ongoing_input_events_count++;
+                view_dispatcher->ongoing_input |= key_bit;
             } else if(message.input.type == InputTypeRelease) {
-                view_dispatcher->ongoing_input_events_count--;
+                view_dispatcher->ongoing_input &= ~key_bit;
             }
         }
     }
@@ -168,7 +169,7 @@ void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t vi
     } else {
         View** view_pp = ViewDict_get(view_dispatcher->views, view_id);
         furi_check(view_pp != NULL);
-        if(view_dispatcher->ongoing_input_events_count > 0) {
+        if(view_dispatcher->ongoing_input) {
             view_dispatcher->delayed_next_view = *view_pp;
         } else {
             view_dispatcher->delayed_next_view = NULL;
@@ -217,13 +218,18 @@ void view_dispatcher_input_callback(InputEvent* event, void* context) {
 }
 
 void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* event) {
-    // Ongoing input events counting
-    if(event->type == InputTypeRelease && view_dispatcher->ongoing_input_events_count > 0) {
-        view_dispatcher->ongoing_input_events_count--;
-    } else if(event->type == InputTypePress) {
-        view_dispatcher->ongoing_input_events_count++;
-    } else if(view_dispatcher->ongoing_input_events_count == 0) {
-        FURI_LOG_E("ViewDispatcher", "non-complementary input, discarding");
+    // Check input complementarity
+    uint8_t key_bit = (1 << event->key);
+    if(event->type == InputTypePress) {
+        view_dispatcher->ongoing_input |= key_bit;
+    } else if(event->type == InputTypeRelease) {
+        view_dispatcher->ongoing_input &= ~key_bit;
+    } else if(!(view_dispatcher->ongoing_input & key_bit)) {
+        FURI_LOG_W(
+            "ViewDispatcher",
+            "non-complementary input, discarding key: %s, type: %s",
+            input_get_key_name(event->key),
+            input_get_type_name(event->type));
         return;
     }
 
@@ -251,7 +257,7 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e
     }
 
     // Delayed view switch
-    if(view_dispatcher->delayed_next_view && view_dispatcher->ongoing_input_events_count == 0) {
+    if(view_dispatcher->delayed_next_view && !(view_dispatcher->ongoing_input)) {
         view_dispatcher_set_current_view(view_dispatcher, view_dispatcher->delayed_next_view);
         view_dispatcher->delayed_next_view = NULL;
     }

+ 1 - 1
applications/gui/view_dispatcher_i.h

@@ -18,7 +18,7 @@ struct ViewDispatcher {
     View* current_view;
 
     View* delayed_next_view;
-    uint8_t ongoing_input_events_count;
+    uint8_t ongoing_input;
 
     ViewDispatcherCustomEventCallback custom_event_callback;
     ViewDispatcherNavigationEventCallback navigation_event_callback;

+ 28 - 4
applications/input/input.c

@@ -91,6 +91,31 @@ void input_cli_send(Cli* cli, string_t args, void* context) {
     notify_pubsub(&input->event_pubsub, &event);
 }
 
+const char* input_get_key_name(InputKey key) {
+    for(size_t i = 0; i < input_pins_count; i++) {
+        if(input_pins[i].key == key) {
+            return input_pins[i].name;
+        }
+    }
+    return "Unknown";
+}
+
+const char* input_get_type_name(InputType type) {
+    switch(type) {
+    case InputTypePress:
+        return "Press";
+    case InputTypeRelease:
+        return "Release";
+    case InputTypeShort:
+        return "Short";
+    case InputTypeLong:
+        return "Long";
+    case InputTypeRepeat:
+        return "Repeat";
+    }
+    return "Unknown";
+}
+
 int32_t input_srv() {
     input = furi_alloc(sizeof(Input));
     input->thread = osThreadGetId();
@@ -103,10 +128,9 @@ int32_t input_srv() {
             input->cli, "input_send", CliCommandFlagParallelSafe, input_cli_send, input);
     }
 
-    const size_t pin_count = input_pins_count;
-    input->pin_states = furi_alloc(pin_count * sizeof(InputPinState));
+    input->pin_states = furi_alloc(input_pins_count * sizeof(InputPinState));
 
-    for(size_t i = 0; i < pin_count; i++) {
+    for(size_t i = 0; i < input_pins_count; i++) {
         GpioPin gpio = {(GPIO_TypeDef*)input_pins[i].port, (uint16_t)input_pins[i].pin};
         hal_gpio_add_int_callback(&gpio, input_isr, NULL);
         input->pin_states[i].pin = &input_pins[i];
@@ -119,7 +143,7 @@ int32_t input_srv() {
 
     while(1) {
         bool is_changing = false;
-        for(size_t i = 0; i < pin_count; i++) {
+        for(size_t i = 0; i < input_pins_count; i++) {
             bool state = GPIO_Read(input->pin_states[i]);
             if(input->pin_states[i].debounce > 0 &&
                input->pin_states[i].debounce < INPUT_DEBOUNCE_TICKS) {

+ 12 - 0
applications/input/input.h

@@ -18,3 +18,15 @@ typedef struct {
     InputKey key;
     InputType type;
 } InputEvent;
+
+/** Get human readable input key name
+ * @param key - InputKey
+ * @return string
+ */
+const char* input_get_key_name(InputKey key);
+
+/** Get human readable input type name
+ * @param type - InputType
+ * @return string
+ */
+const char* input_get_type_name(InputType type);

+ 6 - 6
firmware/targets/f6/furi-hal/furi-hal-resources.c

@@ -3,15 +3,15 @@
 #include <furi.h>
 
 const InputPin input_pins[] = {
-    {.port = BUTTON_UP_GPIO_Port, .pin = BUTTON_UP_Pin, .key = InputKeyUp, .inverted = true},
-    {.port = BUTTON_DOWN_GPIO_Port, .pin = BUTTON_DOWN_Pin, .key = InputKeyDown, .inverted = true},
+    {.port = BUTTON_UP_GPIO_Port, .pin = BUTTON_UP_Pin, .key = InputKeyUp, .inverted = true, .name="Up"},
+    {.port = BUTTON_DOWN_GPIO_Port, .pin = BUTTON_DOWN_Pin, .key = InputKeyDown, .inverted = true, .name="Down"},
     {.port = BUTTON_RIGHT_GPIO_Port,
      .pin = BUTTON_RIGHT_Pin,
      .key = InputKeyRight,
-     .inverted = true},
-    {.port = BUTTON_LEFT_GPIO_Port, .pin = BUTTON_LEFT_Pin, .key = InputKeyLeft, .inverted = true},
-    {.port = BUTTON_OK_GPIO_Port, .pin = BUTTON_OK_Pin, .key = InputKeyOk, .inverted = false},
-    {.port = BUTTON_BACK_GPIO_Port, .pin = BUTTON_BACK_Pin, .key = InputKeyBack, .inverted = true},
+     .inverted = true, .name="Right"},
+    {.port = BUTTON_LEFT_GPIO_Port, .pin = BUTTON_LEFT_Pin, .key = InputKeyLeft, .inverted = true, .name="Left"},
+    {.port = BUTTON_OK_GPIO_Port, .pin = BUTTON_OK_Pin, .key = InputKeyOk, .inverted = false, .name="Ok"},
+    {.port = BUTTON_BACK_GPIO_Port, .pin = BUTTON_BACK_Pin, .key = InputKeyBack, .inverted = true, .name="Back"},
 };
 
 const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin);

+ 1 - 0
firmware/targets/f6/furi-hal/furi-hal-resources.h

@@ -54,6 +54,7 @@ typedef struct {
     const uint16_t pin;
     const InputKey key;
     const bool inverted;
+    const char* name;
 } InputPin;
 
 extern const InputPin input_pins[];