Explorar o código

Initial commit

twisted_pear %!s(int64=2) %!d(string=hai) anos
achega
92011fd210
Modificáronse 3 ficheiros con 507 adicións e 0 borrados
  1. 3 0
      .gitignore
  2. 11 0
      application.fam
  3. 493 0
      esubghz_chat.c

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+*~
+*.swp
+*.swo

+ 11 - 0
application.fam

@@ -0,0 +1,11 @@
+App(
+    appid="esubghz_chat",
+    name="Enhanced Sub-Ghz Chat",
+    apptype=FlipperAppType.EXTERNAL,
+    entry_point="esubghz_chat",
+    requires=[
+        "gui",
+    ],
+    stack_size=2 * 1024,
+    fap_category="Examples",
+)

+ 493 - 0
esubghz_chat.c

@@ -0,0 +1,493 @@
+#include <furi.h>
+#include <gui/gui.h>
+#include <gui/modules/text_box.h>
+#include <gui/modules/text_input.h>
+#include <gui/view_dispatcher.h>
+#include <gui/scene_manager.h>
+
+#define APPLICATION_NAME "ESubGhzChat"
+
+#define CHAT_BOX_STORE_SIZE 4096
+#define TEXT_INPUT_STORE_SIZE 512
+
+typedef struct {
+	SceneManager *scene_manager;
+	ViewDispatcher *view_dispatcher;
+	TextBox *chat_box;
+	FuriString *chat_box_store;
+	TextInput *text_input;
+	char text_input_store[TEXT_INPUT_STORE_SIZE + 1];
+} ESubGhzChatState;
+
+typedef enum {
+	ESubGhzChatScene_FreqInput,
+	ESubGhzChatScene_PassInput,
+	ESubGhzChatScene_ChatInput,
+	ESubGhzChatScene_ChatBox,
+	ESubGhzChatScene_MAX
+} ESubGhzChatScene;
+
+typedef enum {
+	ESubGhzChatView_Input,
+	ESubGhzChatView_ChatBox,
+} ESubGhzChatView;
+
+typedef enum {
+	ESubGhzChatEvent_FreqEntered,
+	ESubGhzChatEvent_PassEntered,
+	ESubGhzChatEvent_MsgEntered
+} ESubGhzChatEvent;
+
+static void freq_input_cb(void *context)
+{
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	scene_manager_handle_custom_event(state->scene_manager,
+			ESubGhzChatEvent_FreqEntered);
+}
+
+static bool freq_input_validator(const char *text, FuriString *error,
+		void *context)
+{
+	UNUSED(text);
+	UNUSED(error);
+	UNUSED(context);
+
+	// TODO
+	return true;
+}
+
+static void pass_input_cb(void *context)
+{
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	scene_manager_handle_custom_event(state->scene_manager,
+			ESubGhzChatEvent_PassEntered);
+}
+
+static bool pass_input_validator(const char *text, FuriString *error,
+		void *context)
+{
+	UNUSED(text);
+	UNUSED(error);
+	UNUSED(context);
+
+	// TODO
+	return true;
+}
+
+static void chat_input_cb(void *context)
+{
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	scene_manager_handle_custom_event(state->scene_manager,
+			ESubGhzChatEvent_MsgEntered);
+}
+
+static void scene_on_enter_freq_input(void* context)
+{
+	FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_freq_input");
+
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	state->text_input_store[0] = 0;
+	text_input_reset(state->text_input);
+	text_input_set_result_callback(
+			state->text_input,
+			freq_input_cb,
+			state,
+			state->text_input_store,
+			sizeof(state->text_input_store),
+			true);
+	text_input_set_validator(
+			state->text_input,
+			freq_input_validator,
+			state);
+	text_input_set_header_text(
+			state->text_input,
+			"Frequency");
+
+	view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_Input);
+}
+
+static bool scene_on_event_freq_input(void* context, SceneManagerEvent event)
+{
+	FURI_LOG_T(APPLICATION_NAME, "scene_on_event_freq_input");
+
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	bool consumed = false;
+
+	switch(event.type) {
+	case SceneManagerEventTypeCustom:
+		switch(event.event) {
+		case ESubGhzChatEvent_FreqEntered:
+			scene_manager_next_scene(state->scene_manager,
+					ESubGhzChatScene_PassInput);
+			consumed = true;
+			break;
+		}
+		break;
+
+	case SceneManagerEventTypeBack:
+		view_dispatcher_stop(state->view_dispatcher);
+		consumed = true;
+		break;
+
+	default:
+		consumed = false;
+		break;
+	}
+
+	return consumed;
+}
+
+static void scene_on_exit_freq_input(void* context)
+{
+	FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_freq_input");
+
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	text_input_reset(state->text_input);
+}
+
+static void scene_on_enter_pass_input(void* context)
+{
+	FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_pass_input");
+
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	state->text_input_store[0] = 0;
+	text_input_reset(state->text_input);
+	text_input_set_result_callback(
+			state->text_input,
+			pass_input_cb,
+			state,
+			state->text_input_store,
+			sizeof(state->text_input_store),
+			true);
+	text_input_set_validator(
+			state->text_input,
+			pass_input_validator,
+			state);
+	text_input_set_header_text(
+			state->text_input,
+			"Password (empty for no encr.)");
+	text_input_set_minimum_length(state->text_input, 0);
+
+	view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_Input);
+}
+
+static bool scene_on_event_pass_input(void* context, SceneManagerEvent event)
+{
+	FURI_LOG_T(APPLICATION_NAME, "scene_on_event_pass_input");
+
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	bool consumed = false;
+
+	switch(event.type) {
+	case SceneManagerEventTypeCustom:
+		switch(event.event) {
+		case ESubGhzChatEvent_PassEntered:
+			scene_manager_next_scene(state->scene_manager,
+					ESubGhzChatScene_ChatInput);
+			consumed = true;
+			break;
+		}
+		break;
+
+	case SceneManagerEventTypeBack:
+		view_dispatcher_stop(state->view_dispatcher);
+		consumed = true;
+		break;
+
+	default:
+		consumed = false;
+		break;
+	}
+
+	return consumed;
+}
+
+static void scene_on_exit_pass_input(void* context)
+{
+	FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_pass_input");
+
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	text_input_reset(state->text_input);
+}
+
+static void scene_on_enter_chat_input(void* context)
+{
+	FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_chat_input");
+
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	state->text_input_store[0] = 0;
+	text_input_reset(state->text_input);
+	text_input_set_result_callback(
+			state->text_input,
+			chat_input_cb,
+			state,
+			state->text_input_store,
+			sizeof(state->text_input_store),
+			true);
+	text_input_set_validator(
+			state->text_input,
+			NULL,
+			NULL);
+	text_input_set_header_text(
+			state->text_input,
+			"Message");
+	text_input_set_minimum_length(state->text_input, 0);
+
+	view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_Input);
+}
+
+static bool scene_on_event_chat_input(void* context, SceneManagerEvent event)
+{
+	FURI_LOG_T(APPLICATION_NAME, "scene_on_event_chat_input");
+
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	bool consumed = false;
+
+	switch(event.type) {
+	case SceneManagerEventTypeCustom:
+		switch(event.event) {
+		case ESubGhzChatEvent_MsgEntered:
+			scene_manager_next_scene(state->scene_manager,
+					ESubGhzChatScene_ChatBox);
+			consumed = true;
+			break;
+		}
+		break;
+
+	case SceneManagerEventTypeBack:
+		view_dispatcher_stop(state->view_dispatcher);
+		consumed = true;
+		break;
+
+	default:
+		consumed = false;
+		break;
+	}
+
+	return consumed;
+}
+
+static void scene_on_exit_chat_input(void* context)
+{
+	FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_chat_input");
+
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	text_input_reset(state->text_input);
+}
+
+static void scene_on_enter_chat_box(void* context)
+{
+	FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_chat_box");
+
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	text_box_reset(state->chat_box);
+	text_box_set_text(state->chat_box,
+			furi_string_get_cstr(state->chat_box_store));
+	text_box_set_focus(state->chat_box, TextBoxFocusEnd);
+
+	view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_ChatBox);
+}
+
+static bool scene_on_event_chat_box(void* context, SceneManagerEvent event)
+{
+	UNUSED(event);
+
+	FURI_LOG_T(APPLICATION_NAME, "scene_on_event_chat_box");
+	furi_assert(context);
+	// TODO
+	return false;
+}
+
+static void scene_on_exit_chat_box(void* context)
+{
+	FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_chat_box");
+
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+
+	text_box_reset(state->chat_box);
+}
+
+static void (*const esubghz_chat_scene_on_enter_handlers[])(void*) = {
+	scene_on_enter_freq_input,
+	scene_on_enter_pass_input,
+	scene_on_enter_chat_input,
+	scene_on_enter_chat_box
+};
+
+static bool (*const esubghz_chat_scene_on_event_handlers[])(void*, SceneManagerEvent) = {
+	scene_on_event_freq_input,
+	scene_on_event_pass_input,
+	scene_on_event_chat_input,
+	scene_on_event_chat_box
+};
+
+static void (*const esubghz_chat_scene_on_exit_handlers[])(void*) = {
+	scene_on_exit_freq_input,
+	scene_on_exit_pass_input,
+	scene_on_exit_chat_input,
+	scene_on_exit_chat_box
+};
+
+static const SceneManagerHandlers esubghz_chat_scene_event_handlers = {
+	.on_enter_handlers = esubghz_chat_scene_on_enter_handlers,
+	.on_event_handlers = esubghz_chat_scene_on_event_handlers,
+	.on_exit_handlers = esubghz_chat_scene_on_exit_handlers,
+	.scene_num = ESubGhzChatScene_MAX};
+
+static bool esubghz_chat_custom_event_callback(void* context, uint32_t event)
+{
+	FURI_LOG_T(APPLICATION_NAME, "esubghz_chat_custom_event_callback");
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+	return scene_manager_handle_custom_event(state->scene_manager, event);
+}
+
+static bool esubghz_chat_navigation_event_callback(void* context)
+{
+	FURI_LOG_T(APPLICATION_NAME, "esubghz_chat_navigation_event_callback");
+	furi_assert(context);
+	ESubGhzChatState* state = context;
+	return scene_manager_handle_back_event(state->scene_manager);
+}
+
+static bool chat_box_alloc(ESubGhzChatState *state)
+{
+	furi_assert(state);
+
+	state->chat_box = text_box_alloc();
+	if (state->chat_box == NULL) {
+		return false;
+	}
+
+	state->chat_box_store = furi_string_alloc();
+	if (state->chat_box_store == NULL) {
+		text_box_free(state->chat_box);
+		return false;
+	}
+
+	furi_string_reserve(state->chat_box_store, CHAT_BOX_STORE_SIZE);
+	furi_string_set_char(state->chat_box_store, 0, 0);
+	text_box_set_text(state->chat_box,
+			furi_string_get_cstr(state->chat_box_store));
+	text_box_set_focus(state->chat_box, TextBoxFocusEnd);
+
+	return true;
+}
+
+static void chat_box_free(ESubGhzChatState *state)
+{
+	furi_assert(state);
+
+	text_box_free(state->chat_box);
+	furi_string_free(state->chat_box_store);
+}
+
+int32_t esubghz_chat(void)
+{
+	int32_t err = -1;
+
+	FURI_LOG_I(APPLICATION_NAME, "Starting...");
+
+	ESubGhzChatState *state = malloc(sizeof(ESubGhzChatState));
+	if (state == NULL) {
+		goto err_alloc;
+	}
+
+	state->scene_manager = scene_manager_alloc(
+			&esubghz_chat_scene_event_handlers, state);
+	if (state->scene_manager == NULL) {
+		goto err_alloc_sm;
+	}
+
+	state->view_dispatcher = view_dispatcher_alloc();
+	if (state->view_dispatcher == NULL) {
+		goto err_alloc_vd;
+	}
+
+	state->text_input = text_input_alloc();
+	if (state->text_input == NULL) {
+		goto err_alloc_ti;
+	}
+
+	if (!chat_box_alloc(state)) {
+		goto err_alloc_cb;
+	}
+
+	view_dispatcher_enable_queue(state->view_dispatcher);
+
+	view_dispatcher_set_event_callback_context(state->view_dispatcher, state);
+	view_dispatcher_set_custom_event_callback(
+			state->view_dispatcher,
+			esubghz_chat_custom_event_callback);
+	view_dispatcher_set_navigation_event_callback(
+			state->view_dispatcher,
+			esubghz_chat_navigation_event_callback);
+
+	view_dispatcher_add_view(state->view_dispatcher, ESubGhzChatView_Input,
+			text_input_get_view(state->text_input));
+	view_dispatcher_add_view(state->view_dispatcher, ESubGhzChatView_ChatBox,
+			text_box_get_view(state->chat_box));
+
+	/* no error handling here, don't know how */
+	Gui *gui = furi_record_open(RECORD_GUI);
+	view_dispatcher_attach_to_gui(state->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
+
+	scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_FreqInput);
+	view_dispatcher_run(state->view_dispatcher);
+
+	err = 0;
+
+    	furi_record_close(RECORD_GUI);
+	view_dispatcher_remove_view(state->view_dispatcher, ESubGhzChatView_Input);
+	view_dispatcher_remove_view(state->view_dispatcher, ESubGhzChatView_ChatBox);
+
+	chat_box_free(state);
+
+err_alloc_cb:
+	text_input_free(state->text_input);
+
+err_alloc_ti:
+	view_dispatcher_free(state->view_dispatcher);
+
+err_alloc_vd:
+	scene_manager_free(state->scene_manager);
+
+err_alloc_sm:
+	free(state);
+
+err_alloc:
+	if (err != 0) {
+		FURI_LOG_E(APPLICATION_NAME, "Failed to launch (alloc error)!");
+	} else {
+		FURI_LOG_I(APPLICATION_NAME, "Clean exit.");
+	}
+
+	return err;
+}