diff --git a/applications/external/subghz_remote_new/application.fam b/applications/external/subghz_remote_new/application.fam new file mode 100644 index 000000000..4f633b961 --- /dev/null +++ b/applications/external/subghz_remote_new/application.fam @@ -0,0 +1,15 @@ +App( + appid="subghz_remote_new", + name="SubRem new", + apptype=FlipperAppType.EXTERNAL, + entry_point="subghz_remote_app", + requires=[ + "gui", + "dialogs", + ], + icon="A_SubGHzRemote_14", + stack_size=4 * 1024, + order=12, + fap_category="Debug", + fap_icon_assets="icons", +) \ No newline at end of file diff --git a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h new file mode 100644 index 000000000..d1559a796 --- /dev/null +++ b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h @@ -0,0 +1,67 @@ +#pragma once + +typedef enum { + // SubRemCustomEventManagerNoSet = 0, + // SubRemCustomEventManagerSet, + // SubRemCustomEventManagerSetRAW, + + //SubmenuIndex + SubmenuIndexOpenMapFile, + SubmenuIndexOpenView, // TODO: temp debug + + //SubRemCustomEvent + SubRemCustomEventViewRemoteBack = 100, + // SubRemCustomEventSceneDeleteSuccess = 100, + // SubRemCustomEventSceneDelete, + // SubRemCustomEventSceneDeleteRAW, + // SubRemCustomEventSceneDeleteRAWBack, + + // SubRemCustomEventSceneReceiverInfoTxStart, + // SubRemCustomEventSceneReceiverInfoTxStop, + // SubRemCustomEventSceneReceiverInfoSave, + // SubRemCustomEventSceneSaveName, + // SubRemCustomEventSceneSaveSuccess, + // SubRemCustomEventSceneShowErrorBack, + // SubRemCustomEventSceneShowErrorOk, + // SubRemCustomEventSceneShowErrorSub, + // SubRemCustomEventSceneShowOnlyRX, + // SubRemCustomEventSceneAnalyzerLock, + // SubRemCustomEventSceneAnalyzerUnlock, + // SubRemCustomEventSceneSettingLock, + + // SubRemCustomEventSceneExit, + // SubRemCustomEventSceneStay, + + // SubRemCustomEventSceneRpcLoad, + // SubRemCustomEventSceneRpcButtonPress, + // SubRemCustomEventSceneRpcButtonRelease, + // SubRemCustomEventSceneRpcSessionClose, + + // SubRemCustomEventViewReceiverOK, + // SubRemCustomEventViewReceiverConfig, + // SubRemCustomEventViewReceiverBack, + // SubRemCustomEventViewReceiverOffDisplay, + // SubRemCustomEventViewReceiverUnlock, + // SubRemCustomEventViewReceiverDeleteItem, + + // SubRemCustomEventViewReadRAWBack, + // SubRemCustomEventViewReadRAWIDLE, + // SubRemCustomEventViewReadRAWREC, + // SubRemCustomEventViewReadRAWConfig, + // SubRemCustomEventViewReadRAWErase, + // SubRemCustomEventViewReadRAWSendStart, + // SubRemCustomEventViewReadRAWSendStop, + // SubRemCustomEventViewReadRAWSave, + // SubRemCustomEventViewReadRAWTXRXStop, + // SubRemCustomEventViewReadRAWMore, + + // SubRemCustomEventViewTransmitterBack, + // SubRemCustomEventViewTransmitterSendStart, + // SubRemCustomEventViewTransmitterSendStop, + // SubRemCustomEventViewTransmitterError, + + // SubRemCustomEventViewFreqAnalOkShort, + // SubRemCustomEventViewFreqAnalOkLong, + + // SubRemCustomEventByteInputDone, +} SubRemCustomEvent; diff --git a/applications/external/subghz_remote_new/helpers/subrem_types.h b/applications/external/subghz_remote_new/helpers/subrem_types.h new file mode 100644 index 000000000..ffb2f8044 --- /dev/null +++ b/applications/external/subghz_remote_new/helpers/subrem_types.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +/* +#define AVR_ISP_VERSION_APP "0.1" +#define AVR_ISP_DEVELOPED "SkorP" +#define AVR_ISP_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" + +#define AVR_ISP_APP_FILE_VERSION 1 +#define AVR_ISP_APP_FILE_TYPE "Flipper Dump AVR" +#define AVR_ISP_APP_EXTENSION ".avr" +*/ + +// TODO: rename Filepath +//#define SUBREMOTEMAP_FOLDER "/ext/subghz_remote" +#define SUBGHZ_REMOTE_APP_EXTENSION ".txt" +#define SUBGHZ_REMOTE_APP_PATH_PREFIX "/ext/subghz_remote" + +typedef enum { + //SubRemViewVariableItemList, + SubRemViewSubmenu, + //SubRemViewProgrammer, + //SubRemViewReader, + //SubRemViewWriter, + SubRemViewWidget, + SubRemViewPopup, + SubRemViewTextInput, + SubRemViewIDRemote, + //SubRemViewChipDetect, +} SubRemViewID; +/* +typedef enum { + SubRemErrorNoError, + SubRemErrorReading, + SubRemErrorWriting, + SubRemErrorVerification, + SubRemErrorWritingFuse, +} SubRemError;*/ \ No newline at end of file diff --git a/applications/external/subghz_remote_new/icons/ButtonDown_7x4.png b/applications/external/subghz_remote_new/icons/ButtonDown_7x4.png new file mode 100644 index 000000000..2954bb6a6 Binary files /dev/null and b/applications/external/subghz_remote_new/icons/ButtonDown_7x4.png differ diff --git a/applications/external/subghz_remote_new/icons/ButtonLeft_4x7.png b/applications/external/subghz_remote_new/icons/ButtonLeft_4x7.png new file mode 100644 index 000000000..0b4655d43 Binary files /dev/null and b/applications/external/subghz_remote_new/icons/ButtonLeft_4x7.png differ diff --git a/applications/external/subghz_remote_new/icons/ButtonRight_4x7.png b/applications/external/subghz_remote_new/icons/ButtonRight_4x7.png new file mode 100644 index 000000000..8e1c74c1c Binary files /dev/null and b/applications/external/subghz_remote_new/icons/ButtonRight_4x7.png differ diff --git a/applications/external/subghz_remote_new/icons/ButtonUp_7x4.png b/applications/external/subghz_remote_new/icons/ButtonUp_7x4.png new file mode 100644 index 000000000..1be79328b Binary files /dev/null and b/applications/external/subghz_remote_new/icons/ButtonUp_7x4.png differ diff --git a/applications/external/subghz_remote_new/icons/Ok_btn_9x9.png b/applications/external/subghz_remote_new/icons/Ok_btn_9x9.png new file mode 100644 index 000000000..9a1539da2 Binary files /dev/null and b/applications/external/subghz_remote_new/icons/Ok_btn_9x9.png differ diff --git a/applications/external/subghz_remote_new/icons/Pin_arrow_up_7x9.png b/applications/external/subghz_remote_new/icons/Pin_arrow_up_7x9.png new file mode 100644 index 000000000..a91a6fd5e Binary files /dev/null and b/applications/external/subghz_remote_new/icons/Pin_arrow_up_7x9.png differ diff --git a/applications/external/subghz_remote_new/icons/Pin_cell_13x13.png b/applications/external/subghz_remote_new/icons/Pin_cell_13x13.png new file mode 100644 index 000000000..1b1ff0c2f Binary files /dev/null and b/applications/external/subghz_remote_new/icons/Pin_cell_13x13.png differ diff --git a/applications/external/subghz_remote_new/icons/Pin_star_7x7.png b/applications/external/subghz_remote_new/icons/Pin_star_7x7.png new file mode 100644 index 000000000..42fdea86e Binary files /dev/null and b/applications/external/subghz_remote_new/icons/Pin_star_7x7.png differ diff --git a/applications/external/subghz_remote_new/icons/back_10px.png b/applications/external/subghz_remote_new/icons/back_10px.png new file mode 100644 index 000000000..f9c615a99 Binary files /dev/null and b/applications/external/subghz_remote_new/icons/back_10px.png differ diff --git a/applications/external/subghz_remote_new/icons/sub1_10px.png b/applications/external/subghz_remote_new/icons/sub1_10px.png new file mode 100644 index 000000000..5a25fdf4e Binary files /dev/null and b/applications/external/subghz_remote_new/icons/sub1_10px.png differ diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene.c b/applications/external/subghz_remote_new/scenes/subrem_scene.c new file mode 100644 index 000000000..c45285b96 --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene.c @@ -0,0 +1,30 @@ +#include "../subghz_remote_app_i.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const subrem_scene_on_enter_handlers[])(void*) = { +#include "subrem_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const subrem_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "subrem_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const subrem_scene_on_exit_handlers[])(void* context) = { +#include "subrem_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers subrem_scene_handlers = { + .on_enter_handlers = subrem_scene_on_enter_handlers, + .on_event_handlers = subrem_scene_on_event_handlers, + .on_exit_handlers = subrem_scene_on_exit_handlers, + .scene_num = SubRemSceneNum, +}; diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene.h b/applications/external/subghz_remote_new/scenes/subrem_scene.h new file mode 100644 index 000000000..5c01f8ca5 --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) SubRemScene##id, +typedef enum { +#include "subrem_scene_config.h" + SubRemSceneNum, +} SubRemScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers subrem_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "subrem_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "subrem_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "subrem_scene_config.h" +#undef ADD_SCENE diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_config.h b/applications/external/subghz_remote_new/scenes/subrem_scene_config.h new file mode 100644 index 000000000..93d4de642 --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_config.h @@ -0,0 +1,3 @@ +ADD_SCENE(subrem, start, Start) +ADD_SCENE(subrem, openmapfile, OpenMapFile) +ADD_SCENE(subrem, remote, Remote) \ No newline at end of file diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c new file mode 100644 index 000000000..8e651a534 --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c @@ -0,0 +1,26 @@ +#include "../subghz_remote_app_i.h" + +void subrem_scene_openmapfile_on_enter(void* context) { + SubGhzRemoteApp* app = context; + + if(subrem_load_from_file(app)) { + // if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) { + // subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); + // scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); + // } else { + // scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu); + // } + } else { + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SubRemSceneStart); + } +} + +bool subrem_scene_openmapfile_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void subrem_scene_openmapfile_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c new file mode 100644 index 000000000..787a71760 --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c @@ -0,0 +1,135 @@ +#include "../subghz_remote_app_i.h" +#include "../views/transmitter.h" + +// TODO: +// #include +// #include + +// #include + +void subrem_scene_remote_callback(SubRemCustomEvent event, void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +bool subrem_scene_remote_update_data_show(void* context) { + SubGhzRemoteApp* app = context; + //UNUSED(app); + bool ret = false; + + subrem_view_remote_add_data_to_show( + //app->subrem_remote_view, "N/A", "N/A", "N/A", "N/A", "N/A"); + app->subrem_remote_view, + "UP", + "DOWN", + "LEFT", + "RIGHT", + "OK"); + // SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(app->txrx); + + // if(decoder) { + // FuriString* key_str = furi_string_alloc(); + // FuriString* frequency_str = furi_string_alloc(); + // FuriString* modulation_str = furi_string_alloc(); + + // if(subghz_protocol_decoder_base_deserialize( + // decoder, subghz_txrx_get_fff_data(app->txrx)) == SubGhzProtocolStatusOk) { + // subghz_protocol_decoder_base_get_string(decoder, key_str); + + // subghz_txrx_get_frequency_and_modulation( + // app->txrx, frequency_str, modulation_str, false); + // subghz_view_transmitter_add_data_to_show( + // app->subghz_transmitter, + // furi_string_get_cstr(key_str), + // furi_string_get_cstr(frequency_str), + // furi_string_get_cstr(modulation_str), + // subghz_txrx_protocol_is_transmittable(app->txrx, false)); + // ret = true; + // } + // furi_string_free(frequency_str); + // furi_string_free(modulation_str); + // furi_string_free(key_str); + // } + return ret; +} + +void subrem_scene_remote_on_enter(void* context) { + SubGhzRemoteApp* app = context; + + // TODO: reset custom btns + // keeloq_reset_original_btn(); + // subghz_custom_btns_reset(); + + // TODO: init view data + + if(!subrem_scene_remote_update_data_show(app)) { + // view_dispatcher_send_custom_event( + // app->view_dispatcher, SubGhzCustomEventViewTransmitterError); + } + subrem_view_remote_set_callback(app->subrem_remote_view, subrem_scene_remote_callback, app); + + // TODO: notifications + // app->state_notifications = SubGhzNotificationStateIDLE; + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDRemote); +} + +bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { + SubGhzRemoteApp* app = context; + if(event.type == SceneManagerEventTypeCustom) { + // if(event.event == SubGhzCustomEventViewTransmitterSendStart) { + // app->state_notifications = SubGhzNotificationStateIDLE; + + // if(subghz_tx_start(app, subghz_txrx_get_fff_data(app->txrx))) { + // app->state_notifications = SubGhzNotificationStateTx; + // subrem_scene_remote_update_data_show(app); + // DOLPHIN_DEED(DolphinDeedSubGhzSend); + // } + // return true; + // } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { + // app->state_notifications = SubGhzNotificationStateIDLE; + // subghz_txrx_stop(app->txrx); + // if(subghz_custom_btn_get() != 0) { + // subghz_custom_btn_set(0); + // uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); + // furi_hal_subghz_set_rolling_counter_mult(0); + // // Calling restore! + // subghz_tx_start(app, subghz_txrx_get_fff_data(app->txrx)); + // subghz_txrx_stop(app->txrx); + // furi_hal_subghz_set_rolling_counter_mult(tmp_counter); + // } + // return true; + // } else + if(event.event == SubRemCustomEventViewRemoteBack) { + // app->state_notifications = SubGhzNotificationStateIDLE; //TODO: notification + scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SubRemSceneStart); + return true; + } + // else if(event.event == SubGhzCustomEventViewTransmitterError) { + // furi_string_set(app->error_str, "Protocol not\nfound!"); + // scene_manager_next_scene(app->scene_manager, SubGhzSceneShowErrorSub); + // } + } else if(event.type == SceneManagerEventTypeTick) { + // if(app->state_notifications == SubGhzNotificationStateTx) { + // notification_message(app->notifications, &sequence_blink_magenta_10); + // } + // return true; + } + return false; +} + +void subrem_scene_remote_on_exit(void* context) { + SubGhzRemoteApp* app = context; + UNUSED(app); + // TODO: notifications and reset KL + + //app->state_notifications = SubGhzNotificationStateIDLE; + + // keeloq_reset_mfname(); + // keeloq_reset_kl_type(); + // keeloq_reset_original_btn(); + // subghz_custom_btns_reset(); + // star_line_reset_mfname(); + // star_line_reset_kl_type(); +} diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_start.c b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c new file mode 100644 index 000000000..0ad9837e9 --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c @@ -0,0 +1,93 @@ +#include "../subghz_remote_app_i.h" +#include "../helpers/subrem_custom_event.h" + +void subrem_scene_start_submenu_callback(void* context, uint32_t index) { + furi_assert(context); + SubGhzRemoteApp* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void subrem_scene_start_on_enter(void* context) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + Submenu* submenu = app->submenu; + submenu_add_item( + submenu, + "Open Map File", + SubmenuIndexOpenMapFile, + subrem_scene_start_submenu_callback, + app); + submenu_add_item( + submenu, "Remote", SubmenuIndexOpenView, subrem_scene_start_submenu_callback, app); + // submenu_add_item( + // submenu, + // "ISP Programmer", + // SubmenuIndexSubGhzRemoteProgrammer, + // subrem_scene_start_submenu_callback, + // app); + // submenu_add_item( + // submenu, + // "Wiring", + // SubmenuIndexAvrIsWiring, + // subrem_scene_start_submenu_callback, + // app); + // submenu_add_item( + // submenu, + // "About", + // SubmenuIndexSubGhzRemoteAbout, + // subrem_scene_start_submenu_callback, + // app); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); + + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewSubmenu); +} + +bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexOpenMapFile) { + scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); + consumed = true; + } else if(event.event == SubmenuIndexOpenView) { + scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); + consumed = true; + } + // } else if(event.event == SubmenuIndexSubGhzRemoteProgrammer) { + // scene_manager_set_scene_state( + // app->scene_manager, SubRemSceneChipDetect, SubGhzRemoteViewProgrammer); + // scene_manager_next_scene(app->scene_manager, SubRemSceneChipDetect); + // consumed = true; + // } else if(event.event == SubmenuIndexSubGhzRemoteReader) { + // scene_manager_set_scene_state( + // app->scene_manager, SubRemSceneChipDetect, SubGhzRemoteViewReader); + // scene_manager_next_scene(app->scene_manager, SubRemSceneChipDetect); + // consumed = true; + // } else if(event.event == SubmenuIndexSubGhzRemoteWriter) { + // scene_manager_set_scene_state( + // app->scene_manager, SubRemSceneChipDetect, SubGhzRemoteViewWriter); + // scene_manager_next_scene(app->scene_manager, SubRemSceneChipDetect); + // consumed = true; + // } else if(event.event == SubmenuIndexAvrIsWiring) { + // scene_manager_next_scene(app->scene_manager, SubRemSceneWiring); + // consumed = true; + // } + scene_manager_set_scene_state(app->scene_manager, SubRemSceneStart, event.event); + } + + return consumed; +} + +void subrem_scene_start_on_exit(void* context) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/external/subghz_remote_new/subghz_remote_app.c b/applications/external/subghz_remote_new/subghz_remote_app.c new file mode 100644 index 000000000..d25e65ce7 --- /dev/null +++ b/applications/external/subghz_remote_new/subghz_remote_app.c @@ -0,0 +1,181 @@ +#include "subghz_remote_app_i.h" + +static bool subghz_remote_app_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + SubGhzRemoteApp* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool subghz_remote_app_back_event_callback(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void subghz_remote_app_tick_event_callback(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + scene_manager_handle_tick_event(app->scene_manager); +} + +SubGhzRemoteApp* subghz_remote_app_alloc() { + SubGhzRemoteApp* app = malloc(sizeof(SubGhzRemoteApp)); + + // // Enable 5v power, multiple attempts to avoid issues with power chip protection false triggering + // uint8_t attempts = 0; + // while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { + // furi_hal_power_enable_otg(); + // furi_delay_ms(10); + // } + + app->file_path = furi_string_alloc(); + furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX); + //app->error = SubGhzRemoteErrorNoError; + + // GUI + app->gui = furi_record_open(RECORD_GUI); + + // View Dispatcher + app->view_dispatcher = view_dispatcher_alloc(); + app->scene_manager = scene_manager_alloc(&subrem_scene_handlers, app); + view_dispatcher_enable_queue(app->view_dispatcher); + + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, subghz_remote_app_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, subghz_remote_app_back_event_callback); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, subghz_remote_app_tick_event_callback, 100); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + // Open Notification record + app->notifications = furi_record_open(RECORD_NOTIFICATION); + + // SubMenu + app->submenu = submenu_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, SubRemViewSubmenu, submenu_get_view(app->submenu)); + + // Widget + app->widget = widget_alloc(); + view_dispatcher_add_view(app->view_dispatcher, SubRemViewWidget, widget_get_view(app->widget)); + + // Text Input + app->text_input = text_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, SubRemViewTextInput, text_input_get_view(app->text_input)); + + // Popup + app->popup = popup_alloc(); + view_dispatcher_add_view(app->view_dispatcher, SubRemViewPopup, popup_get_view(app->popup)); + + //Dialog + app->dialogs = furi_record_open(RECORD_DIALOGS); + + // Remote view + app->subrem_remote_view = subrem_view_remote_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + SubRemViewIDRemote, + subrem_view_remote_get_view(app->subrem_remote_view)); + /* + // Reader view + app->subghz_remote_reader_view = subghz_remote_reader_view_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + SubRemViewReader, + subghz_remote_reader_view_get_view(app->subghz_remote_reader_view)); + + // Writer view + app->subghz_remote_writer_view = subghz_remote_writer_view_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + SubRemViewWriter, + subghz_remote_writer_view_get_view(app->subghz_remote_writer_view)); + + // Chip detect view + app->subghz_remote_chip_detect_view = subghz_remote_chip_detect_view_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + SubRemViewChipDetect, + subghz_remote_chip_detect_view_get_view(app->subghz_remote_chip_detect_view)); +*/ + scene_manager_next_scene(app->scene_manager, SubRemSceneStart); + + return app; +} + +void subghz_remote_app_free(SubGhzRemoteApp* app) { + furi_assert(app); + + // Submenu + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewSubmenu); + submenu_free(app->submenu); + + // Widget + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewWidget); + widget_free(app->widget); + + // TextInput + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewTextInput); + text_input_free(app->text_input); + + // Popup + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewPopup); + popup_free(app->popup); + + //Dialog + furi_record_close(RECORD_DIALOGS); + + // Remote view + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDRemote); + subrem_view_remote_free(app->subrem_remote_view); + + // // Reader view + // view_dispatcher_remove_view(app->view_dispatcher, SubRemViewReader); + // subghz_remote_reader_view_free(app->subghz_remote_reader_view); + + // // Writer view + // view_dispatcher_remove_view(app->view_dispatcher, SubRemViewWriter); + // subghz_remote_writer_view_free(app->subghz_remote_writer_view); + + // // Chip detect view + // view_dispatcher_remove_view(app->view_dispatcher, SubRemViewChipDetect); + // subghz_remote_chip_detect_view_free(app->subghz_remote_chip_detect_view); + + // // View dispatcher + // view_dispatcher_free(app->view_dispatcher); + // scene_manager_free(app->scene_manager); + + // Notifications + furi_record_close(RECORD_NOTIFICATION); + app->notifications = NULL; + + // Close records + furi_record_close(RECORD_GUI); + + // Path strings + furi_string_free(app->file_path); + + // Disable 5v power + // if(furi_hal_power_is_otg_enabled()) { + // furi_hal_power_disable_otg(); + // } + + free(app); +} + +int32_t subghz_remote_app(void* p) { + UNUSED(p); + SubGhzRemoteApp* subghz_remote_app = subghz_remote_app_alloc(); + + furi_string_set(subghz_remote_app->file_path, SUBREM_APP_FOLDER); + + view_dispatcher_run(subghz_remote_app->view_dispatcher); + + subghz_remote_app_free(subghz_remote_app); + + return 0; +} diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c new file mode 100644 index 000000000..43bdd73f3 --- /dev/null +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -0,0 +1,28 @@ +#include "subghz_remote_app_i.h" +#include +#include + +#define TAG "SubGhzRemote" + +bool subrem_load_from_file(SubGhzRemoteApp* app) { + furi_assert(app); + + FuriString* file_path = furi_string_alloc(); + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, SUBREM_APP_EXTENSION, &I_sub1_10px); + browser_options.base_path = SUBREM_APP_FOLDER; + + // Input events and views are managed by file_select + bool res = + dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options); + + if(res) { + // res = subghz_key_load(app, furi_string_get_cstr(app->file_path), true); + res = false; + } + + furi_string_free(file_path); + + return res; +} diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.h b/applications/external/subghz_remote_new/subghz_remote_app_i.h new file mode 100644 index 000000000..bc8c61cdd --- /dev/null +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.h @@ -0,0 +1,53 @@ +#pragma once + +#include "helpers/subrem_types.h" + +#include "views/transmitter.h" + +#include "scenes/subrem_scene.h" + +#include // TODO: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// #include "views/subghz_remote_view_programmer.h" +// #include "views/subghz_remote_view_reader.h" +// #include "views/subghz_remote_view_writer.h" +// #include "views/subghz_remote_view_chip_detect.h" + +#define SUBREM_APP_EXTENSION ".txt" +#define SUBREM_APP_FOLDER "/ext/subghz_remote" +#define SUBGHZ_REMOTE_MAX_LEN_NAME 64 + +typedef struct { + Gui* gui; + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; + NotificationApp* notifications; + DialogsApp* dialogs; + Popup* popup; + Submenu* submenu; + Widget* widget; + TextInput* text_input; + FuriString* file_path; + char file_name_tmp[SUBGHZ_REMOTE_MAX_LEN_NAME]; + + SubRemViewRemote* subrem_remote_view; + + // AvrIspProgrammerView* subghz_remote_programmer_view; + // AvrIspReaderView* subghz_remote_reader_view; + // AvrIspWriterView* subghz_remote_writer_view; + // AvrIspChipDetectView* subghz_remote_chip_detect_view; + + // AvrIspError error; +} SubGhzRemoteApp; + +bool subrem_load_from_file(SubGhzRemoteApp* app); \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/transmitter.c b/applications/external/subghz_remote_new/views/transmitter.c new file mode 100644 index 000000000..a3589339d --- /dev/null +++ b/applications/external/subghz_remote_new/views/transmitter.c @@ -0,0 +1,277 @@ +#include "transmitter.h" +#include "../subghz_remote_app_i.h" + +#include +#include + +#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 16 +struct SubRemViewRemote { + View* view; + SubRemViewRemoteCallback callback; + void* context; +}; +// FIXME: drop +// static char* char_to_str(char* str, int i) { +// char* converted = malloc(sizeof(char) * i + 1); +// memcpy(converted, str, i); + +// converted[i] = '\0'; + +// return converted; +// } + +// TODO: model + +typedef struct { + // FuriString* up_label; + // FuriString* down_label; + // FuriString* left_label; + // FuriString* right_label; + // FuriString* ok_label; + + char* up_label; + char* down_label; + char* left_label; + char* right_label; + char* ok_label; + + uint8_t pressed_btn; + // bool show_button; + // FuriString* temp_button_id; + // bool draw_temp_button; +} SubRemViewRemoteModel; + +void subrem_view_remote_set_callback( + SubRemViewRemote* subrem_view_remote, + SubRemViewRemoteCallback callback, + void* context) { + furi_assert(subrem_view_remote); + + subrem_view_remote->callback = callback; + subrem_view_remote->context = context; +} + +void subrem_view_remote_add_data_to_show( + SubRemViewRemote* subrem_view_remote, + const char* up_label, + const char* down_label, + const char* left_label, + const char* right_label, + const char* ok_label) { + furi_assert(subrem_view_remote); + + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { + strncpy(model->up_label, up_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->down_label, down_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->left_label, left_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->right_label, right_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->ok_label, ok_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + + // model->up_label = char_to_str((char*)up_label, 16); + // model->down_label = char_to_str((char*)down_label, 16); + // model->left_label = char_to_str((char*)left_label, 16); + // model->right_label = char_to_str((char*)right_label, 16); + // model->ok_label = char_to_str((char*)ok_label, 16); + + // furi_string_set(model->up_label, up_label); + // furi_string_set(model->down_label, down_label); + // furi_string_set(model->left_label, left_label); + // furi_string_set(model->right_label, right_label); + // furi_string_set(model->ok_label, ok_label); + }, + true); +} + +void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + + //map found, draw all the things + canvas_clear(canvas); + + //canvas_set_font(canvas, FontPrimary); + //canvas_draw_str(canvas, 0, 10, "U: "); + //canvas_draw_str(canvas, 0, 20, "L: "); + //canvas_draw_str(canvas, 0, 30, "R: "); + //canvas_draw_str(canvas, 0, 40, "D: "); + //canvas_draw_str(canvas, 0, 50, "Ok: "); + + //PNGs are located in assets/icons/SubGHzRemote before compilation + + //Icons for Labels + //canvas_draw_icon(canvas, 0, 0, &I_SubGHzRemote_LeftAlignedButtons_9x64); + canvas_draw_icon(canvas, 1, 5, &I_ButtonUp_7x4); + canvas_draw_icon(canvas, 1, 15, &I_ButtonDown_7x4); + canvas_draw_icon(canvas, 2, 23, &I_ButtonLeft_4x7); + canvas_draw_icon(canvas, 2, 33, &I_ButtonRight_4x7); + canvas_draw_icon(canvas, 0, 42, &I_Ok_btn_9x9); + canvas_draw_icon(canvas, 0, 53, &I_back_10px); + + //Labels + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 10, 10, model->up_label); + canvas_draw_str(canvas, 10, 20, model->down_label); + canvas_draw_str(canvas, 10, 30, model->left_label); + canvas_draw_str(canvas, 10, 40, model->right_label); + canvas_draw_str(canvas, 10, 50, model->ok_label); + // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); + // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); + // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); + // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); + // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); + + canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit."); + + //Status text and indicator + // canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, app->send_status); + + canvas_draw_icon(canvas, 113, 15, &I_Pin_cell_13x13); + switch(model->pressed_btn) { + case 0: + break; + case 1: + canvas_draw_icon(canvas, 116, 17, &I_Pin_arrow_up_7x9); + break; + case 2: + canvas_draw_icon_ex(canvas, 116, 17, &I_Pin_arrow_up_7x9, IconRotation180); + break; + case 3: + canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation90); + break; + case 4: + canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation270); + break; + case 5: + canvas_draw_icon(canvas, 116, 18, &I_Pin_star_7x7); + break; + } + + //Repeat indicator + //canvas_draw_str_aligned(canvas, 125, 40, AlignRight, AlignBottom, "Repeat:"); + //canvas_draw_icon(canvas, 115, 39, &I_SubGHzRemote_Repeat_12x14); + //canvas_draw_str_aligned(canvas, 125, 62, AlignRight, AlignBottom, int_to_char(app->repeat)); +} + +bool subrem_view_remote_input(InputEvent* event, void* context) { + furi_assert(context); + SubRemViewRemote* subrem_view_remote = context; + + if(event->key == InputKeyBack && event->type == InputTypeLong) { + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { + strcpy(model->up_label, "N/A"); + strcpy(model->down_label, "N/A"); + strcpy(model->left_label, "N/A"); + strcpy(model->right_label, "N/A"); + strcpy(model->ok_label, "N/A"); + + // furi_string_reset(model->up_label); + // furi_string_reset(model->down_label); + // furi_string_reset(model->left_label); + // furi_string_reset(model->right_label); + // furi_string_reset(model->ok_label); + }, + false); + return false; + } else if(event->key == InputKeyUp) { + if(event->type == InputTypePress) { + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { model->pressed_btn = 1; }, + true); + return true; + } else if(event->type == InputTypeRelease) { + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { model->pressed_btn = 0; }, + true); + return true; + } + } + return true; +} + +void subrem_view_remote_enter(void* context) { + furi_assert(context); +} + +void subrem_view_remote_exit(void* context) { + furi_assert(context); +} + +SubRemViewRemote* subrem_view_remote_alloc() { + SubRemViewRemote* subrem_view_remote = malloc(sizeof(SubRemViewRemote)); + + // View allocation and configuration + subrem_view_remote->view = view_alloc(); + view_allocate_model( + subrem_view_remote->view, ViewModelTypeLocking, sizeof(SubRemViewRemoteModel)); + view_set_context(subrem_view_remote->view, subrem_view_remote); + view_set_draw_callback(subrem_view_remote->view, (ViewDrawCallback)subrem_view_remote_draw); + view_set_input_callback(subrem_view_remote->view, subrem_view_remote_input); + view_set_enter_callback(subrem_view_remote->view, subrem_view_remote_enter); + view_set_exit_callback(subrem_view_remote->view, subrem_view_remote_exit); + + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { + model->up_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); + model->down_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); + model->left_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); + model->right_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); + model->ok_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); + + strcpy(model->up_label, "N/A"); + strcpy(model->down_label, "N/A"); + strcpy(model->left_label, "N/A"); + strcpy(model->right_label, "N/A"); + strcpy(model->ok_label, "N/A"); + + // model->up_label = furi_string_alloc(); + // model->down_label = furi_string_alloc(); + // model->left_label = furi_string_alloc(); + // model->right_label = furi_string_alloc(); + // model->ok_label = furi_string_alloc(); + + model->pressed_btn = 0; + }, + true); + return subrem_view_remote; +} + +void subrem_view_remote_free(SubRemViewRemote* subghz_remote) { + furi_assert(subghz_remote); + + with_view_model( + subghz_remote->view, + SubRemViewRemoteModel * model, + { + free(model->up_label); + free(model->down_label); + free(model->left_label); + free(model->right_label); + free(model->ok_label); + + // furi_string_free(model->up_label); + // furi_string_free(model->down_label); + // furi_string_free(model->left_label); + // furi_string_free(model->right_label); + // furi_string_free(model->ok_label); + }, + true); + view_free(subghz_remote->view); + free(subghz_remote); +} + +View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote) { + furi_assert(subrem_view_remote); + return subrem_view_remote->view; +} \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/transmitter.h b/applications/external/subghz_remote_new/views/transmitter.h new file mode 100644 index 000000000..a324d09ec --- /dev/null +++ b/applications/external/subghz_remote_new/views/transmitter.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include "../helpers/subrem_custom_event.h" + +typedef struct SubRemViewRemote SubRemViewRemote; + +typedef void (*SubRemViewRemoteCallback)(SubRemCustomEvent event, void* context); + +void subrem_view_remote_set_callback( + SubRemViewRemote* subrem_view_remote, + SubRemViewRemoteCallback callback, + void* context); + +SubRemViewRemote* subrem_view_remote_alloc(); + +void subrem_view_remote_free(SubRemViewRemote* subrem_view_remote); + +View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote); + +void subrem_view_remote_add_data_to_show( + SubRemViewRemote* subrem_view_remote, + const char* up_label, + const char* down_label, + const char* left_label, + const char* right_label, + const char* ok_label); \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/transmitter_old.txt b/applications/external/subghz_remote_new/views/transmitter_old.txt new file mode 100644 index 000000000..ea2dc2f62 --- /dev/null +++ b/applications/external/subghz_remote_new/views/transmitter_old.txt @@ -0,0 +1,317 @@ +#include "transmitter.h" +#include "../subghz_remote_app_i.h" + +#include +#include + +#include + +struct SubGhzRemoteViewRemote { + View* view; + SubGhzRemoteViewRemoteCallback callback; + void* context; +}; + +typedef struct { + FuriString* frequency_str; + FuriString* preset_str; + FuriString* key_str; + // bool show_button; + // FuriString* temp_button_id; + // bool draw_temp_button; +} SubGhzRemoteViewRemoteModel; + +void subghz_view_transmitter_set_callback( + SubGhzRemoteViewRemote* subghz_transmitter, + SubGhzRemoteViewRemoteCallback callback, + void* context) { + furi_assert(subghz_transmitter); + + subghz_transmitter->callback = callback; + subghz_transmitter->context = context; +} + +void subghz_view_transmitter_add_data_to_show( + SubGhzRemoteViewRemote* subghz_transmitter, + const char* key_str, + const char* frequency_str, + const char* preset_str, + bool show_button) { + furi_assert(subghz_transmitter); + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_set(model->key_str, key_str); + furi_string_set(model->frequency_str, frequency_str); + furi_string_set(model->preset_str, preset_str); + model->show_button = show_button; + }, + true); +} + +static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str) { + const uint8_t button_height = 12; + const uint8_t vertical_offset = 3; + const uint8_t horizontal_offset = 1; + const uint8_t string_width = canvas_string_width(canvas, str); + const Icon* icon = &I_ButtonCenter_7x7; + const uint8_t icon_offset = 3; + const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_offset; + const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; + + const uint8_t x = (canvas_width(canvas) - button_width) / 2 + 40; + const uint8_t y = canvas_height(canvas); + + canvas_draw_box(canvas, x, y - button_height, button_width, button_height); + + canvas_draw_line(canvas, x - 1, y, x - 1, y - button_height + 0); + canvas_draw_line(canvas, x - 2, y, x - 2, y - button_height + 1); + canvas_draw_line(canvas, x - 3, y, x - 3, y - button_height + 2); + + canvas_draw_line(canvas, x + button_width + 0, y, x + button_width + 0, y - button_height + 0); + canvas_draw_line(canvas, x + button_width + 1, y, x + button_width + 1, y - button_height + 1); + canvas_draw_line(canvas, x + button_width + 2, y, x + button_width + 2, y - button_height + 2); + + canvas_invert_color(canvas); + canvas_draw_icon( + canvas, + x + horizontal_offset, + y - button_height + vertical_offset - 1, + &I_ButtonCenter_7x7); + canvas_draw_str( + canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str); + canvas_invert_color(canvas); +} + +void subghz_view_transmitter_draw(Canvas* canvas, SubGhzRemoteViewRemoteModel* model) { + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned( + canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(model->key_str)); + canvas_draw_str(canvas, 78, 7, furi_string_get_cstr(model->frequency_str)); + canvas_draw_str(canvas, 113, 7, furi_string_get_cstr(model->preset_str)); + + // if(model->draw_temp_button) { + // canvas_set_font(canvas, FontBatteryPercent); + // canvas_draw_str(canvas, 117, 40, furi_string_get_cstr(model->temp_button_id)); + // canvas_set_font(canvas, FontSecondary); + // } + + // if(model->show_button) { + // canvas_draw_str(canvas, 58, 62, furi_hal_subghz_get_radio_type() ? "R: Ext" : "R: Int"); + // subghz_view_transmitter_button_right(canvas, "Send"); + // } +} + +bool subghz_view_transmitter_input(InputEvent* event, void* context) { + furi_assert(context); + SubGhzRemoteViewRemote* subghz_transmitter = context; + bool can_be_sent = false; + + if(event->key == InputKeyBack && event->type == InputTypeShort) { + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_reset(model->frequency_str); + furi_string_reset(model->preset_str); + furi_string_reset(model->key_str); + furi_string_reset(model->temp_button_id); + model->show_button = false; + model->draw_temp_button = false; + }, + false); + return false; + } + + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + if(model->show_button) { + can_be_sent = true; + } + }, + true); + + if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { + subghz_custom_btn_set(0); + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_reset(model->temp_button_id); + model->draw_temp_button = false; + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + + // Temp Buttons (UP) + if(can_be_sent && event->key == InputKeyUp && event->type == InputTypePress) { + subghz_custom_btn_set(1); + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_reset(model->temp_button_id); + if(subghz_custom_btn_get_original() != 0) { + if(subghz_custom_btn_get() == 1) { + furi_string_printf( + model->temp_button_id, "%01X", subghz_custom_btn_get_original()); + model->draw_temp_button = true; + } + } + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyUp && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + // Down + if(can_be_sent && event->key == InputKeyDown && event->type == InputTypePress) { + subghz_custom_btn_set(2); + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_reset(model->temp_button_id); + if(subghz_custom_btn_get_original() != 0) { + if(subghz_custom_btn_get() == 2) { + furi_string_printf( + model->temp_button_id, "%01X", subghz_custom_btn_get_original()); + model->draw_temp_button = true; + } + } + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyDown && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + // Left + if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypePress) { + subghz_custom_btn_set(3); + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_reset(model->temp_button_id); + if(subghz_custom_btn_get_original() != 0) { + if(subghz_custom_btn_get() == 3) { + furi_string_printf( + model->temp_button_id, "%01X", subghz_custom_btn_get_original()); + model->draw_temp_button = true; + } + } + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + // Right + if(can_be_sent && event->key == InputKeyRight && event->type == InputTypePress) { + subghz_custom_btn_set(4); + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_reset(model->temp_button_id); + if(subghz_custom_btn_get_original() != 0) { + if(subghz_custom_btn_get() == 4) { + furi_string_printf( + model->temp_button_id, "%01X", subghz_custom_btn_get_original()); + model->draw_temp_button = true; + } + } + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyRight && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + + return true; +} + +void subghz_view_transmitter_enter(void* context) { + furi_assert(context); +} + +void subghz_view_transmitter_exit(void* context) { + furi_assert(context); +} + +SubGhzRemoteViewRemote* subghz_view_transmitter_alloc() { + SubGhzRemoteViewRemote* subghz_transmitter = malloc(sizeof(SubGhzRemoteViewRemote)); + + // View allocation and configuration + subghz_transmitter->view = view_alloc(); + view_allocate_model( + subghz_transmitter->view, ViewModelTypeLocking, sizeof(SubGhzRemoteViewRemoteModel)); + view_set_context(subghz_transmitter->view, subghz_transmitter); + view_set_draw_callback( + subghz_transmitter->view, (ViewDrawCallback)subghz_view_transmitter_draw); + view_set_input_callback(subghz_transmitter->view, subghz_view_transmitter_input); + view_set_enter_callback(subghz_transmitter->view, subghz_view_transmitter_enter); + view_set_exit_callback(subghz_transmitter->view, subghz_view_transmitter_exit); + + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + model->frequency_str = furi_string_alloc(); + model->preset_str = furi_string_alloc(); + model->key_str = furi_string_alloc(); + model->temp_button_id = furi_string_alloc(); + }, + true); + return subghz_transmitter; +} + +void subghz_view_transmitter_free(SubGhzRemoteViewRemote* subghz_transmitter) { + furi_assert(subghz_transmitter); + + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_free(model->frequency_str); + furi_string_free(model->preset_str); + furi_string_free(model->key_str); + furi_string_free(model->temp_button_id); + }, + true); + view_free(subghz_transmitter->view); + free(subghz_transmitter); +} + +View* subghz_view_transmitter_get_view(SubGhzRemoteViewRemote* subghz_transmitter) { + furi_assert(subghz_transmitter); + return subghz_transmitter->view; +}