[FL-878] Gui: screen streaming (#337)
* GUI: canvas streaming * Fix right status bar icon alignment
This commit is contained in:
		
							parent
							
								
									b835d7a451
								
							
						
					
					
						commit
						23f66c2cdd
					
				| @ -11,6 +11,8 @@ typedef struct { | |||||||
|     FuriThread* thread; |     FuriThread* thread; | ||||||
|     ViewPort* view_port; |     ViewPort* view_port; | ||||||
|     const FlipperApplication* current_app; |     const FlipperApplication* current_app; | ||||||
|  |     Cli* cli; | ||||||
|  |     Gui* gui; | ||||||
| } AppLoaderState; | } AppLoaderState; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
| @ -73,8 +75,8 @@ static void app_loader_cli_callback(string_t args, void* _ctx) { | |||||||
| 
 | 
 | ||||||
|     printf("Press any key to kill application"); |     printf("Press any key to kill application"); | ||||||
| 
 | 
 | ||||||
|     char c; |     cli_getc(ctx->state->cli); | ||||||
|     cli_read(&c, 1); | 
 | ||||||
|     furi_thread_terminate(ctx->state->thread); |     furi_thread_terminate(ctx->state->thread); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -99,10 +101,10 @@ int32_t app_loader(void* p) { | |||||||
|     view_port_input_callback_set(state.view_port, app_loader_input_callback, &state); |     view_port_input_callback_set(state.view_port, app_loader_input_callback, &state); | ||||||
| 
 | 
 | ||||||
|     ValueMutex* menu_mutex = furi_record_open("menu"); |     ValueMutex* menu_mutex = furi_record_open("menu"); | ||||||
|     Cli* cli = furi_record_open("cli"); |     state.cli = furi_record_open("cli"); | ||||||
|     Gui* gui = furi_record_open("gui"); |     state.gui = furi_record_open("gui"); | ||||||
| 
 | 
 | ||||||
|     gui_add_view_port(gui, state.view_port, GuiLayerFullscreen); |     gui_add_view_port(state.gui, state.view_port, GuiLayerFullscreen); | ||||||
| 
 | 
 | ||||||
|     // Main menu
 |     // Main menu
 | ||||||
|     with_value_mutex( |     with_value_mutex( | ||||||
| @ -124,7 +126,8 @@ int32_t app_loader(void* p) { | |||||||
|                 string_t cli_name; |                 string_t cli_name; | ||||||
|                 string_init_set_str(cli_name, "app_"); |                 string_init_set_str(cli_name, "app_"); | ||||||
|                 string_cat_str(cli_name, FLIPPER_APPS[i].name); |                 string_cat_str(cli_name, FLIPPER_APPS[i].name); | ||||||
|                 cli_add_command(cli, string_get_cstr(cli_name), app_loader_cli_callback, ctx); |                 cli_add_command( | ||||||
|  |                     state.cli, string_get_cstr(cli_name), app_loader_cli_callback, ctx); | ||||||
|                 string_clear(cli_name); |                 string_clear(cli_name); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
| @ -170,7 +173,8 @@ int32_t app_loader(void* p) { | |||||||
|                 string_t cli_name; |                 string_t cli_name; | ||||||
|                 string_init_set_str(cli_name, "app_"); |                 string_init_set_str(cli_name, "app_"); | ||||||
|                 string_cat_str(cli_name, FLIPPER_PLUGINS[i].name); |                 string_cat_str(cli_name, FLIPPER_PLUGINS[i].name); | ||||||
|                 cli_add_command(cli, string_get_cstr(cli_name), app_loader_cli_callback, ctx); |                 cli_add_command( | ||||||
|  |                     state.cli, string_get_cstr(cli_name), app_loader_cli_callback, ctx); | ||||||
|                 string_clear(cli_name); |                 string_clear(cli_name); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -40,8 +40,12 @@ void cli_stdout_callback(void* _cookie, const char* data, size_t size) { | |||||||
|     api_hal_vcp_tx((const uint8_t*)data, size); |     api_hal_vcp_tx((const uint8_t*)data, size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void cli_read(char* buffer, size_t size) { | void cli_write(Cli* cli, uint8_t* buffer, size_t size) { | ||||||
|     api_hal_vcp_rx((uint8_t*)buffer, size); |     return api_hal_vcp_tx(buffer, size); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t cli_read(Cli* cli, uint8_t* buffer, size_t size) { | ||||||
|  |     return api_hal_vcp_rx(buffer, size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void cli_print_version() { | void cli_print_version() { | ||||||
|  | |||||||
| @ -27,12 +27,29 @@ typedef void (*CliCallback)(string_t args, void* context); | |||||||
|  */ |  */ | ||||||
| void cli_add_command(Cli* cli, const char* name, CliCallback callback, void* context); | void cli_add_command(Cli* cli, const char* name, CliCallback callback, void* context); | ||||||
| 
 | 
 | ||||||
| /* Read terminal input.
 | /* Read from terminal
 | ||||||
|  * Do it only from inside of callback. |  * Do it only from inside of cli call. | ||||||
|  * @param buffer - buffer pointer to char buffer |  * @param cli - Cli instance | ||||||
|  |  * @param buffer - pointer to buffer | ||||||
|  * @param size - size of buffer in bytes |  * @param size - size of buffer in bytes | ||||||
|  |  * @return bytes written | ||||||
|  */ |  */ | ||||||
| void cli_read(char* buffer, size_t size); | size_t cli_read(Cli* cli, uint8_t* buffer, size_t size); | ||||||
|  | 
 | ||||||
|  | /* Write to terminal
 | ||||||
|  |  * Do it only from inside of cli call. | ||||||
|  |  * @param cli - Cli instance | ||||||
|  |  * @param buffer - pointer to buffer | ||||||
|  |  * @param size - size of buffer in bytes | ||||||
|  |  * @return bytes written | ||||||
|  |  */ | ||||||
|  | void cli_write(Cli* cli, uint8_t* buffer, size_t size); | ||||||
|  | 
 | ||||||
|  | /* Read character
 | ||||||
|  |  * @param cli - Cli instance | ||||||
|  |  * @return char | ||||||
|  |  */ | ||||||
|  | char cli_getc(Cli* cli); | ||||||
| 
 | 
 | ||||||
| /* New line 
 | /* New line 
 | ||||||
|  * Send new ine sequence |  * Send new ine sequence | ||||||
|  | |||||||
| @ -38,6 +38,5 @@ Cli* cli_alloc(); | |||||||
| void cli_free(Cli* cli); | void cli_free(Cli* cli); | ||||||
| void cli_reset_state(Cli* cli); | void cli_reset_state(Cli* cli); | ||||||
| void cli_print_version(); | void cli_print_version(); | ||||||
| char cli_getc(Cli* cli); |  | ||||||
| void cli_putc(char c); | void cli_putc(char c); | ||||||
| void cli_stdout_callback(void* _cookie, const char* data, size_t size); | void cli_stdout_callback(void* _cookie, const char* data, size_t size); | ||||||
|  | |||||||
| @ -39,6 +39,16 @@ void canvas_commit(Canvas* canvas) { | |||||||
|     u8g2_SendBuffer(&canvas->fb); |     u8g2_SendBuffer(&canvas->fb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | uint8_t* canvas_get_buffer(Canvas* canvas) { | ||||||
|  |     furi_assert(canvas); | ||||||
|  |     return u8g2_GetBufferPtr(&canvas->fb); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t canvas_get_buffer_size(Canvas* canvas) { | ||||||
|  |     furi_assert(canvas); | ||||||
|  |     return u8g2_GetBufferTileWidth(&canvas->fb) * u8g2_GetBufferTileHeight(&canvas->fb) * 8; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void canvas_frame_set( | void canvas_frame_set( | ||||||
|     Canvas* canvas, |     Canvas* canvas, | ||||||
|     uint8_t offset_x, |     uint8_t offset_x, | ||||||
|  | |||||||
| @ -31,6 +31,18 @@ void canvas_reset(Canvas* canvas); | |||||||
|  */ |  */ | ||||||
| void canvas_commit(Canvas* canvas); | void canvas_commit(Canvas* canvas); | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Get canvas buffer. | ||||||
|  |  * @return pointer to buffer | ||||||
|  |  */ | ||||||
|  | uint8_t* canvas_get_buffer(Canvas* canvas); | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Get canvas buffer size. | ||||||
|  |  * @return size of canvas in bytes | ||||||
|  |  */ | ||||||
|  | size_t canvas_get_buffer_size(Canvas* canvas); | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Set drawing region relative to real screen buffer |  * Set drawing region relative to real screen buffer | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -59,7 +59,7 @@ void gui_redraw_status_bar(Gui* gui) { | |||||||
|     uint8_t width; |     uint8_t width; | ||||||
|     ViewPort* view_port; |     ViewPort* view_port; | ||||||
|     // Right side
 |     // Right side
 | ||||||
|     x = 128; |     x = GUI_DISPLAY_WIDTH + 2; | ||||||
|     ViewPortArray_it(it, gui->layers[GuiLayerStatusBarRight]); |     ViewPortArray_it(it, gui->layers[GuiLayerStatusBarRight]); | ||||||
|     while(!ViewPortArray_end_p(it) && x_used < GUI_STATUS_BAR_WIDTH) { |     while(!ViewPortArray_end_p(it) && x_used < GUI_STATUS_BAR_WIDTH) { | ||||||
|         // Render view_port;
 |         // Render view_port;
 | ||||||
| @ -127,6 +127,12 @@ void gui_redraw(Gui* gui) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     canvas_commit(gui->canvas); |     canvas_commit(gui->canvas); | ||||||
|  |     if(gui->canvas_callback) { | ||||||
|  |         gui->canvas_callback( | ||||||
|  |             canvas_get_buffer(gui->canvas), | ||||||
|  |             canvas_get_buffer_size(gui->canvas), | ||||||
|  |             gui->canvas_callback_context); | ||||||
|  |     } | ||||||
|     gui_unlock(gui); |     gui_unlock(gui); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -159,6 +165,27 @@ void gui_unlock(Gui* gui) { | |||||||
|     furi_check(osMutexRelease(gui->mutex) == osOK); |     furi_check(osMutexRelease(gui->mutex) == osOK); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void gui_cli_screen_stream_callback(uint8_t* data, size_t size, void* context) { | ||||||
|  |     furi_assert(data); | ||||||
|  |     furi_assert(size == 1024); | ||||||
|  |     furi_assert(context); | ||||||
|  | 
 | ||||||
|  |     Gui* gui = context; | ||||||
|  |     uint8_t magic[] = {0xF0, 0xE1, 0xD2, 0xC3}; | ||||||
|  |     cli_write(gui->cli, magic, sizeof(magic)); | ||||||
|  |     cli_write(gui->cli, data, size); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void gui_cli_screen_stream(string_t args, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     Gui* gui = context; | ||||||
|  |     gui_set_framebuffer_callback_context(gui, gui); | ||||||
|  |     gui_set_framebuffer_callback(gui, gui_cli_screen_stream_callback); | ||||||
|  |     cli_getc(gui->cli); | ||||||
|  |     gui_set_framebuffer_callback(gui, NULL); | ||||||
|  |     gui_set_framebuffer_callback_context(gui, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void gui_add_view_port(Gui* gui, ViewPort* view_port, GuiLayer layer) { | void gui_add_view_port(Gui* gui, ViewPort* view_port, GuiLayer layer) { | ||||||
|     furi_assert(gui); |     furi_assert(gui); | ||||||
|     furi_assert(view_port); |     furi_assert(view_port); | ||||||
| @ -256,6 +283,16 @@ void gui_send_view_port_back(Gui* gui, ViewPort* view_port) { | |||||||
|     gui_unlock(gui); |     gui_unlock(gui); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback) { | ||||||
|  |     furi_assert(gui); | ||||||
|  |     gui->canvas_callback = callback; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void gui_set_framebuffer_callback_context(Gui* gui, void* context) { | ||||||
|  |     furi_assert(gui); | ||||||
|  |     gui->canvas_callback_context = context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Gui* gui_alloc() { | Gui* gui_alloc() { | ||||||
|     Gui* gui = furi_alloc(sizeof(Gui)); |     Gui* gui = furi_alloc(sizeof(Gui)); | ||||||
|     // Thread ID
 |     // Thread ID
 | ||||||
| @ -276,6 +313,9 @@ Gui* gui_alloc() { | |||||||
|     gui->input_events = furi_record_open("input_events"); |     gui->input_events = furi_record_open("input_events"); | ||||||
|     furi_check(gui->input_events); |     furi_check(gui->input_events); | ||||||
|     subscribe_pubsub(gui->input_events, gui_input_events_callback, gui); |     subscribe_pubsub(gui->input_events, gui_input_events_callback, gui); | ||||||
|  |     // Cli
 | ||||||
|  |     gui->cli = furi_record_open("cli"); | ||||||
|  |     cli_add_command(gui->cli, "screen_stream", gui_cli_screen_stream, gui); | ||||||
| 
 | 
 | ||||||
|     return gui; |     return gui; | ||||||
| } | } | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | /* Gui layers */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     GuiLayerNone, /* Special layer for internal use only */ |     GuiLayerNone, /* Special layer for internal use only */ | ||||||
| 
 | 
 | ||||||
| @ -18,6 +19,9 @@ typedef enum { | |||||||
|     GuiLayerMAX /* Don't use or move, special value */ |     GuiLayerMAX /* Don't use or move, special value */ | ||||||
| } GuiLayer; | } GuiLayer; | ||||||
| 
 | 
 | ||||||
|  | /* Gui frame buffer callback */ | ||||||
|  | typedef void (*GuiCanvasCommitCallback)(uint8_t* data, size_t size, void* context); | ||||||
|  | 
 | ||||||
| typedef struct Gui Gui; | typedef struct Gui Gui; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
| @ -34,18 +38,32 @@ void gui_remove_view_port(Gui* gui, ViewPort* view_port); | |||||||
| 
 | 
 | ||||||
| /* Send ViewPort to the front
 | /* Send ViewPort to the front
 | ||||||
|  * Places selected ViewPort to the top of the drawing stack |  * Places selected ViewPort to the top of the drawing stack | ||||||
|  * @param gui, Gui instance |  * @param gui - Gui instance | ||||||
|  * @param view_port, ViewPort instance |  * @param view_port - ViewPort instance | ||||||
|  */ |  */ | ||||||
| void gui_send_view_port_front(Gui* gui, ViewPort* view_port); | void gui_send_view_port_front(Gui* gui, ViewPort* view_port); | ||||||
| 
 | 
 | ||||||
| /* Send ViewPort to the back
 | /* Send ViewPort to the back
 | ||||||
|  * Places selected ViewPort to the bottom of the drawing stack |  * Places selected ViewPort to the bottom of the drawing stack | ||||||
|  * @param gui, Gui instance |  * @param gui - Gui instance | ||||||
|  * @param view_port, ViewPort instance |  * @param view_port - ViewPort instance | ||||||
|  */ |  */ | ||||||
| void gui_send_view_port_back(Gui* gui, ViewPort* view_port); | void gui_send_view_port_back(Gui* gui, ViewPort* view_port); | ||||||
| 
 | 
 | ||||||
|  | /* Set gui canvas commit callback
 | ||||||
|  |  * This callback will be called upon Canvas commit | ||||||
|  |  * Callback dispatched from GUI thread and is time critical | ||||||
|  |  * @param gui - Gui instance | ||||||
|  |  * @param callback - GuiCanvasCommitCallback | ||||||
|  |  */ | ||||||
|  | void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback); | ||||||
|  | 
 | ||||||
|  | /* Set gui canvas commit callback context
 | ||||||
|  |  * @param gui - Gui instance | ||||||
|  |  * @param context - pointer to context | ||||||
|  |  */ | ||||||
|  | void gui_set_framebuffer_callback_context(Gui* gui, void* context); | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ | |||||||
| #include <m-array.h> | #include <m-array.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
|  | #include <cli/cli.h> | ||||||
| #include "canvas.h" | #include "canvas.h" | ||||||
| #include "canvas_i.h" | #include "canvas_i.h" | ||||||
| #include "view_port.h" | #include "view_port.h" | ||||||
| @ -38,9 +39,13 @@ struct Gui { | |||||||
|     // Layers and Canvas
 |     // Layers and Canvas
 | ||||||
|     ViewPortArray_t layers[GuiLayerMAX]; |     ViewPortArray_t layers[GuiLayerMAX]; | ||||||
|     Canvas* canvas; |     Canvas* canvas; | ||||||
|  |     GuiCanvasCommitCallback canvas_callback; | ||||||
|  |     void* canvas_callback_context; | ||||||
|     // Input
 |     // Input
 | ||||||
|     osMessageQueueId_t input_queue; |     osMessageQueueId_t input_queue; | ||||||
|     PubSub* input_events; |     PubSub* input_events; | ||||||
|  |     // Cli
 | ||||||
|  |     Cli* cli; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| ViewPort* gui_view_port_find_enabled(ViewPortArray_t array); | ViewPort* gui_view_port_find_enabled(ViewPortArray_t array); | ||||||
| @ -58,3 +63,7 @@ void gui_input_events_callback(const void* value, void* ctx); | |||||||
| void gui_lock(Gui* gui); | void gui_lock(Gui* gui); | ||||||
| 
 | 
 | ||||||
| void gui_unlock(Gui* gui); | void gui_unlock(Gui* gui); | ||||||
|  | 
 | ||||||
|  | void gui_cli_screen_stream_callback(uint8_t* data, size_t size, void* context); | ||||||
|  | 
 | ||||||
|  | void gui_cli_screen_stream(string_t args, void* context); | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく