Subghz app example (#365)
* Gui: ported submenu and view_dispatcher_remove_view from iButton branch * App gui-test: use backported submenu api * App subghz: initial commit * App subghz: syntax fix * App gui-test: fix submenu callback * App subghz: add subfolders to build * Gui view: c++ verison of with_view_model * Subghz app: simple spectrum settings view * Subghz app: add spectrum settings view to view manager * Subghz app: spectrum settings scene Co-authored-by: coreglitch <mail@s3f.ru>
This commit is contained in:
		
							parent
							
								
									025b77ecc1
								
							
						
					
					
						commit
						7afdd14a4c
					
				| @ -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); | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
|     } | ||||
| } | ||||
| @ -1,10 +1,14 @@ | ||||
| #pragma once | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| #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); | ||||
| 
 | ||||
| /* Remove all items from submenu
 | ||||
|  * @param submenu - Submenu instance | ||||
|  */ | ||||
| void submenu_clean(Submenu* submenu); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -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<type*>(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 | ||||
| @ -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) { | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
							
								
								
									
										13
									
								
								applications/subghz/scene/subghz-scene-generic.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								applications/subghz/scene/subghz-scene-generic.h
									
									
									
									
									
										Normal file
									
								
							| @ -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: | ||||
| }; | ||||
							
								
								
									
										48
									
								
								applications/subghz/scene/subghz-scene-spectrum-settings.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								applications/subghz/scene/subghz-scene-spectrum-settings.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | ||||
| #include "subghz-scene-spectrum-settings.h" | ||||
| #include "../subghz-app.h" | ||||
| #include "../subghz-view-manager.h" | ||||
| #include "../subghz-event.h" | ||||
| #include <callback-connector.h> | ||||
| 
 | ||||
| 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<SubghzApp*>(context); | ||||
|     SubghzEvent event; | ||||
| 
 | ||||
|     event.type = SubghzEvent::Type::NextScene; | ||||
|     app->get_view_manager()->send_event(&event); | ||||
| } | ||||
							
								
								
									
										12
									
								
								applications/subghz/scene/subghz-scene-spectrum-settings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								applications/subghz/scene/subghz-scene-spectrum-settings.h
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
| }; | ||||
							
								
								
									
										67
									
								
								applications/subghz/scene/subghz-scene-start.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								applications/subghz/scene/subghz-scene-start.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | ||||
| #include "subghz-scene-start.h" | ||||
| #include "../subghz-app.h" | ||||
| #include "../subghz-view-manager.h" | ||||
| #include "../subghz-event.h" | ||||
| #include <callback-connector.h> | ||||
| 
 | ||||
| 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<SubghzApp*>(context); | ||||
|     SubghzEvent event; | ||||
| 
 | ||||
|     event.type = SubghzEvent::Type::MenuSelected; | ||||
|     event.payload.menu_index = index; | ||||
| 
 | ||||
|     app->get_view_manager()->send_event(&event); | ||||
| } | ||||
							
								
								
									
										12
									
								
								applications/subghz/scene/subghz-scene-start.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								applications/subghz/scene/subghz-scene-start.h
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
| }; | ||||
							
								
								
									
										90
									
								
								applications/subghz/subghz-app.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								applications/subghz/subghz-app.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | ||||
| #include "subghz-app.h" | ||||
| #include <api-hal-power.h> | ||||
| #include <stdarg.h> | ||||
| 
 | ||||
| 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<Scene> 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; | ||||
| } | ||||
							
								
								
									
										37
									
								
								applications/subghz/subghz-app.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								applications/subghz/subghz-app.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| #pragma once | ||||
| #include <map> | ||||
| #include <list> | ||||
| #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<Scene> scenes_list); | ||||
|     bool switch_to_previous_scene(uint8_t count = 1); | ||||
|     Scene get_previous_scene(); | ||||
| 
 | ||||
| private: | ||||
|     std::list<Scene> previous_scenes_list = {Scene::SceneExit}; | ||||
|     Scene current_scene = Scene::SceneStart; | ||||
|     SubghzAppViewManager view; | ||||
| 
 | ||||
|     std::map<Scene, SubghzScene*> scenes = { | ||||
|         {Scene::SceneStart, new SubghzSceneStart()}, | ||||
|         {Scene::SceneSpectrumSettings, new SubghzSceneSpectrumSettings()}, | ||||
|     }; | ||||
| }; | ||||
							
								
								
									
										21
									
								
								applications/subghz/subghz-event.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								applications/subghz/subghz-event.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| 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; | ||||
| }; | ||||
							
								
								
									
										81
									
								
								applications/subghz/subghz-view-manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								applications/subghz/subghz-view-manager.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | ||||
| #include "subghz-view-manager.h" | ||||
| #include "subghz-event.h" | ||||
| #include <callback-connector.h> | ||||
| 
 | ||||
| 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<uint32_t>(SubghzAppViewManager::ViewType::Submenu), | ||||
|         submenu_get_view(submenu)); | ||||
| 
 | ||||
|     spectrum_settings = new SubghzViewSpectrumSettings(); | ||||
|     view_dispatcher_add_view( | ||||
|         view_dispatcher, | ||||
|         static_cast<uint32_t>(SubghzAppViewManager::ViewType::SpectrumSettings), | ||||
|         spectrum_settings->get_view()); | ||||
| 
 | ||||
|     gui = static_cast<Gui*>(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<uint32_t>(SubghzAppViewManager::ViewType::Submenu)); | ||||
|     view_dispatcher_remove_view( | ||||
|         view_dispatcher, static_cast<uint32_t>(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<uint32_t>(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; | ||||
| } | ||||
							
								
								
									
										37
									
								
								applications/subghz/subghz-view-manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								applications/subghz/subghz-view-manager.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| #pragma once | ||||
| #include <furi.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <gui/modules/submenu.h> | ||||
| #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; | ||||
| }; | ||||
							
								
								
									
										10
									
								
								applications/subghz/subghz.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								applications/subghz/subghz.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										95
									
								
								applications/subghz/view/subghz-view-spectrum-settings.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								applications/subghz/view/subghz-view-spectrum-settings.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | ||||
| #include "subghz-view-spectrum-settings.h" | ||||
| #include <callback-connector.h> | ||||
| 
 | ||||
| struct SpectrumSettingsModel { | ||||
|     uint32_t start_freq; | ||||
| }; | ||||
| 
 | ||||
| /***************************************************************************************/ | ||||
| 
 | ||||
| static void draw_callback(Canvas* canvas, void* _model) { | ||||
|     SpectrumSettingsModel* model = static_cast<SpectrumSettingsModel*>(_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<SubghzViewSpectrumSettings*>(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); | ||||
| } | ||||
							
								
								
									
										25
									
								
								applications/subghz/view/subghz-view-spectrum-settings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								applications/subghz/view/subghz-view-spectrum-settings.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| 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; | ||||
| }; | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 SG
						SG