Upside down / left handed orientation support (#2462)
* Add backup files to .gitignore * Added lefty support in Settings > System > hand Orient: Fixes: #1015 * Left handed mode * Fix lefthanded mode on vertical interfaces * Input: new composite sequence identifier * Gui: move input mapping from Canvas to ViewPort, properly handle input mapping on View switch in ViewDispatcher * Rpc: proper input sequencing and tagging in RpcGui * Rpc: remove magic from RpcGui Co-authored-by: MrDaGree <5050898+MrDaGree@users.noreply.github.com> Co-authored-by: Willy-JL <willy.leslie@icloud.com> Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com> Co-authored-by: Sergey Gavrilov <who.just.the.doctor@gmail.com>
This commit is contained in:
		
							parent
							
								
									4fd043398a
								
							
						
					
					
						commit
						780da7d4d5
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,4 @@ | |||||||
|  | *~ | ||||||
| *.swp | *.swp | ||||||
| *.swo | *.swo | ||||||
| *.gdb_history | *.gdb_history | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
|  | #include <furi_hal_rtc.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <u8g2_glue.h> | #include <u8g2_glue.h> | ||||||
| 
 | 
 | ||||||
| @ -376,39 +377,36 @@ void canvas_set_bitmap_mode(Canvas* canvas, bool alpha) { | |||||||
| 
 | 
 | ||||||
| void canvas_set_orientation(Canvas* canvas, CanvasOrientation orientation) { | void canvas_set_orientation(Canvas* canvas, CanvasOrientation orientation) { | ||||||
|     furi_assert(canvas); |     furi_assert(canvas); | ||||||
|  |     const u8g2_cb_t* rotate_cb = NULL; | ||||||
|  |     bool need_swap = false; | ||||||
|     if(canvas->orientation != orientation) { |     if(canvas->orientation != orientation) { | ||||||
|         switch(orientation) { |         switch(orientation) { | ||||||
|         case CanvasOrientationHorizontal: |         case CanvasOrientationHorizontal: | ||||||
|             if(canvas->orientation == CanvasOrientationVertical || |             need_swap = canvas->orientation == CanvasOrientationVertical || | ||||||
|                canvas->orientation == CanvasOrientationVerticalFlip) { |                         canvas->orientation == CanvasOrientationVerticalFlip; | ||||||
|                 FURI_SWAP(canvas->width, canvas->height); |             rotate_cb = U8G2_R0; | ||||||
|             } |  | ||||||
|             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R0); |  | ||||||
|             break; |             break; | ||||||
|         case CanvasOrientationHorizontalFlip: |         case CanvasOrientationHorizontalFlip: | ||||||
|             if(canvas->orientation == CanvasOrientationVertical || |             need_swap = canvas->orientation == CanvasOrientationVertical || | ||||||
|                canvas->orientation == CanvasOrientationVerticalFlip) { |                         canvas->orientation == CanvasOrientationVerticalFlip; | ||||||
|                 FURI_SWAP(canvas->width, canvas->height); |             rotate_cb = U8G2_R2; | ||||||
|             } |  | ||||||
|             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R2); |  | ||||||
|             break; |             break; | ||||||
|         case CanvasOrientationVertical: |         case CanvasOrientationVertical: | ||||||
|             if(canvas->orientation == CanvasOrientationHorizontal || |             need_swap = canvas->orientation == CanvasOrientationHorizontal || | ||||||
|                canvas->orientation == CanvasOrientationHorizontalFlip) { |                         canvas->orientation == CanvasOrientationHorizontalFlip; | ||||||
|                 FURI_SWAP(canvas->width, canvas->height); |             rotate_cb = U8G2_R3; | ||||||
|             }; |  | ||||||
|             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R3); |  | ||||||
|             break; |             break; | ||||||
|         case CanvasOrientationVerticalFlip: |         case CanvasOrientationVerticalFlip: | ||||||
|             if(canvas->orientation == CanvasOrientationHorizontal || |             need_swap = canvas->orientation == CanvasOrientationHorizontal || | ||||||
|                canvas->orientation == CanvasOrientationHorizontalFlip) { |                         canvas->orientation == CanvasOrientationHorizontalFlip; | ||||||
|                 FURI_SWAP(canvas->width, canvas->height); |             rotate_cb = U8G2_R1; | ||||||
|             } |  | ||||||
|             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R1); |  | ||||||
|             break; |             break; | ||||||
|         default: |         default: | ||||||
|             furi_assert(0); |             furi_assert(0); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         if(need_swap) FURI_SWAP(canvas->width, canvas->height); | ||||||
|  |         u8g2_SetDisplayRotation(&canvas->fb, rotate_cb); | ||||||
|         canvas->orientation = orientation; |         canvas->orientation = orientation; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -50,7 +50,13 @@ static void gui_redraw_status_bar(Gui* gui, bool need_attention) { | |||||||
|     uint8_t left_used = 0; |     uint8_t left_used = 0; | ||||||
|     uint8_t right_used = 0; |     uint8_t right_used = 0; | ||||||
|     uint8_t width; |     uint8_t width; | ||||||
|     canvas_set_orientation(gui->canvas, CanvasOrientationHorizontal); | 
 | ||||||
|  |     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagHandOrient)) { | ||||||
|  |         canvas_set_orientation(gui->canvas, CanvasOrientationHorizontalFlip); | ||||||
|  |     } else { | ||||||
|  |         canvas_set_orientation(gui->canvas, CanvasOrientationHorizontal); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     canvas_frame_set( |     canvas_frame_set( | ||||||
|         gui->canvas, GUI_STATUS_BAR_X, GUI_STATUS_BAR_Y, GUI_DISPLAY_WIDTH, GUI_STATUS_BAR_HEIGHT); |         gui->canvas, GUI_STATUS_BAR_X, GUI_STATUS_BAR_Y, GUI_DISPLAY_WIDTH, GUI_STATUS_BAR_HEIGHT); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ | |||||||
| #include "gui.h" | #include "gui.h" | ||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
|  | #include <furi_hal_rtc.h> | ||||||
| #include <m-array.h> | #include <m-array.h> | ||||||
| #include <m-algo.h> | #include <m-algo.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
|  | |||||||
| @ -320,6 +320,13 @@ void view_dispatcher_send_custom_event(ViewDispatcher* view_dispatcher, uint32_t | |||||||
|         furi_message_queue_put(view_dispatcher->queue, &message, FuriWaitForever) == FuriStatusOk); |         furi_message_queue_put(view_dispatcher->queue, &message, FuriWaitForever) == FuriStatusOk); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static const ViewPortOrientation view_dispatcher_view_port_orientation_table[] = { | ||||||
|  |     [ViewOrientationVertical] = ViewPortOrientationVertical, | ||||||
|  |     [ViewOrientationVerticalFlip] = ViewPortOrientationVerticalFlip, | ||||||
|  |     [ViewOrientationHorizontal] = ViewPortOrientationHorizontal, | ||||||
|  |     [ViewOrientationHorizontalFlip] = ViewPortOrientationHorizontalFlip, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| void view_dispatcher_set_current_view(ViewDispatcher* view_dispatcher, View* view) { | void view_dispatcher_set_current_view(ViewDispatcher* view_dispatcher, View* view) { | ||||||
|     furi_assert(view_dispatcher); |     furi_assert(view_dispatcher); | ||||||
|     // Dispatch view exit event
 |     // Dispatch view exit event
 | ||||||
| @ -330,15 +337,12 @@ void view_dispatcher_set_current_view(ViewDispatcher* view_dispatcher, View* vie | |||||||
|     view_dispatcher->current_view = view; |     view_dispatcher->current_view = view; | ||||||
|     // Dispatch view enter event
 |     // Dispatch view enter event
 | ||||||
|     if(view_dispatcher->current_view) { |     if(view_dispatcher->current_view) { | ||||||
|         if(view->orientation == ViewOrientationVertical) { |         ViewPortOrientation orientation = | ||||||
|             view_port_set_orientation(view_dispatcher->view_port, ViewPortOrientationVertical); |             view_dispatcher_view_port_orientation_table[view->orientation]; | ||||||
|         } else if(view->orientation == ViewOrientationVerticalFlip) { |         if(view_port_get_orientation(view_dispatcher->view_port) != orientation) { | ||||||
|             view_port_set_orientation(view_dispatcher->view_port, ViewPortOrientationVerticalFlip); |             view_port_set_orientation(view_dispatcher->view_port, orientation); | ||||||
|         } else if(view->orientation == ViewOrientationHorizontal) { |             // we just rotated input keys, now it's time to sacrifice some input
 | ||||||
|             view_port_set_orientation(view_dispatcher->view_port, ViewPortOrientationHorizontal); |             view_dispatcher->ongoing_input = 0; | ||||||
|         } else if(view->orientation == ViewOrientationHorizontalFlip) { |  | ||||||
|             view_port_set_orientation( |  | ||||||
|                 view_dispatcher->view_port, ViewPortOrientationHorizontalFlip); |  | ||||||
|         } |         } | ||||||
|         view_enter(view_dispatcher->current_view); |         view_enter(view_dispatcher->current_view); | ||||||
|         view_port_enabled_set(view_dispatcher->view_port, true); |         view_port_enabled_set(view_dispatcher->view_port, true); | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| #include "view_port_i.h" | #include "view_port_i.h" | ||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
|  | #include <furi_hal.h> | ||||||
|  | #include <furi_hal_rtc.h> | ||||||
| 
 | 
 | ||||||
| #include "gui.h" | #include "gui.h" | ||||||
| #include "gui_i.h" | #include "gui_i.h" | ||||||
| @ -48,27 +50,45 @@ static const InputKey view_port_input_mapping[ViewPortOrientationMAX][InputKeyMA | |||||||
|      InputKeyBack}, //ViewPortOrientationVerticalFlip
 |      InputKeyBack}, //ViewPortOrientationVerticalFlip
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static const InputKey view_port_left_hand_input_mapping[InputKeyMAX] = | ||||||
|  |     {InputKeyDown, InputKeyUp, InputKeyLeft, InputKeyRight, InputKeyOk, InputKeyBack}; | ||||||
|  | 
 | ||||||
|  | static const CanvasOrientation view_port_orientation_mapping[ViewPortOrientationMAX] = { | ||||||
|  |     [ViewPortOrientationHorizontal] = CanvasOrientationHorizontal, | ||||||
|  |     [ViewPortOrientationHorizontalFlip] = CanvasOrientationHorizontalFlip, | ||||||
|  |     [ViewPortOrientationVertical] = CanvasOrientationVertical, | ||||||
|  |     [ViewPortOrientationVerticalFlip] = CanvasOrientationVerticalFlip, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| // Remaps directional pad buttons on Flipper based on ViewPort orientation
 | // Remaps directional pad buttons on Flipper based on ViewPort orientation
 | ||||||
| static void view_port_map_input(InputEvent* event, ViewPortOrientation orientation) { | static void view_port_map_input(InputEvent* event, ViewPortOrientation orientation) { | ||||||
|     furi_assert(orientation < ViewPortOrientationMAX && event->key < InputKeyMAX); |     furi_assert(orientation < ViewPortOrientationMAX && event->key < InputKeyMAX); | ||||||
|  | 
 | ||||||
|  |     if(event->sequence_source != INPUT_SEQUENCE_SOURCE_HARDWARE) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(orientation == ViewPortOrientationHorizontal || | ||||||
|  |        orientation == ViewPortOrientationHorizontalFlip) { | ||||||
|  |         if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagHandOrient)) { | ||||||
|  |             event->key = view_port_left_hand_input_mapping[event->key]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|     event->key = view_port_input_mapping[orientation][event->key]; |     event->key = view_port_input_mapping[orientation][event->key]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void view_port_setup_canvas_orientation(const ViewPort* view_port, Canvas* canvas) { | static void view_port_setup_canvas_orientation(const ViewPort* view_port, Canvas* canvas) { | ||||||
|     switch(view_port->orientation) { |     CanvasOrientation orientation = view_port_orientation_mapping[view_port->orientation]; | ||||||
|     case ViewPortOrientationHorizontalFlip: | 
 | ||||||
|         canvas_set_orientation(canvas, CanvasOrientationHorizontalFlip); |     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagHandOrient)) { | ||||||
|         break; |         if(orientation == CanvasOrientationHorizontal) { | ||||||
|     case ViewPortOrientationVertical: |             orientation = CanvasOrientationHorizontalFlip; | ||||||
|         canvas_set_orientation(canvas, CanvasOrientationVertical); |         } else if(orientation == CanvasOrientationHorizontalFlip) { | ||||||
|         break; |             orientation = CanvasOrientationHorizontal; | ||||||
|     case ViewPortOrientationVerticalFlip: |         } | ||||||
|         canvas_set_orientation(canvas, CanvasOrientationVerticalFlip); |     } | ||||||
|         break; | 
 | ||||||
|     default: |     canvas_set_orientation(canvas, orientation); | ||||||
|         canvas_set_orientation(canvas, CanvasOrientationHorizontal); |  | ||||||
|         break; |  | ||||||
|     }; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ViewPort* view_port_alloc() { | ViewPort* view_port_alloc() { | ||||||
|  | |||||||
| @ -23,7 +23,8 @@ inline static void input_timer_stop(FuriTimer* timer_id) { | |||||||
| 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.sequence = input_pin->counter; |     event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; | ||||||
|  |     event.sequence_counter = input_pin->counter; | ||||||
|     event.key = input_pin->pin->key; |     event.key = input_pin->pin->key; | ||||||
|     input_pin->press_counter++; |     input_pin->press_counter++; | ||||||
|     if(input_pin->press_counter == INPUT_LONG_PRESS_COUNTS) { |     if(input_pin->press_counter == INPUT_LONG_PRESS_COUNTS) { | ||||||
| @ -114,16 +115,17 @@ int32_t input_srv(void* p) { | |||||||
| 
 | 
 | ||||||
|                 // Common state info
 |                 // Common state info
 | ||||||
|                 InputEvent event; |                 InputEvent event; | ||||||
|  |                 event.sequence_source = INPUT_SEQUENCE_SOURCE_HARDWARE; | ||||||
|                 event.key = input->pin_states[i].pin->key; |                 event.key = input->pin_states[i].pin->key; | ||||||
| 
 | 
 | ||||||
|                 // Short / Long / Repeat timer routine
 |                 // Short / Long / Repeat timer routine
 | ||||||
|                 if(state) { |                 if(state) { | ||||||
|                     input->counter++; |                     input->counter++; | ||||||
|                     input->pin_states[i].counter = input->counter; |                     input->pin_states[i].counter = input->counter; | ||||||
|                     event.sequence = input->pin_states[i].counter; |                     event.sequence_counter = input->pin_states[i].counter; | ||||||
|                     input_timer_start(input->pin_states[i].press_timer, INPUT_PRESS_TICKS); |                     input_timer_start(input->pin_states[i].press_timer, INPUT_PRESS_TICKS); | ||||||
|                 } else { |                 } else { | ||||||
|                     event.sequence = input->pin_states[i].counter; |                     event.sequence_counter = input->pin_states[i].counter; | ||||||
|                     input_timer_stop(input->pin_states[i].press_timer); |                     input_timer_stop(input->pin_states[i].press_timer); | ||||||
|                     if(input->pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) { |                     if(input->pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) { | ||||||
|                         event.type = InputTypeShort; |                         event.type = InputTypeShort; | ||||||
|  | |||||||
| @ -12,6 +12,8 @@ extern "C" { | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #define RECORD_INPUT_EVENTS "input_events" | #define RECORD_INPUT_EVENTS "input_events" | ||||||
|  | #define INPUT_SEQUENCE_SOURCE_HARDWARE (0u) | ||||||
|  | #define INPUT_SEQUENCE_SOURCE_SOFTWARE (1u) | ||||||
| 
 | 
 | ||||||
| /** Input Types
 | /** Input Types
 | ||||||
|  * Some of them are physical events and some logical |  * Some of them are physical events and some logical | ||||||
| @ -27,7 +29,13 @@ typedef enum { | |||||||
| 
 | 
 | ||||||
| /** Input Event, dispatches with FuriPubSub */ | /** Input Event, dispatches with FuriPubSub */ | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint32_t sequence; |     union { | ||||||
|  |         uint32_t sequence; | ||||||
|  |         struct { | ||||||
|  |             uint8_t sequence_source : 2; | ||||||
|  |             uint32_t sequence_counter : 30; | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
|     InputKey key; |     InputKey key; | ||||||
|     InputType type; |     InputType type; | ||||||
| } InputEvent; | } InputEvent; | ||||||
|  | |||||||
| @ -12,6 +12,8 @@ typedef enum { | |||||||
| 
 | 
 | ||||||
| #define RpcGuiWorkerFlagAny (RpcGuiWorkerFlagTransmit | RpcGuiWorkerFlagExit) | #define RpcGuiWorkerFlagAny (RpcGuiWorkerFlagTransmit | RpcGuiWorkerFlagExit) | ||||||
| 
 | 
 | ||||||
|  | #define RPC_GUI_INPUT_RESET (0u) | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     RpcSession* session; |     RpcSession* session; | ||||||
|     Gui* gui; |     Gui* gui; | ||||||
| @ -26,6 +28,9 @@ typedef struct { | |||||||
| 
 | 
 | ||||||
|     bool virtual_display_not_empty; |     bool virtual_display_not_empty; | ||||||
|     bool is_streaming; |     bool is_streaming; | ||||||
|  | 
 | ||||||
|  |     uint32_t input_key_counter[InputKeyMAX]; | ||||||
|  |     uint32_t input_counter; | ||||||
| } RpcGuiSystem; | } RpcGuiSystem; | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| @ -194,6 +199,22 @@ static void | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // Event sequence shenanigans
 | ||||||
|  |     event.sequence_source = INPUT_SEQUENCE_SOURCE_SOFTWARE; | ||||||
|  |     if(event.type == InputTypePress) { | ||||||
|  |         rpc_gui->input_counter++; | ||||||
|  |         if(rpc_gui->input_counter == RPC_GUI_INPUT_RESET) rpc_gui->input_counter++; | ||||||
|  |         rpc_gui->input_key_counter[event.key] = rpc_gui->input_counter; | ||||||
|  |     } | ||||||
|  |     if(rpc_gui->input_key_counter[event.key] == RPC_GUI_INPUT_RESET) { | ||||||
|  |         FURI_LOG_W(TAG, "Out of sequence input event: key %d, type %d,", event.key, event.type); | ||||||
|  |     } | ||||||
|  |     event.sequence_counter = rpc_gui->input_key_counter[event.key]; | ||||||
|  |     if(event.type == InputTypeRelease) { | ||||||
|  |         rpc_gui->input_key_counter[event.key] = RPC_GUI_INPUT_RESET; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Submit event
 | ||||||
|     FuriPubSub* input_events = furi_record_open(RECORD_INPUT_EVENTS); |     FuriPubSub* input_events = furi_record_open(RECORD_INPUT_EVENTS); | ||||||
|     furi_check(input_events); |     furi_check(input_events); | ||||||
|     furi_pubsub_publish(input_events, &event); |     furi_pubsub_publish(input_events, &event); | ||||||
|  | |||||||
| @ -124,6 +124,23 @@ static void date_format_changed(VariableItem* item) { | |||||||
|     locale_set_date_format(date_format_value[index]); |     locale_set_date_format(date_format_value[index]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | const char* const hand_mode[] = { | ||||||
|  |     "Righty", | ||||||
|  |     "Lefty", | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void hand_orient_changed(VariableItem* item) { | ||||||
|  |     uint8_t index = variable_item_get_current_value_index(item); | ||||||
|  |     variable_item_set_current_value_text(item, hand_mode[index]); | ||||||
|  |     if(index) { | ||||||
|  |         furi_hal_rtc_set_flag(FuriHalRtcFlagHandOrient); | ||||||
|  |     } else { | ||||||
|  |         furi_hal_rtc_reset_flag(FuriHalRtcFlagHandOrient); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     loader_update_menu(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static uint32_t system_settings_exit(void* context) { | static uint32_t system_settings_exit(void* context) { | ||||||
|     UNUSED(context); |     UNUSED(context); | ||||||
|     return VIEW_NONE; |     return VIEW_NONE; | ||||||
| @ -145,6 +162,12 @@ SystemSettings* system_settings_alloc() { | |||||||
|     uint8_t value_index; |     uint8_t value_index; | ||||||
|     app->var_item_list = variable_item_list_alloc(); |     app->var_item_list = variable_item_list_alloc(); | ||||||
| 
 | 
 | ||||||
|  |     item = variable_item_list_add( | ||||||
|  |         app->var_item_list, "Hand Orient", COUNT_OF(hand_mode), hand_orient_changed, app); | ||||||
|  |     value_index = furi_hal_rtc_is_flag_set(FuriHalRtcFlagHandOrient) ? 1 : 0; | ||||||
|  |     variable_item_set_current_value_index(item, value_index); | ||||||
|  |     variable_item_set_current_value_text(item, hand_mode[value_index]); | ||||||
|  | 
 | ||||||
|     item = variable_item_list_add( |     item = variable_item_list_add( | ||||||
|         app->var_item_list, |         app->var_item_list, | ||||||
|         "Units", |         "Units", | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ typedef enum { | |||||||
|     FuriHalRtcFlagFactoryReset = (1 << 1), |     FuriHalRtcFlagFactoryReset = (1 << 1), | ||||||
|     FuriHalRtcFlagLock = (1 << 2), |     FuriHalRtcFlagLock = (1 << 2), | ||||||
|     FuriHalRtcFlagC2Update = (1 << 3), |     FuriHalRtcFlagC2Update = (1 << 3), | ||||||
|  |     FuriHalRtcFlagHandOrient = (1 << 4), | ||||||
| } FuriHalRtcFlag; | } FuriHalRtcFlag; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Michal Suchánek
						Michal Suchánek