From d279639e53daa4b1ba5ed95def15402ce344a51a Mon Sep 17 00:00:00 2001 From: VerstreuteSeele Date: Fri, 30 Dec 2022 05:12:53 +0100 Subject: [PATCH] Massive overhaul | Part 1 --- .../main/archive/helpers/archive_browser.c | 12 +- applications/main/nfc/nfc.c | 16 - applications/main/nfc/nfc_i.h | 3 - .../main/nfc/scenes/nfc_scene_config.h | 13 - .../main/nfc/scenes/nfc_scene_emulate_nfcv.c | 149 ---- .../main/nfc/scenes/nfc_scene_extra_actions.c | 10 - .../scenes/nfc_scene_mf_classic_dict_attack.c | 6 +- .../nfc/scenes/nfc_scene_mf_classic_keys.c | 4 +- .../scenes/nfc_scene_mf_ultralight_emulate.c | 115 +-- .../nfc_scene_mf_ultralight_key_input.c | 2 +- .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 18 +- .../nfc_scene_mf_ultralight_read_auth.c | 9 +- .../nfc_scene_mf_ultralight_unlock_auto.c | 3 +- .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 170 +---- .../nfc/scenes/nfc_scene_nfcv_key_input.c | 48 -- .../main/nfc/scenes/nfc_scene_nfcv_menu.c | 63 -- .../main/nfc/scenes/nfc_scene_nfcv_unlock.c | 155 ---- .../nfc/scenes/nfc_scene_nfcv_unlock_menu.c | 60 -- .../main/nfc/scenes/nfc_scene_passport_auth.c | 194 ----- .../nfc_scene_passport_auth_save_name.c | 82 --- .../main/nfc/scenes/nfc_scene_passport_date.c | 120 ---- .../nfc/scenes/nfc_scene_passport_docnr.c | 67 -- .../main/nfc/scenes/nfc_scene_passport_menu.c | 57 -- .../nfc/scenes/nfc_scene_passport_pace_todo.c | 40 -- .../main/nfc/scenes/nfc_scene_passport_read.c | 90 --- .../nfc/scenes/nfc_scene_passport_read_auth.c | 142 ---- applications/main/nfc/scenes/nfc_scene_read.c | 22 +- applications/main/nfc/scenes/nfc_scene_rpc.c | 7 - .../main/nfc/scenes/nfc_scene_save_name.c | 2 +- .../main/nfc/scenes/nfc_scene_save_success.c | 6 - .../main/nfc/scenes/nfc_scene_saved_menu.c | 2 - applications/main/nfc/views/dict_attack.c | 4 +- applications/plugins/scorched_tanks/LICENSE | 674 ------------------ applications/plugins/scorched_tanks/README.md | 35 - .../plugins/scorched_tanks/application.fam | 12 - .../scorched_tanks/scorchedTanks_10px.png | Bin 614 -> 0 bytes .../scorched_tanks/scorched_tanks_game_app.c | 540 -------------- .../scorched_tanks/scorched_tanks_v1.gif | Bin 139343 -> 0 bytes .../usbkeyboard/views/usb_hid_keyboard.c | 2 +- .../desktop/scenes/desktop_scene_lock_menu.c | 28 +- .../services/desktop/views/desktop_events.h | 4 +- .../desktop/views/desktop_view_lock_menu.c | 20 +- .../services/dolphin/helpers/dolphin_state.c | 8 +- .../services/dolphin/helpers/dolphin_state.h | 8 +- .../gui/modules/file_browser_worker.c | 3 +- .../gui/modules/file_browser_worker.h | 2 +- .../services/infraredsrv/infrared_cli.c | 2 +- applications/services/loader/loader.c | 15 +- .../settings/dolphin_passport/passport.c | 60 +- firmware/targets/f7/api_symbols.csv | 6 +- site_scons/cc.scons | 14 +- 51 files changed, 100 insertions(+), 3024 deletions(-) delete mode 100644 applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_nfcv_menu.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_nfcv_unlock_menu.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_passport_auth.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_passport_auth_save_name.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_passport_date.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_passport_docnr.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_passport_menu.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_passport_pace_todo.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_passport_read.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_passport_read_auth.c delete mode 100644 applications/plugins/scorched_tanks/LICENSE delete mode 100644 applications/plugins/scorched_tanks/README.md delete mode 100644 applications/plugins/scorched_tanks/application.fam delete mode 100644 applications/plugins/scorched_tanks/scorchedTanks_10px.png delete mode 100644 applications/plugins/scorched_tanks/scorched_tanks_game_app.c delete mode 100644 applications/plugins/scorched_tanks/scorched_tanks_v1.gif diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index 9ff7e49ce..988124e0b 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -64,13 +64,7 @@ static void archive_add_file_item(browser, is_folder, furi_string_get_cstr(item_path)); } else { with_view_model( - browser->view, - ArchiveBrowserViewModel * model, - { - files_array_sort(model->files); - model->list_loading = false; - }, - true); + browser->view, ArchiveBrowserViewModel * model, { model->list_loading = false; }, true); } } @@ -485,7 +479,7 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { // Hide dot files everywhere except Browser bool hide_dot_files = (strcmp(archive_get_tab_ext(tab), "*") == 0) ? false : true; archive_file_browser_set_path( - browser, browser->path, archive_get_tab_ext(tab), skip_assets, false); + browser, browser->path, archive_get_tab_ext(tab), skip_assets, hide_dot_files); tab_empty = false; // Empty check will be performed later } } @@ -533,4 +527,4 @@ void archive_refresh_dir(ArchiveBrowserView* browser) { with_view_model( browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false); file_browser_worker_folder_refresh(browser->worker, idx_temp); -} +} \ No newline at end of file diff --git a/applications/main/nfc/nfc.c b/applications/main/nfc/nfc.c index 90fcf9f27..cf4584d7a 100644 --- a/applications/main/nfc/nfc.c +++ b/applications/main/nfc/nfc.c @@ -87,13 +87,6 @@ Nfc* nfc_alloc() { nfc->view_dispatcher, NfcViewTextBox, text_box_get_view(nfc->text_box)); nfc->text_box_store = furi_string_alloc(); - // Variable Item List - nfc->variable_item_list = variable_item_list_alloc(); - view_dispatcher_add_view( - nfc->view_dispatcher, - NfcViewVarItemList, - variable_item_list_get_view(nfc->variable_item_list)); - // Custom Widget nfc->widget = widget_alloc(); view_dispatcher_add_view(nfc->view_dispatcher, NfcViewWidget, widget_get_view(nfc->widget)); @@ -166,10 +159,6 @@ void nfc_free(Nfc* nfc) { text_box_free(nfc->text_box); furi_string_free(nfc->text_box_store); - // Variable Item List - view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewVarItemList); - variable_item_list_free(nfc->variable_item_list); - // Custom Widget view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewWidget); widget_free(nfc->widget); @@ -301,11 +290,6 @@ int32_t nfc_app(void* p) { } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); DOLPHIN_DEED(DolphinDeedNfcEmulate); - } else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateNfcV); - DOLPHIN_DEED(DolphinDeedNfcEmulate); - } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); DOLPHIN_DEED(DolphinDeedNfcEmulate); diff --git a/applications/main/nfc/nfc_i.h b/applications/main/nfc/nfc_i.h index a3a62972c..f7e489902 100644 --- a/applications/main/nfc/nfc_i.h +++ b/applications/main/nfc/nfc_i.h @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -78,7 +77,6 @@ struct Nfc { TextInput* text_input; ByteInput* byte_input; TextBox* text_box; - VariableItemList* variable_item_list; Widget* widget; DictAttack* dict_attack; DetectReader* detect_reader; @@ -94,7 +92,6 @@ typedef enum { NfcViewTextInput, NfcViewByteInput, NfcViewTextBox, - NfcViewVarItemList, NfcViewWidget, NfcViewDictAttack, NfcViewDetectReader, diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 045080fea..ce51d000d 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -14,11 +14,6 @@ ADD_SCENE(nfc, file_select, FileSelect) ADD_SCENE(nfc, emulate_uid, EmulateUid) ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess) ADD_SCENE(nfc, nfca_menu, NfcaMenu) -ADD_SCENE(nfc, nfcv_menu, NfcVMenu) -ADD_SCENE(nfc, nfcv_unlock_menu, NfcVUnlockMenu) -ADD_SCENE(nfc, nfcv_key_input, NfcVKeyInput) -ADD_SCENE(nfc, nfcv_unlock, NfcVUnlock) -ADD_SCENE(nfc, emulate_nfcv, EmulateNfcV) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData) ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) @@ -50,14 +45,6 @@ ADD_SCENE(nfc, mf_classic_update_success, MfClassicUpdateSuccess) ADD_SCENE(nfc, mf_classic_wrong_card, MfClassicWrongCard) ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) ADD_SCENE(nfc, emv_menu, EmvMenu) -ADD_SCENE(nfc, passport_read, PassportReadSuccess) -ADD_SCENE(nfc, passport_read_auth, PassportReadAuthSuccess) -ADD_SCENE(nfc, passport_menu, PassportMenu) -ADD_SCENE(nfc, passport_auth, PassportAuth) -ADD_SCENE(nfc, passport_auth_save_name, PassportAuthSaveName) -ADD_SCENE(nfc, passport_date, PassportDate) -ADD_SCENE(nfc, passport_docnr, PassportDocNr) -ADD_SCENE(nfc, passport_pace_todo, PassportPaceTodo) ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) ADD_SCENE(nfc, device_info, DeviceInfo) ADD_SCENE(nfc, delete, Delete) diff --git a/applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c b/applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c deleted file mode 100644 index e6fc60d86..000000000 --- a/applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c +++ /dev/null @@ -1,149 +0,0 @@ -#include "../nfc_i.h" - -#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (100) - -enum { - NfcSceneEmulateNfcVStateWidget, - NfcSceneEmulateNfcVStateTextBox, -}; - -bool nfc_emulate_nfcv_worker_callback(NfcWorkerEvent event, void* context) { - UNUSED(event); - furi_assert(context); - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); - return true; -} - -void nfc_scene_emulate_nfcv_widget_callback(GuiButtonType result, InputType type, void* context) { - furi_assert(context); - Nfc* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_emulate_nfcv_textbox_callback(void* context) { - furi_assert(context); - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -// Add widget with device name or inform that data received -static void nfc_scene_emulate_nfcv_widget_config(Nfc* nfc, bool data_received) { - FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; - Widget* widget = nfc->widget; - widget_reset(widget); - FuriString* info_str; - info_str = furi_string_alloc(); - - widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61); - widget_add_string_element( - widget, 89, 32, AlignCenter, AlignTop, FontPrimary, "Emulating NfcV"); - if(strcmp(nfc->dev->dev_name, "")) { - furi_string_printf(info_str, "%s", nfc->dev->dev_name); - } else { - for(uint8_t i = 0; i < data->uid_len; i++) { - furi_string_cat_printf(info_str, "%02X ", data->uid[i]); - } - } - furi_string_trim(info_str); - widget_add_text_box_element( - widget, 56, 43, 70, 21, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true); - furi_string_free(info_str); - if(data_received) { - widget_add_button_element( - widget, GuiButtonTypeCenter, "Log", nfc_scene_emulate_nfcv_widget_callback, nfc); - } -} - -void nfc_scene_emulate_nfcv_on_enter(void* context) { - Nfc* nfc = context; - - // Setup Widget - nfc_scene_emulate_nfcv_widget_config(nfc, false); - // Setup TextBox - TextBox* text_box = nfc->text_box; - text_box_set_font(text_box, TextBoxFontHex); - text_box_set_focus(text_box, TextBoxFocusEnd); - furi_string_reset(nfc->text_box_store); - - // Set Widget state and view - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateNfcV, NfcSceneEmulateNfcVStateWidget); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - // Start worker - memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData)); - nfc_worker_start( - nfc->worker, - NfcWorkerStateNfcVEmulate, - &nfc->dev->dev_data, - nfc_emulate_nfcv_worker_callback, - nfc); - - nfc_blink_emulate_start(nfc); -} - -bool nfc_scene_emulate_nfcv_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data; - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateNfcV); - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventWorkerExit) { - // Add data button to widget if data is received for the first time - if(!furi_string_size(nfc->text_box_store)) { - nfc_scene_emulate_nfcv_widget_config(nfc, true); - } - if(strlen(nfcv_data->last_command) > 0) { - /* use the last n bytes from the log so there's enough space for the new log entry */ - size_t maxSize = - NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX - (strlen(nfcv_data->last_command) + 1); - if(furi_string_size(nfc->text_box_store) >= maxSize) { - furi_string_right(nfc->text_box_store, (strlen(nfcv_data->last_command) + 1)); - } - furi_string_cat_printf(nfc->text_box_store, "%s", nfcv_data->last_command); - furi_string_push_back(nfc->text_box_store, '\n'); - text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store)); - - /* clear previously logged command */ - strcpy(nfcv_data->last_command, ""); - } - consumed = true; - } else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateNfcVStateWidget) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateNfcV, NfcSceneEmulateNfcVStateTextBox); - consumed = true; - } else if(event.event == NfcCustomEventViewExit && state == NfcSceneEmulateNfcVStateTextBox) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateNfcV, NfcSceneEmulateNfcVStateWidget); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - if(state == NfcSceneEmulateNfcVStateTextBox) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateNfcV, NfcSceneEmulateNfcVStateWidget); - consumed = true; - } - } - - return consumed; -} - -void nfc_scene_emulate_nfcv_on_exit(void* context) { - Nfc* nfc = context; - - // Stop worker - nfc_worker_stop(nfc->worker); - - // Clear view - widget_reset(nfc->widget); - text_box_reset(nfc->text_box); - furi_string_reset(nfc->text_box_store); - - nfc_blink_stop(nfc); -} diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 147c89757..717e8efc4 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -4,7 +4,6 @@ enum SubmenuIndex { SubmenuIndexReadCardType, SubmenuIndexMfClassicKeys, SubmenuIndexMfUltralightUnlock, - SubmenuIndexNfcVUnlock, }; void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) { @@ -35,12 +34,6 @@ void nfc_scene_extra_actions_on_enter(void* context) { SubmenuIndexMfUltralightUnlock, nfc_scene_extra_actions_submenu_callback, nfc); - submenu_add_item( - submenu, - "Unlock SLIX-L", - SubmenuIndexNfcVUnlock, - nfc_scene_extra_actions_submenu_callback, - nfc); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } @@ -63,9 +56,6 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType); consumed = true; - } else if(event.event == SubmenuIndexNfcVUnlock) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlockMenu); - consumed = true; } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 9b477e301..b82bf5521 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -58,7 +58,7 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackSt // If failed to load user dictionary - try the system dictionary if(!dict) { - FURI_LOG_E(TAG, "User Dictionary Not Found"); + FURI_LOG_E(TAG, "User dictionary not found"); state = DictAttackStateFlipperDictInProgress; } } @@ -67,8 +67,8 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackSt dict_attack_set_header(nfc->dict_attack, "MF Classic System Dictionary"); dict = mf_classic_dict_alloc(MfClassicDictTypeSystem); if(!dict) { - FURI_LOG_E(TAG, "Flipper Dictionary Not Found"); - // Pass through to let worker handle the failure + FURI_LOG_E(TAG, "Flipper dictionary not found"); + // Pass through to let the worker handle the failure } } // Free previous dictionary diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c index 8b61904b4..8a7dc2c18 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c @@ -28,9 +28,9 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) { widget_add_string_element( nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "MIFARE Classic Keys"); char temp_str[32]; - snprintf(temp_str, sizeof(temp_str), "System Dict: %ld", flipper_dict_keys_total); + snprintf(temp_str, sizeof(temp_str), "System dict: %lu", flipper_dict_keys_total); widget_add_string_element(nfc->widget, 0, 20, AlignLeft, AlignTop, FontSecondary, temp_str); - snprintf(temp_str, sizeof(temp_str), "User Dict: %ld", user_dict_keys_total); + snprintf(temp_str, sizeof(temp_str), "User dict: %lu", user_dict_keys_total); widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str); widget_add_button_element( nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c index e4e2a4493..9d8f17f9a 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c @@ -1,103 +1,20 @@ #include "../nfc_i.h" -#include - -#define NFC_SCENE_MF_ULTRALIGHT_EMULATE_LOG_SIZE_MAX (200) #define NFC_MF_UL_DATA_NOT_CHANGED (0UL) #define NFC_MF_UL_DATA_CHANGED (1UL) -enum { - // View states - NfcSceneMfUltralightEmulateStateWidget, - NfcSceneMfUltralightEmulateStateTextBox, - NfcSceneMfUltralightEmulateStateMax = 0xFF, - // State flags - NfcSceneMfUltralightEmulateStateDataChanged = 1 << 8, - NfcSceneMfUltralightEmulateStateAuthAttempted = 1 << 9, - NfcSceneMfUltralightEmulateStateLogButtonShown = 1 << 10, -}; - bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* context) { + UNUSED(event); Nfc* nfc = context; - uint32_t state = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightEmulate); - - if(event == NfcWorkerEventSuccess) - state |= NfcSceneMfUltralightEmulateStateDataChanged; - else if(event == NfcWorkerEventMfUltralightPwdAuth) { - // Don't update if we're exiting - if(nfc_worker_get_state(nfc->worker) != NfcWorkerStateStop) { - // Event data is only available for the duration of this callback, so we're updating the - // text box right here - MfUltralightAuth* auth = nfc_worker_get_event_data(nfc->worker); - if(auth != NULL && furi_string_size(nfc->text_box_store) < - NFC_SCENE_MF_ULTRALIGHT_EMULATE_LOG_SIZE_MAX) { - furi_string_cat(nfc->text_box_store, "PWD:"); - for(size_t i = 0; i < sizeof(auth->pwd.raw); ++i) { - furi_string_cat_printf(nfc->text_box_store, " %02X", auth->pwd.raw[i]); - } - furi_string_push_back(nfc->text_box_store, '\n'); - text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store)); - } - state |= NfcSceneMfUltralightEmulateStateAuthAttempted; - } - } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightEmulate, state); - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_CHANGED); return true; } -void nfc_scene_mf_ultralight_emulate_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - furi_assert(context); - Nfc* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mf_ultralight_emulate_widget_config(Nfc* nfc, bool auth_attempted) { - Widget* widget = nfc->widget; - widget_reset(widget); - FuriString* info_str; - info_str = furi_string_alloc(); - - widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61); - if(strcmp(nfc->dev->dev_name, "")) { - furi_string_printf(info_str, "Emulating\n%s", nfc->dev->dev_name); - } else { - furi_string_printf(info_str, "Emulating\nMf Ultralight"); - } - - widget_add_string_multiline_element( - widget, 56, 31, AlignLeft, AlignTop, FontPrimary, furi_string_get_cstr(info_str)); - furi_string_free(info_str); - if(auth_attempted) { - widget_add_button_element( - widget, - GuiButtonTypeCenter, - "Log", - nfc_scene_mf_ultralight_emulate_widget_callback, - nfc); - } -} - void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { Nfc* nfc = context; - uint32_t state = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightEmulate); - // Setup Widget - nfc_scene_mf_ultralight_emulate_widget_config(nfc, false); - state &= ~NfcSceneMfUltralightEmulateStateLogButtonShown; - // Setup TextBox - TextBox* text_box = nfc->text_box; - text_box_set_font(text_box, TextBoxFontHex); - text_box_set_focus(text_box, TextBoxFocusEnd); - furi_string_reset(nfc->text_box_store); // Setup view MfUltralightType type = nfc->dev->dev_data.mf_ul_data.type; bool is_ultralight = (type == MfUltralightTypeUL11) || (type == MfUltralightTypeUL21) || @@ -114,12 +31,8 @@ void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { popup_set_icon(popup, 0, 3, &I_NFC_dolphin_emulation_47x61); popup_set_text(popup, nfc->text_store, 90, 28, AlignCenter, AlignTop); - // Set Widget state and view - state = (state & ~NfcSceneMfUltralightEmulateStateMax) | - NfcSceneMfUltralightEmulateStateWidget; - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightEmulate, state); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - // Start worker + // Setup and start worker + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); nfc_worker_start( nfc->worker, NfcWorkerStateMfUltralightEmulate, @@ -131,8 +44,6 @@ void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; - uint32_t state = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightEmulate); bool consumed = false; if(event.type == SceneManagerEventTypeBack) { @@ -148,28 +59,16 @@ bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent e nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); } } + consumed = false; } return consumed; } void nfc_scene_mf_ultralight_emulate_on_exit(void* context) { Nfc* nfc = context; - uint32_t state = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightEmulate); - - // Stop worker - nfc_worker_stop(nfc->worker); - // Check if data changed and save in shadow file - if(state & NfcSceneMfUltralightEmulateStateDataChanged) { - state &= ~NfcSceneMfUltralightEmulateStateDataChanged; - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightEmulate, state); - nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); - } // Clear view - widget_reset(nfc->widget); - text_box_reset(nfc->text_box); - furi_string_reset(nfc->text_box_store); + popup_reset(nfc->popup); nfc_blink_stop(nfc); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c index 174d1a406..089187d5b 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c @@ -11,7 +11,7 @@ void nfc_scene_mf_ultralight_key_input_on_enter(void* context) { // Setup view ByteInput* byte_input = nfc->byte_input; - byte_input_set_header_text(byte_input, "Enter The Password In Hex"); + byte_input_set_header_text(byte_input, "Enter the password in hex"); byte_input_set_result_callback( byte_input, nfc_scene_mf_ultralight_key_input_byte_input_callback, diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c index ddf30c54a..c511e9dcb 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -2,8 +2,7 @@ #include enum SubmenuIndex { - SubmenuIndexUnlockByReader, - SubmenuIndexUnlockByPassword, + SubmenuIndexUnlock, SubmenuIndexSave, SubmenuIndexEmulate, SubmenuIndexInfo, @@ -23,14 +22,8 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { if(!mf_ul_is_full_capture(data)) { submenu_add_item( submenu, - "Unlock With Reader", - SubmenuIndexUnlockByReader, - nfc_scene_mf_ultralight_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Unlock With Password", - SubmenuIndexUnlockByPassword, + "Unlock", + SubmenuIndexUnlock, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); } @@ -70,10 +63,7 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even DOLPHIN_DEED(DolphinDeedNfcEmulate); } consumed = true; - } else if(event.event == SubmenuIndexUnlockByReader) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockAuto); - consumed = true; - } else if(event.event == SubmenuIndexUnlockByPassword) { + } else if(event.event == SubmenuIndexUnlock) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); consumed = true; } else if(event.event == SubmenuIndexInfo) { diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c index 8e2dd0c22..2ab5e3f3f 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c @@ -24,22 +24,21 @@ void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState if(curr_state != state) { if(state == NfcSceneMfUlReadStateDetecting) { popup_reset(nfc->popup); - popup_set_text( - nfc->popup, "Apply Card To\nFlipper's Back", 97, 24, AlignCenter, AlignTop); + popup_set_text(nfc->popup, "Apply the\ntarget card", 97, 24, AlignCenter, AlignTop); popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); nfc_blink_read_start(nfc); } else if(state == NfcSceneMfUlReadStateReading) { popup_reset(nfc->popup); popup_set_header( - nfc->popup, "Reading Card\nDon't Move...", 85, 24, AlignCenter, AlignTop); + nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); popup_set_icon(nfc->popup, 12, 23, &A_Loading_24); nfc_blink_detect_start(nfc); } else if(state == NfcSceneMfUlReadStateNotSupportedCard) { popup_reset(nfc->popup); - popup_set_header(nfc->popup, "Wrong Type Of Card!", 64, 3, AlignCenter, AlignTop); + popup_set_header(nfc->popup, "Wrong type of card!", 64, 3, AlignCenter, AlignTop); popup_set_text( nfc->popup, - "Only MIFARE\nUltralight & NTAG\n Are Supported", + "Only MIFARE\nUltralight & NTAG\nare supported", 4, 22, AlignLeft, diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c index 050f6db1e..c59fe3a7d 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c @@ -31,7 +31,7 @@ void nfc_scene_mf_ultralight_unlock_auto_on_enter(void* context) { nfc_scene_mf_ultralight_unlock_auto_worker_callback, nfc); - nfc_blink_emulate_start(nfc); + nfc_blink_read_start(nfc); } bool nfc_scene_mf_ultralight_unlock_auto_on_event(void* context, SceneManagerEvent event) { @@ -58,7 +58,6 @@ void nfc_scene_mf_ultralight_unlock_auto_on_exit(void* context) { // Stop worker nfc_worker_stop(nfc->worker); // Clear view - popup_reset(nfc->popup); widget_reset(nfc->widget); nfc_blink_stop(nfc); diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index 372da8860..b44ab7823 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -7,17 +7,6 @@ void nfc_scene_nfc_data_info_widget_callback(GuiButtonType result, InputType typ } } -uint32_t nfc_scene_nfc_data_info_get_key(uint8_t* data) { - uint32_t value = 0; - - for(uint32_t pos = 0; pos < 4; pos++) { - value <<= 8; - value |= data[pos]; - } - - return value; -} - void nfc_scene_nfc_data_info_on_enter(void* context) { Nfc* nfc = context; Widget* widget = nfc->widget; @@ -25,8 +14,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { NfcDeviceData* dev_data = &nfc->dev->dev_data; NfcProtocol protocol = dev_data->protocol; uint8_t text_scroll_height = 0; - if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl) || - (protocol == NfcDeviceProtocolNfcV)) { + if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl)) { widget_add_button_element( widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc); text_scroll_height = 52; @@ -44,8 +32,6 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { // Set tag type if(protocol == NfcDeviceProtocolEMV) { furi_string_cat_printf(temp_str, "\e#EMV Bank Card\n"); - } else if(protocol == NfcDeviceProtocolMRTD) { - furi_string_cat_printf(temp_str, "\e#Passport/ID\n"); } else if(protocol == NfcDeviceProtocolMifareUl) { furi_string_cat_printf( temp_str, "\e#%s\n", nfc_mf_ul_type(dev_data->mf_ul_data.type, true)); @@ -54,156 +40,19 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type)); } else if(protocol == NfcDeviceProtocolMifareDesfire) { furi_string_cat_printf(temp_str, "\e#MIFARE DESfire\n"); - } else if(protocol == NfcDeviceProtocolNfcV) { - switch(dev_data->nfcv_data.sub_type) { - case NfcVTypePlain: - furi_string_cat_printf(temp_str, "\e#ISO15693\n"); - break; - case NfcVTypeSlix: - furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX\n"); - break; - case NfcVTypeSlixS: - furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-S\n"); - break; - case NfcVTypeSlixL: - furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-L\n"); - break; - case NfcVTypeSlix2: - furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX2\n"); - break; - default: - furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); - break; - } } else { furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n"); } // Set tag iso data - if(protocol == NfcDeviceProtocolNfcV) { - NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data; - - furi_string_cat_printf(temp_str, "UID:\n"); - for(size_t i = 0; i < nfc_data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); - } - furi_string_cat_printf(temp_str, "\n"); - - furi_string_cat_printf(temp_str, "DSFID: %02X\n", nfcv_data->dsfid); - furi_string_cat_printf(temp_str, "AFI: %02X\n", nfcv_data->afi); - furi_string_cat_printf(temp_str, "IC Ref: %02X\n", nfcv_data->ic_ref); - furi_string_cat_printf(temp_str, "Blocks: %02X\n", nfcv_data->block_num); - furi_string_cat_printf(temp_str, "Blocksize: %02X\n", nfcv_data->block_size); - - furi_string_cat_printf( - temp_str, "Data (%d byte)\n", nfcv_data->block_num * nfcv_data->block_size); - - int maxBlocks = nfcv_data->block_num; - if(maxBlocks > 32) { - maxBlocks = 32; - furi_string_cat_printf(temp_str, "(truncated to %d blocks)\n", maxBlocks); - } - - for(int block = 0; block < maxBlocks; block++) { - for(int pos = 0; pos < nfcv_data->block_size; pos++) { - furi_string_cat_printf( - temp_str, " %02X", nfcv_data->data[block * nfcv_data->block_size + pos]); - } - furi_string_cat_printf(temp_str, "\n"); - } - furi_string_cat_printf(temp_str, "\n"); - - switch(dev_data->nfcv_data.sub_type) { - case NfcVTypePlain: - furi_string_cat_printf(temp_str, "Type: Plain\n"); - break; - case NfcVTypeSlix: - furi_string_cat_printf(temp_str, "Type: SLIX\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf( - temp_str, - " EAS %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); - break; - case NfcVTypeSlixS: - furi_string_cat_printf(temp_str, "Type: SLIX-S\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf( - temp_str, - " Read %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read)); - furi_string_cat_printf( - temp_str, - " Write %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write)); - furi_string_cat_printf( - temp_str, - " Privacy %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); - furi_string_cat_printf( - temp_str, - " Destroy %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); - furi_string_cat_printf( - temp_str, - " EAS %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); - break; - case NfcVTypeSlixL: - furi_string_cat_printf(temp_str, "Type: SLIX-L\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf( - temp_str, - " Privacy %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); - furi_string_cat_printf( - temp_str, - " Destroy %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); - furi_string_cat_printf( - temp_str, - " EAS %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); - break; - case NfcVTypeSlix2: - furi_string_cat_printf(temp_str, "Type: SLIX2\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf( - temp_str, - " Read %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_read)); - furi_string_cat_printf( - temp_str, - " Write %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_write)); - furi_string_cat_printf( - temp_str, - " Privacy %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_privacy)); - furi_string_cat_printf( - temp_str, - " Destroy %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_destroy)); - furi_string_cat_printf( - temp_str, - " EAS %08lX\n", - nfc_scene_nfc_data_info_get_key(nfcv_data->sub_data.slix.key_eas)); - break; - default: - furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); - break; - } - } else { - char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3'; - furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type); - furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < nfc_data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); - } - furi_string_cat_printf( - temp_str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]); - furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak); + char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3'; + furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type); + furi_string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); } + furi_string_cat_printf(temp_str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]); + furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak); // Set application specific data if(protocol == NfcDeviceProtocolMifareDesfire) { @@ -287,9 +136,6 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { } else if(protocol == NfcDeviceProtocolMifareUl) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData); consumed = true; - } else if(protocol == NfcDeviceProtocolNfcV) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu); - consumed = true; } } } diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c b/applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c deleted file mode 100644 index cc53c4dcb..000000000 --- a/applications/main/nfc/scenes/nfc_scene_nfcv_key_input.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "../nfc_i.h" -#include - -void nfc_scene_nfcv_key_input_byte_input_callback(void* context) { - Nfc* nfc = context; - NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix; - - memcpy(data->key_privacy, nfc->byte_input_store, 4); - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); -} - -void nfc_scene_nfcv_key_input_on_enter(void* context) { - Nfc* nfc = context; - - // Setup view - ByteInput* byte_input = nfc->byte_input; - byte_input_set_header_text(byte_input, "Enter The Password In Hex"); - byte_input_set_result_callback( - byte_input, - nfc_scene_nfcv_key_input_byte_input_callback, - NULL, - nfc, - nfc->byte_input_store, - 4); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); -} - -bool nfc_scene_nfcv_key_input_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventByteInputDone) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlock); - DOLPHIN_DEED(DolphinDeedNfcRead); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_nfcv_key_input_on_exit(void* context) { - Nfc* nfc = context; - - // Clear view - byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(nfc->byte_input, ""); -} diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_menu.c b/applications/main/nfc/scenes/nfc_scene_nfcv_menu.c deleted file mode 100644 index b30495a05..000000000 --- a/applications/main/nfc/scenes/nfc_scene_nfcv_menu.c +++ /dev/null @@ -1,63 +0,0 @@ -#include "../nfc_i.h" -#include - -enum SubmenuIndex { - SubmenuIndexSave, - SubmenuIndexEmulate, -}; - -void nfc_scene_nfcv_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_nfcv_menu_on_enter(void* context) { - Nfc* nfc = context; - Submenu* submenu = nfc->submenu; - - submenu_add_item(submenu, "Save", SubmenuIndexSave, nfc_scene_nfcv_menu_submenu_callback, nfc); - submenu_add_item( - submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_nfcv_menu_submenu_callback, nfc); - - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_nfcv_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexSave) { - nfc->dev->format = NfcDeviceSaveFormatNfcV; - // Clear device name - nfc_device_set_name(nfc->dev, ""); - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - consumed = true; - } else if(event.event == SubmenuIndexEmulate) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateNfcV); - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); - } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); - } - consumed = true; - } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcVMenu, event.event); - - } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - - return consumed; -} - -void nfc_scene_nfcv_menu_on_exit(void* context) { - Nfc* nfc = context; - - // Clear view - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c b/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c deleted file mode 100644 index b52cc0caa..000000000 --- a/applications/main/nfc/scenes/nfc_scene_nfcv_unlock.c +++ /dev/null @@ -1,155 +0,0 @@ -#include "../nfc_i.h" -#include - -typedef enum { - NfcSceneNfcVUnlockStateIdle, - NfcSceneNfcVUnlockStateDetecting, - NfcSceneNfcVUnlockStateUnlocked, - NfcSceneNfcVUnlockStateAlreadyUnlocked, - NfcSceneNfcVUnlockStateNotSupportedCard, -} NfcSceneNfcVUnlockState; - -static bool nfc_scene_nfcv_unlock_worker_callback(NfcWorkerEvent event, void* context) { - Nfc* nfc = context; - NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix; - - if(event == NfcWorkerEventNfcVPassKey) { - memcpy(data->key_privacy, nfc->byte_input_store, 4); - } else { - view_dispatcher_send_custom_event(nfc->view_dispatcher, event); - } - return true; -} - -void nfc_scene_nfcv_unlock_popup_callback(void* context) { - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -void nfc_scene_nfcv_unlock_set_state(Nfc* nfc, NfcSceneNfcVUnlockState state) { - FuriHalNfcDevData* nfc_data = &(nfc->dev->dev_data.nfc_data); - NfcVData* nfcv_data = &(nfc->dev->dev_data.nfcv_data); - - uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVUnlock); - if(curr_state != state) { - Popup* popup = nfc->popup; - if(state == NfcSceneNfcVUnlockStateDetecting) { - popup_reset(popup); - popup_set_text( - popup, "Put figurine on\nFlipper's back", 97, 24, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 8, &I_NFC_manual_60x50); - } else if(state == NfcSceneNfcVUnlockStateUnlocked) { - popup_reset(popup); - - if(nfc_worker_get_state(nfc->worker) == NfcWorkerStateNfcVUnlockAndSave) { - nfc_text_store_set( - nfc, - "%s/SLIX_%02X%02X%02X%02X%02X%02X%02X%02X%s", - NFC_APP_FOLDER, - nfc_data->uid[0], - nfc_data->uid[1], - nfc_data->uid[2], - nfc_data->uid[3], - nfc_data->uid[4], - nfc_data->uid[5], - nfc_data->uid[6], - nfc_data->uid[7], - NFC_APP_EXTENSION); - - nfc->dev->format = NfcDeviceSaveFormatNfcV; - - if(nfc_device_save(nfc->dev, nfc->text_store)) { - popup_set_header(popup, "Successfully\nsaved", 94, 3, AlignCenter, AlignTop); - } else { - popup_set_header( - popup, "Unlocked but\nsave failed!", 94, 3, AlignCenter, AlignTop); - } - } else { - popup_set_header(popup, "Successfully\nunlocked", 94, 3, AlignCenter, AlignTop); - } - - notification_message(nfc->notifications, &sequence_single_vibro); - //notification_message(nfc->notifications, &sequence_success); - - popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57); - popup_set_context(popup, nfc); - popup_set_callback(popup, nfc_scene_nfcv_unlock_popup_callback); - popup_set_timeout(popup, 1500); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - - } else if(state == NfcSceneNfcVUnlockStateAlreadyUnlocked) { - popup_reset(popup); - - popup_set_header(popup, "Already\nUnlocked!", 94, 3, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57); - popup_set_context(popup, nfc); - popup_set_callback(popup, nfc_scene_nfcv_unlock_popup_callback); - popup_set_timeout(popup, 1500); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - } else if(state == NfcSceneNfcVUnlockStateNotSupportedCard) { - popup_reset(popup); - popup_set_header(popup, "Wrong Type Of Card!", 64, 3, AlignCenter, AlignTop); - popup_set_text(popup, nfcv_data->error, 4, 22, AlignLeft, AlignTop); - popup_set_icon(popup, 73, 20, &I_DolphinCommon_56x48); - } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcVUnlock, state); - } -} - -void nfc_scene_nfcv_unlock_on_enter(void* context) { - Nfc* nfc = context; - - nfc_device_clear(nfc->dev); - // Setup view - nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateDetecting); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - - // Start worker - nfc_worker_start( - nfc->worker, - NfcWorkerStateNfcVUnlockAndSave, - &nfc->dev->dev_data, - nfc_scene_nfcv_unlock_worker_callback, - nfc); - - nfc_blink_read_start(nfc); -} - -bool nfc_scene_nfcv_unlock_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcWorkerEventCardDetected) { - nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateUnlocked); - consumed = true; - } else if(event.event == NfcWorkerEventAborted) { - nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateAlreadyUnlocked); - consumed = true; - } else if(event.event == NfcWorkerEventNoCardDetected) { - nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateDetecting); - consumed = true; - } else if(event.event == NfcWorkerEventWrongCardDetected) { - nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateNotSupportedCard); - } - } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneNfcVUnlockMenu); - } - return consumed; -} - -void nfc_scene_nfcv_unlock_on_exit(void* context) { - Nfc* nfc = context; - - // Stop worker - nfc_worker_stop(nfc->worker); - // Clear view - popup_reset(nfc->popup); - nfc_blink_stop(nfc); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneNfcVUnlock, NfcSceneNfcVUnlockStateIdle); -} diff --git a/applications/main/nfc/scenes/nfc_scene_nfcv_unlock_menu.c b/applications/main/nfc/scenes/nfc_scene_nfcv_unlock_menu.c deleted file mode 100644 index 9c4c81fbd..000000000 --- a/applications/main/nfc/scenes/nfc_scene_nfcv_unlock_menu.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "../nfc_i.h" -#include - -enum SubmenuIndex { - SubmenuIndexNfcVUnlockMenuManual, - SubmenuIndexNfcVUnlockMenuTonieBox, -}; - -void nfc_scene_nfcv_unlock_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_nfcv_unlock_menu_on_enter(void* context) { - Nfc* nfc = context; - Submenu* submenu = nfc->submenu; - - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVUnlockMenu); - submenu_add_item( - submenu, - "Enter PWD Manually", - SubmenuIndexNfcVUnlockMenuManual, - nfc_scene_nfcv_unlock_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Auth As TonieBox", - SubmenuIndexNfcVUnlockMenuTonieBox, - nfc_scene_nfcv_unlock_menu_submenu_callback, - nfc); - submenu_set_selected_item(submenu, state); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_nfcv_unlock_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexNfcVUnlockMenuManual) { - nfc->dev->dev_data.nfcv_data.auth_method = NfcVAuthMethodManual; - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVKeyInput); - consumed = true; - } else if(event.event == SubmenuIndexNfcVUnlockMenuTonieBox) { - nfc->dev->dev_data.nfcv_data.auth_method = NfcVAuthMethodTonieBox; - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlock); - DOLPHIN_DEED(DolphinDeedNfcRead); - consumed = true; - } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcVUnlockMenu, event.event); - } - return consumed; -} - -void nfc_scene_nfcv_unlock_menu_on_exit(void* context) { - Nfc* nfc = context; - - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_passport_auth.c b/applications/main/nfc/scenes/nfc_scene_passport_auth.c deleted file mode 100644 index c78c8b70e..000000000 --- a/applications/main/nfc/scenes/nfc_scene_passport_auth.c +++ /dev/null @@ -1,194 +0,0 @@ -#include "../nfc_i.h" - -#define TAG "PassportAuth" - -#define MRTD_AUTH_METHOD_COUNT 4 -// Must match MrtdAuthMethod size (lib/nfc/protocols/mrtd_helpers.h) - -typedef enum { - NfcScenePassportAuthSelectDob, - NfcScenePassportAuthSelectDoe, - NfcScenePassportAuthSelectDocNr, - NfcScenePassportAuthSelectMethod, - NfcScenePassportAuthSelectAuth, - NfcScenePassportAuthSelectSave, - NfcScenePassportAuthSelectLoad, -} NfcScenePassportAuthSelect; - -void nfc_scene_passport_auth_var_list_enter_callback(void* context, uint32_t index) { - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_passport_auth_method_changed(VariableItem* item) { - Nfc* nfc = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - nfc->dev->dev_data.mrtd_data.auth.method = index; - variable_item_set_current_value_text(item, mrtd_auth_method_string(index)); -} - -bool nfc_scene_passport_auth_load(Nfc* nfc) { - const DialogsFileBrowserOptions browser_options = { - .extension = MRTD_APP_EXTENSION, - .skip_assets = true, - .icon = &I_u2f_10px, - .hide_ext = true, - .item_loader_callback = NULL, - .item_loader_context = NULL, - }; - - FuriString* mrtd_app_folder; - mrtd_app_folder = furi_string_alloc_set(MRTD_APP_FOLDER); - - FuriString* file_path; - file_path = furi_string_alloc(); - - bool res = - dialog_file_browser_show(nfc->dev->dialogs, file_path, mrtd_app_folder, &browser_options); - - furi_string_free(mrtd_app_folder); - - if(res) { - mrtd_auth_params_load( - nfc->dev->storage, - nfc->dev->dialogs, - &nfc->dev->dev_data.mrtd_data.auth, - furi_string_get_cstr(file_path), - true); - - nfc_scene_passport_auth_on_enter(nfc); - variable_item_list_set_selected_item( - nfc->variable_item_list, NfcScenePassportAuthSelectAuth); - } - - return res; -} - -void nfc_scene_passport_auth_on_enter(void* context) { - Nfc* nfc = context; - MrtdData* mrtd_data = &nfc->dev->dev_data.mrtd_data; - - // By entering the Auth menu, we default to Auth: Any - MrtdAuthMethod* auth_method = &mrtd_data->auth.method; - if(*auth_method == MrtdAuthMethodNone) { - *auth_method = MrtdAuthMethodAny; - } - - VariableItemList* variable_item_list = nfc->variable_item_list; - variable_item_list_reset(variable_item_list); - - VariableItem* item; - uint8_t value_index; - - const size_t temp_str_size = 15; - char temp_str[temp_str_size]; - snprintf( - temp_str, - temp_str_size, - "%02u%02u%02u", - mrtd_data->auth.birth_date.year, - mrtd_data->auth.birth_date.month, - mrtd_data->auth.birth_date.day); - - item = variable_item_list_add(variable_item_list, "Birth Date", 1, NULL, NULL); - variable_item_set_current_value_text(item, temp_str); - - snprintf( - temp_str, - temp_str_size, - "%02u%02u%02u", - mrtd_data->auth.expiry_date.year, - mrtd_data->auth.expiry_date.month, - mrtd_data->auth.expiry_date.day); - - item = variable_item_list_add(variable_item_list, "Expiry Date", 1, NULL, NULL); - variable_item_set_current_value_text(item, temp_str); - - item = variable_item_list_add(variable_item_list, "Document Nr.", 1, NULL, NULL); - - strncpy(temp_str, mrtd_data->auth.doc_number, temp_str_size); - temp_str[temp_str_size] = '\x00'; - if(strlen(temp_str) > 8) { - temp_str[8] = '.'; - temp_str[9] = '.'; - temp_str[10] = '.'; - temp_str[11] = '\x00'; - } - variable_item_set_current_value_text(item, temp_str); - - item = variable_item_list_add( - variable_item_list, - "Method", - MRTD_AUTH_METHOD_COUNT, - nfc_scene_passport_auth_method_changed, - nfc); - - value_index = *auth_method; - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, mrtd_auth_method_string(value_index)); - - variable_item_list_add(variable_item_list, "Authenticate and read", 1, NULL, NULL); - - variable_item_list_add(variable_item_list, "Save parameters", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Load parameters", 1, NULL, NULL); - - variable_item_list_set_enter_callback( - variable_item_list, nfc_scene_passport_auth_var_list_enter_callback, nfc); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewVarItemList); -} - -bool nfc_scene_passport_auth_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - FURI_LOG_D(TAG, "event.event: %ld", event.event); - switch(event.event) { - case NfcScenePassportAuthSelectLoad: - nfc_scene_passport_auth_load(nfc); - consumed = true; - break; - case NfcScenePassportAuthSelectDob: - scene_manager_set_scene_state(nfc->scene_manager, NfcScenePassportDate, 0); - scene_manager_next_scene(nfc->scene_manager, NfcScenePassportDate); - consumed = true; - break; - case NfcScenePassportAuthSelectDoe: - scene_manager_set_scene_state(nfc->scene_manager, NfcScenePassportDate, 1); - scene_manager_next_scene(nfc->scene_manager, NfcScenePassportDate); - consumed = true; - break; - case NfcScenePassportAuthSelectDocNr: - scene_manager_next_scene(nfc->scene_manager, NfcScenePassportDocNr); - consumed = true; - break; - case NfcScenePassportAuthSelectMethod: - consumed = true; - break; - case NfcScenePassportAuthSelectAuth: - if(nfc->dev->dev_data.mrtd_data.auth.method == MrtdAuthMethodPace) { - scene_manager_next_scene(nfc->scene_manager, NfcScenePassportPaceTodo); - } else { - nfc_device_clear(nfc->dev); - scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); - } - consumed = true; - break; - case NfcScenePassportAuthSelectSave: - scene_manager_next_scene(nfc->scene_manager, NfcScenePassportAuthSaveName); - consumed = true; - break; - } - } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - - return consumed; -} - -void nfc_scene_passport_auth_on_exit(void* context) { - Nfc* nfc = context; - - // Clear view - variable_item_list_reset(nfc->variable_item_list); -} diff --git a/applications/main/nfc/scenes/nfc_scene_passport_auth_save_name.c b/applications/main/nfc/scenes/nfc_scene_passport_auth_save_name.c deleted file mode 100644 index 65fee0bcf..000000000 --- a/applications/main/nfc/scenes/nfc_scene_passport_auth_save_name.c +++ /dev/null @@ -1,82 +0,0 @@ -#include "../nfc_i.h" -#include -#include -#include - -void nfc_scene_passport_auth_save_name_text_input_callback(void* context) { - Nfc* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone); -} - -void nfc_scene_passport_auth_save_name_on_enter(void* context) { - Nfc* nfc = context; - - MrtdData* mrtd_data = &nfc->dev->dev_data.mrtd_data; - - // Setup view - TextInput* text_input = nfc->text_input; - bool docnr_empty = false; - if(!strcmp(mrtd_data->auth.doc_number, "")) { - set_random_name(nfc->text_store, sizeof(nfc->text_store)); - docnr_empty = true; - } else { - nfc_text_store_set(nfc, mrtd_data->auth.doc_number); - } - text_input_set_header_text(text_input, "Name the parameters"); - text_input_set_result_callback( - text_input, - nfc_scene_passport_auth_save_name_text_input_callback, - nfc, - nfc->text_store, - NFC_DEV_NAME_MAX_LEN, - docnr_empty); - - FuriString* folder_path; - folder_path = furi_string_alloc(); - - if(furi_string_end_with(nfc->dev->load_path, NFC_APP_EXTENSION)) { - path_extract_dirname(furi_string_get_cstr(nfc->dev->load_path), folder_path); - } else { - furi_string_set(folder_path, NFC_APP_FOLDER); - } - - ValidatorIsFile* validator_is_file = - validator_is_file_alloc_init(furi_string_get_cstr(folder_path), NFC_APP_EXTENSION, NULL); - text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput); - - furi_string_free(folder_path); -} - -bool nfc_scene_passport_auth_save_name_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - MrtdData* mrtd_data = &nfc->dev->dev_data.mrtd_data; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventTextInputDone) { - if(mrtd_auth_params_save( - nfc->dev->storage, nfc->dev->dialogs, &mrtd_data->auth, nfc->text_store)) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); - consumed = true; - } else { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneStart); - } - } - } - return consumed; -} - -void nfc_scene_passport_auth_save_name_on_exit(void* context) { - Nfc* nfc = context; - - // Clear view - void* validator_context = text_input_get_validator_callback_context(nfc->text_input); - text_input_set_validator(nfc->text_input, NULL, NULL); - validator_is_file_free(validator_context); - - text_input_reset(nfc->text_input); -} diff --git a/applications/main/nfc/scenes/nfc_scene_passport_date.c b/applications/main/nfc/scenes/nfc_scene_passport_date.c deleted file mode 100644 index 4dc174326..000000000 --- a/applications/main/nfc/scenes/nfc_scene_passport_date.c +++ /dev/null @@ -1,120 +0,0 @@ -#include "../nfc_i.h" -#include "m-string.h" -#include - -#define TAG "PassportDate" - -#define DATE_LENGTH 6 - -//TODO: use types in .h file? also in nfc_scene_passport_bac.c -#define NFC_PASSPORT_DATE_BIRTH 0 -#define NFC_PASSPORT_DATE_EXPIRY 1 - -void nfc_scene_passport_date_text_input_callback(void* context) { - Nfc* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone); -} - -void nfc_scene_passport_date_on_enter(void* context) { - Nfc* nfc = context; - - MrtdDate date_value; - - uint32_t date_type = scene_manager_get_scene_state(nfc->scene_manager, NfcScenePassportDate); - - //TODO: numbers only - TextInput* text_input = nfc->text_input; - - switch(date_type) { - case NFC_PASSPORT_DATE_BIRTH: - text_input_set_header_text(text_input, "Birth Date"); - date_value = nfc->dev->dev_data.mrtd_data.auth.birth_date; - break; - case NFC_PASSPORT_DATE_EXPIRY: - text_input_set_header_text(text_input, "Expiry Date"); - date_value = nfc->dev->dev_data.mrtd_data.auth.expiry_date; - break; - } - - bool date_empty = false; - if(date_value.year == 0 || date_value.month == 0 || date_value.day == 0 || - date_value.year > 100 || date_value.month > 13 || date_value.day > 31) { - nfc_text_store_set(nfc, "YYMMDD"); - date_empty = true; - } else { - char temp_str[10]; - snprintf(temp_str, 10, "%02u%02u%02u", date_value.year, date_value.month, date_value.day); - - memcpy(nfc->text_store, temp_str, DATE_LENGTH); - nfc->text_store[DATE_LENGTH] = '\x00'; - } - - text_input_set_result_callback( - text_input, - nfc_scene_passport_date_text_input_callback, - nfc, - nfc->text_store, - DATE_LENGTH + 1, // incl. '\x00' - date_empty); // Use as template - - //TODO: add validator for valid date (YYMMDD) - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput); -} - -bool nfc_scene_passport_date_save(Nfc* nfc) { - int year; - int month; - int day; - int ret = sscanf(nfc->text_store, "%02d%02d%02d", &year, &month, &day); - - if(ret != 3) { - FURI_LOG_E(TAG, "Invalid date entered (YYMMDD): %s", nfc->text_store); - return false; - } - - MrtdDate date_value; - date_value.year = year; - date_value.month = month; - date_value.day = day; - - uint32_t date_type = scene_manager_get_scene_state(nfc->scene_manager, NfcScenePassportDate); - - //TODO: use types in .h file? also in nfc_scene_passport_bac.c - switch(date_type) { - case NFC_PASSPORT_DATE_BIRTH: - nfc->dev->dev_data.mrtd_data.auth.birth_date = date_value; - break; - case NFC_PASSPORT_DATE_EXPIRY: - nfc->dev->dev_data.mrtd_data.auth.expiry_date = date_value; - break; - } - - return true; -} - -bool nfc_scene_passport_date_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventTextInputDone) { - nfc_scene_passport_date_save(nfc); - //TODO: handle invalid date (returned false) - - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcScenePassportAuth); - } - } - return consumed; -} - -void nfc_scene_passport_date_on_exit(void* context) { - Nfc* nfc = context; - - // Clear view - // TODO: clear validator - - text_input_reset(nfc->text_input); -} diff --git a/applications/main/nfc/scenes/nfc_scene_passport_docnr.c b/applications/main/nfc/scenes/nfc_scene_passport_docnr.c deleted file mode 100644 index 109415759..000000000 --- a/applications/main/nfc/scenes/nfc_scene_passport_docnr.c +++ /dev/null @@ -1,67 +0,0 @@ -#include "../nfc_i.h" -#include "m-string.h" -#include - -#define TAG "PassportDocnr" - -void nfc_scene_passport_docnr_text_input_callback(void* context) { - Nfc* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone); -} - -void nfc_scene_passport_docnr_on_enter(void* context) { - Nfc* nfc = context; - - TextInput* text_input = nfc->text_input; - text_input_set_header_text(text_input, "Document Nr."); - - char* docnr = nfc->dev->dev_data.mrtd_data.auth.doc_number; - bool docnr_empty = false; - - if(*docnr) { - nfc_text_store_set(nfc, docnr); - docnr_empty = false; - } else { - nfc_text_store_set(nfc, "PA7HJ34M8"); - docnr_empty = true; - } - - text_input_set_result_callback( - text_input, - nfc_scene_passport_docnr_text_input_callback, - nfc, - nfc->text_store, - MRTD_DOCNR_MAX_LENGTH, // incl. '\x00' - docnr_empty); // Use as template - - //TODO: add validator? - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput); -} - -bool nfc_scene_passport_docnr_save(Nfc* nfc) { - strncpy(nfc->dev->dev_data.mrtd_data.auth.doc_number, nfc->text_store, MRTD_DOCNR_MAX_LENGTH); - return true; -} - -bool nfc_scene_passport_docnr_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventTextInputDone) { - nfc_scene_passport_docnr_save(nfc); - - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcScenePassportAuth); - } - } - return consumed; -} - -void nfc_scene_passport_docnr_on_exit(void* context) { - Nfc* nfc = context; - - text_input_reset(nfc->text_input); -} diff --git a/applications/main/nfc/scenes/nfc_scene_passport_menu.c b/applications/main/nfc/scenes/nfc_scene_passport_menu.c deleted file mode 100644 index 27febcb18..000000000 --- a/applications/main/nfc/scenes/nfc_scene_passport_menu.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "../nfc_i.h" - -enum SubmenuIndex { - SubmenuIndexSave, - SubmenuIndexInfo, -}; - -void nfc_scene_passport_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_passport_menu_on_enter(void* context) { - Nfc* nfc = context; - Submenu* submenu = nfc->submenu; - - submenu_add_item( - submenu, "Save", SubmenuIndexSave, nfc_scene_passport_menu_submenu_callback, nfc); - submenu_add_item( - submenu, "Info", SubmenuIndexInfo, nfc_scene_passport_menu_submenu_callback, nfc); - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcScenePassportMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_passport_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexSave) { - //TODO: save more than just UID - nfc->dev->format = NfcDeviceSaveFormatUid; - // Clear device name - nfc_device_set_name(nfc->dev, ""); - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - consumed = true; - } else if(event.event == SubmenuIndexInfo) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); - consumed = true; - } - scene_manager_set_scene_state(nfc->scene_manager, NfcScenePassportMenu, event.event); - } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - - return consumed; -} - -void nfc_scene_passport_menu_on_exit(void* context) { - Nfc* nfc = context; - - // Clear view - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_passport_pace_todo.c b/applications/main/nfc/scenes/nfc_scene_passport_pace_todo.c deleted file mode 100644 index c6d7d7f6c..000000000 --- a/applications/main/nfc/scenes/nfc_scene_passport_pace_todo.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "../nfc_i.h" - -void nfc_scene_passport_pace_todo_popup_callback(void* context) { - Nfc* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -void nfc_scene_passport_pace_todo_on_enter(void* context) { - Nfc* nfc = context; - - // Setup view - Popup* popup = nfc->popup; - popup_set_icon(popup, 64, 16, &I_DolphinCommon_56x48); - popup_set_header(popup, "PACE not yet implemented", 4, 4, AlignLeft, AlignTop); - popup_set_timeout(popup, 2000); - popup_set_context(popup, nfc); - popup_set_callback(popup, nfc_scene_passport_pace_todo_popup_callback); - popup_enable_timeout(popup); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); -} - -bool nfc_scene_passport_pace_todo_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventViewExit) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcScenePassportAuth); - } - } - return consumed; -} - -void nfc_scene_passport_pace_todo_on_exit(void* context) { - Nfc* nfc = context; - - // Clear view - popup_reset(nfc->popup); -} diff --git a/applications/main/nfc/scenes/nfc_scene_passport_read.c b/applications/main/nfc/scenes/nfc_scene_passport_read.c deleted file mode 100644 index 74f173b52..000000000 --- a/applications/main/nfc/scenes/nfc_scene_passport_read.c +++ /dev/null @@ -1,90 +0,0 @@ -#include "../nfc_i.h" -#include - -void nfc_scene_passport_read_widget_callback(GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_passport_read_on_enter(void* context) { - Nfc* nfc = context; - FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; - MrtdData* mrtd_data = &nfc->dev->dev_data.mrtd_data; - - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - - Widget* widget = nfc->widget; - - // Setup Custom Widget view - FuriString* temp_str; - temp_str = furi_string_alloc(); - furi_string_set(temp_str, "\e#Passport\n"); - char iso_type = FURI_BIT(data->sak, 5) ? '4' : '3'; - - char nfc_type; - switch(data->type) { - case FuriHalNfcTypeA: - nfc_type = 'A'; - break; - case FuriHalNfcTypeB: - nfc_type = 'B'; - break; - default: - nfc_type = '?'; - break; - } - furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-%c)\n", iso_type, nfc_type); - furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", data->uid[i]); - } - furi_string_cat_printf(temp_str, "\nATQA: %02X %02X ", data->atqa[1], data->atqa[0]); - furi_string_cat_printf(temp_str, " SAK: %02X\n", data->sak); - - if(mrtd_data->auth.method != MrtdAuthMethodNone && !mrtd_data->auth_success) { - furi_string_cat_printf(temp_str, "Auth failed. Wrong params?"); - } - - widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); - furi_string_free(temp_str); - - widget_add_button_element( - nfc->widget, GuiButtonTypeLeft, "Retry", nfc_scene_passport_read_widget_callback, nfc); - widget_add_button_element( - nfc->widget, GuiButtonTypeCenter, "Auth", nfc_scene_passport_read_widget_callback, nfc); - widget_add_button_element( - nfc->widget, GuiButtonTypeRight, "More", nfc_scene_passport_read_widget_callback, nfc); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_passport_read_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeLeft) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); - consumed = true; - } else if(event.event == GuiButtonTypeCenter) { - scene_manager_next_scene(nfc->scene_manager, NfcScenePassportAuth); - consumed = true; - } else if(event.event == GuiButtonTypeRight) { - scene_manager_next_scene(nfc->scene_manager, NfcScenePassportMenu); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } - return consumed; -} - -void nfc_scene_passport_read_on_exit(void* context) { - Nfc* nfc = context; - - // Clear view - widget_reset(nfc->widget); -} diff --git a/applications/main/nfc/scenes/nfc_scene_passport_read_auth.c b/applications/main/nfc/scenes/nfc_scene_passport_read_auth.c deleted file mode 100644 index 31a9e8ce1..000000000 --- a/applications/main/nfc/scenes/nfc_scene_passport_read_auth.c +++ /dev/null @@ -1,142 +0,0 @@ -#include "../nfc_i.h" -#include - -const char months[13][4] = { - "---", - "JAN", - "FEB", - "MAR", - "APR", - "MAY", - "JUN", - "JUL", - "AUG", - "SEP", - "OCT", - "NOV", - "DEC", -}; - -void nfc_scene_passport_read_auth_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - Nfc* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_passport_read_auth_on_enter(void* context) { - Nfc* nfc = context; - MrtdData* mrtd_data = &nfc->dev->dev_data.mrtd_data; - - Widget* widget = nfc->widget; - - // Setup Custom Widget view - FuriString* temp_str; - temp_str = furi_string_alloc(); - furi_string_set(temp_str, "\e#Passport\n"); - furi_string_cat_printf( - temp_str, "Auth.method: %s\n", mrtd_auth_method_string(mrtd_data->auth_method_used)); - // TODO: indicate BAC / PACE used - - uint16_t lds_version = mrtd_data->files.EF_COM.lds_version; - furi_string_cat_printf(temp_str, "LDS version: %d.%d\n", lds_version / 100, lds_version % 100); - - uint32_t unicode_version = mrtd_data->files.EF_COM.unicode_version; - furi_string_cat_printf( - temp_str, - "Unicode version: %d.%d.%d\n", - (uint8_t)(unicode_version / 10000), - (uint8_t)(unicode_version / 100 % 100), - (uint8_t)(unicode_version % 100)); - - furi_string_cat_printf(temp_str, "Avail.files: "); - for(size_t i = 0; i < MAX_EFCOM_TAGS; ++i) { - uint8_t tag = mrtd_data->files.EF_COM.tag_list[i]; - const EFFile* file = mrtd_tag_to_file(tag); - if(file->tag) { - if(i > 0) furi_string_cat_printf(temp_str, ", "); - furi_string_cat_printf(temp_str, "%s", file->name); - } - } - furi_string_cat_printf(temp_str, "\n"); - - EF_DIR_contents* EF_DIR = &mrtd_data->files.EF_DIR; - if(EF_DIR->applications_count > 0) { - furi_string_cat_printf(temp_str, "Apps:\n"); - for(uint8_t i = 0; i < EF_DIR->applications_count; ++i) { - for(uint8_t n = 0; n < sizeof(AIDValue); ++n) { - furi_string_cat_printf(temp_str, "%02X ", EF_DIR->applications[i][n]); - } - furi_string_cat_printf(temp_str, "\n"); - } - } - - EF_DG1_contents* DG1 = &mrtd_data->files.DG1; - furi_string_cat_printf(temp_str, "\e#DG1\n"); - furi_string_cat_printf(temp_str, "Doc Type: %s\n", DG1->doctype); - furi_string_cat_printf(temp_str, "Issuing State: %s\n", DG1->issuing_state); - furi_string_cat_printf(temp_str, "Name: %s\n", DG1->name); - furi_string_cat_printf(temp_str, "DocNr: %s\n", DG1->docnr); - furi_string_cat_printf(temp_str, "Nationality: %s\n", DG1->nationality); - furi_string_cat_printf( - temp_str, - "Birth Date: %02d %s %02d\n", - DG1->birth_date.day, - months[DG1->birth_date.month], - DG1->birth_date.year); - furi_string_cat_printf(temp_str, "Sex: %s\n", DG1->sex); - furi_string_cat_printf( - temp_str, - "Expiry Date: %02d %s %02d\n", - DG1->expiry_date.day, - months[DG1->expiry_date.month], - DG1->expiry_date.year); - - widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); - furi_string_free(temp_str); - - widget_add_button_element( - nfc->widget, GuiButtonTypeLeft, "Retry", nfc_scene_passport_read_auth_widget_callback, nfc); - /* - widget_add_button_element( - nfc->widget, GuiButtonTypeCenter, "Auth", nfc_scene_passport_read_auth_widget_callback, nfc); - widget_add_button_element( - nfc->widget, GuiButtonTypeRight, "More", nfc_scene_passport_read_auth_widget_callback, nfc); - */ - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_passport_read_auth_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeLeft) { - nfc->dev->dev_data.mrtd_data.auth_success = false; - nfc->dev->dev_data.mrtd_data.auth.method = MrtdAuthMethodNone; - scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); - consumed = true; - } else if(event.event == GuiButtonTypeCenter) { - //scene_manager_next_scene(nfc->scene_manager, NfcScenePassportAuth); - //consumed = true; - } else if(event.event == GuiButtonTypeRight) { - //scene_manager_next_scene(nfc->scene_manager, NfcScenePassportMenu); - //consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } - return consumed; -} - -void nfc_scene_passport_read_auth_on_exit(void* context) { - Nfc* nfc = context; - - // Clear view - widget_reset(nfc->widget); -} diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 7164a155f..4252883b2 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -25,12 +25,12 @@ void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) { if(state == NfcSceneReadStateDetecting) { popup_reset(nfc->popup); popup_set_text( - nfc->popup, "Apply Card To\nFlipper's Back", 97, 24, AlignCenter, AlignTop); + nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); } else if(state == NfcSceneReadStateReading) { popup_reset(nfc->popup); popup_set_header( - nfc->popup, "Reading Card\nDon't Move...", 85, 24, AlignCenter, AlignTop); + nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); popup_set_icon(nfc->popup, 12, 23, &A_Loading_24); } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, state); @@ -68,11 +68,6 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; - } else if(event.event == NfcWorkerEventReadNfcV) { - notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - consumed = true; } else if(event.event == NfcWorkerEventReadMfUltralight) { notification_message(nfc->notifications, &sequence_success); // Set unlock password input to 0xFFFFFFFF only on fresh read @@ -95,19 +90,6 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; - } else if(event.event == NfcWorkerEventReadPassport) { - notification_message(nfc->notifications, &sequence_success); - FURI_LOG_D( - "NFC", - "Read passport, auth: %d, success: %d", - nfc->dev->dev_data.mrtd_data.auth.method, - nfc->dev->dev_data.mrtd_data.auth_success); - if(nfc->dev->dev_data.mrtd_data.auth_success) { - scene_manager_next_scene(nfc->scene_manager, NfcScenePassportReadAuthSuccess); - } else { - scene_manager_next_scene(nfc->scene_manager, NfcScenePassportReadSuccess); - } - consumed = true; } else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack); diff --git a/applications/main/nfc/scenes/nfc_scene_rpc.c b/applications/main/nfc/scenes/nfc_scene_rpc.c index d06ee7564..60d01a30d 100644 --- a/applications/main/nfc/scenes/nfc_scene_rpc.c +++ b/applications/main/nfc/scenes/nfc_scene_rpc.c @@ -55,13 +55,6 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { &nfc->dev->dev_data, nfc_scene_rpc_emulate_callback, nfc); - } else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) { - nfc_worker_start( - nfc->worker, - NfcWorkerStateNfcVEmulate, - &nfc->dev->dev_data, - nfc_scene_rpc_emulate_callback, - nfc); } else { nfc_worker_start( nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc); diff --git a/applications/main/nfc/scenes/nfc_scene_save_name.c b/applications/main/nfc/scenes/nfc_scene_save_name.c index 8f0e889ec..007274226 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_name.c +++ b/applications/main/nfc/scenes/nfc_scene_save_name.c @@ -22,7 +22,7 @@ void nfc_scene_save_name_on_enter(void* context) { } else { nfc_text_store_set(nfc, nfc->dev->dev_name); } - text_input_set_header_text(text_input, "Name The Card"); + text_input_set_header_text(text_input, "Name the card"); text_input_set_result_callback( text_input, nfc_scene_save_name_text_input_callback, diff --git a/applications/main/nfc/scenes/nfc_scene_save_success.c b/applications/main/nfc/scenes/nfc_scene_save_success.c index 43f2246cd..34919cbd8 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_success.c +++ b/applications/main/nfc/scenes/nfc_scene_save_success.c @@ -31,12 +31,6 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneSavedMenu); - } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcScenePassportAuth)) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcScenePassportAuth); - } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneNfcDataInfo)) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneNfcDataInfo); } else { consumed = scene_manager_search_and_switch_to_another_scene( nfc->scene_manager, NfcSceneFileSelect); diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index 616dc0ef7..c0d3ed5c6 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -117,8 +117,6 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); - } else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateNfcV); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); } diff --git a/applications/main/nfc/views/dict_attack.c b/applications/main/nfc/views/dict_attack.c index 9ee9b1e15..a539e514b 100644 --- a/applications/main/nfc/views/dict_attack.c +++ b/applications/main/nfc/views/dict_attack.c @@ -32,7 +32,7 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) { DictAttackViewModel* m = model; if(m->state == DictAttackStateCardRemoved) { canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Lost The Tag!"); + canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Lost the tag!"); canvas_set_font(canvas, FontSecondary); elements_multiline_text_aligned( canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly."); @@ -69,7 +69,7 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) { } elements_progress_bar_with_text(canvas, 0, 20, 128, dict_progress, draw_str); canvas_set_font(canvas, FontSecondary); - snprintf(draw_str, sizeof(draw_str), "Keys Found: %d/%d", m->keys_found, m->keys_total); + snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total); canvas_draw_str_aligned(canvas, 0, 33, AlignLeft, AlignTop, draw_str); snprintf( draw_str, sizeof(draw_str), "Sectors Read: %d/%d", m->sectors_read, m->sectors_total); diff --git a/applications/plugins/scorched_tanks/LICENSE b/applications/plugins/scorched_tanks/LICENSE deleted file mode 100644 index f288702d2..000000000 --- a/applications/plugins/scorched_tanks/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/applications/plugins/scorched_tanks/README.md b/applications/plugins/scorched_tanks/README.md deleted file mode 100644 index 1c1970c19..000000000 --- a/applications/plugins/scorched_tanks/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Scorched tanks - flipper zero game -A flipper zero game inspired by scorched earth. - -Current state is shown below: - -![input](scorched_tanks_v1.gif) - -## How to do: -Do not hesitate to create PRs. If you start working on sth, please start branch name with TODO id (e.g. `feature/2-change-tank-icon`) - -If you see an improvement, modify this readme and add suggestions via PR. Bugs can be reported via Issues - -## What to do next (it's not in the priority order): -5. flatten surface beneath tanks -7. explosion animation -9. sub-ghz multi-player -11. add other types of weapons -12. code AI -13. add terain destruction -14. add terain gravity (fall down after hitting the middle of the mountain) -18. Add menu with settings (vibartion on/off, difficulty) -20. add more ground modifiers (currently there is only one hill in the middle, maybe 2 hills, skew map, etc) - -## What have been done: -1. ~~remove movement~~ -2. ~~change tank icon~~ -3. ~~power as variable not constant~~ -4. ~~better map generation: high, low regions~~ (continuation in point 20.) -6. ~~collision with the enemy~~ -8. ~~local multi-player~~ -10. ~~improve projectile trace draw on angles > 80~~ -15. ~~FIX: firing stops when bullet fly above the screen~~ -16. ~~Slightly randomize player and enemy spawn locations~~ -17. ~~Shooting vibration~~ -19. ~~Add wind~~ diff --git a/applications/plugins/scorched_tanks/application.fam b/applications/plugins/scorched_tanks/application.fam deleted file mode 100644 index fa0e6dd2b..000000000 --- a/applications/plugins/scorched_tanks/application.fam +++ /dev/null @@ -1,12 +0,0 @@ -App( - appid="Scorched_Tanks", - name="Scorched Tanks", - apptype=FlipperAppType.EXTERNAL, - entry_point="scorched_tanks_game_app", - cdefines=["APP_SCORCHED_TANKS_GAME"], - requires=["gui"], - stack_size=1 * 1024, - order=100, - fap_icon="scorchedTanks_10px.png", - fap_category="Games", -) diff --git a/applications/plugins/scorched_tanks/scorchedTanks_10px.png b/applications/plugins/scorched_tanks/scorchedTanks_10px.png deleted file mode 100644 index 6e1ae4c04b973c4015b6c4bb84ee6e806c4cde04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 614 zcmV-s0-61ZP)EX>4Tx04R}tkv&MmKpe$iQ$;Bi5j%)DWT;LSM5Q`P6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=;Wm6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La) z#baVNw<`9$B7gyeFoUSXOg)ia%)oPe-NVP%y9m$nKKJM7Q}QMQd?N82(+!JwgE+cr z>74h8L#!kz#OK8023?T&k?XR{Z=8z`3p_JqWK#3QA!4!E!Ey()lA#h$6NeR5qkJLj zvch?bvs$UK);;+PgL!Qw&2^e1h+_!}Bq2gZ4P{hdAwsK0iis5M$2|PQjz38*nOtQs zax9<<6_Voz|AXJ%nuV!JHz^ncx?gPjV-)Dw1)6o+{yw(t<_X|`2ClTWzuEw1KS{5* zweS(pzYSbmw>5bWxZDATo^;8O9LY~pC=`JAGy0|+Fn9|D*4*A&`#607GSt=b4RCM> zj1?(+-Q(T8oxS~grq$mM6zy{8hfi!q00006VoOIv00000008+zyMF)x010qNS#tmY zE+YT{E+YYWr9XB6000McNliru<_Z!C4+Jw!Hq!tA02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{002HoL_t&-(~Xcx3IH$+0yXsiU!I-{g>=zVz(I@#P@qa6 z+pYuxs05OvaWdDv_pck&lzjc|*yeeqF3;)U6GWsW10ayR(*OVf07*qoM6N<$g4ARE A`Tzg` diff --git a/applications/plugins/scorched_tanks/scorched_tanks_game_app.c b/applications/plugins/scorched_tanks/scorched_tanks_game_app.c deleted file mode 100644 index fd4c73ee7..000000000 --- a/applications/plugins/scorched_tanks/scorched_tanks_game_app.c +++ /dev/null @@ -1,540 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#define SCREEN_WIDTH 128 -#define SCREEN_HEIGHT 64 -#define PLAYER_INIT_LOCATION_X 20 -#define PLAYER_INIT_AIM 45 -#define PLAYER_INIT_POWER 50 -#define ENEMY_INIT_LOCATION_X 108 -#define TANK_BARREL_LENGTH 8 -#define GRAVITY_FORCE (double)0.5 -#define MIN_GROUND_HEIGHT 35 -#define MAX_GROUND_HEIGHT 55 -#define MAX_FIRE_POWER 100 -#define MIN_FIRE_POWER 0 -#define TANK_COLLIDER_SIZE 3 -#define MAX_WIND 10 -#define MAX_PLAYER_DIFF_X 20 -#define MAX_ENEMY_DIFF_X 20 - -// That's a filthy workaround but sin(player.aimAngle) breaks it all... If you're able to fix it, please do create a PR! -double scorched_tanks_sin[91] = { - 0.000, -0.017, -0.035, -0.052, -0.070, -0.087, -0.105, -0.122, -0.139, -0.156, -0.174, -0.191, - -0.208, -0.225, -0.242, -0.259, -0.276, -0.292, -0.309, -0.326, -0.342, -0.358, -0.375, -0.391, - -0.407, -0.423, -0.438, -0.454, -0.469, -0.485, -0.500, -0.515, -0.530, -0.545, -0.559, -0.574, - -0.588, -0.602, -0.616, -0.629, -0.643, -0.656, -0.669, -0.682, -0.695, -0.707, -0.719, -0.731, - -0.743, -0.755, -0.766, -0.777, -0.788, -0.799, -0.809, -0.819, -0.829, -0.839, -0.848, -0.857, - -0.866, -0.875, -0.883, -0.891, -0.899, -0.906, -0.914, -0.921, -0.927, -0.934, -0.940, -0.946, - -0.951, -0.956, -0.961, -0.966, -0.970, -0.974, -0.978, -0.982, -0.985, -0.988, -0.990, -0.993, - -0.995, -0.996, -0.998, -0.999, -0.999, -1.000, -1.000}; -double scorched_tanks_cos[91] = { - 1.000, 1.000, 0.999, 0.999, 0.998, 0.996, 0.995, 0.993, 0.990, 0.988, 0.985, 0.982, 0.978, - 0.974, 0.970, 0.966, 0.961, 0.956, 0.951, 0.946, 0.940, 0.934, 0.927, 0.921, 0.914, 0.906, - 0.899, 0.891, 0.883, 0.875, 0.866, 0.857, 0.848, 0.839, 0.829, 0.819, 0.809, 0.799, 0.788, - 0.777, 0.766, 0.755, 0.743, 0.731, 0.719, 0.707, 0.695, 0.682, 0.669, 0.656, 0.643, 0.629, - 0.616, 0.602, 0.588, 0.574, 0.559, 0.545, 0.530, 0.515, 0.500, 0.485, 0.469, 0.454, 0.438, - 0.423, 0.407, 0.391, 0.375, 0.358, 0.342, 0.326, 0.309, 0.292, 0.276, 0.259, 0.242, 0.225, - 0.208, 0.191, 0.174, 0.156, 0.139, 0.122, 0.105, 0.087, 0.070, 0.052, 0.035, 0.017, 0.000}; -double scorched_tanks_tan[91] = { - 0.000, -0.017, -0.035, -0.052, -0.070, -0.087, -0.105, -0.123, -0.141, -0.158, -0.176, - -0.194, -0.213, -0.231, -0.249, -0.268, -0.287, -0.306, -0.325, -0.344, -0.364, -0.384, - -0.404, -0.424, -0.445, -0.466, -0.488, -0.510, -0.532, -0.554, -0.577, -0.601, -0.625, - -0.649, -0.674, -0.700, -0.727, -0.754, -0.781, -0.810, -0.839, -0.869, -0.900, -0.932, - -0.966, -1.000, -1.036, -1.072, -1.111, -1.150, -1.192, -1.235, -1.280, -1.327, -1.376, - -1.428, -1.483, -1.540, -1.600, -1.664, -1.732, -1.804, -1.881, -1.963, -2.050, -2.144, - -2.246, -2.356, -2.475, -2.605, -2.747, -2.904, -3.078, -3.271, -3.487, -3.732, -4.011, - -4.331, -4.704, -5.144, -5.671, -6.313, -7.115, -8.144, -9.513, -11.429, -14.298, -19.077, - -28.627, -57.254, -90747.269}; -unsigned char scorched_tanks_ground_modifiers[SCREEN_WIDTH] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 28, 26, 24, 22, 20, - 18, 16, 14, 12, 10, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -typedef struct { - // +-----x - // | - // | - // y - uint8_t x; - uint8_t y; -} Point; - -typedef struct { - // +-----x - // | - // | - // y - double x; - double y; -} PointDetailed; - -typedef struct { - unsigned char locationX; - unsigned char hp; - int aimAngle; - unsigned char firePower; -} Tank; - -typedef struct { - Point ground[SCREEN_WIDTH]; - Tank player; - Tank enemy; - bool isPlayerTurn; - bool isShooting; - int windSpeed; - Point trajectory[SCREEN_WIDTH]; - unsigned char trajectoryAnimationStep; - PointDetailed bulletPosition; - PointDetailed bulletVector; -} Game; - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} ScorchedTanksEvent; - -int scorched_tanks_random(int min, int max) { - return min + rand() % ((max + 1) - min); -} - -void scorched_tanks_generate_ground(Game* game_state) { - int lastHeight = 45; - - for(unsigned char a = 0; a < SCREEN_WIDTH; a++) { - int diffHeight = scorched_tanks_random(-2, 3); - int changeLength = scorched_tanks_random(1, 6); - - if(diffHeight == 0) { - changeLength = 1; - } - - for(int b = 0; b < changeLength; b++) { - if(a + b < SCREEN_WIDTH) { - int index = a + b; - int newPoint = lastHeight + diffHeight; - newPoint = newPoint < MIN_GROUND_HEIGHT ? MIN_GROUND_HEIGHT : newPoint; - newPoint = newPoint > MAX_GROUND_HEIGHT ? MAX_GROUND_HEIGHT : newPoint; - game_state->ground[index].x = index; - game_state->ground[index].y = newPoint - scorched_tanks_ground_modifiers[a]; - lastHeight = newPoint; - } else { - a += b; - break; - } - } - - a += changeLength - 1; - } -} - -void scorched_tanks_init_game(Game* game_state) { - game_state->player.locationX = PLAYER_INIT_LOCATION_X + - scorched_tanks_random(0, MAX_PLAYER_DIFF_X) - - MAX_PLAYER_DIFF_X / 2; - game_state->player.aimAngle = PLAYER_INIT_AIM; - game_state->player.firePower = PLAYER_INIT_POWER; - game_state->enemy.aimAngle = PLAYER_INIT_AIM; - game_state->enemy.firePower = PLAYER_INIT_POWER; - game_state->enemy.locationX = - ENEMY_INIT_LOCATION_X + scorched_tanks_random(0, MAX_ENEMY_DIFF_X) - MAX_ENEMY_DIFF_X / 2; - game_state->isPlayerTurn = true; - - game_state->windSpeed = scorched_tanks_random(0, MAX_WIND); - - for(int x = 0; x < SCREEN_WIDTH; x++) { - game_state->trajectory[x].x = 0; - game_state->trajectory[x].y = 0; - } - - scorched_tanks_generate_ground(game_state); -} - -void scorched_tanks_calculate_trajectory(Game* game_state) { - if(game_state->isShooting) { - game_state->bulletVector.x += ((double)game_state->windSpeed - MAX_WIND / 2) / 40; - game_state->bulletVector.y += GRAVITY_FORCE; - - game_state->bulletPosition.x += game_state->bulletVector.x; - game_state->bulletPosition.y += game_state->bulletVector.y; - - int totalDistanceToEnemy = 100; - - if(game_state->isPlayerTurn) { - double distanceToEnemyX = game_state->enemy.locationX - game_state->bulletPosition.x; - double distanceToEnemyY = game_state->ground[game_state->enemy.locationX].y - - TANK_COLLIDER_SIZE - game_state->bulletPosition.y; - totalDistanceToEnemy = - sqrt(distanceToEnemyX * distanceToEnemyX + distanceToEnemyY * distanceToEnemyY); - } else { - double distanceToEnemyX = game_state->player.locationX - game_state->bulletPosition.x; - double distanceToEnemyY = game_state->ground[game_state->player.locationX].y - - TANK_COLLIDER_SIZE - game_state->bulletPosition.y; - totalDistanceToEnemy = - sqrt(distanceToEnemyX * distanceToEnemyX + distanceToEnemyY * distanceToEnemyY); - } - - if(totalDistanceToEnemy <= TANK_COLLIDER_SIZE) { - game_state->isShooting = false; - scorched_tanks_init_game(game_state); - game_state->isPlayerTurn = !game_state->isPlayerTurn; - return; - } - - if(game_state->bulletPosition.x > SCREEN_WIDTH || - game_state->bulletPosition.y > - game_state->ground[(int)round(game_state->bulletPosition.x)].y) { - game_state->isShooting = false; - game_state->bulletPosition.x = 0; - game_state->bulletPosition.y = 0; - game_state->windSpeed = scorched_tanks_random(0, MAX_WIND); - game_state->isPlayerTurn = !game_state->isPlayerTurn; - return; - } - - if(game_state->bulletPosition.y > 0) { - game_state->trajectory[game_state->trajectoryAnimationStep].x = - round(game_state->bulletPosition.x); - game_state->trajectory[game_state->trajectoryAnimationStep].y = - round(game_state->bulletPosition.y); - game_state->trajectoryAnimationStep++; - } - } -} - -static void scorched_tanks_draw_tank( - Canvas* const canvas, - unsigned char x, - unsigned char y, - bool isPlayer) { - unsigned char lineIndex = 0; - - if(isPlayer) { - // Draw tank base - canvas_draw_line(canvas, x - 3, y - lineIndex, x + 3, y - lineIndex++); - canvas_draw_line(canvas, x - 4, y - lineIndex, x + 4, y - lineIndex++); - canvas_draw_line(canvas, x - 4, y - lineIndex, x + 4, y - lineIndex++); - - // draw turret - canvas_draw_line(canvas, x - 2, y - lineIndex, x + 1, y - lineIndex++); - canvas_draw_line(canvas, x - 2, y - lineIndex, x, y - lineIndex++); - } else { - // Draw tank base - canvas_draw_line(canvas, x - 3, y - lineIndex, x + 3, y - lineIndex++); - canvas_draw_line(canvas, x - 4, y - lineIndex, x + 4, y - lineIndex++); - canvas_draw_line(canvas, x - 4, y - lineIndex, x + 4, y - lineIndex++); - - // draw turret - canvas_draw_line(canvas, x - 1, y - lineIndex, x + 2, y - lineIndex++); - canvas_draw_line(canvas, x, y - lineIndex, x + 2, y - lineIndex++); - } -} - -static void scorched_tanks_render_callback(Canvas* const canvas, void* ctx) { - const Game* game_state = acquire_mutex((ValueMutex*)ctx, 25); - - if(game_state == NULL) { - return; - } - - canvas_draw_frame(canvas, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - - canvas_set_color(canvas, ColorBlack); - - if(game_state->isShooting) { - canvas_draw_dot(canvas, game_state->bulletPosition.x, game_state->bulletPosition.y); - } - - for(int a = 1; a < SCREEN_WIDTH; a++) { - canvas_draw_line( - canvas, - game_state->ground[a - 1].x, - game_state->ground[a - 1].y, - game_state->ground[a].x, - game_state->ground[a].y); - - if(game_state->trajectory[a].y != 0) { - canvas_draw_dot(canvas, game_state->trajectory[a].x, game_state->trajectory[a].y); - } - } - - scorched_tanks_draw_tank( - canvas, - game_state->enemy.locationX, - game_state->ground[game_state->enemy.locationX].y - TANK_COLLIDER_SIZE, - true); - - scorched_tanks_draw_tank( - canvas, - game_state->player.locationX, - game_state->ground[game_state->player.locationX].y - TANK_COLLIDER_SIZE, - false); - - int aimX1 = 0; - int aimY1 = 0; - int aimX2 = 0; - int aimY2 = 0; - - if(game_state->isPlayerTurn) { - aimX1 = game_state->player.locationX; - aimY1 = game_state->ground[game_state->player.locationX].y - TANK_COLLIDER_SIZE; - - double sinFromAngle = scorched_tanks_sin[game_state->player.aimAngle]; - double cosFromAngle = scorched_tanks_cos[game_state->player.aimAngle]; - aimX2 = aimX1 + TANK_BARREL_LENGTH * cosFromAngle; - aimY2 = aimY1 + TANK_BARREL_LENGTH * sinFromAngle; - - aimX1 += 1; - aimX2 += 1; - } else { - aimX1 = game_state->enemy.locationX; - aimY1 = game_state->ground[game_state->enemy.locationX].y - TANK_COLLIDER_SIZE; - - double sinFromAngle = scorched_tanks_sin[game_state->enemy.aimAngle]; - double cosFromAngle = scorched_tanks_cos[game_state->enemy.aimAngle]; - aimX2 = aimX1 + TANK_BARREL_LENGTH * cosFromAngle; - aimY2 = aimY1 + TANK_BARREL_LENGTH * sinFromAngle; - - aimX2 = aimX1 - (aimX2 - aimX1); - - aimX1 -= 1; - aimX2 -= 1; - } - - canvas_draw_line(canvas, aimX1, aimY1 - 3, aimX2, aimY2 - 3); - - canvas_set_font(canvas, FontSecondary); - - char buffer2[12]; - snprintf(buffer2, sizeof(buffer2), "wind: %i", game_state->windSpeed - MAX_WIND / 2); - canvas_draw_str(canvas, 55, 10, buffer2); - - if(game_state->isPlayerTurn) { - canvas_draw_str(canvas, 93, 10, "player1"); - - char buffer[12]; - snprintf(buffer, sizeof(buffer), "a: %u", game_state->player.aimAngle); - canvas_draw_str(canvas, 2, 10, buffer); - - snprintf(buffer, sizeof(buffer), "p: %u", game_state->player.firePower); - canvas_draw_str(canvas, 27, 10, buffer); - } else { - canvas_draw_str(canvas, 93, 10, "player2"); - - char buffer[12]; - snprintf(buffer, sizeof(buffer), "a: %u", game_state->enemy.aimAngle); - canvas_draw_str(canvas, 2, 10, buffer); - - snprintf(buffer, sizeof(buffer), "p: %u", game_state->enemy.firePower); - canvas_draw_str(canvas, 27, 10, buffer); - } - - release_mutex((ValueMutex*)ctx, game_state); -} - -static void scorched_tanks_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - ScorchedTanksEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void scorched_tanks_update_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - ScorchedTanksEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -static void scorched_tanks_increase_power(Game* game_state) { - if(game_state->player.firePower < MAX_FIRE_POWER && !game_state->isShooting) { - if(game_state->isPlayerTurn && game_state->player.firePower < MAX_FIRE_POWER) { - game_state->player.firePower++; - } - - if(!game_state->isPlayerTurn && game_state->enemy.firePower < MAX_FIRE_POWER) { - game_state->enemy.firePower++; - } - } -} - -static void scorched_tanks_decrease_power(Game* game_state) { - if(game_state->player.firePower > MIN_FIRE_POWER && !game_state->isShooting) { - if(game_state->isPlayerTurn && game_state->player.firePower > MIN_FIRE_POWER) { - game_state->player.firePower--; - } - - if(!game_state->isPlayerTurn && game_state->enemy.firePower > MIN_FIRE_POWER) { - game_state->enemy.firePower--; - } - } -} - -static void scorched_tanks_aim_up(Game* game_state) { - if(!game_state->isShooting) { - if(game_state->isPlayerTurn && game_state->player.aimAngle < 90) { - game_state->player.aimAngle++; - } - - if(!game_state->isPlayerTurn && game_state->enemy.aimAngle < 90) { - game_state->enemy.aimAngle++; - } - } -} - -static void scorched_tanks_aim_down(Game* game_state) { - if(game_state->player.aimAngle > 0 && !game_state->isShooting) { - if(game_state->isPlayerTurn) { - game_state->player.aimAngle--; - } else { - game_state->enemy.aimAngle--; - } - } -} - -const NotificationSequence sequence_long_vibro = { - &message_vibro_on, - &message_delay_500, - &message_vibro_off, - NULL, -}; - -static void scorched_tanks_fire(Game* game_state) { - if(!game_state->isShooting) { - if(game_state->isPlayerTurn) { - double sinFromAngle = scorched_tanks_sin[game_state->player.aimAngle]; - double cosFromAngle = scorched_tanks_cos[game_state->player.aimAngle]; - unsigned char aimX1 = game_state->player.locationX; - unsigned char aimY1 = - game_state->ground[game_state->player.locationX].y - TANK_COLLIDER_SIZE; - int aimX2 = aimX1 + TANK_BARREL_LENGTH * cosFromAngle; - int aimY2 = aimY1 + TANK_BARREL_LENGTH * sinFromAngle; - game_state->bulletPosition.x = aimX2; - game_state->bulletPosition.y = aimY2; - game_state->bulletVector.x = scorched_tanks_cos[game_state->player.aimAngle] * - ((double)game_state->player.firePower / 10); - game_state->bulletVector.y = scorched_tanks_sin[game_state->player.aimAngle] * - ((double)game_state->player.firePower / 10); - } else { - double sinFromAngle = scorched_tanks_sin[game_state->enemy.aimAngle]; - double cosFromAngle = scorched_tanks_cos[game_state->enemy.aimAngle]; - unsigned char aimX1 = game_state->enemy.locationX; - unsigned char aimY1 = - game_state->ground[game_state->enemy.locationX].y - TANK_COLLIDER_SIZE; - int aimX2 = aimX1 + TANK_BARREL_LENGTH * cosFromAngle; - int aimY2 = aimY1 + TANK_BARREL_LENGTH * sinFromAngle; - aimX2 = aimX1 - (aimX2 - aimX1); - - game_state->bulletPosition.x = aimX2; - game_state->bulletPosition.y = aimY2; - game_state->bulletVector.x = -scorched_tanks_cos[game_state->enemy.aimAngle] * - ((double)game_state->enemy.firePower / 10); - game_state->bulletVector.y = scorched_tanks_sin[game_state->enemy.aimAngle] * - ((double)game_state->enemy.firePower / 10); - } - - game_state->trajectoryAnimationStep = 0; - - for(int x = 0; x < SCREEN_WIDTH; x++) { - game_state->trajectory[x].x = 0; - game_state->trajectory[x].y = 0; - } - - game_state->isShooting = true; - - NotificationApp* notification = furi_record_open("notification"); - notification_message(notification, &sequence_long_vibro); - notification_message(notification, &sequence_blink_white_100); - furi_record_close("notification"); - } -} - -int32_t scorched_tanks_game_app(void* p) { - UNUSED(p); - srand(DWT->CYCCNT); - - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(ScorchedTanksEvent)); - - Game* game_state = malloc(sizeof(Game)); - scorched_tanks_init_game(game_state); - - ValueMutex state_mutex; - if(!init_mutex(&state_mutex, game_state, sizeof(ScorchedTanksEvent))) { - FURI_LOG_E("ScorchedTanks", "cannot create mutex\r\n"); - free(game_state); - return 255; - } - - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, scorched_tanks_render_callback, &state_mutex); - view_port_input_callback_set(view_port, scorched_tanks_input_callback, event_queue); - - FuriTimer* timer = - furi_timer_alloc(scorched_tanks_update_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, 2000); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - ScorchedTanksEvent event; - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 50); - - if(event.type == EventTypeKey) { // && game->isPlayerTurn - if(event.input.type == InputTypeRepeat || event.input.type == InputTypeShort) { - switch(event.input.key) { - case InputKeyUp: - scorched_tanks_aim_up(game_state); - break; - case InputKeyDown: - scorched_tanks_aim_down(game_state); - break; - case InputKeyRight: - scorched_tanks_increase_power(game_state); - break; - case InputKeyLeft: - scorched_tanks_decrease_power(game_state); - break; - case InputKeyOk: - scorched_tanks_fire(game_state); - break; - case InputKeyBack: - processing = false; - break; - default: - break; - } - } - } else if(event.type == EventTypeTick) { - scorched_tanks_calculate_trajectory(game_state); - } - - view_port_update(view_port); - release_mutex(&state_mutex, game_state); - } - - furi_timer_free(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_message_queue_free(event_queue); - delete_mutex(&state_mutex); - free(game_state); - - return 0; -} diff --git a/applications/plugins/scorched_tanks/scorched_tanks_v1.gif b/applications/plugins/scorched_tanks/scorched_tanks_v1.gif deleted file mode 100644 index 45b2ce117a4e9c56705397c95873c0416cf5e5bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 139343 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 diff --git a/applications/plugins/usbkeyboard/views/usb_hid_keyboard.c b/applications/plugins/usbkeyboard/views/usb_hid_keyboard.c index 18b278685..f8e61e4c3 100644 --- a/applications/plugins/usbkeyboard/views/usb_hid_keyboard.c +++ b/applications/plugins/usbkeyboard/views/usb_hid_keyboard.c @@ -43,7 +43,7 @@ typedef struct { #define KEY_WIDTH 9 #define KEY_HEIGHT 12 #define KEY_PADDING 1 -#define ROW_COUNT 6 +#define ROW_COUNT 7 #define COLUMN_COUNT 12 // 0 width items are not drawn, but there value is used diff --git a/applications/services/desktop/scenes/desktop_scene_lock_menu.c b/applications/services/desktop/scenes/desktop_scene_lock_menu.c index 6f3d14749..d5582bf76 100644 --- a/applications/services/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/services/desktop/scenes/desktop_scene_lock_menu.c @@ -11,7 +11,6 @@ #include "desktop_scene_i.h" #include "desktop_scene.h" #include "../helpers/pin_lock.h" -#include #define TAG "DesktopSceneLock" @@ -69,33 +68,12 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { } consumed = true; break; - case DesktopLockMenuEventPinLockShutdown: - if(desktop->settings.pin_code.length > 0) { - desktop_pin_lock(&desktop->settings); - desktop_lock(desktop); - } else { - LoaderStatus status = - loader_start(desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG); - if(status == LoaderStatusOk) { - scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 1); - } else { - FURI_LOG_E(TAG, "Unable to start desktop settings"); - } - } - consumed = true; - Power* power = furi_record_open(RECORD_POWER); - furi_delay_ms(666); - power_off(power); - furi_record_close(RECORD_POWER); - break; - case DesktopLockMenuEventExit: - scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); - case DesktopLockMenuEventDummyModeOn: + case DesktopLockMenuEventSFWModeOn: desktop_set_sfw_mode_state(desktop, true); scene_manager_search_and_switch_to_previous_scene( desktop->scene_manager, DesktopSceneMain); break; - case DesktopLockMenuEventDummyModeOff: + case DesktopLockMenuEventSFWModeOff: desktop_set_sfw_mode_state(desktop, false); scene_manager_search_and_switch_to_previous_scene( desktop->scene_manager, DesktopSceneMain); @@ -111,4 +89,4 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { void desktop_scene_lock_menu_on_exit(void* context) { UNUSED(context); -} +} \ No newline at end of file diff --git a/applications/services/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h index 3c9cfab8f..82ca43c4c 100644 --- a/applications/services/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -43,8 +43,8 @@ typedef enum { DesktopLockMenuEventPinLock, DesktopLockMenuEventPinLockShutdown, DesktopLockMenuEventExit, - DesktopLockMenuEventDummyModeOn, - DesktopLockMenuEventDummyModeOff, + DesktopLockMenuEventSFWModeOn, + DesktopLockMenuEventSFWModeOff, DesktopAnimationEventCheckAnimation, DesktopAnimationEventNewIdleAnimation, diff --git a/applications/services/desktop/views/desktop_view_lock_menu.c b/applications/services/desktop/views/desktop_view_lock_menu.c index 60083e499..77eedcb8c 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.c +++ b/applications/services/desktop/views/desktop_view_lock_menu.c @@ -9,19 +9,11 @@ #define LOCK_MENU_ITEMS_NB 5 -static void desktop_view_lock_menu_sfwmode_changed(bool isThisGameMode) { - DesktopSettingsApp* app = malloc(sizeof(DesktopSettingsApp)); - DESKTOP_SETTINGS_LOAD(&app->settings); - app->settings.is_sfwmode = isThisGameMode; - DESKTOP_SETTINGS_SAVE(&app->settings); -} - typedef enum { DesktopLockMenuIndexLock, DesktopLockMenuIndexPinLock, DesktopLockMenuIndexPinLockShutdown, - // DesktopLockMenuIndexGameMode, - DesktopLockMenuIndexDummy, + DesktopLockMenuIndexSFW, DesktopLockMenuIndexTotalCount } DesktopLockMenuIndex; @@ -83,9 +75,7 @@ void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) { } else { str = "Set PIN + Off"; } - // } else if(i == DesktopLockMenuIndexGameMode) { - // str = "Games Mode"; - } else if(i == DesktopLockMenuIndexDummy) { + } else if(i == DesktopLockMenuIndexSFW) { if(m->sfw_mode) { str = "NSFW Mode"; } else { @@ -155,12 +145,12 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { // desktop_view_lock_menu_sfwmode_changed(1); // DOLPHIN_DEED(getRandomDeed()); // lock_menu->callback(DesktopLockMenuEventExit, lock_menu->context); - } else if(idx == DesktopLockMenuIndexDummy) { + } else if(idx == DesktopLockMenuIndexSFW) { // DOLPHIN_DEED(getRandomDeed()); if((sfw_mode == false) && (event->type == InputTypeShort)) { - lock_menu->callback(DesktopLockMenuEventDummyModeOn, lock_menu->context); + lock_menu->callback(DesktopLockMenuEventSFWModeOn, lock_menu->context); } else if((sfw_mode == true) && (event->type == InputTypeShort)) { - lock_menu->callback(DesktopLockMenuEventDummyModeOff, lock_menu->context); + lock_menu->callback(DesktopLockMenuEventSFWModeOff, lock_menu->context); } } consumed = true; diff --git a/applications/services/dolphin/helpers/dolphin_state.c b/applications/services/dolphin/helpers/dolphin_state.c index 806259b69..eb34e87ea 100644 --- a/applications/services/dolphin/helpers/dolphin_state.c +++ b/applications/services/dolphin/helpers/dolphin_state.c @@ -81,7 +81,7 @@ uint64_t dolphin_state_timestamp() { return furi_hal_rtc_datetime_to_timestamp(&datetime); } -bool dolphin_state_is_levelup(uint32_t icounter) { +bool dolphin_state_is_levelup(int icounter) { for (int i = 0; i<30; ++i) { if ((icounter == level_array[i])) { return true; @@ -90,7 +90,7 @@ bool dolphin_state_is_levelup(uint32_t icounter) { return false; } -uint8_t dolphin_get_level(uint32_t icounter) { +uint8_t dolphin_get_level(int icounter) { for (int i = 0; i < 29; ++i) { if (icounter <= level_array[i]) { return i + 1; @@ -99,7 +99,7 @@ for (int i = 0; i < 29; ++i) { return 30; } -uint32_t dolphin_state_xp_above_last_levelup(uint32_t icounter) { +uint32_t dolphin_state_xp_above_last_levelup(int icounter) { if(level_array[0] > icounter) { for(int i = 1; i < 29; ++i) { if(icounter <= level_array[i]) { @@ -110,7 +110,7 @@ uint32_t dolphin_state_xp_above_last_levelup(uint32_t icounter) { return icounter; } -uint32_t dolphin_state_xp_to_levelup(uint32_t icounter) { +uint32_t dolphin_state_xp_to_levelup(int icounter) { for(int i = 0; i < 29; ++i) { if(icounter <= level_array[i]) { return level_array[i] - icounter; diff --git a/applications/services/dolphin/helpers/dolphin_state.h b/applications/services/dolphin/helpers/dolphin_state.h index 3e02fb872..edd7878e9 100644 --- a/applications/services/dolphin/helpers/dolphin_state.h +++ b/applications/services/dolphin/helpers/dolphin_state.h @@ -37,12 +37,12 @@ void dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed); void dolphin_state_butthurted(DolphinState* dolphin_state); -uint32_t dolphin_state_xp_to_levelup(uint32_t icounter); +uint32_t dolphin_state_xp_to_levelup(int icounter); -uint32_t dolphin_state_xp_above_last_levelup(uint32_t icounter); +uint32_t dolphin_state_xp_above_last_levelup(int icounter); -bool dolphin_state_is_levelup(uint32_t icounter); +bool dolphin_state_is_levelup(int icounter); void dolphin_state_increase_level(DolphinState* dolphin_state); -uint8_t dolphin_get_level(uint32_t icounter); +uint8_t dolphin_get_level(int icounter); diff --git a/applications/services/gui/modules/file_browser_worker.c b/applications/services/gui/modules/file_browser_worker.c index 9f99617a1..eadc7f219 100644 --- a/applications/services/gui/modules/file_browser_worker.c +++ b/applications/services/gui/modules/file_browser_worker.c @@ -386,7 +386,6 @@ BrowserWorker* file_browser_worker_alloc( browser->filter_extension = furi_string_alloc_set(filter_ext); browser->skip_assets = skip_assets; browser->hide_dot_files = hide_dot_files; - browser->path_start = furi_string_alloc_set(path); browser->path_current = furi_string_alloc_set(path); browser->path_next = furi_string_alloc_set(path); @@ -494,4 +493,4 @@ void file_browser_worker_load(BrowserWorker* browser, uint32_t offset, uint32_t browser->load_offset = offset; browser->load_count = count; furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtLoad); -} +} \ No newline at end of file diff --git a/applications/services/gui/modules/file_browser_worker.h b/applications/services/gui/modules/file_browser_worker.h index 3b4be6aa7..3b1373c14 100644 --- a/applications/services/gui/modules/file_browser_worker.h +++ b/applications/services/gui/modules/file_browser_worker.h @@ -67,4 +67,4 @@ void file_browser_worker_load(BrowserWorker* browser, uint32_t offset, uint32_t #ifdef __cplusplus } -#endif +#endif \ No newline at end of file diff --git a/applications/services/infraredsrv/infrared_cli.c b/applications/services/infraredsrv/infrared_cli.c index 5f5e2d4bb..b584919ea 100644 --- a/applications/services/infraredsrv/infrared_cli.c +++ b/applications/services/infraredsrv/infrared_cli.c @@ -455,7 +455,7 @@ static void } while(false); furi_string_free(remote_path); - infrared_brute_force_reset(brute_force); + //infrared_brute_force_reset(brute_force); infrared_brute_force_free(brute_force); } diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index e648342e1..8636137b7 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -48,18 +48,13 @@ static void loader_menu_callback(void* _ctx, uint32_t index) { furi_assert(application->app); furi_assert(application->name); - furi_assert(application->link); - if(strcmp(application->link, "NULL") != 0) { - LoaderStatus status = loader_start(NULL, "Applications", application->link); - } else { - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return; - } - - loader_start_application(application, NULL); + if(!loader_lock(loader_instance)) { + FURI_LOG_E(TAG, "Loader is locked"); + return; } + + loader_start_application(application, NULL); } static void loader_submenu_callback(void* context, uint32_t index) { diff --git a/applications/settings/dolphin_passport/passport.c b/applications/settings/dolphin_passport/passport.c index ea7f823c9..36d97da47 100644 --- a/applications/settings/dolphin_passport/passport.c +++ b/applications/settings/dolphin_passport/passport.c @@ -12,18 +12,15 @@ #define MOODS_TOTAL 3 #define BUTTHURT_MAX 3 -static const Icon* const portrait_happy[BUTTHURT_MAX] = { - &I_flipper}; +static const Icon* const portrait_happy[BUTTHURT_MAX] = {&I_flipper}; // &I_passport_happy1_46x49, // &I_passport_happy2_46x49, // &I_passport_happy3_46x49}; -static const Icon* const portrait_ok[BUTTHURT_MAX] = { - &I_flipper}; +static const Icon* const portrait_ok[BUTTHURT_MAX] = {&I_flipper}; // &I_passport_okay1_46x49, // &I_passport_okay2_46x49, // &I_passport_okay3_46x49}; -static const Icon* const portrait_bad[BUTTHURT_MAX] = { - &I_flipper}; +static const Icon* const portrait_bad[BUTTHURT_MAX] = {&I_flipper}; // &I_passport_bad1_46x49, // &I_passport_bad2_46x49, // &I_passport_bad3_46x49}; @@ -43,37 +40,39 @@ static void render_callback(Canvas* canvas, void* ctx) { DolphinStats* stats = ctx; DesktopSettings* settings = malloc(sizeof(DesktopSettings)); - DESKTOP_SETTINGS_LOAD(settings) + DESKTOP_SETTINGS_LOAD(settings); char level_str[20]; char xp_str[12]; char mood_str[32]; uint8_t mood = 0; - if(Settings->sfw_mode) ( - if(stats->butthurt <= 4) { - mood = 0; - snprintf(mood_str, 20, "Mood: Happy"); - } else if(stats->butthurt <= 9) { - mood = 1; - snprintf(mood_str, 20, "Mood: Okay"); - } else { - mood = 2; - snprintf(mood_str, 20, "Mood: Angry"); - } - ) else ( - if(stats->butthurt <= 4) { - mood = 0; - snprintf(mood_str, 20, "Status: Wet"); - } else if(stats->butthurt <= 9) { - mood = 1; - snprintf(mood_str, 20, "Status: Horny"); - } else { - mood = 2; - snprintf(mood_str, 20, "Status: Desperate"); - } + if(settings->sfw_mode) + { + if(stats->butthurt <= 4) { + mood = 0; + snprintf(mood_str, 20, "Mood: Happy"); + } else if(stats->butthurt <= 9) { + mood = 1; + snprintf(mood_str, 20, "Mood: Okay"); + } else { + mood = 2; + snprintf(mood_str, 20, "Mood: Angry"); + }} + else + { + if(stats->butthurt <= 4) { + mood = 0; + snprintf(mood_str, 20, "Status: Wet"); + } else if(stats->butthurt <= 9) { + mood = 1; + snprintf(mood_str, 20, "Status: Horny"); + } else { + mood = 2; + snprintf(mood_str, 20, "Status: Desperate"); + } - ) + }; uint32_t xp_progress = 0; uint32_t xp_to_levelup = dolphin_state_xp_to_levelup(stats->icounter); uint32_t xp_above_last_levelup = dolphin_state_xp_above_last_levelup(stats->icounter); @@ -109,7 +108,6 @@ static void render_callback(Canvas* canvas, void* ctx) { canvas_set_color(canvas, ColorWhite); canvas_draw_box(canvas, 123 - xp_progress, 45, xp_progress + 1, 5); canvas_set_color(canvas, ColorBlack); - free(settings); } diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 1ef4999b9..02e56b233 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,11.4,, +Version,v,14.2,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -846,7 +846,7 @@ Function,+,file_browser_set_callback,void,"FileBrowser*, FileBrowserCallback, vo Function,+,file_browser_set_item_callback,void,"FileBrowser*, FileBrowserLoadItemCallback, void*" Function,+,file_browser_start,void,"FileBrowser*, FuriString*" Function,+,file_browser_stop,void,FileBrowser* -Function,+,file_browser_worker_alloc,BrowserWorker*,"FuriString*, const char*, const char*, _Bool, _Bool" +Function,?,file_browser_worker_alloc,BrowserWorker*,"FuriString*, const char*, const char*, _Bool, _Bool" Function,+,file_browser_worker_folder_enter,void,"BrowserWorker*, FuriString*, int32_t" Function,+,file_browser_worker_folder_exit,void,BrowserWorker* Function,+,file_browser_worker_folder_refresh,void,"BrowserWorker*, int32_t" @@ -854,7 +854,7 @@ Function,+,file_browser_worker_free,void,BrowserWorker* Function,+,file_browser_worker_is_in_start_folder,_Bool,BrowserWorker* Function,+,file_browser_worker_load,void,"BrowserWorker*, uint32_t, uint32_t" Function,+,file_browser_worker_set_callback_context,void,"BrowserWorker*, void*" -Function,+,file_browser_worker_set_config,void,"BrowserWorker*, FuriString*, const char*, _Bool, _Bool" +Function,?,file_browser_worker_set_config,void,"BrowserWorker*, FuriString*, const char*, _Bool, _Bool" Function,+,file_browser_worker_set_folder_callback,void,"BrowserWorker*, BrowserWorkerFolderOpenCallback" Function,+,file_browser_worker_set_item_callback,void,"BrowserWorker*, BrowserWorkerListItemCallback" Function,+,file_browser_worker_set_list_callback,void,"BrowserWorker*, BrowserWorkerListLoadCallback" diff --git a/site_scons/cc.scons b/site_scons/cc.scons index 5c7df2575..95888dc95 100644 --- a/site_scons/cc.scons +++ b/site_scons/cc.scons @@ -21,14 +21,11 @@ ENV.AppendUnique( # "-MMD", # "-MP", "-Wall", - # "-Wextra", - # "-Werror", + "-Wextra", + "-Werror", "-Wno-address-of-packed-member", - "-Wimplicit-function-declaration", - "-Wbuiltin-declaration-mismatch", "-Wredundant-decls", "-Wdouble-promotion", - "-Wchar-subscripts", "-fdata-sections", "-ffunction-sections", "-fsingle-precision-constant", @@ -36,11 +33,6 @@ ENV.AppendUnique( # Generates .su files with stack usage information # "-fstack-usage", "-g", - "-Wno-unused-parameter", - "-Wno-type-limits", - "-Wno-unused-variable", - # "-Wno-stringop-overread", - # "-Wno-stringop-overflow", ], CPPDEFINES=[ "_GNU_SOURCE", @@ -52,4 +44,4 @@ ENV.AppendUnique( "-mlittle-endian", "-mthumb", ], -) +) \ No newline at end of file