[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; | ||||
|     ViewPort* view_port; | ||||
|     const FlipperApplication* current_app; | ||||
|     Cli* cli; | ||||
|     Gui* gui; | ||||
| } AppLoaderState; | ||||
| 
 | ||||
| typedef struct { | ||||
| @ -73,8 +75,8 @@ static void app_loader_cli_callback(string_t args, void* _ctx) { | ||||
| 
 | ||||
|     printf("Press any key to kill application"); | ||||
| 
 | ||||
|     char c; | ||||
|     cli_read(&c, 1); | ||||
|     cli_getc(ctx->state->cli); | ||||
| 
 | ||||
|     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); | ||||
| 
 | ||||
|     ValueMutex* menu_mutex = furi_record_open("menu"); | ||||
|     Cli* cli = furi_record_open("cli"); | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     state.cli = furi_record_open("cli"); | ||||
|     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
 | ||||
|     with_value_mutex( | ||||
| @ -124,7 +126,8 @@ int32_t app_loader(void* p) { | ||||
|                 string_t cli_name; | ||||
|                 string_init_set_str(cli_name, "app_"); | ||||
|                 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); | ||||
|             } | ||||
|         }); | ||||
| @ -170,7 +173,8 @@ int32_t app_loader(void* p) { | ||||
|                 string_t cli_name; | ||||
|                 string_init_set_str(cli_name, "app_"); | ||||
|                 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); | ||||
|             } | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
| 
 | ||||
| void cli_read(char* buffer, size_t size) { | ||||
|     api_hal_vcp_rx((uint8_t*)buffer, size); | ||||
| void cli_write(Cli* cli, uint8_t* buffer, size_t 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() { | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
| /* Read terminal input.
 | ||||
|  * Do it only from inside of callback. | ||||
|  * @param buffer - buffer pointer to char buffer | ||||
| /* Read from 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_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 
 | ||||
|  * Send new ine sequence | ||||
|  | ||||
| @ -38,6 +38,5 @@ Cli* cli_alloc(); | ||||
| void cli_free(Cli* cli); | ||||
| void cli_reset_state(Cli* cli); | ||||
| void cli_print_version(); | ||||
| char cli_getc(Cli* cli); | ||||
| void cli_putc(char c); | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| 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( | ||||
|     Canvas* canvas, | ||||
|     uint8_t offset_x, | ||||
| @ -219,4 +229,4 @@ void canvas_draw_glyph(Canvas* canvas, uint8_t x, uint8_t y, uint16_t ch) { | ||||
|     x += canvas->offset_x; | ||||
|     y += canvas->offset_y; | ||||
|     u8g2_DrawGlyph(&canvas->fb, x, y, ch); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -31,6 +31,18 @@ void canvas_reset(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 | ||||
|  */ | ||||
|  | ||||
| @ -59,7 +59,7 @@ void gui_redraw_status_bar(Gui* gui) { | ||||
|     uint8_t width; | ||||
|     ViewPort* view_port; | ||||
|     // Right side
 | ||||
|     x = 128; | ||||
|     x = GUI_DISPLAY_WIDTH + 2; | ||||
|     ViewPortArray_it(it, gui->layers[GuiLayerStatusBarRight]); | ||||
|     while(!ViewPortArray_end_p(it) && x_used < GUI_STATUS_BAR_WIDTH) { | ||||
|         // Render view_port;
 | ||||
| @ -127,6 +127,12 @@ void gui_redraw(Gui* gui) { | ||||
|     } | ||||
| 
 | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
| @ -159,6 +165,27 @@ void gui_unlock(Gui* gui) { | ||||
|     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) { | ||||
|     furi_assert(gui); | ||||
|     furi_assert(view_port); | ||||
| @ -256,6 +283,16 @@ void gui_send_view_port_back(Gui* gui, ViewPort* view_port) { | ||||
|     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 = furi_alloc(sizeof(Gui)); | ||||
|     // Thread ID
 | ||||
| @ -276,6 +313,9 @@ Gui* gui_alloc() { | ||||
|     gui->input_events = furi_record_open("input_events"); | ||||
|     furi_check(gui->input_events); | ||||
|     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; | ||||
| } | ||||
|  | ||||
| @ -7,6 +7,7 @@ | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /* Gui layers */ | ||||
| typedef enum { | ||||
|     GuiLayerNone, /* Special layer for internal use only */ | ||||
| 
 | ||||
| @ -18,6 +19,9 @@ typedef enum { | ||||
|     GuiLayerMAX /* Don't use or move, special value */ | ||||
| } GuiLayer; | ||||
| 
 | ||||
| /* Gui frame buffer callback */ | ||||
| typedef void (*GuiCanvasCommitCallback)(uint8_t* data, size_t size, void* context); | ||||
| 
 | ||||
| typedef struct Gui Gui; | ||||
| 
 | ||||
| /*
 | ||||
| @ -34,18 +38,32 @@ void gui_remove_view_port(Gui* gui, ViewPort* view_port); | ||||
| 
 | ||||
| /* Send ViewPort to the front
 | ||||
|  * Places selected ViewPort to the top of the drawing stack | ||||
|  * @param gui, Gui instance | ||||
|  * @param view_port, ViewPort instance | ||||
|  * @param gui - Gui instance | ||||
|  * @param view_port - ViewPort instance | ||||
|  */ | ||||
| void gui_send_view_port_front(Gui* gui, ViewPort* view_port); | ||||
| 
 | ||||
| /* Send ViewPort to the back
 | ||||
|  * Places selected ViewPort to the bottom of the drawing stack | ||||
|  * @param gui, Gui instance | ||||
|  * @param view_port, ViewPort instance | ||||
|  * @param gui - Gui instance | ||||
|  * @param view_port - ViewPort instance | ||||
|  */ | ||||
| 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 | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| #include <m-array.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| #include <cli/cli.h> | ||||
| #include "canvas.h" | ||||
| #include "canvas_i.h" | ||||
| #include "view_port.h" | ||||
| @ -38,9 +39,13 @@ struct Gui { | ||||
|     // Layers and Canvas
 | ||||
|     ViewPortArray_t layers[GuiLayerMAX]; | ||||
|     Canvas* canvas; | ||||
|     GuiCanvasCommitCallback canvas_callback; | ||||
|     void* canvas_callback_context; | ||||
|     // Input
 | ||||
|     osMessageQueueId_t input_queue; | ||||
|     PubSub* input_events; | ||||
|     // Cli
 | ||||
|     Cli* cli; | ||||
| }; | ||||
| 
 | ||||
| ViewPort* gui_view_port_find_enabled(ViewPortArray_t array); | ||||
| @ -57,4 +62,8 @@ void gui_input_events_callback(const void* value, void* ctx); | ||||
| 
 | ||||
| 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
	 あく
						あく