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

Add support for background loader

twisted_pear 2 лет назад
Родитель
Сommit
36e14b8b3d
6 измененных файлов с 163 добавлено и 16 удалено
  1. 21 0
      bgloader_api.h
  2. 132 16
      esubghz_chat.c
  3. 3 0
      esubghz_chat_i.h
  4. 2 0
      scenes/esubghz_chat_chat_box.c
  5. 3 0
      scenes/esubghz_chat_freq_input.c
  6. 2 0
      scenes/esubghz_chat_key_display.c

+ 21 - 0
bgloader_api.h

@@ -0,0 +1,21 @@
+#include <furi.h>
+#include <flipper_application/flipper_application.h>
+
+#define APP_BASE_ARGS "run_in_background"
+
+typedef enum {
+	BGLoaderMessageType_AppReattached,
+	BGLoaderMessageType_LoaderBackground,
+	BGLoaderMessageType_LoaderExit,
+} BGLoaderMessageType;
+
+typedef struct {
+	BGLoaderMessageType type;
+} BGLoaderMessage;
+
+typedef struct {
+	FlipperApplication *fap;
+	FuriThread *thread;
+	FuriMessageQueue *to_app;
+	FuriMessageQueue *to_loader;
+} BGLoaderApp;

+ 132 - 16
esubghz_chat.c

@@ -5,6 +5,8 @@
 #include "helpers/radio_device_loader.h"
 #include "helpers/radio_device_loader.h"
 #include "esubghz_chat_i.h"
 #include "esubghz_chat_i.h"
 
 
+#include "bgloader_api.h"
+
 #define CHAT_LEAVE_DELAY 10
 #define CHAT_LEAVE_DELAY 10
 #define TICK_INTERVAL 50
 #define TICK_INTERVAL 50
 #define MESSAGE_COMPLETION_TIMEOUT 500
 #define MESSAGE_COMPLETION_TIMEOUT 500
@@ -252,21 +254,8 @@ static bool esubghz_chat_navigation_event_callback(void* context)
 	return scene_manager_handle_back_event(state->scene_manager);
 	return scene_manager_handle_back_event(state->scene_manager);
 }
 }
 
 
-/* Tick event callback for view dispatcher. Called every TICK_INTERVAL. Resets
- * the locked message if necessary. Retrieves a received message from the
- * Sub-GHz worker and calls post_rx(). Then calls the scene manager. */
-static void esubghz_chat_tick_event_callback(void* context)
+static void esubghz_chat_check_messages(ESubGhzChatState *state)
 {
 {
-	FURI_LOG_T(APPLICATION_NAME, "esubghz_chat_tick_event_callback");
-
-	furi_assert(context);
-	ESubGhzChatState* state = context;
-
-	/* reset locked message if necessary */
-	if (kbd_lock_msg_reset_timeout(state)) {
-		kbd_lock_msg_reset(state, true);
-	}
-
 	/* if the maximum message size was reached or the
 	/* if the maximum message size was reached or the
 	 * MESSAGE_COMPLETION_TIMEOUT has expired, retrieve a message and call
 	 * MESSAGE_COMPLETION_TIMEOUT has expired, retrieve a message and call
 	 * post_rx() */
 	 * post_rx() */
@@ -284,6 +273,24 @@ static void esubghz_chat_tick_event_callback(void* context)
 				state->rx_buffer, RX_TX_BUFFER_SIZE);
 				state->rx_buffer, RX_TX_BUFFER_SIZE);
 		post_rx(state, rx_size);
 		post_rx(state, rx_size);
 	}
 	}
+}
+
+/* Tick event callback for view dispatcher. Called every TICK_INTERVAL. Resets
+ * the locked message if necessary. Retrieves a received message from the
+ * Sub-GHz worker and calls post_rx(). Then calls the scene manager. */
+static void esubghz_chat_tick_event_callback(void* context)
+{
+	FURI_LOG_T(APPLICATION_NAME, "esubghz_chat_tick_event_callback");
+
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	/* reset locked message if necessary */
+	if (kbd_lock_msg_reset_timeout(state)) {
+		kbd_lock_msg_reset(state, true);
+	}
+
+	esubghz_chat_check_messages(state);
 
 
 	/* call scene manager */
 	/* call scene manager */
 	scene_manager_handle_tick_event(state->scene_manager);
 	scene_manager_handle_tick_event(state->scene_manager);
@@ -355,6 +362,18 @@ static void esubghz_hooked_input_callback(InputEvent* event, void* context)
 		return;
 		return;
 	}
 	}
 
 
+	/* handle long press of back key to exit for real */
+	if (event->key == InputKeyBack) {
+		if (state->view_dispatcher->current_view ==
+				text_input_get_view(state->text_input)) {
+			if (event->type == InputTypeLong) {
+				state->exit_for_real = true;
+				view_dispatcher_stop(state->view_dispatcher);
+				return;
+			}
+		}
+	}
+
 	if (event->key == InputKeyOk) {
 	if (event->key == InputKeyOk) {
 		/* if we are in the chat view and no input is ongoing, allow
 		/* if we are in the chat view and no input is ongoing, allow
 		 * locking */
 		 * locking */
@@ -434,6 +453,95 @@ static void esubghz_hooked_input_callback(InputEvent* event, void* context)
 	state->orig_input_cb(event, state->view_dispatcher);
 	state->orig_input_cb(event, state->view_dispatcher);
 }
 }
 
 
+static const char *esubghz_get_bgloader_app_path(const char *args)
+{
+	size_t base_args_len = strlen(APP_BASE_ARGS);
+
+	return (args + base_args_len + 1);
+}
+
+static bool esubghz_run_with_bgloader(const char *args)
+{
+	size_t base_args_len = strlen(APP_BASE_ARGS);
+
+	if (args == NULL) {
+		return false;
+	}
+
+	if (strncmp(args, APP_BASE_ARGS, base_args_len) != 0) {
+		return false;
+	}
+
+	if (strlen(args) < base_args_len + 2) {
+		return false;
+	}
+
+	if (args[base_args_len] != ':') {
+		return false;
+	}
+
+	const char *app_path = esubghz_get_bgloader_app_path(args);
+	return furi_record_exists(app_path);
+}
+
+static void esubghz_attach_to_gui(ESubGhzChatState *state)
+{
+	Gui *gui = furi_record_open(RECORD_GUI);
+	view_dispatcher_attach_to_gui(state->view_dispatcher, gui,
+			ViewDispatcherTypeFullscreen);
+}
+
+static void esubghz_detach_from_gui(ESubGhzChatState *state)
+{
+	gui_remove_view_port(state->view_dispatcher->gui,
+			state->view_dispatcher->view_port);
+	state->view_dispatcher->gui = NULL;
+	furi_record_close(RECORD_GUI);
+}
+
+static void esubghz_bgloader_loop(ESubGhzChatState *state, const char
+		*bg_app_path)
+{
+	while (true) {
+		view_dispatcher_run(state->view_dispatcher);
+		
+		if (state->exit_for_real) {
+			/* exit for real */
+			break;
+		}
+		
+		BGLoaderApp *bg_app = furi_record_open(bg_app_path);
+		
+		/* signal loader that we're ready to go to background */
+		BGLoaderMessage msg;
+		msg.type = BGLoaderMessageType_LoaderBackground;
+		furi_check(furi_message_queue_put(bg_app->to_loader, &msg,
+					FuriWaitForever) == FuriStatusOk);
+		
+		esubghz_detach_from_gui(state);
+
+		while (true) {
+			/* wait for loader to wake us up again */
+			if (furi_message_queue_get(bg_app->to_app, &msg,
+						TICK_INTERVAL) != FuriStatusOk)
+			{
+				/* check for messages on timeout */
+				esubghz_chat_check_messages(state);
+				continue;
+			}
+			if (msg.type == BGLoaderMessageType_AppReattached) {
+				break;
+			} else {
+				furi_check(0);
+			}
+		}
+		
+		furi_record_close(bg_app_path);
+		
+		esubghz_attach_to_gui(state);
+        }
+}
+
 static bool helper_strings_alloc(ESubGhzChatState *state)
 static bool helper_strings_alloc(ESubGhzChatState *state)
 {
 {
 	furi_assert(state);
 	furi_assert(state);
@@ -492,7 +600,7 @@ static void chat_box_free(ESubGhzChatState *state)
 	furi_string_free(state->chat_box_store);
 	furi_string_free(state->chat_box_store);
 }
 }
 
 
-int32_t esubghz_chat(void)
+int32_t esubghz_chat(const char *args)
 {
 {
 	/* init the crypto system */
 	/* init the crypto system */
 	crypto_init();
 	crypto_init();
@@ -577,6 +685,9 @@ int32_t esubghz_chat(void)
 	/* set the default frequency */
 	/* set the default frequency */
 	state->frequency = DEFAULT_FREQ;
 	state->frequency = DEFAULT_FREQ;
 
 
+	/* in the first few views there is no background support */
+	state->exit_for_real = true;
+
 	/* set the have_read callback of the Sub-GHz worker */
 	/* set the have_read callback of the Sub-GHz worker */
 	subghz_tx_rx_worker_set_callback_have_read(state->subghz_worker,
 	subghz_tx_rx_worker_set_callback_have_read(state->subghz_worker,
 			have_read_cb, state);
 			have_read_cb, state);
@@ -649,7 +760,12 @@ int32_t esubghz_chat(void)
 
 
 	/* run the view dispatcher, this call only returns when we close the
 	/* run the view dispatcher, this call only returns when we close the
 	 * application */
 	 * application */
-	view_dispatcher_run(state->view_dispatcher);
+	if (!esubghz_run_with_bgloader(args)) {
+		view_dispatcher_run(state->view_dispatcher);
+	} else {
+		const char *bg_app_path = esubghz_get_bgloader_app_path(args);
+		esubghz_bgloader_loop(state, bg_app_path);
+	}
 
 
 	/* if it is running, stop the Sub-GHz worker */
 	/* if it is running, stop the Sub-GHz worker */
 	if (subghz_tx_rx_worker_is_running(state->subghz_worker)) {
 	if (subghz_tx_rx_worker_is_running(state->subghz_worker)) {

+ 3 - 0
esubghz_chat_i.h

@@ -88,6 +88,9 @@ typedef struct {
 	bool kbd_ok_input_ongoing;
 	bool kbd_ok_input_ongoing;
 	bool kbd_left_input_ongoing;
 	bool kbd_left_input_ongoing;
 	bool kbd_right_input_ongoing;
 	bool kbd_right_input_ongoing;
+
+	// for background support
+	bool exit_for_real;
 } ESubGhzChatState;
 } ESubGhzChatState;
 
 
 typedef enum {
 typedef enum {

+ 2 - 0
scenes/esubghz_chat_chat_box.c

@@ -33,6 +33,8 @@ bool scene_on_event_chat_box(void* context, SceneManagerEvent event)
 		case ESubGhzChatEvent_GotoMsgInput:
 		case ESubGhzChatEvent_GotoMsgInput:
 			if (!scene_manager_previous_scene(
 			if (!scene_manager_previous_scene(
 						state->scene_manager)) {
 						state->scene_manager)) {
+				/* error condition, exit for real */
+				state->exit_for_real = true;
 				view_dispatcher_stop(state->view_dispatcher);
 				view_dispatcher_stop(state->view_dispatcher);
 			}
 			}
 			consumed = true;
 			consumed = true;

+ 3 - 0
scenes/esubghz_chat_freq_input.c

@@ -8,6 +8,9 @@ static void freq_input_cb(void *context)
 
 
 	enter_chat(state);
 	enter_chat(state);
 
 
+	/* starting from here running in background is supported */
+	state->exit_for_real = false;
+
 	view_dispatcher_send_custom_event(state->view_dispatcher,
 	view_dispatcher_send_custom_event(state->view_dispatcher,
 			ESubGhzChatEvent_FreqEntered);
 			ESubGhzChatEvent_FreqEntered);
 }
 }

+ 2 - 0
scenes/esubghz_chat_key_display.c

@@ -93,6 +93,8 @@ bool scene_on_event_key_display(void* context, SceneManagerEvent event)
 		case ESubGhzChatEvent_KeyDisplayBack:
 		case ESubGhzChatEvent_KeyDisplayBack:
 			if (!scene_manager_previous_scene(
 			if (!scene_manager_previous_scene(
 						state->scene_manager)) {
 						state->scene_manager)) {
+				/* error condition, exit for real */
+				state->exit_for_real = true;
 				view_dispatcher_stop(state->view_dispatcher);
 				view_dispatcher_stop(state->view_dispatcher);
 			}
 			}
 			consumed = true;
 			consumed = true;