diff --git a/applications/app-loader/app-loader.c b/applications/app-loader/app-loader.c index 9c8349d5..3b824157 100644 --- a/applications/app-loader/app-loader.c +++ b/applications/app-loader/app-loader.c @@ -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); } diff --git a/applications/cli/cli.c b/applications/cli/cli.c index 0f384377..77163b77 100644 --- a/applications/cli/cli.c +++ b/applications/cli/cli.c @@ -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() { diff --git a/applications/cli/cli.h b/applications/cli/cli.h index 0b6a787a..514cc288 100644 --- a/applications/cli/cli.h +++ b/applications/cli/cli.h @@ -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 diff --git a/applications/cli/cli_i.h b/applications/cli/cli_i.h index 5ed2b6df..ebb508a8 100644 --- a/applications/cli/cli_i.h +++ b/applications/cli/cli_i.h @@ -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); diff --git a/applications/gui/canvas.c b/applications/gui/canvas.c index 1c1e06e3..7076fdc6 100644 --- a/applications/gui/canvas.c +++ b/applications/gui/canvas.c @@ -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); -} \ No newline at end of file +} diff --git a/applications/gui/canvas_i.h b/applications/gui/canvas_i.h index 80b0abe7..f1b7d027 100644 --- a/applications/gui/canvas_i.h +++ b/applications/gui/canvas_i.h @@ -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 */ diff --git a/applications/gui/gui.c b/applications/gui/gui.c index 2fffd182..df7dcc41 100644 --- a/applications/gui/gui.c +++ b/applications/gui/gui.c @@ -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; } diff --git a/applications/gui/gui.h b/applications/gui/gui.h index a7283e99..eb557bbc 100644 --- a/applications/gui/gui.h +++ b/applications/gui/gui.h @@ -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 diff --git a/applications/gui/gui_i.h b/applications/gui/gui_i.h index 2f9d3c91..cde4ab61 100644 --- a/applications/gui/gui_i.h +++ b/applications/gui/gui_i.h @@ -6,6 +6,7 @@ #include #include +#include #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); \ No newline at end of file +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); \ No newline at end of file