diff --git a/applications/applications.c b/applications/applications.c index 33977a67..b66d8cda 100644 --- a/applications/applications.c +++ b/applications/applications.c @@ -31,6 +31,7 @@ int32_t music_player(void* p); int32_t sdnfc(void* p); int32_t floopper_bloopper(void* p); int32_t sd_filesystem(void* p); +int32_t app_subghz(void* p); int32_t gui_test(void* p); @@ -148,6 +149,10 @@ const FlipperApplication FLIPPER_SERVICES[] = { #ifdef APP_GUI_TEST {.app = gui_test, .name = "gui_test", .icon = A_Plugins_14}, #endif + +#ifdef APP_SUBGHZ + {.app = app_subghz, .name = "app_subghz", .icon = A_Plugins_14}, +#endif }; const size_t FLIPPER_SERVICES_COUNT = sizeof(FLIPPER_SERVICES) / sizeof(FlipperApplication); @@ -220,6 +225,10 @@ const FlipperApplication FLIPPER_PLUGINS[] = { #ifdef BUILD_GUI_TEST {.app = gui_test, .name = "gui_test", .icon = A_Plugins_14}, #endif + +#ifdef BUILD_SUBGHZ + {.app = app_subghz, .name = "app_subghz", .icon = A_Plugins_14}, +#endif }; const size_t FLIPPER_PLUGINS_COUNT = sizeof(FLIPPER_PLUGINS) / sizeof(FlipperApplication); diff --git a/applications/applications.mk b/applications/applications.mk index 73a66f19..fe6a5092 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -30,6 +30,7 @@ BUILD_MUSIC_PLAYER = 1 BUILD_FLOOPPER_BLOOPPER = 1 BUILD_IBUTTON = 1 BUILD_GUI_TEST = 1 +BUILD_SUBGHZ = 1 endif APP_NFC ?= 0 @@ -276,6 +277,18 @@ CFLAGS += -DBUILD_GUI_TEST C_SOURCES += $(wildcard $(APP_DIR)/gui-test/*.c) endif +APP_SUBGHZ ?= 0 +ifeq ($(APP_SUBGHZ), 1) +CFLAGS += -DAPP_SUBGHZ +BUILD_SUBGHZ = 1 +endif +BUILD_SUBGHZ ?= 0 +ifeq ($(BUILD_SUBGHZ), 1) +CFLAGS += -DBUILD_SUBGHZ +CPP_SOURCES += $(wildcard $(APP_DIR)/subghz/*.cpp) +CPP_SOURCES += $(wildcard $(APP_DIR)/subghz/*/*.cpp) +endif + APP_SDNFC ?= 0 ifeq ($(APP_SDNFC), 1) CFLAGS += -DAPP_SDNFC diff --git a/applications/gui-test/gui-test.c b/applications/gui-test/gui-test.c index f80b913e..e4cdfce8 100644 --- a/applications/gui-test/gui-test.c +++ b/applications/gui-test/gui-test.c @@ -76,7 +76,7 @@ void popup_callback(void* context) { next_view(context); } -void submenu_callback(void* context) { +void submenu_callback(void* context, uint32_t index) { next_view(context); } @@ -100,15 +100,16 @@ int32_t gui_test(void* param) { view_dispatcher_attach_to_gui(gui_tester->view_dispatcher, gui, ViewDispatcherTypeFullscreen); // Submenu - submenu_add_item(gui_tester->submenu, "Read", submenu_callback, gui_tester); - submenu_add_item(gui_tester->submenu, "Saved", submenu_callback, gui_tester); - submenu_add_item(gui_tester->submenu, "Emulate", submenu_callback, gui_tester); - submenu_add_item(gui_tester->submenu, "Enter manually", submenu_callback, gui_tester); - submenu_add_item(gui_tester->submenu, "Blah blah", submenu_callback, gui_tester); - submenu_add_item(gui_tester->submenu, "Set time", submenu_callback, gui_tester); - submenu_add_item(gui_tester->submenu, "Gender-bender", submenu_callback, gui_tester); - submenu_add_item(gui_tester->submenu, "Hack American Elections", submenu_callback, gui_tester); - submenu_add_item(gui_tester->submenu, "Hack the White House", submenu_callback, gui_tester); + submenu_add_item(gui_tester->submenu, "Read", 0, submenu_callback, gui_tester); + submenu_add_item(gui_tester->submenu, "Saved", 0, submenu_callback, gui_tester); + submenu_add_item(gui_tester->submenu, "Emulate", 0, submenu_callback, gui_tester); + submenu_add_item(gui_tester->submenu, "Enter manually", 0, submenu_callback, gui_tester); + submenu_add_item(gui_tester->submenu, "Blah blah", 0, submenu_callback, gui_tester); + submenu_add_item(gui_tester->submenu, "Set time", 0, submenu_callback, gui_tester); + submenu_add_item(gui_tester->submenu, "Gender-bender", 0, submenu_callback, gui_tester); + submenu_add_item( + gui_tester->submenu, "Hack American Elections", 0, submenu_callback, gui_tester); + submenu_add_item(gui_tester->submenu, "Hack the White House", 0, submenu_callback, gui_tester); // Dialog dialog_set_result_callback(gui_tester->dialog, dialog_callback); diff --git a/applications/gui/modules/submenu.c b/applications/gui/modules/submenu.c index df1584df..79738534 100644 --- a/applications/gui/modules/submenu.c +++ b/applications/gui/modules/submenu.c @@ -5,6 +5,7 @@ struct SubmenuItem { const char* label; + uint32_t index; SubmenuItemCallback callback; void* callback_context; }; @@ -108,6 +109,7 @@ Submenu* submenu_alloc() { submenu->view, (SubmenuModel * model) { SubmenuItemArray_init(model->items); model->position = 0; + model->window_position = 0; return true; }); @@ -134,6 +136,7 @@ View* submenu_get_view(Submenu* submenu) { SubmenuItem* submenu_add_item( Submenu* submenu, const char* label, + uint32_t index, SubmenuItemCallback callback, void* callback_context) { SubmenuItem* item = NULL; @@ -144,6 +147,7 @@ SubmenuItem* submenu_add_item( submenu->view, (SubmenuModel * model) { item = SubmenuItemArray_push_new(model->items); item->label = label; + item->index = index; item->callback = callback; item->callback_context = callback_context; return true; @@ -152,6 +156,18 @@ SubmenuItem* submenu_add_item( return item; } +void submenu_clean(Submenu* submenu) { + furi_assert(submenu); + + with_view_model( + submenu->view, (SubmenuModel * model) { + SubmenuItemArray_clean(model->items); + model->position = 0; + model->window_position = 0; + return true; + }); +} + void submenu_process_up(Submenu* submenu) { with_view_model( submenu->view, (SubmenuModel * model) { @@ -162,7 +178,9 @@ void submenu_process_up(Submenu* submenu) { } } else { model->position = SubmenuItemArray_size(model->items) - 1; - model->window_position = model->position - 3; + if(model->position > 3) { + model->window_position = model->position - 3; + } } return true; }); @@ -197,6 +215,6 @@ void submenu_process_ok(Submenu* submenu) { }); if(item && item->callback) { - item->callback(item->callback_context); + item->callback(item->callback_context, item->index); } } \ No newline at end of file diff --git a/applications/gui/modules/submenu.h b/applications/gui/modules/submenu.h index 401b1b69..6528ff4f 100644 --- a/applications/gui/modules/submenu.h +++ b/applications/gui/modules/submenu.h @@ -1,10 +1,14 @@ #pragma once #include +#ifdef __cplusplus +extern "C" { +#endif + /* Submenu anonymous structure */ typedef struct Submenu Submenu; typedef struct SubmenuItem SubmenuItem; -typedef void (*SubmenuItemCallback)(void* context); +typedef void (*SubmenuItemCallback)(void* context, uint32_t index); /* Allocate and initialize submenu * This submenu is used to select one option @@ -25,6 +29,7 @@ View* submenu_get_view(Submenu* submenu); /* Add item to submenu * @param submenu - Submenu instance * @param label - menu item label + * @param index - menu item index, used for callback, may be the same with other items * @param callback - menu item callback * @param callback_context - menu item callback context * @return SubmenuItem instance that can be used to modify or delete that item @@ -32,5 +37,15 @@ View* submenu_get_view(Submenu* submenu); SubmenuItem* submenu_add_item( Submenu* submenu, const char* label, + uint32_t index, SubmenuItemCallback callback, - void* callback_context); \ No newline at end of file + void* callback_context); + +/* Remove all items from submenu + * @param submenu - Submenu instance + */ +void submenu_clean(Submenu* submenu); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/gui/view.h b/applications/gui/view.h index ccd6cadd..ef864325 100644 --- a/applications/gui/view.h +++ b/applications/gui/view.h @@ -141,6 +141,18 @@ void* view_get_model(View* view); */ void view_commit_model(View* view, bool update); +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +#define with_view_model_cpp(view, type, var, function_body) \ + { \ + type* p = static_cast(view_get_model(view)); \ + bool update = [&](type * var) function_body(p); \ + view_commit_model(view, update); \ + } +#else /* * With clause for view model * @param view, View instance pointer @@ -153,7 +165,4 @@ void view_commit_model(View* view, bool update); bool update = ({ bool __fn__ function_body __fn__; })(p); \ view_commit_model(view, update); \ } - -#ifdef __cplusplus -} -#endif +#endif \ No newline at end of file diff --git a/applications/gui/view_dispatcher.c b/applications/gui/view_dispatcher.c index 7cf9e422..758cc0db 100644 --- a/applications/gui/view_dispatcher.c +++ b/applications/gui/view_dispatcher.c @@ -42,6 +42,17 @@ void view_dispatcher_add_view(ViewDispatcher* view_dispatcher, uint32_t view_id, view_set_dispatcher(view, view_dispatcher); } +void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_id) { + furi_assert(view_dispatcher); + + // Disable the view if it is active + if(view_dispatcher->current_view == *ViewDict_get(view_dispatcher->views, view_id)) { + view_dispatcher_set_current_view(view_dispatcher, NULL); + } + // Remove view + ViewDict_erase(view_dispatcher->views, view_id); +} + void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t view_id) { furi_assert(view_dispatcher); if(view_id == VIEW_NONE) { diff --git a/applications/gui/view_dispatcher.h b/applications/gui/view_dispatcher.h index 5530922f..71fb5ff1 100644 --- a/applications/gui/view_dispatcher.h +++ b/applications/gui/view_dispatcher.h @@ -33,6 +33,12 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher); */ void view_dispatcher_add_view(ViewDispatcher* view_dispatcher, uint32_t view_id, View* view); +/* Remove view from ViewDispatcher + * @param view_dispatcher, ViewDispatcher instance + * @param view_id, View id to remove + */ +void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_id); + /* Switch to View * @param view_dispatcher, ViewDispatcher instance * @param view_id, View id to register diff --git a/applications/subghz/scene/subghz-scene-generic.h b/applications/subghz/scene/subghz-scene-generic.h new file mode 100644 index 00000000..52fbdc50 --- /dev/null +++ b/applications/subghz/scene/subghz-scene-generic.h @@ -0,0 +1,13 @@ +#pragma once +#include "../subghz-event.h" + +class SubghzApp; + +class SubghzScene { +public: + virtual void on_enter(SubghzApp* app) = 0; + virtual bool on_event(SubghzApp* app, SubghzEvent* event) = 0; + virtual void on_exit(SubghzApp* app) = 0; + +private: +}; \ No newline at end of file diff --git a/applications/subghz/scene/subghz-scene-spectrum-settings.cpp b/applications/subghz/scene/subghz-scene-spectrum-settings.cpp new file mode 100644 index 00000000..c15d2553 --- /dev/null +++ b/applications/subghz/scene/subghz-scene-spectrum-settings.cpp @@ -0,0 +1,48 @@ +#include "subghz-scene-spectrum-settings.h" +#include "../subghz-app.h" +#include "../subghz-view-manager.h" +#include "../subghz-event.h" +#include + +void SubghzSceneSpectrumSettings::on_enter(SubghzApp* app) { + SubghzAppViewManager* view_manager = app->get_view_manager(); + SubghzViewSpectrumSettings* spectrum_settings = view_manager->get_spectrum_settings(); + + auto callback = cbc::obtain_connector(this, &SubghzSceneSpectrumSettings::ok_callback); + spectrum_settings->set_ok_callback(callback, app); + spectrum_settings->set_start_freq(433); + + view_manager->switch_to(SubghzAppViewManager::ViewType::SpectrumSettings); +} + +bool SubghzSceneSpectrumSettings::on_event(SubghzApp* app, SubghzEvent* event) { + bool consumed = false; + + if(event->type == SubghzEvent::Type::NextScene) { + // save data + // uint32_t start_freq = app->get_view_manager()->get_spectrum_settings()->get_start_freq(); + // app->get_spectrum_analyzer()->set_start_freq(start_freq); + + // switch to next scene + // app->switch_to_next_scene(SubghzApp::Scene::SceneSpectrumAnalyze); + consumed = true; + } + + return consumed; +} + +void SubghzSceneSpectrumSettings::on_exit(SubghzApp* app) { + SubghzAppViewManager* view_manager = app->get_view_manager(); + SubghzViewSpectrumSettings* spectrum_settings = view_manager->get_spectrum_settings(); + + spectrum_settings->set_ok_callback(nullptr, nullptr); + spectrum_settings->set_start_freq(0); +} + +void SubghzSceneSpectrumSettings::ok_callback(void* context) { + SubghzApp* app = static_cast(context); + SubghzEvent event; + + event.type = SubghzEvent::Type::NextScene; + app->get_view_manager()->send_event(&event); +} \ No newline at end of file diff --git a/applications/subghz/scene/subghz-scene-spectrum-settings.h b/applications/subghz/scene/subghz-scene-spectrum-settings.h new file mode 100644 index 00000000..24e68c14 --- /dev/null +++ b/applications/subghz/scene/subghz-scene-spectrum-settings.h @@ -0,0 +1,12 @@ +#pragma once +#include "subghz-scene-generic.h" + +class SubghzSceneSpectrumSettings : public SubghzScene { +public: + void on_enter(SubghzApp* app) final; + bool on_event(SubghzApp* app, SubghzEvent* event) final; + void on_exit(SubghzApp* app) final; + +private: + void ok_callback(void* context); +}; \ No newline at end of file diff --git a/applications/subghz/scene/subghz-scene-start.cpp b/applications/subghz/scene/subghz-scene-start.cpp new file mode 100644 index 00000000..868c39dd --- /dev/null +++ b/applications/subghz/scene/subghz-scene-start.cpp @@ -0,0 +1,67 @@ +#include "subghz-scene-start.h" +#include "../subghz-app.h" +#include "../subghz-view-manager.h" +#include "../subghz-event.h" +#include + +typedef enum { + SubmenuIndexSpectrumAnalyzer, + SubmenuIndexFrequencyScanner, + SubmenuIndexSignalAnalyzer, + SubmenuIndexSignalTransmitter, + SubmenuIndexApplications, +} SubmenuIndex; + +void SubghzSceneStart::on_enter(SubghzApp* app) { + SubghzAppViewManager* view_manager = app->get_view_manager(); + Submenu* submenu = view_manager->get_submenu(); + auto callback = cbc::obtain_connector(this, &SubghzSceneStart::submenu_callback); + + submenu_add_item(submenu, "Spectrum Analyzer", SubmenuIndexSpectrumAnalyzer, callback, app); + submenu_add_item(submenu, "Frequency Scanner", SubmenuIndexFrequencyScanner, callback, app); + submenu_add_item(submenu, "Signal Analyzer", SubmenuIndexSignalAnalyzer, callback, app); + submenu_add_item(submenu, "Signal Transmitter", SubmenuIndexSignalTransmitter, callback, app); + submenu_add_item(submenu, "Applications", SubmenuIndexApplications, callback, app); + + view_manager->switch_to(SubghzAppViewManager::ViewType::Submenu); +} + +bool SubghzSceneStart::on_event(SubghzApp* app, SubghzEvent* event) { + bool consumed = false; + + if(event->type == SubghzEvent::Type::MenuSelected) { + switch(event->payload.menu_index) { + case SubmenuIndexSpectrumAnalyzer: + app->switch_to_next_scene(SubghzApp::Scene::SceneSpectrumSettings); + break; + case SubmenuIndexFrequencyScanner: + break; + case SubmenuIndexSignalAnalyzer: + break; + case SubmenuIndexSignalTransmitter: + break; + case SubmenuIndexApplications: + break; + } + consumed = true; + } + + return consumed; +} + +void SubghzSceneStart::on_exit(SubghzApp* app) { + SubghzAppViewManager* view_manager = app->get_view_manager(); + Submenu* submenu = view_manager->get_submenu(); + + submenu_clean(submenu); +} + +void SubghzSceneStart::submenu_callback(void* context, uint32_t index) { + SubghzApp* app = static_cast(context); + SubghzEvent event; + + event.type = SubghzEvent::Type::MenuSelected; + event.payload.menu_index = index; + + app->get_view_manager()->send_event(&event); +} \ No newline at end of file diff --git a/applications/subghz/scene/subghz-scene-start.h b/applications/subghz/scene/subghz-scene-start.h new file mode 100644 index 00000000..517973c1 --- /dev/null +++ b/applications/subghz/scene/subghz-scene-start.h @@ -0,0 +1,12 @@ +#pragma once +#include "subghz-scene-generic.h" + +class SubghzSceneStart : public SubghzScene { +public: + void on_enter(SubghzApp* app) final; + bool on_event(SubghzApp* app, SubghzEvent* event) final; + void on_exit(SubghzApp* app) final; + +private: + void submenu_callback(void* context, uint32_t index); +}; \ No newline at end of file diff --git a/applications/subghz/subghz-app.cpp b/applications/subghz/subghz-app.cpp new file mode 100644 index 00000000..42078b21 --- /dev/null +++ b/applications/subghz/subghz-app.cpp @@ -0,0 +1,90 @@ +#include "subghz-app.h" +#include +#include + +void SubghzApp::run(void) { + SubghzEvent event; + bool consumed; + bool exit = false; + + scenes[current_scene]->on_enter(this); + + while(!exit) { + view.receive_event(&event); + + consumed = scenes[current_scene]->on_event(this, &event); + + if(!consumed) { + if(event.type == SubghzEvent::Type::Back) { + exit = switch_to_previous_scene(); + } + } + }; + + scenes[current_scene]->on_exit(this); +} + +SubghzApp::SubghzApp() { + api_hal_power_insomnia_enter(); +} + +SubghzApp::~SubghzApp() { + api_hal_power_insomnia_exit(); +} + +SubghzAppViewManager* SubghzApp::get_view_manager() { + return &view; +} + +void SubghzApp::switch_to_next_scene(Scene next_scene) { + previous_scenes_list.push_front(current_scene); + + if(next_scene != Scene::SceneExit) { + scenes[current_scene]->on_exit(this); + current_scene = next_scene; + scenes[current_scene]->on_enter(this); + } +} + +void SubghzApp::search_and_switch_to_previous_scene(std::initializer_list scenes_list) { + Scene previous_scene = Scene::SceneStart; + bool scene_found = false; + + while(!scene_found) { + previous_scene = get_previous_scene(); + for(Scene element : scenes_list) { + if(previous_scene == element || previous_scene == Scene::SceneStart) { + scene_found = true; + break; + } + } + } + + scenes[current_scene]->on_exit(this); + current_scene = previous_scene; + scenes[current_scene]->on_enter(this); +} + +bool SubghzApp::switch_to_previous_scene(uint8_t count) { + Scene previous_scene = Scene::SceneStart; + + for(uint8_t i = 0; i < count; i++) { + previous_scene = get_previous_scene(); + if(previous_scene == Scene::SceneExit) break; + } + + if(previous_scene == Scene::SceneExit) { + return true; + } else { + scenes[current_scene]->on_exit(this); + current_scene = previous_scene; + scenes[current_scene]->on_enter(this); + return false; + } +} + +SubghzApp::Scene SubghzApp::get_previous_scene() { + Scene scene = previous_scenes_list.front(); + previous_scenes_list.pop_front(); + return scene; +} \ No newline at end of file diff --git a/applications/subghz/subghz-app.h b/applications/subghz/subghz-app.h new file mode 100644 index 00000000..1cea4b35 --- /dev/null +++ b/applications/subghz/subghz-app.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include +#include "subghz-view-manager.h" + +#include "scene/subghz-scene-start.h" +#include "scene/subghz-scene-spectrum-settings.h" + +class SubghzApp { +public: + void run(void); + + SubghzApp(); + ~SubghzApp(); + + enum class Scene : uint8_t { + SceneExit, + SceneStart, + SceneSpectrumSettings, + }; + + SubghzAppViewManager* get_view_manager(); + void switch_to_next_scene(Scene index); + void search_and_switch_to_previous_scene(std::initializer_list scenes_list); + bool switch_to_previous_scene(uint8_t count = 1); + Scene get_previous_scene(); + +private: + std::list previous_scenes_list = {Scene::SceneExit}; + Scene current_scene = Scene::SceneStart; + SubghzAppViewManager view; + + std::map scenes = { + {Scene::SceneStart, new SubghzSceneStart()}, + {Scene::SceneSpectrumSettings, new SubghzSceneSpectrumSettings()}, + }; +}; \ No newline at end of file diff --git a/applications/subghz/subghz-event.h b/applications/subghz/subghz-event.h new file mode 100644 index 00000000..4f216a02 --- /dev/null +++ b/applications/subghz/subghz-event.h @@ -0,0 +1,21 @@ +#pragma once +#include + +class SubghzEvent { +public: + // events enum + enum class Type : uint8_t { + Tick, + Back, + MenuSelected, + NextScene, + }; + + // payload + union { + uint32_t menu_index; + } payload; + + // event type + Type type; +}; diff --git a/applications/subghz/subghz-view-manager.cpp b/applications/subghz/subghz-view-manager.cpp new file mode 100644 index 00000000..810376d2 --- /dev/null +++ b/applications/subghz/subghz-view-manager.cpp @@ -0,0 +1,81 @@ +#include "subghz-view-manager.h" +#include "subghz-event.h" +#include + +SubghzAppViewManager::SubghzAppViewManager() { + event_queue = osMessageQueueNew(10, sizeof(SubghzEvent), NULL); + + view_dispatcher = view_dispatcher_alloc(); + auto callback = cbc::obtain_connector(this, &SubghzAppViewManager::previous_view_callback); + + // allocate views + submenu = submenu_alloc(); + view_dispatcher_add_view( + view_dispatcher, + static_cast(SubghzAppViewManager::ViewType::Submenu), + submenu_get_view(submenu)); + + spectrum_settings = new SubghzViewSpectrumSettings(); + view_dispatcher_add_view( + view_dispatcher, + static_cast(SubghzAppViewManager::ViewType::SpectrumSettings), + spectrum_settings->get_view()); + + gui = static_cast(furi_record_open("gui")); + view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); + + // set previous view callback for all views + view_set_previous_callback(submenu_get_view(submenu), callback); + view_set_previous_callback(spectrum_settings->get_view(), callback); +} + +SubghzAppViewManager::~SubghzAppViewManager() { + // remove views + view_dispatcher_remove_view( + view_dispatcher, static_cast(SubghzAppViewManager::ViewType::Submenu)); + view_dispatcher_remove_view( + view_dispatcher, static_cast(SubghzAppViewManager::ViewType::SpectrumSettings)); + + // free view modules + submenu_free(submenu); + free(spectrum_settings); + + // free dispatcher + view_dispatcher_free(view_dispatcher); + + // free event queue + osMessageQueueDelete(event_queue); +} + +void SubghzAppViewManager::switch_to(ViewType type) { + view_dispatcher_switch_to_view(view_dispatcher, static_cast(type)); +} + +Submenu* SubghzAppViewManager::get_submenu() { + return submenu; +} + +SubghzViewSpectrumSettings* SubghzAppViewManager::get_spectrum_settings() { + return spectrum_settings; +} + +void SubghzAppViewManager::receive_event(SubghzEvent* event) { + if(osMessageQueueGet(event_queue, event, NULL, 100) != osOK) { + event->type = SubghzEvent::Type::Tick; + } +} + +void SubghzAppViewManager::send_event(SubghzEvent* event) { + osStatus_t result = osMessageQueuePut(event_queue, event, 0, 0); + furi_check(result == osOK); +} + +uint32_t SubghzAppViewManager::previous_view_callback(void* context) { + if(event_queue != NULL) { + SubghzEvent event; + event.type = SubghzEvent::Type::Back; + send_event(&event); + } + + return VIEW_IGNORE; +} \ No newline at end of file diff --git a/applications/subghz/subghz-view-manager.h b/applications/subghz/subghz-view-manager.h new file mode 100644 index 00000000..733a8356 --- /dev/null +++ b/applications/subghz/subghz-view-manager.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include +#include +#include "subghz-event.h" +#include "view/subghz-view-spectrum-settings.h" + +class SubghzAppViewManager { +public: + enum class ViewType : uint8_t { + Submenu, + SpectrumSettings, + }; + + osMessageQueueId_t event_queue; + + SubghzAppViewManager(); + ~SubghzAppViewManager(); + + void switch_to(ViewType type); + + void receive_event(SubghzEvent* event); + void send_event(SubghzEvent* event); + + Submenu* get_submenu(); + SubghzViewSpectrumSettings* get_spectrum_settings(); + +private: + ViewDispatcher* view_dispatcher; + Gui* gui; + + uint32_t previous_view_callback(void* context); + + // view elements + Submenu* submenu; + SubghzViewSpectrumSettings* spectrum_settings; +}; \ No newline at end of file diff --git a/applications/subghz/subghz.cpp b/applications/subghz/subghz.cpp new file mode 100644 index 00000000..52540a6e --- /dev/null +++ b/applications/subghz/subghz.cpp @@ -0,0 +1,10 @@ +#include "subghz-app.h" + +// app enter function +extern "C" int32_t app_subghz(void* p) { + SubghzApp* app = new SubghzApp(); + app->run(); + delete app; + + return 255; +} \ No newline at end of file diff --git a/applications/subghz/view/subghz-view-spectrum-settings.cpp b/applications/subghz/view/subghz-view-spectrum-settings.cpp new file mode 100644 index 00000000..715c2a01 --- /dev/null +++ b/applications/subghz/view/subghz-view-spectrum-settings.cpp @@ -0,0 +1,95 @@ +#include "subghz-view-spectrum-settings.h" +#include + +struct SpectrumSettingsModel { + uint32_t start_freq; +}; + +/***************************************************************************************/ + +static void draw_callback(Canvas* canvas, void* _model) { + SpectrumSettingsModel* model = static_cast(_model); + const uint8_t str_size = 64; + char str_buffer[str_size]; + + canvas_clear(canvas); + snprintf(str_buffer, str_size, "Start freq < %ld > MHz", model->start_freq); + canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, str_buffer); +} + +static bool input_callback(InputEvent* event, void* context) { + SubghzViewSpectrumSettings* _this = static_cast(context); + + bool consumed = false; + + // Process key presses only + if(event->type == InputTypeShort) { + if(event->key == InputKeyOk) { + _this->call_ok_callback(); + consumed = true; + } else if(event->key == InputKeyLeft) { + with_view_model_cpp(_this->get_view(), SpectrumSettingsModel, model, { + model->start_freq--; + return true; + }); + consumed = true; + } else if(event->key == InputKeyRight) { + with_view_model_cpp(_this->get_view(), SpectrumSettingsModel, model, { + model->start_freq++; + return true; + }); + consumed = true; + } + } + + return consumed; +} + +/***************************************************************************************/ + +View* SubghzViewSpectrumSettings::get_view() { + return view; +} + +void SubghzViewSpectrumSettings::set_ok_callback(OkCallback callback, void* context) { + ok_callback = callback; + ok_callback_context = context; +} + +void SubghzViewSpectrumSettings::call_ok_callback() { + if(ok_callback != nullptr) { + ok_callback(ok_callback_context); + } +} + +void SubghzViewSpectrumSettings::set_start_freq(uint32_t start_freq) { + with_view_model_cpp(view, SpectrumSettingsModel, model, { + model->start_freq = start_freq; + return true; + }); +} + +uint32_t SubghzViewSpectrumSettings::get_start_freq() { + uint32_t result; + + with_view_model_cpp(view, SpectrumSettingsModel, model, { + result = model->start_freq; + return false; + }); + + return result; +} + +SubghzViewSpectrumSettings::SubghzViewSpectrumSettings() { + view = view_alloc(); + view_set_context(view, this); + view_allocate_model(view, ViewModelTypeLocking, sizeof(SpectrumSettingsModel)); + + view_set_draw_callback(view, draw_callback); + + view_set_input_callback(view, input_callback); +} + +SubghzViewSpectrumSettings::~SubghzViewSpectrumSettings() { + view_free(view); +} \ No newline at end of file diff --git a/applications/subghz/view/subghz-view-spectrum-settings.h b/applications/subghz/view/subghz-view-spectrum-settings.h new file mode 100644 index 00000000..6eb47e4f --- /dev/null +++ b/applications/subghz/view/subghz-view-spectrum-settings.h @@ -0,0 +1,25 @@ +#include + +class SubghzViewSpectrumSettings { +public: + SubghzViewSpectrumSettings(); + ~SubghzViewSpectrumSettings(); + + View* get_view(); + + // ok callback methods + typedef void (*OkCallback)(void* context); + void set_ok_callback(OkCallback callback, void* context); + void call_ok_callback(); + + // model data getters/setters + void set_start_freq(uint32_t start_freq); + uint32_t get_start_freq(); + +private: + View* view; + + // ok callback data + OkCallback ok_callback = nullptr; + void* ok_callback_context = nullptr; +};