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

[FL-878] Gui: screen streaming (#337)

* GUI: canvas streaming
* Fix right status bar icon alignment
あく 4 лет назад
Родитель
Сommit
23f66c2cdd

+ 11 - 7
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);
             }
 

+ 6 - 2
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() {

+ 21 - 4
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

+ 0 - 1
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);

+ 11 - 1
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);
-}
+}

+ 12 - 0
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
  */

+ 41 - 1
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;
 }

+ 22 - 4
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

+ 10 - 1
applications/gui/gui_i.h

@@ -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);