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:
39
applications/rpc/rpc.c
Executable file → Normal file
39
applications/rpc/rpc.c
Executable file → Normal 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;
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user