From eed49bf863db42257c7f23615da6a821e55fb207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 17 Mar 2022 16:44:54 +0700 Subject: [PATCH 1/3] [FL-2335] Gui, Rpc: multisession, asynchronous screen streaming with adaptive frame rate (#1033) * Gui,Rpc: multisession, asynchronous screen streaming with adaptive frame rate * Fix compact build, add missing aray initialization. --- applications/gui/gui.c | 48 +++++++++++++------- applications/gui/gui.h | 20 +++++--- applications/gui/gui_i.h | 15 +++++- applications/rpc/rpc.c | 9 +++- applications/rpc/rpc_gui.c | 93 +++++++++++++++++++++++++++++--------- applications/rpc/rpc_i.h | 3 ++ 6 files changed, 139 insertions(+), 49 deletions(-) diff --git a/applications/gui/gui.c b/applications/gui/gui.c index 067335431..69f0e2488 100644 --- a/applications/gui/gui.c +++ b/applications/gui/gui.c @@ -211,12 +211,11 @@ 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); - } + for + M_EACH(p, gui->canvas_callback_pair, CanvasCallbackPairArray_t) { + p->callback( + canvas_get_buffer(gui->canvas), canvas_get_buffer_size(gui->canvas), p->context); + } gui_unlock(gui); } @@ -396,24 +395,36 @@ void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port) { gui_unlock(gui); } -void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context) { +void gui_add_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context) { furi_assert(gui); - gui_lock(gui); - gui->canvas_callback = callback; - gui->canvas_callback_context = context; - gui_unlock(gui); - if(callback != NULL) { - gui_update(gui); - } + const CanvasCallbackPair p = {callback, context}; + + gui_lock(gui); + + furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 0); + CanvasCallbackPairArray_push_back(gui->canvas_callback_pair, p); + + gui_unlock(gui); + gui_update(gui); } -GuiCanvasCommitCallback gui_get_framebuffer_callback(Gui* gui) { +void gui_remove_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context) { furi_assert(gui); + + const CanvasCallbackPair p = {callback, context}; + gui_lock(gui); - GuiCanvasCommitCallback callback = gui->canvas_callback; + + furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 1); + CanvasCallbackPairArray_remove_val(gui->canvas_callback_pair, p); + gui_unlock(gui); - return callback; +} + +size_t gui_get_framebuffer_size(Gui* gui) { + furi_assert(gui); + return canvas_get_buffer_size(gui->canvas); } void gui_set_lockdown(Gui* gui, bool lockdown) { @@ -437,9 +448,12 @@ Gui* gui_alloc() { } // Drawing canvas gui->canvas = canvas_init(); + CanvasCallbackPairArray_init(gui->canvas_callback_pair); + // Input gui->input_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL); gui->input_events = furi_record_open("input_events"); + furi_check(gui->input_events); furi_pubsub_subscribe(gui->input_events, gui_input_events_callback, gui); diff --git a/applications/gui/gui.h b/applications/gui/gui.h index 39d81c796..e32352426 100644 --- a/applications/gui/gui.h +++ b/applications/gui/gui.h @@ -68,7 +68,7 @@ void gui_view_port_send_to_front(Gui* gui, ViewPort* view_port); */ void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port); -/** Set gui canvas commit callback +/** Add gui canvas commit callback * * This callback will be called upon Canvas commit Callback dispatched from GUI * thread and is time critical @@ -77,16 +77,22 @@ void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port); * @param callback GuiCanvasCommitCallback * @param context GuiCanvasCommitCallback context */ -void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context); +void gui_add_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context); -/** Get gui canvas commit callback - * - * Can be used to check if some application is using framebufer +/** Remove gui canvas commit callback * * @param gui Gui instance - * @return GuiCanvasCommitCallback + * @param callback GuiCanvasCommitCallback + * @param context GuiCanvasCommitCallback context */ -GuiCanvasCommitCallback gui_get_framebuffer_callback(Gui* gui); +void gui_remove_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context); + +/** Get gui canvas frame buffer size + * * + * @param gui Gui instance + * @return size_t size of frame buffer in bytes + */ +size_t gui_get_framebuffer_size(Gui* gui); /** Set lockdown mode * diff --git a/applications/gui/gui_i.h b/applications/gui/gui_i.h index 479b55922..ea26339d2 100644 --- a/applications/gui/gui_i.h +++ b/applications/gui/gui_i.h @@ -9,6 +9,7 @@ #include #include +#include #include #include "canvas.h" @@ -42,6 +43,17 @@ ARRAY_DEF(ViewPortArray, ViewPort*, M_PTR_OPLIST); +typedef struct { + GuiCanvasCommitCallback callback; + void* context; +} CanvasCallbackPair; + +ARRAY_DEF(CanvasCallbackPairArray, CanvasCallbackPair, M_POD_OPLIST); + +#define M_OPL_CanvasCallbackPairArray_t() ARRAY_OPLIST(CanvasCallbackPairArray, M_POD_OPLIST) + +ALGO_DEF(CanvasCallbackPairArray, CanvasCallbackPairArray_t); + /** Gui structure */ struct Gui { // Thread and lock @@ -52,8 +64,7 @@ struct Gui { bool lockdown; ViewPortArray_t layers[GuiLayerMAX]; Canvas* canvas; - GuiCanvasCommitCallback canvas_callback; - void* canvas_callback_context; + CanvasCallbackPairArray_t canvas_callback_pair; // Input osMessageQueueId_t input_queue; diff --git a/applications/rpc/rpc.c b/applications/rpc/rpc.c index b67d036b4..efd5ed876 100644 --- a/applications/rpc/rpc.c +++ b/applications/rpc/rpc.c @@ -623,7 +623,7 @@ RpcSession* rpc_session_open(Rpc* rpc) { rpc_add_handler(session, PB_Main_stop_session_tag, &rpc_handler); session->thread = furi_thread_alloc(); - furi_thread_set_name(session->thread, "RPC Session"); + furi_thread_set_name(session->thread, "RpcSessionWorker"); furi_thread_set_stack_size(session->thread, 2048); furi_thread_set_context(session->thread, session); furi_thread_set_callback(session->thread, rpc_session_worker); @@ -666,9 +666,10 @@ void rpc_add_handler(RpcSession* session, pb_size_t message_tag, RpcHandler* han RpcHandlerDict_set_at(session->handlers, message_tag, *handler); } -void rpc_send_and_release(RpcSession* session, PB_Main* message) { +void rpc_send(RpcSession* session, PB_Main* message) { furi_assert(session); furi_assert(message); + pb_ostream_t ostream = PB_OSTREAM_SIZING; #if SRV_RPC_DEBUG @@ -695,6 +696,10 @@ void rpc_send_and_release(RpcSession* session, PB_Main* message) { osMutexRelease(session->callbacks_mutex); free(buffer); +} + +void rpc_send_and_release(RpcSession* session, PB_Main* message) { + rpc_send(session, message); pb_release(&PB_Main_msg, message); } diff --git a/applications/rpc/rpc_gui.c b/applications/rpc/rpc_gui.c index 1e4b0fe26..3a4e21f08 100644 --- a/applications/rpc/rpc_gui.c +++ b/applications/rpc/rpc_gui.c @@ -5,11 +5,25 @@ #define TAG "RpcGui" +typedef enum { + RpcGuiWorkerFlagTransmit = (1 << 0), + RpcGuiWorkerFlagExit = (1 << 1), +} RpcGuiWorkerFlag; + +#define RpcGuiWorkerFlagAny (RpcGuiWorkerFlagTransmit | RpcGuiWorkerFlagExit) + typedef struct { RpcSession* session; Gui* gui; + + // Receive part ViewPort* virtual_display_view_port; uint8_t* virtual_display_buffer; + + // Transmit + PB_Main* transmit_frame; + FuriThread* transmit_thread; + bool virtual_display_not_empty; bool is_streaming; } RpcGuiSystem; @@ -17,25 +31,35 @@ typedef struct { static 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); RpcGuiSystem* rpc_gui = (RpcGuiSystem*)context; - RpcSession* session = rpc_gui->session; + uint8_t* buffer = rpc_gui->transmit_frame->content.gui_screen_frame.data->bytes; - PB_Main* frame = malloc(sizeof(PB_Main)); + furi_assert(size == rpc_gui->transmit_frame->content.gui_screen_frame.data->size); - frame->which_content = PB_Main_gui_screen_frame_tag; - frame->command_status = PB_CommandStatus_OK; - frame->content.gui_screen_frame.data = malloc(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); - rpc_send_and_release(session, frame); + osThreadFlagsSet( + furi_thread_get_thread_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagTransmit); +} - free(frame); +static int32_t rpc_system_gui_screen_stream_frame_transmit_thread(void* context) { + furi_assert(context); + + RpcGuiSystem* rpc_gui = (RpcGuiSystem*)context; + + while(true) { + uint32_t flags = osThreadFlagsWait(RpcGuiWorkerFlagAny, osFlagsWaitAny, osWaitForever); + if(flags & RpcGuiWorkerFlagTransmit) { + rpc_send(rpc_gui->session, rpc_gui->transmit_frame); + } + if(flags & RpcGuiWorkerFlagExit) { + break; + } + } + + return 0; } static void rpc_system_gui_start_screen_stream_process(const PB_Main* request, void* context) { @@ -45,15 +69,30 @@ static void rpc_system_gui_start_screen_stream_process(const PB_Main* request, v RpcSession* session = rpc_gui->session; furi_assert(session); + furi_assert(!rpc_gui->is_streaming); - if(gui_get_framebuffer_callback(rpc_gui->gui) == NULL) { - rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK); - rpc_gui->is_streaming = true; - gui_set_framebuffer_callback( - rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context); - } else { - rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_ERROR_BUSY); - } + rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK); + + rpc_gui->is_streaming = true; + size_t framebuffer_size = gui_get_framebuffer_size(rpc_gui->gui); + // Reusable Frame + rpc_gui->transmit_frame = malloc(sizeof(PB_Main)); + rpc_gui->transmit_frame->which_content = PB_Main_gui_screen_frame_tag; + rpc_gui->transmit_frame->command_status = PB_CommandStatus_OK; + rpc_gui->transmit_frame->content.gui_screen_frame.data = + malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(framebuffer_size)); + rpc_gui->transmit_frame->content.gui_screen_frame.data->size = framebuffer_size; + // Transmission thread for async TX + rpc_gui->transmit_thread = furi_thread_alloc(); + furi_thread_set_name(rpc_gui->transmit_thread, "GuiRpcWorker"); + furi_thread_set_callback( + rpc_gui->transmit_thread, rpc_system_gui_screen_stream_frame_transmit_thread); + furi_thread_set_context(rpc_gui->transmit_thread, rpc_gui); + furi_thread_set_stack_size(rpc_gui->transmit_thread, 1024); + furi_thread_start(rpc_gui->transmit_thread); + // GUI framebuffer callback + gui_add_framebuffer_callback( + rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context); } static void rpc_system_gui_stop_screen_stream_process(const PB_Main* request, void* context) { @@ -66,7 +105,18 @@ static void rpc_system_gui_stop_screen_stream_process(const PB_Main* request, vo if(rpc_gui->is_streaming) { rpc_gui->is_streaming = false; - gui_set_framebuffer_callback(rpc_gui->gui, NULL, NULL); + // Remove GUI framebuffer callback + gui_remove_framebuffer_callback( + rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context); + // Stop and release worker thread + osThreadFlagsSet( + furi_thread_get_thread_id(rpc_gui->transmit_thread), RpcGuiWorkerFlagExit); + furi_thread_join(rpc_gui->transmit_thread); + furi_thread_free(rpc_gui->transmit_thread); + // Release frame + pb_release(&PB_Main_msg, rpc_gui->transmit_frame); + free(rpc_gui->transmit_frame); + rpc_gui->transmit_frame = NULL; } rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK); @@ -296,7 +346,8 @@ void rpc_system_gui_free(void* context) { } if(rpc_gui->is_streaming) { - gui_set_framebuffer_callback(rpc_gui->gui, NULL, NULL); + gui_remove_framebuffer_callback( + rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context); } furi_record_close("gui"); free(rpc_gui); diff --git a/applications/rpc/rpc_i.h b/applications/rpc/rpc_i.h index a8ffff288..f84cc991e 100644 --- a/applications/rpc/rpc_i.h +++ b/applications/rpc/rpc_i.h @@ -17,7 +17,10 @@ typedef struct { void* context; } RpcHandler; +void rpc_send(RpcSession* session, PB_Main* main_message); + void rpc_send_and_release(RpcSession* session, PB_Main* main_message); + void rpc_send_and_release_empty(RpcSession* session, uint32_t command_id, PB_CommandStatus status); void rpc_add_handler(RpcSession* session, pb_size_t message_tag, RpcHandler* handler); From c098292a53e795b393708dcde2a4e2468c1da3c1 Mon Sep 17 00:00:00 2001 From: MuddledBox <101580720+MuddledBox@users.noreply.github.com> Date: Thu, 17 Mar 2022 04:49:36 -0500 Subject: [PATCH 2/3] CLI Enhancement: Added Debug (#1030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial commit for Debug in CLI Added Debug as option in CLI * Update cli_commands.c Whoops, swapped the printf, now working as expected! * Fixing Menu Update Now menu should update Co-authored-by: SG Co-authored-by: あく --- applications/cli/cli_commands.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/applications/cli/cli_commands.c b/applications/cli/cli_commands.c index 2e6078f22..53595a081 100644 --- a/applications/cli/cli_commands.c +++ b/applications/cli/cli_commands.c @@ -5,6 +5,7 @@ #include #include #include +#include // Close to ISO, `date +'%Y-%m-%d %H:%M:%S %u'` #define CLI_DATE_FORMAT "%.4d-%.2d-%.2d %.2d:%.2d:%.2d %d" @@ -146,6 +147,20 @@ void cli_command_vibro(Cli* cli, string_t args, void* context) { } } +void cli_command_debug(Cli* cli, string_t args, void* context) { + if(!string_cmp(args, "0")) { + furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); + loader_update_menu(); + printf("Debug disabled."); + } else if(!string_cmp(args, "1")) { + furi_hal_rtc_set_flag(FuriHalRtcFlagDebug); + loader_update_menu(); + printf("Debug enabled."); + } else { + cli_print_usage("debug", "<1|0>", string_get_cstr(args)); + } +} + void cli_command_led(Cli* cli, string_t args, void* context) { // Get first word as light name NotificationMessage notification_led_message; @@ -348,6 +363,7 @@ void cli_commands_init(Cli* cli) { cli_add_command(cli, "date", CliCommandFlagParallelSafe, cli_command_date, NULL); cli_add_command(cli, "log", CliCommandFlagParallelSafe, cli_command_log, NULL); + cli_add_command(cli, "debug", CliCommandFlagDefault, cli_command_debug, NULL); cli_add_command(cli, "ps", CliCommandFlagParallelSafe, cli_command_ps, NULL); cli_add_command(cli, "free", CliCommandFlagParallelSafe, cli_command_free, NULL); cli_add_command(cli, "free_blocks", CliCommandFlagParallelSafe, cli_command_free_blocks, NULL); From b86a400a82d0703e464a29bc5e3dd25ae46140fa Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Thu, 17 Mar 2022 13:55:53 +0400 Subject: [PATCH 3/3] SubGhz: add frequencies and add DoorHan 315.00 (#1028) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: add frequencies and add DoorHan 315.00 * SubGhz: fix syntax Co-authored-by: あく --- .../subghz/scenes/subghz_scene_set_type.c | 37 +++++++++++++++++-- applications/subghz/subghz.c | 31 ++++++++++++++-- applications/subghz/subghz_i.h | 1 + 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/applications/subghz/scenes/subghz_scene_set_type.c b/applications/subghz/scenes/subghz_scene_set_type.c index 79d6bcf6a..32aecc146 100644 --- a/applications/subghz/scenes/subghz_scene_set_type.c +++ b/applications/subghz/scenes/subghz_scene_set_type.c @@ -17,7 +17,8 @@ enum SubmenuIndex { SubmenuIndexNeroSketch, SubmenuIndexNeroRadio, SubmenuIndexGateTX, - SubmenuIndexDoorHan, + SubmenuIndexDoorHan_315_00, + SubmenuIndexDoorHan_433_92, }; bool subghz_scene_set_type_submenu_gen_data_protocol( @@ -122,10 +123,16 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexGateTX, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "DoorHan_315", + SubmenuIndexDoorHan_315_00, + subghz_scene_set_type_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "DoorHan_433", - SubmenuIndexDoorHan, + SubmenuIndexDoorHan_433_92, subghz_scene_set_type_submenu_callback, subghz); @@ -195,7 +202,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { generated_protocol = true; } break; - case SubmenuIndexDoorHan: + case SubmenuIndexDoorHan_433_92: subghz->txrx->transmitter = subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq"); if(subghz->txrx->transmitter) { @@ -219,6 +226,30 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); } break; + case SubmenuIndexDoorHan_315_00: + subghz->txrx->transmitter = + subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq"); + if(subghz->txrx->transmitter) { + subghz_protocol_keeloq_create_data( + subghz->txrx->transmitter->protocol_instance, + subghz->txrx->fff_data, + key & 0x0FFFFFFF, + 0x2, + 0x0003, + "DoorHan", + subghz_frequencies[subghz_frequencies_315_00], + FuriHalSubGhzPresetOok650Async); + generated_protocol = true; + } else { + generated_protocol = false; + } + subghz_transmitter_free(subghz->txrx->transmitter); + if(!generated_protocol) { + string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; default: return false; break; diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index 7a1406859..0fb2f6d98 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -4,33 +4,57 @@ #include const char* const subghz_frequencies_text[] = { + + "300.00", + "303.88", + "304.25", "315.00", + "318.00", + + "390.00", + "418.00", "433.08", "433.42", "433.92", "434.42", + "434.78", + "438.90", + "868.35", "915.00", + "925.00", }; const uint32_t subghz_frequencies[] = { + /* 300 - 348 */ + 300000000, + 303875000, + 304250000, 315000000, + 318000000, /* 387 - 464 */ - + 390000000, + 418000000, 433075000, /* LPD433 first */ 433420000, 433920000, /* LPD433 mid */ 434420000, - /* 779 - 928 */ + 434775000, /* LPD433 last channels */ + 438900000, + /* 779 - 928 */ 868350000, 915000000, + 925000000, + }; const uint32_t subghz_hopper_frequencies[] = { 315000000, + 318000000, + 390000000, 433920000, 868350000, }; @@ -38,7 +62,8 @@ const uint32_t subghz_hopper_frequencies[] = { const uint32_t subghz_frequencies_count = sizeof(subghz_frequencies) / sizeof(uint32_t); const uint32_t subghz_hopper_frequencies_count = sizeof(subghz_hopper_frequencies) / sizeof(uint32_t); -const uint32_t subghz_frequencies_433_92 = 3; +const uint32_t subghz_frequencies_433_92 = 9; +const uint32_t subghz_frequencies_315_00 = 3; bool subghz_custom_event_callback(void* context, uint32_t event) { furi_assert(context); diff --git a/applications/subghz/subghz_i.h b/applications/subghz/subghz_i.h index 98dced1cd..efb3eafa1 100644 --- a/applications/subghz/subghz_i.h +++ b/applications/subghz/subghz_i.h @@ -41,6 +41,7 @@ extern const uint32_t subghz_hopper_frequencies[]; extern const uint32_t subghz_frequencies_count; extern const uint32_t subghz_hopper_frequencies_count; extern const uint32_t subghz_frequencies_433_92; +extern const uint32_t subghz_frequencies_315_00; /** SubGhzNotification state */ typedef enum {