RPC: Add Virtual Display & Unify log tags (#814)

* RPC: Update protobuf sources
* RPC: Add Virtual Display
* Unify log tags
* RPC: Virtual Display placeholder
* Rpc: clear frame buffer callback before confirm.
* Firmware: full assert for hal, move fatfs initialization to furi hal.
* FuriHal: VCP optimizations, thread safe console. Rpc: adjust buffer sizes.

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
Anna Prosvetova
2021-11-12 16:04:35 +03:00
committed by GitHub
parent b564e8eb38
commit 558fa5670b
123 changed files with 1050 additions and 694 deletions

39
applications/rpc/rpc.c Executable file → Normal file
View File

@@ -9,6 +9,7 @@
#include <cmsis_os2.h>
#include <portmacro.h>
#include <furi.h>
#include <cli/cli.h>
#include <stdint.h>
#include <stdio.h>
@@ -16,14 +17,12 @@
#include <m-string.h>
#include <m-dict.h>
#define RPC_TAG "RPC"
#define TAG "RpcSrv"
#define RPC_EVENT_NEW_DATA (1 << 0)
#define RPC_EVENT_DISCONNECT (1 << 1)
#define RPC_EVENTS_ALL (RPC_EVENT_DISCONNECT | RPC_EVENT_NEW_DATA)
#define DEBUG_PRINT 0
DICT_DEF2(RpcHandlerDict, pb_size_t, M_DEFAULT_OPLIST, RpcHandler, M_POD_OPLIST)
typedef struct {
@@ -264,6 +263,7 @@ void rpc_print_message(const PB_Main* message) {
size_t msg_file_count = message->content.storage_list_response.file_count;
string_cat_printf(str, "\tlist_response {\r\n");
rpc_sprintf_msg_file(str, "\t\t", msg_file, msg_file_count);
break;
}
case PB_Main_gui_start_screen_stream_request_tag:
string_cat_printf(str, "\tstart_screen_stream {\r\n");
@@ -271,8 +271,8 @@ void rpc_print_message(const PB_Main* message) {
case PB_Main_gui_stop_screen_stream_request_tag:
string_cat_printf(str, "\tstop_screen_stream {\r\n");
break;
case PB_Main_gui_screen_stream_frame_tag:
string_cat_printf(str, "\tscreen_stream_frame {\r\n");
case PB_Main_gui_screen_frame_tag:
string_cat_printf(str, "\tscreen_frame {\r\n");
break;
case PB_Main_gui_send_input_event_request_tag:
string_cat_printf(str, "\tsend_input_event {\r\n");
@@ -281,6 +281,12 @@ void rpc_print_message(const PB_Main* message) {
string_cat_printf(
str, "\t\type: %d\r\n", message->content.gui_send_input_event_request.type);
break;
case PB_Main_gui_start_virtual_display_request_tag:
string_cat_printf(str, "\tstart_virtual_display {\r\n");
break;
case PB_Main_gui_stop_virtual_display_request_tag:
string_cat_printf(str, "\tstop_virtual_display {\r\n");
break;
}
string_cat_printf(str, "\t}\r\n}\r\n");
printf("%s", string_get_cstr(str));
@@ -335,7 +341,7 @@ RpcSession* rpc_session_open(Rpc* rpc) {
};
rpc_add_handler(rpc, PB_Main_stop_session_tag, &rpc_handler);
FURI_LOG_D(RPC_TAG, "Session started\r\n");
FURI_LOG_D(TAG, "Session started\r\n");
}
return result ? &rpc->session : NULL; /* support 1 open session for now */
@@ -468,7 +474,7 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) {
}
}
#if DEBUG_PRINT
#if SRV_RPC_DEBUG
rpc_print_data("INPUT", buf, bytes_received);
#endif
@@ -481,8 +487,8 @@ void rpc_send_and_release(Rpc* rpc, PB_Main* message) {
RpcSession* session = &rpc->session;
pb_ostream_t ostream = PB_OSTREAM_SIZING;
#if DEBUG_PRINT
FURI_LOG_I(RPC_TAG, "OUTPUT:");
#if SRV_RPC_DEBUG
FURI_LOG_I(TAG, "OUTPUT:");
rpc_print_message(message);
#endif
@@ -494,7 +500,7 @@ void rpc_send_and_release(Rpc* rpc, PB_Main* message) {
pb_encode_ex(&ostream, &PB_Main_msg, message, PB_ENCODE_DELIMITED);
#if DEBUG_PRINT
#if SRV_RPC_DEBUG
rpc_print_data("OUTPUT", buffer, ostream.bytes_written);
#endif
@@ -535,12 +541,12 @@ int32_t rpc_srv(void* p) {
.callback = rpc_pb_stream_read,
.state = rpc,
.errmsg = NULL,
.bytes_left = 1024, /* max incoming message size */
.bytes_left = RPC_MAX_MESSAGE_SIZE, /* max incoming message size */
};
if(pb_decode_ex(&istream, &PB_Main_msg, rpc->decoded_message, PB_DECODE_DELIMITED)) {
#if DEBUG_PRINT
FURI_LOG_I(RPC_TAG, "INPUT:");
#if SRV_RPC_DEBUG
FURI_LOG_I(TAG, "INPUT:");
rpc_print_message(rpc->decoded_message);
#endif
RpcHandler* handler =
@@ -549,20 +555,19 @@ int32_t rpc_srv(void* p) {
if(handler && handler->message_handler) {
handler->message_handler(rpc->decoded_message, handler->context);
} else if(!handler && !rpc->session.terminate) {
FURI_LOG_E(
RPC_TAG, "Unhandled message, tag: %d", rpc->decoded_message->which_content);
FURI_LOG_E(TAG, "Unhandled message, tag: %d", rpc->decoded_message->which_content);
}
} else {
xStreamBufferReset(rpc->stream);
if(!rpc->session.terminate) {
FURI_LOG_E(RPC_TAG, "Decode failed, error: \'%.128s\'", PB_GET_ERROR(&istream));
FURI_LOG_E(TAG, "Decode failed, error: \'%.128s\'", PB_GET_ERROR(&istream));
}
}
pb_release(&PB_Main_msg, rpc->decoded_message);
if(rpc->session.terminate) {
FURI_LOG_D(RPC_TAG, "Session terminated");
FURI_LOG_D(TAG, "Session terminated");
osEventFlagsClear(rpc->events, RPC_EVENTS_ALL);
rpc_free_session(&rpc->session);
rpc->busy = false;

View File

@@ -5,6 +5,7 @@
#include "cmsis_os.h"
#define RPC_BUFFER_SIZE (1024)
#define RPC_MAX_MESSAGE_SIZE (1536)
/** Rpc interface. Used for opening session only. */
typedef struct Rpc Rpc;

View File

@@ -1,14 +1,14 @@
#include <cli/cli.h>
#include <furi.h>
#include <rpc/rpc.h>
#include <furi-hal-vcp.h>
#include <furi-hal.h>
typedef struct {
Cli* cli;
bool session_close_request;
} CliRpc;
#define CLI_READ_BUFFER_SIZE 100
#define CLI_READ_BUFFER_SIZE 64
static void rpc_send_bytes_callback(void* context, uint8_t* bytes, size_t bytes_len) {
furi_assert(context);
@@ -50,7 +50,8 @@ void rpc_cli_command_start_session(Cli* cli, string_t args, void* context) {
}
if(size_received) {
rpc_session_feed(rpc_session, buffer, size_received, 3000);
furi_assert(
rpc_session_feed(rpc_session, buffer, size_received, 3000) == size_received);
}
}

View File

@@ -3,12 +3,17 @@
#include "gui.pb.h"
#include <gui/gui_i.h>
#define TAG "RpcGui"
typedef struct {
Rpc* rpc;
Gui* gui;
ViewPort* virtual_display_view_port;
uint8_t* virtual_display_buffer;
bool virtual_display_not_empty;
} RpcGuiSystem;
void rpc_system_gui_screen_frame_callback(uint8_t* data, size_t size, void* context) {
void rpc_system_gui_screen_stream_frame_callback(uint8_t* data, size_t size, void* context) {
furi_assert(data);
furi_assert(size == 1024);
furi_assert(context);
@@ -17,11 +22,11 @@ void rpc_system_gui_screen_frame_callback(uint8_t* data, size_t size, void* cont
PB_Main* frame = furi_alloc(sizeof(PB_Main));
frame->which_content = PB_Main_gui_screen_stream_frame_tag;
frame->which_content = PB_Main_gui_screen_frame_tag;
frame->command_status = PB_CommandStatus_OK;
frame->content.gui_screen_stream_frame.data = furi_alloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size));
uint8_t* buffer = frame->content.gui_screen_stream_frame.data->bytes;
uint16_t* frame_size_msg = &frame->content.gui_screen_stream_frame.data->size;
frame->content.gui_screen_frame.data = furi_alloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size));
uint8_t* buffer = frame->content.gui_screen_frame.data->bytes;
uint16_t* frame_size_msg = &frame->content.gui_screen_frame.data->size;
*frame_size_msg = size;
memcpy(buffer, data, size);
@@ -37,7 +42,8 @@ void rpc_system_gui_start_screen_stream_process(const PB_Main* request, void* co
rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK);
gui_set_framebuffer_callback(rpc_gui->gui, rpc_system_gui_screen_frame_callback, context);
gui_set_framebuffer_callback(
rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context);
}
void rpc_system_gui_stop_screen_stream_process(const PB_Main* request, void* context) {
@@ -45,9 +51,9 @@ void rpc_system_gui_stop_screen_stream_process(const PB_Main* request, void* con
furi_assert(context);
RpcGuiSystem* rpc_gui = context;
rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK);
gui_set_framebuffer_callback(rpc_gui->gui, NULL, NULL);
rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK);
}
void rpc_system_gui_send_input_event_request_process(const PB_Main* request, void* context) {
@@ -120,6 +126,88 @@ void rpc_system_gui_send_input_event_request_process(const PB_Main* request, voi
rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK);
}
static void rpc_system_gui_virtual_display_render_callback(Canvas* canvas, void* context) {
furi_assert(canvas);
furi_assert(context);
RpcGuiSystem* rpc_gui = context;
if(!rpc_gui->virtual_display_not_empty) {
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 64, 20, AlignCenter, AlignCenter, "Virtual Display");
canvas_draw_str_aligned(canvas, 64, 36, AlignCenter, AlignCenter, "Waiting for frames...");
return;
}
canvas_draw_xbm(canvas, 0, 0, canvas->width, canvas->height, rpc_gui->virtual_display_buffer);
}
void rpc_system_gui_start_virtual_display_process(const PB_Main* request, void* context) {
furi_assert(request);
furi_assert(context);
RpcGuiSystem* rpc_gui = context;
if(rpc_gui->virtual_display_view_port) {
rpc_send_and_release_empty(
rpc_gui->rpc,
request->command_id,
PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_ALREADY_STARTED);
return;
}
// TODO: consider refactoring
// Using display framebuffer size as an XBM buffer size is like comparing apples and oranges
// Glad they both are 1024 for now
size_t buffer_size = canvas_get_buffer_size(rpc_gui->gui->canvas);
rpc_gui->virtual_display_buffer = furi_alloc(buffer_size);
rpc_gui->virtual_display_view_port = view_port_alloc();
view_port_draw_callback_set(
rpc_gui->virtual_display_view_port,
rpc_system_gui_virtual_display_render_callback,
rpc_gui);
gui_add_view_port(rpc_gui->gui, rpc_gui->virtual_display_view_port, GuiLayerFullscreen);
rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK);
}
void rpc_system_gui_stop_virtual_display_process(const PB_Main* request, void* context) {
furi_assert(request);
furi_assert(context);
RpcGuiSystem* rpc_gui = context;
if(!rpc_gui->virtual_display_view_port) {
rpc_send_and_release_empty(
rpc_gui->rpc, request->command_id, PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_NOT_STARTED);
return;
}
gui_remove_view_port(rpc_gui->gui, rpc_gui->virtual_display_view_port);
view_port_free(rpc_gui->virtual_display_view_port);
free(rpc_gui->virtual_display_buffer);
rpc_gui->virtual_display_view_port = NULL;
rpc_gui->virtual_display_not_empty = false;
rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK);
}
void rpc_system_gui_virtual_display_frame_process(const PB_Main* request, void* context) {
furi_assert(request);
furi_assert(context);
RpcGuiSystem* rpc_gui = context;
if(!rpc_gui->virtual_display_view_port) {
FURI_LOG_W(TAG, "Virtual display is not started, ignoring incoming frame packet");
return;
}
size_t buffer_size = canvas_get_buffer_size(rpc_gui->gui->canvas);
memcpy(
rpc_gui->virtual_display_buffer,
request->content.gui_screen_frame.data->bytes,
buffer_size);
rpc_gui->virtual_display_not_empty = true;
view_port_update(rpc_gui->virtual_display_view_port);
}
void* rpc_system_gui_alloc(Rpc* rpc) {
furi_assert(rpc);
@@ -142,6 +230,15 @@ void* rpc_system_gui_alloc(Rpc* rpc) {
rpc_handler.message_handler = rpc_system_gui_send_input_event_request_process;
rpc_add_handler(rpc, PB_Main_gui_send_input_event_request_tag, &rpc_handler);
rpc_handler.message_handler = rpc_system_gui_start_virtual_display_process;
rpc_add_handler(rpc, PB_Main_gui_start_virtual_display_request_tag, &rpc_handler);
rpc_handler.message_handler = rpc_system_gui_stop_virtual_display_process;
rpc_add_handler(rpc, PB_Main_gui_stop_virtual_display_request_tag, &rpc_handler);
rpc_handler.message_handler = rpc_system_gui_virtual_display_frame_process;
rpc_add_handler(rpc, PB_Main_gui_screen_frame_tag, &rpc_handler);
return rpc_gui;
}
@@ -149,6 +246,15 @@ void rpc_system_gui_free(void* ctx) {
furi_assert(ctx);
RpcGuiSystem* rpc_gui = ctx;
furi_assert(rpc_gui->gui);
if(rpc_gui->virtual_display_view_port) {
gui_remove_view_port(rpc_gui->gui, rpc_gui->virtual_display_view_port);
view_port_free(rpc_gui->virtual_display_view_port);
free(rpc_gui->virtual_display_buffer);
rpc_gui->virtual_display_view_port = NULL;
rpc_gui->virtual_display_not_empty = false;
}
gui_set_framebuffer_callback(rpc_gui->gui, NULL, NULL);
furi_record_close("gui");
free(rpc_gui);