diff --git a/applications/archive/helpers/archive_browser.c b/applications/archive/helpers/archive_browser.c index faf10de98..cb3d3ca83 100644 --- a/applications/archive/helpers/archive_browser.c +++ b/applications/archive/helpers/archive_browser.c @@ -21,14 +21,14 @@ void archive_update_offset(ArchiveBrowserView* browser) { browser->view, (ArchiveBrowserViewModel * model) { uint16_t bounds = model->item_cnt > 3 ? 2 : model->item_cnt; - if((model->item_cnt > 3u) && ((uint32_t)model->item_idx >= (model->item_cnt - 1))) { + if((model->item_cnt > 3u) && (model->item_idx >= ((int32_t)model->item_cnt - 1))) { model->list_offset = model->item_idx - 3; } else if(model->list_offset < model->item_idx - bounds) { model->list_offset = - CLAMP((uint32_t)model->item_idx - 2, model->item_cnt - bounds, 0u); + CLAMP(model->item_idx - 2, (int32_t)model->item_cnt - bounds, 0); } else if(model->list_offset > model->item_idx - bounds) { model->list_offset = - CLAMP((uint32_t)model->item_idx - 1, model->item_cnt - bounds, 0u); + CLAMP(model->item_idx - 1, (int32_t)model->item_cnt - bounds, 0); } return true; @@ -80,7 +80,7 @@ void archive_set_item_count(ArchiveBrowserView* browser, uint32_t count) { with_view_model( browser->view, (ArchiveBrowserViewModel * model) { model->item_cnt = count; - model->item_idx = CLAMP((uint32_t)model->item_idx, model->item_cnt - 1, 0u); + model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0); return false; }); archive_update_offset(browser); @@ -97,7 +97,7 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) { model->item_idx - model->array_offset, model->item_idx - model->array_offset + 1); model->item_cnt--; - model->item_idx = CLAMP((uint32_t)model->item_idx, model->item_cnt - 1, 0u); + model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0); items_cnt = model->item_cnt; return false; }); @@ -160,7 +160,7 @@ bool archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) { } else { offset_new = model->item_idx - FILE_LIST_BUF_LEN / 4 * 1; } - offset_new = CLAMP((uint32_t)offset_new, model->item_cnt - FILE_LIST_BUF_LEN, 0u); + offset_new = CLAMP(offset_new, (int32_t)model->item_cnt - FILE_LIST_BUF_LEN, 0); } return false; }); diff --git a/applications/ibutton/ibutton.c b/applications/ibutton/ibutton.c new file mode 100644 index 000000000..a38f077f3 --- /dev/null +++ b/applications/ibutton/ibutton.c @@ -0,0 +1,349 @@ +#include "ibutton.h" +#include "ibutton_i.h" +#include "ibutton/scenes/ibutton_scene.h" + +#include +#include + +static const NotificationSequence* ibutton_notification_sequences[] = { + &sequence_error, + &sequence_success, + &sequence_blink_cyan_10, + &sequence_blink_magenta_10, + &sequence_blink_yellow_10, + &sequence_set_red_255, + &sequence_reset_red, + &sequence_set_green_255, + &sequence_reset_green, +}; + +static void ibutton_make_app_folder(iButton* ibutton) { + if(!storage_simply_mkdir(ibutton->storage, IBUTTON_APP_FOLDER)) { + dialog_message_show_storage_error(ibutton->dialogs, "Cannot create\napp folder"); + } +} + +static bool ibutton_load_key_data(iButton* ibutton, string_t key_path) { + FlipperFormat* file = flipper_format_file_alloc(ibutton->storage); + bool result = false; + string_t data; + string_init(data); + + do { + if(!flipper_format_file_open_existing(file, string_get_cstr(key_path))) break; + + // header + uint32_t version; + if(!flipper_format_read_header(file, data, &version)) break; + if(string_cmp_str(data, IBUTTON_APP_FILE_TYPE) != 0) break; + if(version != 1) break; + + // key type + iButtonKeyType type; + if(!flipper_format_read_string(file, "Key type", data)) break; + if(!ibutton_key_get_type_by_string(string_get_cstr(data), &type)) break; + + // key data + uint8_t key_data[IBUTTON_KEY_DATA_SIZE] = {0}; + if(!flipper_format_read_hex(file, "Data", key_data, ibutton_key_get_size_by_type(type))) + break; + + ibutton_key_set_type(ibutton->key, type); + ibutton_key_set_data(ibutton->key, key_data, IBUTTON_KEY_DATA_SIZE); + + result = true; + } while(false); + + flipper_format_free(file); + string_clear(data); + + if(!result) { + dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file"); + } + + return result; +} + +bool ibutton_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + iButton* ibutton = context; + return scene_manager_handle_custom_event(ibutton->scene_manager, event); +} + +bool ibutton_back_event_callback(void* context) { + furi_assert(context); + iButton* ibutton = context; + return scene_manager_handle_back_event(ibutton->scene_manager); +} + +void ibutton_tick_event_callback(void* context) { + furi_assert(context); + iButton* ibutton = context; + scene_manager_handle_tick_event(ibutton->scene_manager); +} + +iButton* ibutton_alloc() { + iButton* ibutton = malloc(sizeof(iButton)); + + ibutton->scene_manager = scene_manager_alloc(&ibutton_scene_handlers, ibutton); + + ibutton->view_dispatcher = view_dispatcher_alloc(); + view_dispatcher_enable_queue(ibutton->view_dispatcher); + view_dispatcher_set_event_callback_context(ibutton->view_dispatcher, ibutton); + view_dispatcher_set_custom_event_callback( + ibutton->view_dispatcher, ibutton_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + ibutton->view_dispatcher, ibutton_back_event_callback); + view_dispatcher_set_tick_event_callback( + ibutton->view_dispatcher, ibutton_tick_event_callback, 100); + + ibutton->gui = furi_record_open("gui"); + view_dispatcher_attach_to_gui( + ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen); + + ibutton->storage = furi_record_open("storage"); + ibutton->dialogs = furi_record_open("dialogs"); + ibutton->notifications = furi_record_open("notification"); + + ibutton->key = ibutton_key_alloc(); + ibutton->key_worker = ibutton_worker_alloc(); + ibutton_worker_start_thread(ibutton->key_worker); + + ibutton->submenu = submenu_alloc(); + view_dispatcher_add_view( + ibutton->view_dispatcher, iButtonViewSubmenu, submenu_get_view(ibutton->submenu)); + + ibutton->byte_input = byte_input_alloc(); + view_dispatcher_add_view( + ibutton->view_dispatcher, iButtonViewByteInput, byte_input_get_view(ibutton->byte_input)); + + ibutton->text_input = text_input_alloc(); + view_dispatcher_add_view( + ibutton->view_dispatcher, iButtonViewTextInput, text_input_get_view(ibutton->text_input)); + + ibutton->popup = popup_alloc(); + view_dispatcher_add_view( + ibutton->view_dispatcher, iButtonViewPopup, popup_get_view(ibutton->popup)); + + ibutton->widget = widget_alloc(); + view_dispatcher_add_view( + ibutton->view_dispatcher, iButtonViewWidget, widget_get_view(ibutton->widget)); + + ibutton->dialog_ex = dialog_ex_alloc(); + view_dispatcher_add_view( + ibutton->view_dispatcher, iButtonViewDialogEx, dialog_ex_get_view(ibutton->dialog_ex)); + + return ibutton; +} + +void ibutton_free(iButton* ibutton) { + furi_assert(ibutton); + + view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewDialogEx); + dialog_ex_free(ibutton->dialog_ex); + + view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewWidget); + widget_free(ibutton->widget); + + view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewPopup); + popup_free(ibutton->popup); + + view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewTextInput); + text_input_free(ibutton->text_input); + + view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewByteInput); + byte_input_free(ibutton->byte_input); + + view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewSubmenu); + submenu_free(ibutton->submenu); + + view_dispatcher_free(ibutton->view_dispatcher); + scene_manager_free(ibutton->scene_manager); + + furi_record_close("storage"); + ibutton->storage = NULL; + + furi_record_close("notification"); + ibutton->notifications = NULL; + + furi_record_close("dialogs"); + ibutton->dialogs = NULL; + + furi_record_close("gui"); + ibutton->gui = NULL; + + ibutton_worker_stop_thread(ibutton->key_worker); + ibutton_worker_free(ibutton->key_worker); + ibutton_key_free(ibutton->key); + + free(ibutton); +} + +bool ibutton_file_select(iButton* ibutton) { + bool success = dialog_file_select_show( + ibutton->dialogs, + IBUTTON_APP_FOLDER, + IBUTTON_APP_EXTENSION, + ibutton->file_name, + IBUTTON_FILE_NAME_SIZE, + ibutton_key_get_name_p(ibutton->key)); + + if(success) { + string_t key_str; + string_init_printf( + key_str, "%s/%s%s", IBUTTON_APP_FOLDER, ibutton->file_name, IBUTTON_APP_EXTENSION); + success = ibutton_load_key_data(ibutton, key_str); + + if(success) { + ibutton_key_set_name(ibutton->key, ibutton->file_name); + } + + string_clear(key_str); + } + + return success; +} + +bool ibutton_load_key(iButton* ibutton, const char* key_name) { + string_t key_path; + string_init_set_str(key_path, key_name); + + const bool success = ibutton_load_key_data(ibutton, key_path); + + if(success) { + path_extract_filename_no_ext(key_name, key_path); + ibutton_key_set_name(ibutton->key, string_get_cstr(key_path)); + } + + string_clear(key_path); + return success; +} + +bool ibutton_save_key(iButton* ibutton, const char* key_name) { + // Create ibutton directory if necessary + ibutton_make_app_folder(ibutton); + + FlipperFormat* file = flipper_format_file_alloc(ibutton->storage); + iButtonKey* key = ibutton->key; + + string_t key_file_name; + bool result = false; + string_init(key_file_name); + + do { + // First remove key if it was saved (we rename the key) + if(!ibutton_delete_key(ibutton)) break; + + // Save the key + ibutton_key_set_name(key, key_name); + + // Set full file name, for new key + string_printf( + key_file_name, + "%s/%s%s", + IBUTTON_APP_FOLDER, + ibutton_key_get_name_p(key), + IBUTTON_APP_EXTENSION); + + // Open file for write + if(!flipper_format_file_open_always(file, string_get_cstr(key_file_name))) break; + + // Write header + if(!flipper_format_write_header_cstr(file, IBUTTON_APP_FILE_TYPE, 1)) break; + + // Write key type + if(!flipper_format_write_comment_cstr(file, "Key type can be Cyfral, Dallas or Metakom")) + break; + const char* key_type = ibutton_key_get_string_by_type(ibutton_key_get_type(key)); + if(!flipper_format_write_string_cstr(file, "Key type", key_type)) break; + + // Write data + if(!flipper_format_write_comment_cstr( + file, "Data size for Cyfral is 2, for Metakom is 4, for Dallas is 8")) + break; + + if(!flipper_format_write_hex( + file, "Data", ibutton_key_get_data_p(key), ibutton_key_get_data_size(key))) + break; + result = true; + + } while(false); + + flipper_format_free(file); + + string_clear(key_file_name); + + if(!result) { + dialog_message_show_storage_error(ibutton->dialogs, "Cannot save\nkey file"); + } + + return result; +} + +bool ibutton_delete_key(iButton* ibutton) { + string_t file_name; + bool result = false; + + string_init_printf( + file_name, + "%s/%s%s", + IBUTTON_APP_FOLDER, + ibutton_key_get_name_p(ibutton->key), + IBUTTON_APP_EXTENSION); + result = storage_simply_remove(ibutton->storage, string_get_cstr(file_name)); + string_clear(file_name); + + return result; +} + +void ibutton_text_store_set(iButton* ibutton, const char* text, ...) { + va_list args; + va_start(args, text); + + vsnprintf(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE, text, args); + + va_end(args); +} + +void ibutton_text_store_clear(iButton* ibutton) { + memset(ibutton->text_store, 0, IBUTTON_TEXT_STORE_SIZE); +} + +void ibutton_switch_to_previous_scene_one_of( + iButton* ibutton, + const uint32_t* scene_ids, + size_t scene_ids_size) { + furi_assert(scene_ids_size); + SceneManager* scene_manager = ibutton->scene_manager; + + for(size_t i = 0; i < scene_ids_size; ++i) { + const uint32_t scene_id = scene_ids[i]; + if(scene_manager_has_previous_scene(scene_manager, scene_id)) { + scene_manager_search_and_switch_to_previous_scene(scene_manager, scene_id); + return; + } + } +} + +void ibutton_notification_message(iButton* ibutton, uint32_t message) { + furi_assert(message < sizeof(ibutton_notification_sequences) / sizeof(NotificationSequence*)); + notification_message(ibutton->notifications, ibutton_notification_sequences[message]); +} + +int32_t ibutton_app(void* p) { + iButton* ibutton = ibutton_alloc(); + + ibutton_make_app_folder(ibutton); + + if(p && ibutton_load_key(ibutton, (const char*)p)) { + // TODO: Display an error if the key from p could not be loaded + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); + } else { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneStart); + } + + view_dispatcher_run(ibutton->view_dispatcher); + + ibutton_free(ibutton); + return 0; +} diff --git a/applications/ibutton/ibutton.cpp b/applications/ibutton/ibutton.cpp deleted file mode 100644 index aae0d3173..000000000 --- a/applications/ibutton/ibutton.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "ibutton_app.h" - -// app enter function -extern "C" int32_t ibutton_app(void* p) { - iButtonApp* app = new iButtonApp(); - app->run(p); - delete app; - - return 255; -} diff --git a/applications/ibutton/ibutton.h b/applications/ibutton/ibutton.h new file mode 100644 index 000000000..56d6e3b6b --- /dev/null +++ b/applications/ibutton/ibutton.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct iButton iButton; diff --git a/applications/ibutton/ibutton_app.cpp b/applications/ibutton/ibutton_app.cpp deleted file mode 100644 index 43eb36924..000000000 --- a/applications/ibutton/ibutton_app.cpp +++ /dev/null @@ -1,342 +0,0 @@ -#include "ibutton_app.h" -#include -#include -#include -#include -#include - -const char* iButtonApp::app_folder = "/any/ibutton"; -const char* iButtonApp::app_extension = ".ibtn"; -const char* iButtonApp::app_filetype = "Flipper iButton key"; - -void iButtonApp::run(void* args) { - iButtonEvent event; - bool consumed; - bool exit = false; - - make_app_folder(); - - if(args && load_key((const char*)args)) { - current_scene = Scene::SceneEmulate; - } - - scenes[current_scene]->on_enter(this); - - while(!exit) { - view.receive_event(&event); - - consumed = scenes[current_scene]->on_event(this, &event); - - if(!consumed) { - if(event.type == iButtonEvent::Type::EventTypeBack) { - exit = switch_to_previous_scene(); - } - } - }; - - scenes[current_scene]->on_exit(this); -} - -iButtonApp::iButtonApp() - : notification{"notification"} - , storage{"storage"} - , dialogs{"dialogs"} { - key = ibutton_key_alloc(); - key_worker = ibutton_worker_alloc(); - ibutton_worker_start_thread(key_worker); -} - -iButtonApp::~iButtonApp() { - for(std::map::iterator it = scenes.begin(); it != scenes.end(); ++it) { - delete it->second; - } - scenes.clear(); - - ibutton_worker_stop_thread(key_worker); - ibutton_worker_free(key_worker); - ibutton_key_free(key); -} - -iButtonAppViewManager* iButtonApp::get_view_manager() { - return &view; -} - -void iButtonApp::switch_to_next_scene(Scene next_scene) { - previous_scenes_list.push_front(current_scene); - - if(next_scene != Scene::SceneExit) { - scenes[current_scene]->on_exit(this); - current_scene = next_scene; - scenes[current_scene]->on_enter(this); - } -} - -void iButtonApp::search_and_switch_to_previous_scene(std::initializer_list scenes_list) { - Scene previous_scene = Scene::SceneStart; - bool scene_found = false; - - while(!scene_found) { - previous_scene = get_previous_scene(); - for(Scene element : scenes_list) { - if(previous_scene == element || previous_scene == Scene::SceneStart) { - scene_found = true; - break; - } - } - } - - scenes[current_scene]->on_exit(this); - current_scene = previous_scene; - scenes[current_scene]->on_enter(this); -} - -bool iButtonApp::switch_to_previous_scene(uint8_t count) { - Scene previous_scene = Scene::SceneStart; - - for(uint8_t i = 0; i < count; i++) { - previous_scene = get_previous_scene(); - if(previous_scene == Scene::SceneExit) break; - } - - if(previous_scene == Scene::SceneExit) { - return true; - } else { - scenes[current_scene]->on_exit(this); - current_scene = previous_scene; - scenes[current_scene]->on_enter(this); - return false; - } -} - -iButtonApp::Scene iButtonApp::get_previous_scene() { - Scene scene = previous_scenes_list.front(); - previous_scenes_list.pop_front(); - return scene; -} - -iButtonWorker* iButtonApp::get_key_worker() { - return key_worker; -} - -iButtonKey* iButtonApp::get_key() { - return key; -} - -char* iButtonApp::get_file_name() { - return file_name; -} - -uint8_t iButtonApp::get_file_name_size() { - return file_name_size; -} - -void iButtonApp::notify_read() { - notification_message(notification, &sequence_blink_cyan_10); -} - -void iButtonApp::notify_emulate() { - notification_message(notification, &sequence_blink_magenta_10); -} - -void iButtonApp::notify_yellow_blink() { - notification_message(notification, &sequence_blink_yellow_10); -} - -void iButtonApp::notify_error() { - notification_message(notification, &sequence_error); -} - -void iButtonApp::notify_success() { - notification_message(notification, &sequence_success); -} - -void iButtonApp::notify_green_on() { - notification_message_block(notification, &sequence_set_green_255); -} - -void iButtonApp::notify_green_off() { - notification_message(notification, &sequence_reset_green); -} - -void iButtonApp::notify_red_on() { - notification_message_block(notification, &sequence_set_red_255); -} - -void iButtonApp::notify_red_off() { - notification_message(notification, &sequence_reset_red); -} - -void iButtonApp::set_text_store(const char* text...) { - va_list args; - va_start(args, text); - - vsnprintf(text_store, text_store_size, text, args); - - va_end(args); -} - -char* iButtonApp::get_text_store() { - return text_store; -} - -uint8_t iButtonApp::get_text_store_size() { - return text_store_size; -} - -// file managment -bool iButtonApp::save_key(const char* key_name) { - // Create ibutton directory if necessary - make_app_folder(); - - FlipperFormat* file = flipper_format_file_alloc(storage); - string_t key_file_name; - bool result = false; - string_init(key_file_name); - - do { - // First remove key if it was saved (we rename the key) - if(!delete_key()) break; - - // Save the key - ibutton_key_set_name(key, key_name); - - // Set full file name, for new key - string_printf( - key_file_name, "%s/%s%s", app_folder, ibutton_key_get_name_p(key), app_extension); - - // Open file for write - if(!flipper_format_file_open_always(file, string_get_cstr(key_file_name))) break; - - // Write header - if(!flipper_format_write_header_cstr(file, iButtonApp::app_filetype, 1)) break; - - // Write key type - if(!flipper_format_write_comment_cstr(file, "Key type can be Cyfral, Dallas or Metakom")) - break; - const char* key_type = ibutton_key_get_string_by_type(ibutton_key_get_type(key)); - if(!flipper_format_write_string_cstr(file, "Key type", key_type)) break; - - // Write data - if(!flipper_format_write_comment_cstr( - file, "Data size for Cyfral is 2, for Metakom is 4, for Dallas is 8")) - break; - - if(!flipper_format_write_hex( - file, "Data", ibutton_key_get_data_p(key), ibutton_key_get_data_size(key))) - break; - result = true; - - } while(false); - - flipper_format_free(file); - - string_clear(key_file_name); - - if(!result) { - dialog_message_show_storage_error(dialogs, "Cannot save\nkey file"); - } - - return result; -} - -bool iButtonApp::load_key_data(string_t key_path) { - FlipperFormat* file = flipper_format_file_alloc(storage); - bool result = false; - string_t data; - string_init(data); - - do { - if(!flipper_format_file_open_existing(file, string_get_cstr(key_path))) break; - - // header - uint32_t version; - if(!flipper_format_read_header(file, data, &version)) break; - if(string_cmp_str(data, iButtonApp::app_filetype) != 0) break; - if(version != 1) break; - - // key type - iButtonKeyType type; - if(!flipper_format_read_string(file, "Key type", data)) break; - if(!ibutton_key_get_type_by_string(string_get_cstr(data), &type)) break; - - // key data - uint8_t key_data[IBUTTON_KEY_DATA_SIZE] = {0}; - if(!flipper_format_read_hex(file, "Data", key_data, ibutton_key_get_size_by_type(type))) - break; - - ibutton_key_set_type(key, type); - ibutton_key_set_data(key, key_data, IBUTTON_KEY_DATA_SIZE); - - result = true; - } while(false); - - flipper_format_free(file); - string_clear(data); - - if(!result) { - dialog_message_show_storage_error(dialogs, "Cannot load\nkey file"); - } - - return result; -} - -bool iButtonApp::load_key(const char* key_name) { - bool result = false; - string_t key_path; - - string_init_set_str(key_path, key_name); - - result = load_key_data(key_path); - if(result) { - path_extract_filename_no_ext(key_name, key_path); - ibutton_key_set_name(key, string_get_cstr(key_path)); - } - string_clear(key_path); - return result; -} - -bool iButtonApp::load_key() { - bool result = false; - - // Input events and views are managed by file_select - bool res = dialog_file_select_show( - dialogs, - app_folder, - app_extension, - get_file_name(), - get_file_name_size(), - ibutton_key_get_name_p(key)); - - if(res) { - string_t key_str; - - // Get key file path - string_init_printf(key_str, "%s/%s%s", app_folder, get_file_name(), app_extension); - - result = load_key_data(key_str); - if(result) { - ibutton_key_set_name(key, get_file_name()); - } - string_clear(key_str); - } - - return result; -} - -bool iButtonApp::delete_key() { - string_t file_name; - bool result = false; - - string_init_printf( - file_name, "%s/%s%s", app_folder, ibutton_key_get_name_p(key), app_extension); - result = storage_simply_remove(storage, string_get_cstr(file_name)); - string_clear(file_name); - - return result; -} - -void iButtonApp::make_app_folder() { - if(!storage_simply_mkdir(storage, app_folder)) { - dialog_message_show_storage_error(dialogs, "Cannot create\napp folder"); - } -} diff --git a/applications/ibutton/ibutton_app.h b/applications/ibutton/ibutton_app.h deleted file mode 100644 index 08af38573..000000000 --- a/applications/ibutton/ibutton_app.h +++ /dev/null @@ -1,144 +0,0 @@ -#pragma once -#include -#include - -#include "ibutton_view_manager.h" -#include "scene/ibutton_scene_generic.h" -#include "scene/ibutton_scene_start.h" -#include "scene/ibutton_scene_read.h" -#include "scene/ibutton_scene_read_crc_error.h" -#include "scene/ibutton_scene_read_not_key_error.h" -#include "scene/ibutton_scene_read_success.h" -#include "scene/ibutton_scene_retry_confirm.h" -#include "scene/ibutton_scene_exit_confirm.h" -#include "scene/ibutton_scene_read_key_menu.h" -#include "scene/ibutton_scene_write.h" -#include "scene/ibutton_scene_write_success.h" -#include "scene/ibutton_scene_saved_key_menu.h" -#include "scene/ibutton_scene_delete_confirm.h" -#include "scene/ibutton_scene_delete_success.h" -#include "scene/ibutton_scene_emulate.h" -#include "scene/ibutton_scene_save_name.h" -#include "scene/ibutton_scene_save_success.h" -#include "scene/ibutton_scene_info.h" -#include "scene/ibutton_scene_select_key.h" -#include "scene/ibutton_scene_add_type.h" -#include "scene/ibutton_scene_add_value.h" -#include -#include -#include -#include -#include - -class iButtonApp { -public: - void run(void* args); - - iButtonApp(); - ~iButtonApp(); - - enum class Scene : uint8_t { - SceneExit, - SceneStart, - SceneRead, - SceneReadNotKeyError, - SceneReadCRCError, - SceneReadSuccess, - SceneRetryConfirm, - SceneExitConfirm, - SceneReadKeyMenu, - SceneWrite, - SceneWriteSuccess, - SceneEmulate, - SceneSavedKeyMenu, - SceneDeleteConfirm, - SceneDeleteSuccess, - SceneSaveName, - SceneSaveSuccess, - SceneInfo, - SceneSelectKey, - SceneAddType, - SceneAddValue, - }; - - static const char* app_folder; - static const char* app_extension; - static const char* app_filetype; - - iButtonAppViewManager* get_view_manager(); - void switch_to_next_scene(Scene index); - void search_and_switch_to_previous_scene(std::initializer_list scenes_list); - bool switch_to_previous_scene(uint8_t count = 1); - Scene get_previous_scene(); - - const GpioPin* get_ibutton_pin(); - iButtonWorker* get_key_worker(); - iButtonKey* get_key(); - - void notify_read(); - void notify_yellow_blink(); - void notify_emulate(); - - void notify_error(); - void notify_success(); - void notify_green_on(); - void notify_green_off(); - void notify_red_on(); - void notify_red_off(); - - void set_text_store(const char* text...); - char* get_text_store(); - uint8_t get_text_store_size(); - - char* get_file_name(); - uint8_t get_file_name_size(); - - bool save_key(const char* key_name); - bool load_key(); - bool load_key(const char* key_name); - bool delete_key(); - -private: - std::list previous_scenes_list = {Scene::SceneExit}; - Scene current_scene = Scene::SceneStart; - iButtonAppViewManager view; - - std::map scenes = { - {Scene::SceneStart, new iButtonSceneStart()}, - {Scene::SceneRead, new iButtonSceneRead()}, - {Scene::SceneReadCRCError, new iButtonSceneReadCRCError()}, - {Scene::SceneReadNotKeyError, new iButtonSceneReadNotKeyError()}, - {Scene::SceneReadSuccess, new iButtonSceneReadSuccess()}, - {Scene::SceneRetryConfirm, new iButtonSceneRetryConfirm()}, - {Scene::SceneExitConfirm, new iButtonSceneExitConfirm()}, - {Scene::SceneReadKeyMenu, new iButtonSceneReadKeyMenu()}, - {Scene::SceneWrite, new iButtonSceneWrite()}, - {Scene::SceneWriteSuccess, new iButtonSceneWriteSuccess()}, - {Scene::SceneEmulate, new iButtonSceneEmulate()}, - {Scene::SceneSavedKeyMenu, new iButtonSceneSavedKeyMenu()}, - {Scene::SceneDeleteConfirm, new iButtonSceneDeleteConfirm()}, - {Scene::SceneDeleteSuccess, new iButtonSceneDeleteSuccess()}, - {Scene::SceneSaveName, new iButtonSceneSaveName()}, - {Scene::SceneSaveSuccess, new iButtonSceneSaveSuccess()}, - {Scene::SceneInfo, new iButtonSceneInfo()}, - {Scene::SceneSelectKey, new iButtonSceneSelectKey()}, - {Scene::SceneAddType, new iButtonSceneAddType()}, - {Scene::SceneAddValue, new iButtonSceneAddValue()}, - }; - - iButtonWorker* key_worker; - iButtonKey* key; - - RecordController notification; - RecordController storage; - RecordController dialogs; - - static const uint8_t file_name_size = 100; - char file_name[file_name_size]; - - static const uint8_t text_store_size = 128; - char text_store[text_store_size + 1]; - - bool load_key_data(string_t key_path); - void make_app_folder(); -}; diff --git a/applications/ibutton/ibutton_custom_event.h b/applications/ibutton/ibutton_custom_event.h new file mode 100644 index 000000000..2be42d66d --- /dev/null +++ b/applications/ibutton/ibutton_custom_event.h @@ -0,0 +1,12 @@ +#pragma once + +enum iButtonCustomEvent { + // Reserve first 100 events for button types and indexes, starting from 0 + iButtonCustomEventReserved = 100, + + iButtonCustomEventBack, + iButtonCustomEventTextEditResult, + iButtonCustomEventByteEditResult, + iButtonCustomEventWorkerEmulated, + iButtonCustomEventWorkerRead, +}; diff --git a/applications/ibutton/ibutton_event.h b/applications/ibutton/ibutton_event.h deleted file mode 100644 index 8b1775c1b..000000000 --- a/applications/ibutton/ibutton_event.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include -#include -#include -#include - -class iButtonApp; - -class iButtonEvent { -public: - // events enum - enum class Type : uint8_t { - EventTypeTick, - EventTypeBack, - EventTypeMenuSelected, - EventTypeDialogResult, - EventTypeTextEditResult, - EventTypeByteEditResult, - EventTypeWidgetButtonResult, - EventTypeWorkerEmulated, - EventTypeWorkerRead, - EventTypeWorkerWrite, - }; - - // payload - union { - uint32_t dummy; - uint32_t menu_index; - DialogExResult dialog_result; - GuiButtonType widget_button_result; - iButtonWorkerWriteResult worker_write_result; - } payload; - - // event type - Type type; -}; diff --git a/applications/ibutton/ibutton_i.h b/applications/ibutton/ibutton_i.h new file mode 100644 index 000000000..36857fd64 --- /dev/null +++ b/applications/ibutton/ibutton_i.h @@ -0,0 +1,86 @@ +#pragma once + +#include "ibutton.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ibutton_custom_event.h" +#include "scenes/ibutton_scene.h" + +#define IBUTTON_FILE_NAME_SIZE 100 +#define IBUTTON_TEXT_STORE_SIZE 128 + +#define IBUTTON_APP_FOLDER "/any/ibutton" +#define IBUTTON_APP_EXTENSION ".ibtn" +#define IBUTTON_APP_FILE_TYPE "Flipper iButton key" + +struct iButton { + SceneManager* scene_manager; + ViewDispatcher* view_dispatcher; + + Gui* gui; + Storage* storage; + DialogsApp* dialogs; + NotificationApp* notifications; + + iButtonWorker* key_worker; + iButtonKey* key; + + char file_name[IBUTTON_FILE_NAME_SIZE]; + char text_store[IBUTTON_TEXT_STORE_SIZE + 1]; + + Submenu* submenu; + ByteInput* byte_input; + TextInput* text_input; + Popup* popup; + Widget* widget; + DialogEx* dialog_ex; +}; + +typedef enum { + iButtonViewSubmenu, + iButtonViewByteInput, + iButtonViewTextInput, + iButtonViewPopup, + iButtonViewWidget, + iButtonViewDialogEx, +} iButtonView; + +typedef enum { + iButtonNotificationMessageError, + iButtonNotificationMessageSuccess, + iButtonNotificationMessageRead, + iButtonNotificationMessageEmulate, + iButtonNotificationMessageYellowBlink, + iButtonNotificationMessageRedOn, + iButtonNotificationMessageRedOff, + iButtonNotificationMessageGreenOn, + iButtonNotificationMessageGreenOff, +} iButtonNotificationMessage; + +bool ibutton_file_select(iButton* ibutton); +bool ibutton_load_key(iButton* ibutton, const char* key_name); +bool ibutton_save_key(iButton* ibutton, const char* key_name); +bool ibutton_delete_key(iButton* ibutton); +void ibutton_text_store_set(iButton* ibutton, const char* text, ...); +void ibutton_text_store_clear(iButton* ibutton); +void ibutton_switch_to_previous_scene_one_of( + iButton* ibutton, + const uint32_t* scene_ids, + size_t scene_ids_size); +void ibutton_notification_message(iButton* ibutton, uint32_t message); diff --git a/applications/ibutton/ibutton_view_manager.cpp b/applications/ibutton/ibutton_view_manager.cpp deleted file mode 100755 index 5a2c94f1e..000000000 --- a/applications/ibutton/ibutton_view_manager.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include "ibutton_view_manager.h" -#include "ibutton_event.h" -#include - -iButtonAppViewManager::iButtonAppViewManager() { - event_queue = osMessageQueueNew(10, sizeof(iButtonEvent), NULL); - - view_dispatcher = view_dispatcher_alloc(); - auto callback = cbc::obtain_connector(this, &iButtonAppViewManager::previous_view_callback); - - dialog_ex = dialog_ex_alloc(); - view_dispatcher_add_view( - view_dispatcher, - static_cast(iButtonAppViewManager::Type::iButtonAppViewDialogEx), - dialog_ex_get_view(dialog_ex)); - - submenu = submenu_alloc(); - view_dispatcher_add_view( - view_dispatcher, - static_cast(iButtonAppViewManager::Type::iButtonAppViewSubmenu), - submenu_get_view(submenu)); - - text_input = text_input_alloc(); - view_dispatcher_add_view( - view_dispatcher, - static_cast(iButtonAppViewManager::Type::iButtonAppViewTextInput), - text_input_get_view(text_input)); - - byte_input = byte_input_alloc(); - view_dispatcher_add_view( - view_dispatcher, - static_cast(iButtonAppViewManager::Type::iButtonAppViewByteInput), - byte_input_get_view(byte_input)); - - popup = popup_alloc(); - view_dispatcher_add_view( - view_dispatcher, - static_cast(iButtonAppViewManager::Type::iButtonAppViewPopup), - popup_get_view(popup)); - - widget = widget_alloc(); - view_dispatcher_add_view( - view_dispatcher, - static_cast(iButtonAppViewManager::Type::iButtonAppViewWidget), - widget_get_view(widget)); - - gui = static_cast(furi_record_open("gui")); - view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); - - //TODO think about that method, seems unsafe and over-engineered - view_set_previous_callback(dialog_ex_get_view(dialog_ex), callback); - view_set_previous_callback(submenu_get_view(submenu), callback); - view_set_previous_callback(text_input_get_view(text_input), callback); - view_set_previous_callback(byte_input_get_view(byte_input), callback); - view_set_previous_callback(popup_get_view(popup), callback); - view_set_previous_callback(widget_get_view(widget), callback); -} - -iButtonAppViewManager::~iButtonAppViewManager() { - // remove views - view_dispatcher_remove_view( - view_dispatcher, - static_cast(iButtonAppViewManager::Type::iButtonAppViewDialogEx)); - view_dispatcher_remove_view( - view_dispatcher, - static_cast(iButtonAppViewManager::Type::iButtonAppViewSubmenu)); - view_dispatcher_remove_view( - view_dispatcher, - static_cast(iButtonAppViewManager::Type::iButtonAppViewTextInput)); - view_dispatcher_remove_view( - view_dispatcher, static_cast(iButtonAppViewManager::Type::iButtonAppViewPopup)); - view_dispatcher_remove_view( - view_dispatcher, - static_cast(iButtonAppViewManager::Type::iButtonAppViewByteInput)); - view_dispatcher_remove_view( - view_dispatcher, static_cast(iButtonAppViewManager::Type::iButtonAppViewWidget)); - - // free view modules - popup_free(popup); - text_input_free(text_input); - byte_input_free(byte_input); - submenu_free(submenu); - dialog_ex_free(dialog_ex); - widget_free(widget); - - // free dispatcher - view_dispatcher_free(view_dispatcher); - - // free event queue - osMessageQueueDelete(event_queue); -} - -void iButtonAppViewManager::switch_to(Type type) { - view_dispatcher_switch_to_view(view_dispatcher, static_cast(type)); -} - -Submenu* iButtonAppViewManager::get_submenu() { - return submenu; -} - -Popup* iButtonAppViewManager::get_popup() { - return popup; -} - -DialogEx* iButtonAppViewManager::get_dialog_ex() { - return dialog_ex; -} - -TextInput* iButtonAppViewManager::get_text_input() { - return text_input; -} - -ByteInput* iButtonAppViewManager::get_byte_input() { - return byte_input; -} - -Widget* iButtonAppViewManager::get_widget() { - return widget; -} - -void iButtonAppViewManager::receive_event(iButtonEvent* event) { - if(osMessageQueueGet(event_queue, event, NULL, 100) != osOK) { - event->type = iButtonEvent::Type::EventTypeTick; - } -} - -void iButtonAppViewManager::send_event(iButtonEvent* event) { - osStatus_t result = osMessageQueuePut(event_queue, event, 0, 0); - furi_check(result == osOK); -} - -uint32_t iButtonAppViewManager::previous_view_callback(void*) { - if(event_queue != NULL) { - iButtonEvent event; - event.type = iButtonEvent::Type::EventTypeBack; - send_event(&event); - } - - return VIEW_IGNORE; -} diff --git a/applications/ibutton/ibutton_view_manager.h b/applications/ibutton/ibutton_view_manager.h deleted file mode 100644 index 336ba6e2f..000000000 --- a/applications/ibutton/ibutton_view_manager.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include "ibutton_event.h" - -class iButtonAppViewManager { -public: - enum class Type : uint8_t { - iButtonAppViewTextInput, - iButtonAppViewByteInput, - iButtonAppViewSubmenu, - iButtonAppViewDialogEx, - iButtonAppViewPopup, - iButtonAppViewWidget, - }; - - osMessageQueueId_t event_queue; - - iButtonAppViewManager(); - ~iButtonAppViewManager(); - - void switch_to(Type type); - - Submenu* get_submenu(); - Popup* get_popup(); - DialogEx* get_dialog_ex(); - TextInput* get_text_input(); - ByteInput* get_byte_input(); - Widget* get_widget(); - - void receive_event(iButtonEvent* event); - void send_event(iButtonEvent* event); - -private: - ViewDispatcher* view_dispatcher; - DialogEx* dialog_ex; - Submenu* submenu; - TextInput* text_input; - ByteInput* byte_input; - Popup* popup; - Widget* widget; - Gui* gui; - - uint32_t previous_view_callback(void* context); -}; diff --git a/applications/ibutton/scene/ibutton_scene_add_type.cpp b/applications/ibutton/scene/ibutton_scene_add_type.cpp deleted file mode 100644 index c9537768b..000000000 --- a/applications/ibutton/scene/ibutton_scene_add_type.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "ibutton_scene_add_type.h" -#include "../ibutton_app.h" -#include - -typedef enum { - SubmenuIndexCyfral, - SubmenuIndexDallas, - SubmenuIndexMetakom, -} SubmenuIndex; - -static void submenu_callback(void* context, uint32_t index) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeMenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void iButtonSceneAddType::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_add_item(submenu, "Cyfral", SubmenuIndexCyfral, submenu_callback, app); - submenu_add_item(submenu, "Dallas", SubmenuIndexDallas, submenu_callback, app); - submenu_add_item(submenu, "Metakom", SubmenuIndexMetakom, submenu_callback, app); - submenu_set_selected_item(submenu, submenu_item_selected); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu); -} - -bool iButtonSceneAddType::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeMenuSelected) { - submenu_item_selected = event->payload.menu_index; - iButtonKey* key = app->get_key(); - - switch(event->payload.menu_index) { - case SubmenuIndexCyfral: - ibutton_key_set_type(key, iButtonKeyCyfral); - break; - case SubmenuIndexDallas: - ibutton_key_set_type(key, iButtonKeyDS1990); - break; - case SubmenuIndexMetakom: - ibutton_key_set_type(key, iButtonKeyMetakom); - break; - } - ibutton_key_set_name(key, ""); - ibutton_key_clear_data(key); - app->switch_to_next_scene(iButtonApp::Scene::SceneAddValue); - consumed = true; - } - - return consumed; -} - -void iButtonSceneAddType::on_exit(iButtonApp* app) { - iButtonAppViewManager* view = app->get_view_manager(); - Submenu* submenu = view->get_submenu(); - - submenu_reset(submenu); -} diff --git a/applications/ibutton/scene/ibutton_scene_add_type.h b/applications/ibutton/scene/ibutton_scene_add_type.h deleted file mode 100644 index 6a3d07e59..000000000 --- a/applications/ibutton/scene/ibutton_scene_add_type.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneAddType : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; - -private: - uint32_t submenu_item_selected = 0; -}; diff --git a/applications/ibutton/scene/ibutton_scene_add_value.cpp b/applications/ibutton/scene/ibutton_scene_add_value.cpp deleted file mode 100755 index d0108ae57..000000000 --- a/applications/ibutton/scene/ibutton_scene_add_value.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "ibutton_scene_add_value.h" -#include "../ibutton_app.h" -#include - -static void byte_input_callback(void* context) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeByteEditResult; - app->get_view_manager()->send_event(&event); -} - -void iButtonSceneAddValue::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - ByteInput* byte_input = view_manager->get_byte_input(); - iButtonKey* key = app->get_key(); - - memcpy(this->new_key_data, ibutton_key_get_data_p(key), ibutton_key_get_data_size(key)); - - byte_input_set_result_callback( - byte_input, - byte_input_callback, - NULL, - app, - this->new_key_data, - ibutton_key_get_data_size(key)); - - byte_input_set_header_text(byte_input, "Enter the key"); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewByteInput); -} - -bool iButtonSceneAddValue::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeByteEditResult) { - ibutton_key_set_data(app->get_key(), this->new_key_data, IBUTTON_KEY_DATA_SIZE); - DOLPHIN_DEED(DolphinDeedIbuttonAdd); - app->switch_to_next_scene(iButtonApp::Scene::SceneSaveName); - consumed = true; - } - - return consumed; -} - -void iButtonSceneAddValue::on_exit(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - ByteInput* byte_input = view_manager->get_byte_input(); - - byte_input_set_result_callback(byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(byte_input, {0}); -} diff --git a/applications/ibutton/scene/ibutton_scene_add_value.h b/applications/ibutton/scene/ibutton_scene_add_value.h deleted file mode 100644 index 7a7341603..000000000 --- a/applications/ibutton/scene/ibutton_scene_add_value.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" -#include - -class iButtonSceneAddValue : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; - -private: - uint8_t new_key_data[IBUTTON_KEY_DATA_SIZE] = {}; -}; diff --git a/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp b/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp deleted file mode 100755 index 8e782e330..000000000 --- a/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "ibutton_scene_delete_confirm.h" -#include "../ibutton_app.h" - -static void widget_callback(GuiButtonType result, InputType type, void* context) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - - if(type == InputTypeShort) { - event.type = iButtonEvent::Type::EventTypeWidgetButtonResult; - event.payload.widget_button_result = result; - app->get_view_manager()->send_event(&event); - } -} - -void iButtonSceneDeleteConfirm::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Widget* widget = view_manager->get_widget(); - iButtonKey* key = app->get_key(); - const uint8_t* key_data = ibutton_key_get_data_p(key); - - app->set_text_store("\e#Delete %s?\e#", ibutton_key_get_name_p(key)); - widget_add_text_box_element( - widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store(), false); - widget_add_button_element(widget, GuiButtonTypeLeft, "Cancel", widget_callback, app); - widget_add_button_element(widget, GuiButtonTypeRight, "Delete", widget_callback, app); - - switch(ibutton_key_get_type(key)) { - case iButtonKeyDS1990: - app->set_text_store( - "%02X %02X %02X %02X %02X %02X %02X %02X", - key_data[0], - key_data[1], - key_data[2], - key_data[3], - key_data[4], - key_data[5], - key_data[6], - key_data[7]); - widget_add_string_element( - widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Dallas"); - break; - case iButtonKeyCyfral: - app->set_text_store("%02X %02X", key_data[0], key_data[1]); - widget_add_string_element( - widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Cyfral"); - break; - case iButtonKeyMetakom: - app->set_text_store( - "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]); - widget_add_string_element( - widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Metakom"); - break; - } - widget_add_string_element( - widget, 64, 33, AlignCenter, AlignBottom, FontSecondary, app->get_text_store()); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewWidget); -} - -bool iButtonSceneDeleteConfirm::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeWidgetButtonResult) { - if(event->payload.widget_button_result == GuiButtonTypeRight) { - if(app->delete_key()) { - app->switch_to_next_scene(iButtonApp::Scene::SceneDeleteSuccess); - } - } else { - app->switch_to_previous_scene(); - } - - consumed = true; - } - - return consumed; -} - -void iButtonSceneDeleteConfirm::on_exit(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Widget* widget = view_manager->get_widget(); - - app->set_text_store(""); - - widget_reset(widget); -} diff --git a/applications/ibutton/scene/ibutton_scene_delete_confirm.h b/applications/ibutton/scene/ibutton_scene_delete_confirm.h deleted file mode 100644 index cacbb7fe5..000000000 --- a/applications/ibutton/scene/ibutton_scene_delete_confirm.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneDeleteConfirm : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scene/ibutton_scene_delete_success.cpp b/applications/ibutton/scene/ibutton_scene_delete_success.cpp deleted file mode 100644 index ba1381610..000000000 --- a/applications/ibutton/scene/ibutton_scene_delete_success.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "ibutton_scene_delete_success.h" -#include "../ibutton_app.h" - -static void popup_callback(void* context) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - event.type = iButtonEvent::Type::EventTypeBack; - app->get_view_manager()->send_event(&event); -} - -void iButtonSceneDeleteSuccess::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - - popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); - popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); - - popup_set_callback(popup, popup_callback); - popup_set_context(popup, app); - popup_set_timeout(popup, 1500); - popup_enable_timeout(popup); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup); -} - -bool iButtonSceneDeleteSuccess::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeBack) { - app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneSelectKey}); - consumed = true; - } - - return consumed; -} - -void iButtonSceneDeleteSuccess::on_exit(iButtonApp* app) { - Popup* popup = app->get_view_manager()->get_popup(); - - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); - - popup_disable_timeout(popup); - popup_set_context(popup, NULL); - popup_set_callback(popup, NULL); -} diff --git a/applications/ibutton/scene/ibutton_scene_delete_success.h b/applications/ibutton/scene/ibutton_scene_delete_success.h deleted file mode 100644 index 1fbe5230a..000000000 --- a/applications/ibutton/scene/ibutton_scene_delete_success.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneDeleteSuccess : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scene/ibutton_scene_emulate.h b/applications/ibutton/scene/ibutton_scene_emulate.h deleted file mode 100644 index 61107b94b..000000000 --- a/applications/ibutton/scene/ibutton_scene_emulate.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneEmulate : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scene/ibutton_scene_exit_confirm.cpp b/applications/ibutton/scene/ibutton_scene_exit_confirm.cpp deleted file mode 100644 index 2c9fe94cb..000000000 --- a/applications/ibutton/scene/ibutton_scene_exit_confirm.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "ibutton_scene_exit_confirm.h" -#include "../ibutton_app.h" - -static void widget_callback(GuiButtonType result, InputType type, void* context) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - - if(type == InputTypeShort) { - event.type = iButtonEvent::Type::EventTypeWidgetButtonResult; - event.payload.widget_button_result = result; - app->get_view_manager()->send_event(&event); - } -} - -void iButtonSceneExitConfirm::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Widget* widget = view_manager->get_widget(); - - widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", widget_callback, app); - widget_add_button_element(widget, GuiButtonTypeRight, "Stay", widget_callback, app); - widget_add_string_element( - widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton menu"); - widget_add_string_element( - widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost"); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewWidget); -} - -bool iButtonSceneExitConfirm::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeWidgetButtonResult) { - if(event->payload.widget_button_result == GuiButtonTypeLeft) { - app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneStart}); - } else if(event->payload.widget_button_result == GuiButtonTypeRight) { - app->switch_to_previous_scene(); - } - consumed = true; - } else if(event->type == iButtonEvent::Type::EventTypeBack) { - consumed = true; - } - - return consumed; -} - -void iButtonSceneExitConfirm::on_exit(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Widget* widget = view_manager->get_widget(); - widget_reset(widget); -} diff --git a/applications/ibutton/scene/ibutton_scene_exit_confirm.h b/applications/ibutton/scene/ibutton_scene_exit_confirm.h deleted file mode 100644 index f621a59a5..000000000 --- a/applications/ibutton/scene/ibutton_scene_exit_confirm.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneExitConfirm : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scene/ibutton_scene_generic.h b/applications/ibutton/scene/ibutton_scene_generic.h deleted file mode 100644 index 0e2444b58..000000000 --- a/applications/ibutton/scene/ibutton_scene_generic.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include "../ibutton_event.h" - -class iButtonApp; - -class iButtonScene { -public: - virtual void on_enter(iButtonApp* app) = 0; - virtual bool on_event(iButtonApp* app, iButtonEvent* event) = 0; - virtual void on_exit(iButtonApp* app) = 0; - virtual ~iButtonScene(){}; - -private: -}; diff --git a/applications/ibutton/scene/ibutton_scene_info.cpp b/applications/ibutton/scene/ibutton_scene_info.cpp deleted file mode 100755 index dd7797892..000000000 --- a/applications/ibutton/scene/ibutton_scene_info.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "ibutton_scene_info.h" -#include "../ibutton_app.h" - -void iButtonSceneInfo::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Widget* widget = view_manager->get_widget(); - iButtonKey* key = app->get_key(); - const uint8_t* key_data = ibutton_key_get_data_p(key); - - app->set_text_store("%s", ibutton_key_get_name_p(key)); - widget_add_text_box_element( - widget, 0, 0, 128, 28, AlignCenter, AlignCenter, app->get_text_store(), false); - - switch(ibutton_key_get_type(key)) { - case iButtonKeyDS1990: - app->set_text_store( - "%02X %02X %02X %02X %02X %02X %02X %02X", - key_data[0], - key_data[1], - key_data[2], - key_data[3], - key_data[4], - key_data[5], - key_data[6], - key_data[7]); - widget_add_string_element( - widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Dallas"); - break; - case iButtonKeyMetakom: - app->set_text_store( - "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]); - widget_add_string_element( - widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Metakom"); - break; - case iButtonKeyCyfral: - app->set_text_store("%02X %02X", key_data[0], key_data[1]); - widget_add_string_element( - widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Cyfral"); - break; - } - widget_add_string_element( - widget, 64, 35, AlignCenter, AlignBottom, FontPrimary, app->get_text_store()); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewWidget); -} - -bool iButtonSceneInfo::on_event(iButtonApp*, iButtonEvent*) { - return false; -} - -void iButtonSceneInfo::on_exit(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Widget* widget = view_manager->get_widget(); - - app->set_text_store(""); - - widget_reset(widget); -} diff --git a/applications/ibutton/scene/ibutton_scene_info.h b/applications/ibutton/scene/ibutton_scene_info.h deleted file mode 100644 index bbfb0c607..000000000 --- a/applications/ibutton/scene/ibutton_scene_info.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneInfo : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scene/ibutton_scene_read.cpp b/applications/ibutton/scene/ibutton_scene_read.cpp deleted file mode 100644 index 1cfdbfe32..000000000 --- a/applications/ibutton/scene/ibutton_scene_read.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "ibutton_scene_read.h" -#include "../ibutton_app.h" -#include - -static void read_callback(void* context) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event = { - .payload = {.dummy = 0}, - .type = iButtonEvent::Type::EventTypeWorkerRead, - }; - app->get_view_manager()->send_event(&event); -} - -void iButtonSceneRead::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - iButtonKey* key = app->get_key(); - iButtonWorker* worker = app->get_key_worker(); - DOLPHIN_DEED(DolphinDeedIbuttonRead); - - popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom); - popup_set_text(popup, "waiting\nfor key ...", 95, 30, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 5, &I_DolphinWait_61x59); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup); - ibutton_key_set_name(key, ""); - - ibutton_worker_read_set_callback(worker, read_callback, app); - ibutton_worker_read_start(worker, key); -} - -bool iButtonSceneRead::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeWorkerRead) { - consumed = true; - - iButtonKey* key = app->get_key(); - bool success = false; - if(ibutton_key_get_type(key) == iButtonKeyDS1990) { - if(!ibutton_key_dallas_crc_is_valid(key)) { - app->switch_to_next_scene(iButtonApp::Scene::SceneReadCRCError); - } else if(!ibutton_key_dallas_is_1990_key(key)) { - app->switch_to_next_scene(iButtonApp::Scene::SceneReadNotKeyError); - } else { - success = true; - } - } else { - success = true; - } - if(success) { - app->notify_success(); - app->notify_green_on(); - DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); - app->switch_to_next_scene(iButtonApp::Scene::SceneReadSuccess); - } - } else if(event->type == iButtonEvent::Type::EventTypeTick) { - consumed = true; - app->notify_read(); - } - - return consumed; -} - -void iButtonSceneRead::on_exit(iButtonApp* app) { - Popup* popup = app->get_view_manager()->get_popup(); - ibutton_worker_stop(app->get_key_worker()); - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); -} diff --git a/applications/ibutton/scene/ibutton_scene_read.h b/applications/ibutton/scene/ibutton_scene_read.h deleted file mode 100644 index 565477784..000000000 --- a/applications/ibutton/scene/ibutton_scene_read.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneRead : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scene/ibutton_scene_read_crc_error.cpp b/applications/ibutton/scene/ibutton_scene_read_crc_error.cpp deleted file mode 100644 index d9d3ffd5c..000000000 --- a/applications/ibutton/scene/ibutton_scene_read_crc_error.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "ibutton_scene_read_crc_error.h" -#include "../ibutton_app.h" -#include - -static void dialog_ex_callback(DialogExResult result, void* context) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeDialogResult; - event.payload.dialog_result = result; - - app->get_view_manager()->send_event(&event); -} - -void iButtonSceneReadCRCError::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - const uint8_t* key_data = ibutton_key_get_data_p(app->get_key()); - - app->set_text_store( - "%02X %02X %02X %02X %02X %02X %02X %02X\nExpected CRC: %X", - key_data[0], - key_data[1], - key_data[2], - key_data[3], - key_data[4], - key_data[5], - key_data[6], - key_data[7], - maxim_crc8(key_data, 7, MAXIM_CRC8_INIT)); - - dialog_ex_set_header(dialog_ex, "CRC ERROR", 64, 10, AlignCenter, AlignCenter); - dialog_ex_set_text(dialog_ex, app->get_text_store(), 64, 19, AlignCenter, AlignTop); - dialog_ex_set_left_button_text(dialog_ex, "Retry"); - dialog_ex_set_right_button_text(dialog_ex, "More"); - dialog_ex_set_result_callback(dialog_ex, dialog_ex_callback); - dialog_ex_set_context(dialog_ex, app); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewDialogEx); - app->notify_error(); - app->notify_red_on(); -} - -bool iButtonSceneReadCRCError::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeDialogResult) { - if(event->payload.dialog_result == DialogExResultRight) { - app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu); - } else { - app->switch_to_previous_scene(); - } - - consumed = true; - } - - return consumed; -} - -void iButtonSceneReadCRCError::on_exit(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - - app->set_text_store(""); - - dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); - dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); - dialog_ex_set_left_button_text(dialog_ex, NULL); - dialog_ex_set_result_callback(dialog_ex, NULL); - dialog_ex_set_context(dialog_ex, NULL); - - app->notify_red_off(); -} diff --git a/applications/ibutton/scene/ibutton_scene_read_crc_error.h b/applications/ibutton/scene/ibutton_scene_read_crc_error.h deleted file mode 100644 index db72d068a..000000000 --- a/applications/ibutton/scene/ibutton_scene_read_crc_error.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneReadCRCError : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scene/ibutton_scene_read_key_menu.cpp b/applications/ibutton/scene/ibutton_scene_read_key_menu.cpp deleted file mode 100644 index 215eb76f6..000000000 --- a/applications/ibutton/scene/ibutton_scene_read_key_menu.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "ibutton_scene_read_key_menu.h" -#include "../ibutton_app.h" - -typedef enum { - SubmenuIndexSave, - SubmenuIndexEmulate, - SubmenuIndexWrite, -} SubmenuIndex; - -static void submenu_callback(void* context, uint32_t index) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeMenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void iButtonSceneReadKeyMenu::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_add_item(submenu, "Save", SubmenuIndexSave, submenu_callback, app); - submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app); - if(ibutton_key_get_type(app->get_key()) == iButtonKeyDS1990) { - submenu_add_item(submenu, "Write", SubmenuIndexWrite, submenu_callback, app); - } - submenu_set_selected_item(submenu, submenu_item_selected); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu); -} - -bool iButtonSceneReadKeyMenu::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeMenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { - case SubmenuIndexWrite: - app->switch_to_next_scene(iButtonApp::Scene::SceneWrite); - break; - case SubmenuIndexEmulate: - app->switch_to_next_scene(iButtonApp::Scene::SceneEmulate); - break; - case SubmenuIndexSave: - app->switch_to_next_scene(iButtonApp::Scene::SceneSaveName); - break; - } - consumed = true; - } else if(event->type == iButtonEvent::Type::EventTypeBack) { - app->switch_to_previous_scene(); - consumed = true; - } - - return consumed; -} - -void iButtonSceneReadKeyMenu::on_exit(iButtonApp* app) { - iButtonAppViewManager* view = app->get_view_manager(); - Submenu* submenu = view->get_submenu(); - - submenu_reset(submenu); -} diff --git a/applications/ibutton/scene/ibutton_scene_read_key_menu.h b/applications/ibutton/scene/ibutton_scene_read_key_menu.h deleted file mode 100644 index d68a4d1db..000000000 --- a/applications/ibutton/scene/ibutton_scene_read_key_menu.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneReadKeyMenu : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; - -private: - uint32_t submenu_item_selected = 0; -}; diff --git a/applications/ibutton/scene/ibutton_scene_read_not_key_error.cpp b/applications/ibutton/scene/ibutton_scene_read_not_key_error.cpp deleted file mode 100644 index 58ea853c1..000000000 --- a/applications/ibutton/scene/ibutton_scene_read_not_key_error.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "ibutton_scene_read_not_key_error.h" -#include "../ibutton_app.h" -#include - -static void dialog_ex_callback(DialogExResult result, void* context) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeDialogResult; - event.payload.dialog_result = result; - - app->get_view_manager()->send_event(&event); -} - -void iButtonSceneReadNotKeyError::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - const uint8_t* key_data = ibutton_key_get_data_p(app->get_key()); - - app->set_text_store( - "THIS IS NOT A KEY\n%02X %02X %02X %02X %02X %02X %02X %02X", - key_data[0], - key_data[1], - key_data[2], - key_data[3], - key_data[4], - key_data[5], - key_data[6], - key_data[7], - maxim_crc8(key_data, 7, MAXIM_CRC8_INIT)); - - dialog_ex_set_header(dialog_ex, "ERROR:", 64, 10, AlignCenter, AlignCenter); - dialog_ex_set_text(dialog_ex, app->get_text_store(), 64, 19, AlignCenter, AlignTop); - dialog_ex_set_left_button_text(dialog_ex, "Retry"); - dialog_ex_set_right_button_text(dialog_ex, "More"); - dialog_ex_set_result_callback(dialog_ex, dialog_ex_callback); - dialog_ex_set_context(dialog_ex, app); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewDialogEx); - app->notify_error(); - app->notify_red_on(); -} - -bool iButtonSceneReadNotKeyError::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeDialogResult) { - if(event->payload.dialog_result == DialogExResultRight) { - app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu); - } else { - app->switch_to_previous_scene(); - } - - consumed = true; - } - - return consumed; -} - -void iButtonSceneReadNotKeyError::on_exit(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - - app->set_text_store(""); - - dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); - dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); - dialog_ex_set_left_button_text(dialog_ex, NULL); - dialog_ex_set_result_callback(dialog_ex, NULL); - dialog_ex_set_context(dialog_ex, NULL); - - app->notify_red_off(); -} diff --git a/applications/ibutton/scene/ibutton_scene_read_not_key_error.h b/applications/ibutton/scene/ibutton_scene_read_not_key_error.h deleted file mode 100644 index 30d20033e..000000000 --- a/applications/ibutton/scene/ibutton_scene_read_not_key_error.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneReadNotKeyError : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scene/ibutton_scene_read_success.cpp b/applications/ibutton/scene/ibutton_scene_read_success.cpp deleted file mode 100644 index c4523904d..000000000 --- a/applications/ibutton/scene/ibutton_scene_read_success.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "ibutton_scene_read_success.h" -#include "../ibutton_app.h" -#include - -static void dialog_ex_callback(DialogExResult result, void* context) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeDialogResult; - event.payload.dialog_result = result; - - app->get_view_manager()->send_event(&event); -} - -void iButtonSceneReadSuccess::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - iButtonKey* key = app->get_key(); - const uint8_t* key_data = ibutton_key_get_data_p(key); - - switch(ibutton_key_get_type(key)) { - case iButtonKeyDS1990: - app->set_text_store( - "Dallas\n%02X %02X %02X %02X\n%02X %02X %02X %02X", - key_data[0], - key_data[1], - key_data[2], - key_data[3], - key_data[4], - key_data[5], - key_data[6], - key_data[7]); - break; - case iButtonKeyCyfral: - app->set_text_store("Cyfral\n%02X %02X", key_data[0], key_data[1]); - break; - case iButtonKeyMetakom: - app->set_text_store( - "Metakom\n%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]); - break; - } - - dialog_ex_set_text(dialog_ex, app->get_text_store(), 95, 30, AlignCenter, AlignCenter); - dialog_ex_set_left_button_text(dialog_ex, "Retry"); - dialog_ex_set_right_button_text(dialog_ex, "More"); - dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinReadingSuccess_59x63); - dialog_ex_set_result_callback(dialog_ex, dialog_ex_callback); - dialog_ex_set_context(dialog_ex, app); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewDialogEx); -} - -bool iButtonSceneReadSuccess::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeDialogResult) { - if(event->payload.dialog_result == DialogExResultRight) { - app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu); - } else { - app->switch_to_next_scene(iButtonApp::Scene::SceneRetryConfirm); - } - consumed = true; - } else if(event->type == iButtonEvent::Type::EventTypeBack) { - app->switch_to_next_scene(iButtonApp::Scene::SceneExitConfirm); - consumed = true; - } - - return consumed; -} - -void iButtonSceneReadSuccess::on_exit(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - DialogEx* dialog_ex = view_manager->get_dialog_ex(); - - app->set_text_store(""); - - dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); - dialog_ex_set_left_button_text(dialog_ex, NULL); - dialog_ex_set_right_button_text(dialog_ex, NULL); - dialog_ex_set_result_callback(dialog_ex, NULL); - dialog_ex_set_context(dialog_ex, NULL); - dialog_ex_set_icon(dialog_ex, 0, 0, NULL); - - app->notify_green_off(); -} diff --git a/applications/ibutton/scene/ibutton_scene_read_success.h b/applications/ibutton/scene/ibutton_scene_read_success.h deleted file mode 100644 index bf9003c23..000000000 --- a/applications/ibutton/scene/ibutton_scene_read_success.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneReadSuccess : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scene/ibutton_scene_retry_confirm.cpp b/applications/ibutton/scene/ibutton_scene_retry_confirm.cpp deleted file mode 100644 index aa3483b3d..000000000 --- a/applications/ibutton/scene/ibutton_scene_retry_confirm.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "ibutton_scene_retry_confirm.h" -#include "../ibutton_app.h" - -static void widget_callback(GuiButtonType result, InputType type, void* context) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - - if(type == InputTypeShort) { - event.type = iButtonEvent::Type::EventTypeWidgetButtonResult; - event.payload.widget_button_result = result; - app->get_view_manager()->send_event(&event); - } -} - -void iButtonSceneRetryConfirm::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Widget* widget = view_manager->get_widget(); - - widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", widget_callback, app); - widget_add_button_element(widget, GuiButtonTypeRight, "Stay", widget_callback, app); - widget_add_string_element( - widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?"); - widget_add_string_element( - widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost"); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewWidget); -} - -bool iButtonSceneRetryConfirm::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeWidgetButtonResult) { - if(event->payload.widget_button_result == GuiButtonTypeLeft) { - app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneRead}); - } else if(event->payload.widget_button_result == GuiButtonTypeRight) { - app->switch_to_previous_scene(); - } - consumed = true; - } else if(event->type == iButtonEvent::Type::EventTypeBack) { - consumed = true; - } - - return consumed; -} - -void iButtonSceneRetryConfirm::on_exit(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Widget* widget = view_manager->get_widget(); - widget_reset(widget); -} diff --git a/applications/ibutton/scene/ibutton_scene_retry_confirm.h b/applications/ibutton/scene/ibutton_scene_retry_confirm.h deleted file mode 100644 index 0fa71ad11..000000000 --- a/applications/ibutton/scene/ibutton_scene_retry_confirm.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneRetryConfirm : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scene/ibutton_scene_save_name.cpp b/applications/ibutton/scene/ibutton_scene_save_name.cpp deleted file mode 100644 index 71eee148b..000000000 --- a/applications/ibutton/scene/ibutton_scene_save_name.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "ibutton_scene_save_name.h" -#include "../ibutton_app.h" -#include - -static void text_input_callback(void* context) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeTextEditResult; - - app->get_view_manager()->send_event(&event); -} - -void iButtonSceneSaveName::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - TextInput* text_input = view_manager->get_text_input(); - - const char* key_name = ibutton_key_get_name_p(app->get_key()); - bool key_name_empty = !strcmp(key_name, ""); - - if(key_name_empty) { - set_random_name(app->get_text_store(), app->get_text_store_size()); - } else { - app->set_text_store("%s", key_name); - } - - text_input_set_header_text(text_input, "Name the key"); - text_input_set_result_callback( - text_input, - text_input_callback, - app, - app->get_text_store(), - IBUTTON_KEY_NAME_SIZE, - key_name_empty); - - ValidatorIsFile* validator_is_file = - validator_is_file_alloc_init(app->app_folder, app->app_extension, key_name); - text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewTextInput); -} - -bool iButtonSceneSaveName::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeTextEditResult) { - if(app->save_key(app->get_text_store())) { - app->switch_to_next_scene(iButtonApp::Scene::SceneSaveSuccess); - } else { - app->search_and_switch_to_previous_scene( - {iButtonApp::Scene::SceneReadKeyMenu, - iButtonApp::Scene::SceneSavedKeyMenu, - iButtonApp::Scene::SceneAddType}); - } - consumed = true; - } - - return consumed; -} - -void iButtonSceneSaveName::on_exit(iButtonApp* app) { - TextInput* text_input = app->get_view_manager()->get_text_input(); - - void* validator_context = text_input_get_validator_callback_context(text_input); - text_input_set_validator(text_input, NULL, NULL); - validator_is_file_free((ValidatorIsFile*)validator_context); - - text_input_reset(text_input); -} diff --git a/applications/ibutton/scene/ibutton_scene_save_name.h b/applications/ibutton/scene/ibutton_scene_save_name.h deleted file mode 100644 index 2d7f102e1..000000000 --- a/applications/ibutton/scene/ibutton_scene_save_name.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneSaveName : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scene/ibutton_scene_save_success.cpp b/applications/ibutton/scene/ibutton_scene_save_success.cpp deleted file mode 100644 index 92c0e6956..000000000 --- a/applications/ibutton/scene/ibutton_scene_save_success.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "ibutton_scene_save_success.h" -#include "../ibutton_app.h" -#include - -static void popup_callback(void* context) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - event.type = iButtonEvent::Type::EventTypeBack; - app->get_view_manager()->send_event(&event); -} - -void iButtonSceneSaveSuccess::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - DOLPHIN_DEED(DolphinDeedIbuttonSave); - - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); - - popup_set_callback(popup, popup_callback); - popup_set_context(popup, app); - popup_set_timeout(popup, 1500); - popup_enable_timeout(popup); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup); -} - -bool iButtonSceneSaveSuccess::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeBack) { - app->search_and_switch_to_previous_scene( - {iButtonApp::Scene::SceneReadKeyMenu, - iButtonApp::Scene::SceneSavedKeyMenu, - iButtonApp::Scene::SceneAddType}); - consumed = true; - } - - return consumed; -} - -void iButtonSceneSaveSuccess::on_exit(iButtonApp* app) { - Popup* popup = app->get_view_manager()->get_popup(); - - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); - - popup_disable_timeout(popup); - popup_set_context(popup, NULL); - popup_set_callback(popup, NULL); -} diff --git a/applications/ibutton/scene/ibutton_scene_save_success.h b/applications/ibutton/scene/ibutton_scene_save_success.h deleted file mode 100644 index 14c7412dc..000000000 --- a/applications/ibutton/scene/ibutton_scene_save_success.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneSaveSuccess : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp b/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp deleted file mode 100644 index d9d042d9c..000000000 --- a/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "ibutton_scene_saved_key_menu.h" -#include "../ibutton_app.h" -#include - -typedef enum { - SubmenuIndexEmulate, - SubmenuIndexWrite, - SubmenuIndexEdit, - SubmenuIndexDelete, - SubmenuIndexInfo, -} SubmenuIndex; - -static void submenu_callback(void* context, uint32_t index) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeMenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void iButtonSceneSavedKeyMenu::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app); - if(ibutton_key_get_type(app->get_key()) == iButtonKeyDS1990) { - submenu_add_item(submenu, "Write", SubmenuIndexWrite, submenu_callback, app); - } - submenu_add_item(submenu, "Edit", SubmenuIndexEdit, submenu_callback, app); - submenu_add_item(submenu, "Delete", SubmenuIndexDelete, submenu_callback, app); - submenu_add_item(submenu, "Info", SubmenuIndexInfo, submenu_callback, app); - submenu_set_selected_item(submenu, submenu_item_selected); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu); -} - -bool iButtonSceneSavedKeyMenu::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeMenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { - case SubmenuIndexWrite: - app->switch_to_next_scene(iButtonApp::Scene::SceneWrite); - break; - case SubmenuIndexEmulate: - app->switch_to_next_scene(iButtonApp::Scene::SceneEmulate); - break; - case SubmenuIndexEdit: - app->switch_to_next_scene(iButtonApp::Scene::SceneAddValue); - break; - case SubmenuIndexDelete: - app->switch_to_next_scene(iButtonApp::Scene::SceneDeleteConfirm); - break; - case SubmenuIndexInfo: - app->switch_to_next_scene(iButtonApp::Scene::SceneInfo); - break; - } - consumed = true; - } - - return consumed; -} - -void iButtonSceneSavedKeyMenu::on_exit(iButtonApp* app) { - iButtonAppViewManager* view = app->get_view_manager(); - Submenu* submenu = view->get_submenu(); - - submenu_reset(submenu); -} diff --git a/applications/ibutton/scene/ibutton_scene_saved_key_menu.h b/applications/ibutton/scene/ibutton_scene_saved_key_menu.h deleted file mode 100644 index 08809779d..000000000 --- a/applications/ibutton/scene/ibutton_scene_saved_key_menu.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneSavedKeyMenu : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; - -private: - uint32_t submenu_item_selected = 0; -}; diff --git a/applications/ibutton/scene/ibutton_scene_select_key.cpp b/applications/ibutton/scene/ibutton_scene_select_key.cpp deleted file mode 100644 index 6a1246a49..000000000 --- a/applications/ibutton/scene/ibutton_scene_select_key.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "ibutton_scene_select_key.h" -#include "../ibutton_app.h" - -void iButtonSceneSelectKey::on_enter(iButtonApp* app) { - // Process file_select return - if(app->load_key()) { - app->switch_to_next_scene(iButtonApp::Scene::SceneSavedKeyMenu); - } else { - app->switch_to_previous_scene(); - } -} - -bool iButtonSceneSelectKey::on_event(iButtonApp*, iButtonEvent*) { - return false; -} - -void iButtonSceneSelectKey::on_exit(iButtonApp*) { -} diff --git a/applications/ibutton/scene/ibutton_scene_select_key.h b/applications/ibutton/scene/ibutton_scene_select_key.h deleted file mode 100644 index d68199099..000000000 --- a/applications/ibutton/scene/ibutton_scene_select_key.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneSelectKey : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scene/ibutton_scene_start.cpp b/applications/ibutton/scene/ibutton_scene_start.cpp deleted file mode 100644 index f74654595..000000000 --- a/applications/ibutton/scene/ibutton_scene_start.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "ibutton_scene_start.h" -#include "../ibutton_app.h" - -typedef enum { - SubmenuIndexRead, - SubmenuIndexSaved, - SubmenuIndexAdd, -} SubmenuIndex; - -static void submenu_callback(void* context, uint32_t index) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - - event.type = iButtonEvent::Type::EventTypeMenuSelected; - event.payload.menu_index = index; - - app->get_view_manager()->send_event(&event); -} - -void iButtonSceneStart::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Submenu* submenu = view_manager->get_submenu(); - - submenu_add_item(submenu, "Read", SubmenuIndexRead, submenu_callback, app); - submenu_add_item(submenu, "Saved", SubmenuIndexSaved, submenu_callback, app); - submenu_add_item(submenu, "Add Manually", SubmenuIndexAdd, submenu_callback, app); - submenu_set_selected_item(submenu, submenu_item_selected); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu); -} - -bool iButtonSceneStart::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeMenuSelected) { - submenu_item_selected = event->payload.menu_index; - switch(event->payload.menu_index) { - case SubmenuIndexRead: - app->switch_to_next_scene(iButtonApp::Scene::SceneRead); - break; - case SubmenuIndexSaved: - app->switch_to_next_scene(iButtonApp::Scene::SceneSelectKey); - break; - case SubmenuIndexAdd: - app->switch_to_next_scene(iButtonApp::Scene::SceneAddType); - break; - } - consumed = true; - } - - return consumed; -} - -void iButtonSceneStart::on_exit(iButtonApp* app) { - iButtonAppViewManager* view = app->get_view_manager(); - Submenu* submenu = view->get_submenu(); - - submenu_reset(submenu); -} diff --git a/applications/ibutton/scene/ibutton_scene_start.h b/applications/ibutton/scene/ibutton_scene_start.h deleted file mode 100644 index 28ef28d35..000000000 --- a/applications/ibutton/scene/ibutton_scene_start.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneStart : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; - -private: - uint32_t submenu_item_selected = 0; -}; diff --git a/applications/ibutton/scene/ibutton_scene_write.cpp b/applications/ibutton/scene/ibutton_scene_write.cpp deleted file mode 100644 index d4f84e11c..000000000 --- a/applications/ibutton/scene/ibutton_scene_write.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "ibutton_scene_write.h" -#include "../ibutton_app.h" - -static void ibutton_worker_write_cb(void* context, iButtonWorkerWriteResult result) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - event.type = iButtonEvent::Type::EventTypeWorkerWrite; - event.payload.worker_write_result = result; - - app->get_view_manager()->send_event(&event); -} - -void iButtonSceneWrite::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - iButtonKey* key = app->get_key(); - iButtonWorker* worker = app->get_key_worker(); - const uint8_t* key_data = ibutton_key_get_data_p(key); - const char* key_name = ibutton_key_get_name_p(key); - uint8_t line_count = 2; - - // check that stored key has name - if(strcmp(key_name, "") != 0) { - app->set_text_store("writing\n%s", key_name); - line_count = 2; - } else { - // if not, show key data - switch(ibutton_key_get_type(key)) { - case iButtonKeyDS1990: - app->set_text_store( - "writing\n%02X %02X %02X %02X\n%02X %02X %02X %02X", - key_data[0], - key_data[1], - key_data[2], - key_data[3], - key_data[4], - key_data[5], - key_data[6], - key_data[7]); - line_count = 3; - break; - case iButtonKeyCyfral: - app->set_text_store("writing\n%02X %02X", key_data[0], key_data[1]); - line_count = 2; - break; - case iButtonKeyMetakom: - app->set_text_store( - "writing\n%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]); - line_count = 2; - break; - } - } - - switch(line_count) { - case 3: - popup_set_header(popup, "iButton", 82, 18, AlignCenter, AlignBottom); - popup_set_text(popup, app->get_text_store(), 82, 22, AlignCenter, AlignTop); - break; - - default: - popup_set_header(popup, "iButton", 82, 24, AlignCenter, AlignBottom); - popup_set_text(popup, app->get_text_store(), 82, 28, AlignCenter, AlignTop); - break; - } - - popup_set_icon(popup, 2, 10, &I_iButtonKey_49x44); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup); - - blink_yellow = false; - ibutton_worker_write_set_callback(worker, ibutton_worker_write_cb, app); - ibutton_worker_write_start(worker, key); -} - -bool iButtonSceneWrite::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeWorkerWrite) { - consumed = true; - - switch(event->payload.worker_write_result) { - case iButtonWorkerWriteOK: - case iButtonWorkerWriteSameKey: - app->switch_to_next_scene(iButtonApp::Scene::SceneWriteSuccess); - break; - case iButtonWorkerWriteNoDetect: - blink_yellow = false; - break; - case iButtonWorkerWriteCannotWrite: - blink_yellow = true; - break; - } - } else if(event->type == iButtonEvent::Type::EventTypeTick) { - if(blink_yellow) { - app->notify_yellow_blink(); - } else { - app->notify_emulate(); - } - } - - return consumed; -} - -void iButtonSceneWrite::on_exit(iButtonApp* app) { - Popup* popup = app->get_view_manager()->get_popup(); - ibutton_worker_stop(app->get_key_worker()); - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); -} diff --git a/applications/ibutton/scene/ibutton_scene_write.h b/applications/ibutton/scene/ibutton_scene_write.h deleted file mode 100644 index 8b52473af..000000000 --- a/applications/ibutton/scene/ibutton_scene_write.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneWrite : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; - -private: - bool blink_yellow; -}; diff --git a/applications/ibutton/scene/ibutton_scene_write_success.cpp b/applications/ibutton/scene/ibutton_scene_write_success.cpp deleted file mode 100644 index 3f27c6724..000000000 --- a/applications/ibutton/scene/ibutton_scene_write_success.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "ibutton_scene_write_success.h" -#include "../ibutton_app.h" - -static void popup_callback(void* context) { - furi_assert(context); - iButtonApp* app = static_cast(context); - iButtonEvent event; - event.type = iButtonEvent::Type::EventTypeBack; - app->get_view_manager()->send_event(&event); - app->notify_green_off(); -} - -void iButtonSceneWriteSuccess::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - - popup_set_icon(popup, 0, 12, &I_iButtonDolphinVerySuccess_108x52); - popup_set_text(popup, "Successfully written!", 40, 12, AlignLeft, AlignBottom); - - popup_set_callback(popup, popup_callback); - popup_set_context(popup, app); - popup_set_timeout(popup, 1500); - popup_enable_timeout(popup); - - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup); - - app->notify_success(); - app->notify_green_on(); -} - -bool iButtonSceneWriteSuccess::on_event(iButtonApp* app, iButtonEvent* event) { - bool consumed = false; - - if(event->type == iButtonEvent::Type::EventTypeBack) { - app->search_and_switch_to_previous_scene( - {iButtonApp::Scene::SceneReadKeyMenu, iButtonApp::Scene::SceneStart}); - consumed = true; - } - - return consumed; -} - -void iButtonSceneWriteSuccess::on_exit(iButtonApp* app) { - Popup* popup = app->get_view_manager()->get_popup(); - - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); - - popup_disable_timeout(popup); - popup_set_context(popup, NULL); - popup_set_callback(popup, NULL); -} diff --git a/applications/ibutton/scene/ibutton_scene_write_success.h b/applications/ibutton/scene/ibutton_scene_write_success.h deleted file mode 100644 index 99680c7dd..000000000 --- a/applications/ibutton/scene/ibutton_scene_write_success.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "ibutton_scene_generic.h" - -class iButtonSceneWriteSuccess : public iButtonScene { -public: - void on_enter(iButtonApp* app) final; - bool on_event(iButtonApp* app, iButtonEvent* event) final; - void on_exit(iButtonApp* app) final; -}; diff --git a/applications/ibutton/scenes/ibutton_scene.c b/applications/ibutton/scenes/ibutton_scene.c new file mode 100644 index 000000000..c36a0eb5d --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene.c @@ -0,0 +1,30 @@ +#include "ibutton_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const ibutton_on_enter_handlers[])(void*) = { +#include "ibutton_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const ibutton_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "ibutton_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const ibutton_on_exit_handlers[])(void* context) = { +#include "ibutton_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers ibutton_scene_handlers = { + .on_enter_handlers = ibutton_on_enter_handlers, + .on_event_handlers = ibutton_on_event_handlers, + .on_exit_handlers = ibutton_on_exit_handlers, + .scene_num = iButtonSceneNum, +}; diff --git a/applications/ibutton/scenes/ibutton_scene.h b/applications/ibutton/scenes/ibutton_scene.h new file mode 100644 index 000000000..60d2353ed --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) iButtonScene##id, +typedef enum { +#include "ibutton_scene_config.h" + iButtonSceneNum, +} iButtonScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers ibutton_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "ibutton_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "ibutton_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "ibutton_scene_config.h" +#undef ADD_SCENE diff --git a/applications/ibutton/scenes/ibutton_scene_add_type.c b/applications/ibutton/scenes/ibutton_scene_add_type.c new file mode 100644 index 000000000..db129295a --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_add_type.c @@ -0,0 +1,58 @@ +#include "../ibutton_i.h" + +enum SubmenuIndex { + SubmenuIndexCyfral, + SubmenuIndexDallas, + SubmenuIndexMetakom, +}; + +void ibutton_scene_add_type_submenu_callback(void* context, uint32_t index) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, index); +} + +void ibutton_scene_add_type_on_enter(void* context) { + iButton* ibutton = context; + Submenu* submenu = ibutton->submenu; + + submenu_add_item( + submenu, "Cyfral", SubmenuIndexCyfral, ibutton_scene_add_type_submenu_callback, ibutton); + submenu_add_item( + submenu, "Dallas", SubmenuIndexDallas, ibutton_scene_add_type_submenu_callback, ibutton); + submenu_add_item( + submenu, "Metakom", SubmenuIndexMetakom, ibutton_scene_add_type_submenu_callback, ibutton); + + submenu_set_selected_item(submenu, SubmenuIndexCyfral); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu); +} + +bool ibutton_scene_add_type_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + iButtonKey* key = ibutton->key; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == SubmenuIndexCyfral) { + ibutton_key_set_type(key, iButtonKeyCyfral); + } else if(event.event == SubmenuIndexDallas) { + ibutton_key_set_type(key, iButtonKeyDS1990); + } else if(event.event == SubmenuIndexMetakom) { + ibutton_key_set_type(key, iButtonKeyMetakom); + } else { + furi_crash("Unknown key type"); + } + + ibutton_key_set_name(key, ""); + ibutton_key_clear_data(key); + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue); + } + + return consumed; +} + +void ibutton_scene_add_type_on_exit(void* context) { + iButton* ibutton = context; + submenu_reset(ibutton->submenu); +} diff --git a/applications/ibutton/scenes/ibutton_scene_add_value.c b/applications/ibutton/scenes/ibutton_scene_add_value.c new file mode 100644 index 000000000..b3ec11a50 --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_add_value.c @@ -0,0 +1,57 @@ +#include "../ibutton_i.h" + +#include + +void ibutton_scene_add_type_byte_input_callback(void* context) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventByteEditResult); +} + +void ibutton_scene_add_value_on_enter(void* context) { + iButton* ibutton = context; + iButtonKey* key = ibutton->key; + uint8_t* new_key_data = malloc(IBUTTON_KEY_DATA_SIZE); + + scene_manager_set_scene_state( + ibutton->scene_manager, iButtonSceneAddValue, (uint32_t)new_key_data); + memcpy(new_key_data, ibutton_key_get_data_p(key), ibutton_key_get_data_size(key)); + + byte_input_set_result_callback( + ibutton->byte_input, + ibutton_scene_add_type_byte_input_callback, + NULL, + ibutton, + new_key_data, + ibutton_key_get_data_size(key)); + + byte_input_set_header_text(ibutton->byte_input, "Enter the key"); + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewByteInput); +} + +bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + uint8_t* new_key_data = + (uint8_t*)scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddValue); + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == iButtonCustomEventByteEditResult) { + ibutton_key_set_data(ibutton->key, new_key_data, IBUTTON_KEY_DATA_SIZE); + DOLPHIN_DEED(DolphinDeedIbuttonAdd); + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName); + } + } + + return consumed; +} + +void ibutton_scene_add_value_on_exit(void* context) { + iButton* ibutton = context; + uint8_t* new_key_data = + (uint8_t*)scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddValue); + + byte_input_set_result_callback(ibutton->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(ibutton->byte_input, NULL); + free(new_key_data); +} diff --git a/applications/ibutton/scenes/ibutton_scene_config.h b/applications/ibutton/scenes/ibutton_scene_config.h new file mode 100644 index 000000000..d30b43beb --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_config.h @@ -0,0 +1,20 @@ +ADD_SCENE(ibutton, start, Start) +ADD_SCENE(ibutton, emulate, Emulate) +ADD_SCENE(ibutton, write, Write) +ADD_SCENE(ibutton, write_success, WriteSuccess) +ADD_SCENE(ibutton, info, Info) +ADD_SCENE(ibutton, read, Read) +ADD_SCENE(ibutton, read_key_menu, ReadKeyMenu) +ADD_SCENE(ibutton, read_success, ReadSuccess) +ADD_SCENE(ibutton, read_crc_error, ReadCRCError) +ADD_SCENE(ibutton, read_not_key_error, ReadNotKeyError) +ADD_SCENE(ibutton, select_key, SelectKey) +ADD_SCENE(ibutton, add_type, AddType) +ADD_SCENE(ibutton, add_value, AddValue) +ADD_SCENE(ibutton, saved_key_menu, SavedKeyMenu) +ADD_SCENE(ibutton, save_name, SaveName) +ADD_SCENE(ibutton, save_success, SaveSuccess) +ADD_SCENE(ibutton, delete_confirm, DeleteConfirm) +ADD_SCENE(ibutton, delete_success, DeleteSuccess) +ADD_SCENE(ibutton, retry_confirm, RetryConfirm) +ADD_SCENE(ibutton, exit_confirm, ExitConfirm) diff --git a/applications/ibutton/scenes/ibutton_scene_delete_confirm.c b/applications/ibutton/scenes/ibutton_scene_delete_confirm.c new file mode 100644 index 000000000..73ea97cc6 --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_delete_confirm.c @@ -0,0 +1,91 @@ +#include "../ibutton_i.h" + +static void ibutton_scene_delete_confirm_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + iButton* ibutton = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(ibutton->view_dispatcher, result); + } +} + +void ibutton_scene_delete_confirm_on_enter(void* context) { + iButton* ibutton = context; + Widget* widget = ibutton->widget; + iButtonKey* key = ibutton->key; + const uint8_t* key_data = ibutton_key_get_data_p(key); + + ibutton_text_store_set(ibutton, "\e#Delete %s?\e#", ibutton_key_get_name_p(key)); + widget_add_text_box_element( + widget, 0, 0, 128, 27, AlignCenter, AlignCenter, ibutton->text_store, false); + widget_add_button_element( + widget, GuiButtonTypeLeft, "Cancel", ibutton_scene_delete_confirm_widget_callback, ibutton); + widget_add_button_element( + widget, + GuiButtonTypeRight, + "Delete", + ibutton_scene_delete_confirm_widget_callback, + ibutton); + + switch(ibutton_key_get_type(key)) { + case iButtonKeyDS1990: + ibutton_text_store_set( + ibutton, + "%02X %02X %02X %02X %02X %02X %02X %02X", + key_data[0], + key_data[1], + key_data[2], + key_data[3], + key_data[4], + key_data[5], + key_data[6], + key_data[7]); + widget_add_string_element( + widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Dallas"); + break; + + case iButtonKeyCyfral: + ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]); + widget_add_string_element( + widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Cyfral"); + break; + + case iButtonKeyMetakom: + ibutton_text_store_set( + ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]); + widget_add_string_element( + widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Metakom"); + break; + } + widget_add_string_element( + widget, 64, 33, AlignCenter, AlignBottom, FontSecondary, ibutton->text_store); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); +} + +bool ibutton_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + SceneManager* scene_manager = ibutton->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeRight) { + if(ibutton_delete_key(ibutton)) { + scene_manager_next_scene(scene_manager, iButtonSceneDeleteSuccess); + } + //TODO: What if the key could not be deleted? + } else if(event.event == GuiButtonTypeLeft) { + scene_manager_previous_scene(scene_manager); + } + } + + return consumed; +} + +void ibutton_scene_delete_confirm_on_exit(void* context) { + iButton* ibutton = context; + ibutton_text_store_clear(ibutton); + widget_reset(ibutton->widget); +} diff --git a/applications/ibutton/scenes/ibutton_scene_delete_success.c b/applications/ibutton/scenes/ibutton_scene_delete_success.c new file mode 100644 index 000000000..8b7d9dfc0 --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_delete_success.c @@ -0,0 +1,48 @@ +#include "../ibutton_i.h" + +static void ibutton_scene_delete_success_popup_callback(void* context) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventBack); +} + +void ibutton_scene_delete_success_on_enter(void* context) { + iButton* ibutton = context; + Popup* popup = ibutton->popup; + + popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); + popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + + popup_set_callback(popup, ibutton_scene_delete_success_popup_callback); + popup_set_context(popup, ibutton); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); +} + +bool ibutton_scene_delete_success_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == iButtonCustomEventBack) { + scene_manager_search_and_switch_to_previous_scene( + ibutton->scene_manager, iButtonSceneSelectKey); + } + } + + return consumed; +} + +void ibutton_scene_delete_success_on_exit(void* context) { + iButton* ibutton = context; + Popup* popup = ibutton->popup; + + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); + + popup_disable_timeout(popup); + popup_set_context(popup, NULL); + popup_set_callback(popup, NULL); +} diff --git a/applications/ibutton/scene/ibutton_scene_emulate.cpp b/applications/ibutton/scenes/ibutton_scene_emulate.c similarity index 50% rename from applications/ibutton/scene/ibutton_scene_emulate.cpp rename to applications/ibutton/scenes/ibutton_scene_emulate.c index c00535f8c..8ffe73b66 100644 --- a/applications/ibutton/scene/ibutton_scene_emulate.cpp +++ b/applications/ibutton/scenes/ibutton_scene_emulate.c @@ -1,37 +1,35 @@ -#include "ibutton_scene_emulate.h" -#include "../ibutton_app.h" +#include "../ibutton_i.h" #include -static void emulate_callback(void* context, bool emulated) { - furi_assert(context); +static void ibutton_scene_emulate_callback(void* context, bool emulated) { + iButton* ibutton = context; if(emulated) { - iButtonApp* app = static_cast(context); - iButtonEvent event = { - .payload = {.worker_write_result = iButtonWorkerWriteOK}, - .type = iButtonEvent::Type::EventTypeWorkerEmulated, - }; - app->get_view_manager()->send_event(&event); + view_dispatcher_send_custom_event( + ibutton->view_dispatcher, iButtonCustomEventWorkerEmulated); } } -void iButtonSceneEmulate::on_enter(iButtonApp* app) { - iButtonAppViewManager* view_manager = app->get_view_manager(); - Popup* popup = view_manager->get_popup(); - iButtonKey* key = app->get_key(); +void ibutton_scene_emulate_on_enter(void* context) { + iButton* ibutton = context; + Popup* popup = ibutton->popup; + iButtonKey* key = ibutton->key; + const uint8_t* key_data = ibutton_key_get_data_p(key); const char* key_name = ibutton_key_get_name_p(key); + uint8_t line_count = 2; DOLPHIN_DEED(DolphinDeedIbuttonEmulate); // check that stored key has name if(strcmp(key_name, "") != 0) { - app->set_text_store("emulating\n%s", key_name); + ibutton_text_store_set(ibutton, "emulating\n%s", key_name); line_count = 2; } else { // if not, show key data switch(ibutton_key_get_type(key)) { case iButtonKeyDS1990: - app->set_text_store( + ibutton_text_store_set( + ibutton, "emulating\n%02X %02X %02X %02X\n%02X %02X %02X %02X", key_data[0], key_data[1], @@ -44,11 +42,12 @@ void iButtonSceneEmulate::on_enter(iButtonApp* app) { line_count = 3; break; case iButtonKeyCyfral: - app->set_text_store("emulating\n%02X %02X", key_data[0], key_data[1]); + ibutton_text_store_set(ibutton, "emulating\n%02X %02X", key_data[0], key_data[1]); line_count = 2; break; case iButtonKeyMetakom: - app->set_text_store( + ibutton_text_store_set( + ibutton, "emulating\n%02X %02X %02X %02X", key_data[0], key_data[1], @@ -62,40 +61,45 @@ void iButtonSceneEmulate::on_enter(iButtonApp* app) { switch(line_count) { case 3: popup_set_header(popup, "iButton", 82, 18, AlignCenter, AlignBottom); - popup_set_text(popup, app->get_text_store(), 82, 22, AlignCenter, AlignTop); + popup_set_text(popup, ibutton->text_store, 82, 22, AlignCenter, AlignTop); break; default: popup_set_header(popup, "iButton", 82, 24, AlignCenter, AlignBottom); - popup_set_text(popup, app->get_text_store(), 82, 28, AlignCenter, AlignTop); + popup_set_text(popup, ibutton->text_store, 82, 28, AlignCenter, AlignTop); break; } popup_set_icon(popup, 2, 10, &I_iButtonKey_49x44); - view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup); + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); - ibutton_worker_emulate_set_callback(app->get_key_worker(), emulate_callback, app); - ibutton_worker_emulate_start(app->get_key_worker(), key); + ibutton_worker_emulate_set_callback( + ibutton->key_worker, ibutton_scene_emulate_callback, ibutton); + ibutton_worker_emulate_start(ibutton->key_worker, key); } -bool iButtonSceneEmulate::on_event(iButtonApp* app, iButtonEvent* event) { +bool ibutton_scene_emulate_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; bool consumed = false; - if(event->type == iButtonEvent::Type::EventTypeWorkerEmulated) { - app->notify_yellow_blink(); + if(event.type == SceneManagerEventTypeTick) { consumed = true; - } else if(event->type == iButtonEvent::Type::EventTypeTick) { - app->notify_emulate(); + ibutton_notification_message(ibutton, iButtonNotificationMessageEmulate); + } else if(event.type == SceneManagerEventTypeCustom) { consumed = true; + if(event.event == iButtonCustomEventWorkerEmulated) { + ibutton_notification_message(ibutton, iButtonNotificationMessageYellowBlink); + } } return consumed; } -void iButtonSceneEmulate::on_exit(iButtonApp* app) { - Popup* popup = app->get_view_manager()->get_popup(); - ibutton_worker_stop(app->get_key_worker()); +void ibutton_scene_emulate_on_exit(void* context) { + iButton* ibutton = context; + Popup* popup = ibutton->popup; + ibutton_worker_stop(ibutton->key_worker); popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); popup_set_icon(popup, 0, 0, NULL); diff --git a/applications/ibutton/scenes/ibutton_scene_exit_confirm.c b/applications/ibutton/scenes/ibutton_scene_exit_confirm.c new file mode 100644 index 000000000..abd171f6a --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_exit_confirm.c @@ -0,0 +1,51 @@ +#include "../ibutton_i.h" + +static void ibutton_scene_exit_confirm_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + iButton* ibutton = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(ibutton->view_dispatcher, result); + } +} + +void ibutton_scene_exit_confirm_on_enter(void* context) { + iButton* ibutton = context; + Widget* widget = ibutton->widget; + + widget_add_button_element( + widget, GuiButtonTypeLeft, "Exit", ibutton_scene_exit_confirm_widget_callback, ibutton); + widget_add_button_element( + widget, GuiButtonTypeRight, "Stay", ibutton_scene_exit_confirm_widget_callback, ibutton); + widget_add_string_element( + widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton menu"); + widget_add_string_element( + widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost"); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); +} + +bool ibutton_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + SceneManager* scene_manager = ibutton->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; // Ignore Back button presses + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(scene_manager, iButtonSceneStart); + } else if(event.event == GuiButtonTypeRight) { + scene_manager_previous_scene(scene_manager); + } + } + + return consumed; +} + +void ibutton_scene_exit_confirm_on_exit(void* context) { + iButton* ibutton = context; + widget_reset(ibutton->widget); +} diff --git a/applications/ibutton/scenes/ibutton_scene_info.c b/applications/ibutton/scenes/ibutton_scene_info.c new file mode 100644 index 000000000..5b0af1d8f --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_info.c @@ -0,0 +1,61 @@ +#include "../ibutton_i.h" + +void ibutton_scene_info_on_enter(void* context) { + iButton* ibutton = context; + Widget* widget = ibutton->widget; + iButtonKey* key = ibutton->key; + + const uint8_t* key_data = ibutton_key_get_data_p(key); + + ibutton_text_store_set(ibutton, "%s", ibutton_key_get_name_p(key)); + widget_add_text_box_element( + widget, 0, 0, 128, 28, AlignCenter, AlignCenter, ibutton->text_store, false); + + switch(ibutton_key_get_type(key)) { + case iButtonKeyDS1990: + ibutton_text_store_set( + ibutton, + "%02X %02X %02X %02X %02X %02X %02X %02X", + key_data[0], + key_data[1], + key_data[2], + key_data[3], + key_data[4], + key_data[5], + key_data[6], + key_data[7]); + widget_add_string_element( + widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Dallas"); + break; + + case iButtonKeyMetakom: + ibutton_text_store_set( + ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]); + widget_add_string_element( + widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Metakom"); + break; + + case iButtonKeyCyfral: + ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]); + widget_add_string_element( + widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Cyfral"); + break; + } + + widget_add_string_element( + widget, 64, 35, AlignCenter, AlignBottom, FontPrimary, ibutton->text_store); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); +} + +bool ibutton_scene_info_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void ibutton_scene_info_on_exit(void* context) { + iButton* ibutton = context; + ibutton_text_store_clear(ibutton); + widget_reset(ibutton->widget); +} diff --git a/applications/ibutton/scenes/ibutton_scene_read.c b/applications/ibutton/scenes/ibutton_scene_read.c new file mode 100644 index 000000000..a25f27e60 --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_read.c @@ -0,0 +1,72 @@ +#include "../ibutton_i.h" +#include + +static void ibutton_scene_read_callback(void* context) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventWorkerRead); +} + +void ibutton_scene_read_on_enter(void* context) { + iButton* ibutton = context; + Popup* popup = ibutton->popup; + iButtonKey* key = ibutton->key; + iButtonWorker* worker = ibutton->key_worker; + DOLPHIN_DEED(DolphinDeedIbuttonRead); + + popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom); + popup_set_text(popup, "waiting\nfor key ...", 95, 30, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 5, &I_DolphinWait_61x59); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); + ibutton_key_set_name(key, ""); + + ibutton_worker_read_set_callback(worker, ibutton_scene_read_callback, ibutton); + ibutton_worker_read_start(worker, key); +} + +bool ibutton_scene_read_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + SceneManager* scene_manager = ibutton->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeTick) { + consumed = true; + ibutton_notification_message(ibutton, iButtonNotificationMessageRead); + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == iButtonCustomEventWorkerRead) { + bool success = false; + iButtonKey* key = ibutton->key; + + if(ibutton_key_get_type(key) == iButtonKeyDS1990) { + if(!ibutton_key_dallas_crc_is_valid(key)) { + scene_manager_next_scene(scene_manager, iButtonSceneReadCRCError); + } else if(!ibutton_key_dallas_is_1990_key(key)) { + scene_manager_next_scene(scene_manager, iButtonSceneReadNotKeyError); + } else { + success = true; + } + } else { + success = true; + } + + if(success) { + ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess); + ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOn); + DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); + scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess); + } + } + } + + return consumed; +} + +void ibutton_scene_read_on_exit(void* context) { + iButton* ibutton = context; + Popup* popup = ibutton->popup; + ibutton_worker_stop(ibutton->key_worker); + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); +} diff --git a/applications/ibutton/scenes/ibutton_scene_read_crc_error.c b/applications/ibutton/scenes/ibutton_scene_read_crc_error.c new file mode 100644 index 000000000..4df96d641 --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_read_crc_error.c @@ -0,0 +1,71 @@ +#include "../ibutton_i.h" +#include + +static void ibutton_scene_read_crc_error_dialog_ex_callback(DialogExResult result, void* context) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, result); +} + +void ibutton_scene_read_crc_error_on_enter(void* context) { + iButton* ibutton = context; + DialogEx* dialog_ex = ibutton->dialog_ex; + iButtonKey* key = ibutton->key; + const uint8_t* key_data = ibutton_key_get_data_p(key); + + ibutton_text_store_set( + ibutton, + "%02X %02X %02X %02X %02X %02X %02X %02X\nExpected CRC: %X", + key_data[0], + key_data[1], + key_data[2], + key_data[3], + key_data[4], + key_data[5], + key_data[6], + key_data[7], + maxim_crc8(key_data, 7, MAXIM_CRC8_INIT)); + + dialog_ex_set_header(dialog_ex, "CRC ERROR", 64, 10, AlignCenter, AlignCenter); + dialog_ex_set_text(dialog_ex, ibutton->text_store, 64, 19, AlignCenter, AlignTop); + dialog_ex_set_left_button_text(dialog_ex, "Retry"); + dialog_ex_set_right_button_text(dialog_ex, "More"); + dialog_ex_set_result_callback(dialog_ex, ibutton_scene_read_crc_error_dialog_ex_callback); + dialog_ex_set_context(dialog_ex, ibutton); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewDialogEx); + + ibutton_notification_message(ibutton, iButtonNotificationMessageError); + ibutton_notification_message(ibutton, iButtonNotificationMessageRedOn); +} + +bool ibutton_scene_read_crc_error_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + SceneManager* scene_manager = ibutton->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == DialogExResultRight) { + scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu); + } else if(event.event == DialogExResultLeft) { + scene_manager_previous_scene(scene_manager); + } + } + + return consumed; +} + +void ibutton_scene_read_crc_error_on_exit(void* context) { + iButton* ibutton = context; + DialogEx* dialog_ex = ibutton->dialog_ex; + + ibutton_text_store_clear(ibutton); + + dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); + dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); + dialog_ex_set_left_button_text(dialog_ex, NULL); + dialog_ex_set_result_callback(dialog_ex, NULL); + dialog_ex_set_context(dialog_ex, NULL); + + ibutton_notification_message(ibutton, iButtonNotificationMessageRedOff); +} diff --git a/applications/ibutton/scenes/ibutton_scene_read_key_menu.c b/applications/ibutton/scenes/ibutton_scene_read_key_menu.c new file mode 100644 index 000000000..7d479a463 --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_read_key_menu.c @@ -0,0 +1,61 @@ +#include "../ibutton_i.h" + +typedef enum { + SubmenuIndexSave, + SubmenuIndexEmulate, + SubmenuIndexWrite, +} SubmenuIndex; + +void ibutton_scene_read_key_menu_submenu_callback(void* context, uint32_t index) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, index); +} + +void ibutton_scene_read_key_menu_on_enter(void* context) { + iButton* ibutton = context; + Submenu* submenu = ibutton->submenu; + + submenu_add_item( + submenu, "Save", SubmenuIndexSave, ibutton_scene_read_key_menu_submenu_callback, ibutton); + submenu_add_item( + submenu, + "Emulate", + SubmenuIndexEmulate, + ibutton_scene_read_key_menu_submenu_callback, + ibutton); + if(ibutton_key_get_type(ibutton->key) == iButtonKeyDS1990) { + submenu_add_item( + submenu, + "Write", + SubmenuIndexWrite, + ibutton_scene_read_key_menu_submenu_callback, + ibutton); + } + + submenu_set_selected_item(submenu, SubmenuIndexSave); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu); +} + +bool ibutton_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == SubmenuIndexSave) { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName); + } else if(event.event == SubmenuIndexEmulate) { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); + } else if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); + } + } + + return consumed; +} + +void ibutton_scene_read_key_menu_on_exit(void* context) { + iButton* ibutton = context; + submenu_reset(ibutton->submenu); +} diff --git a/applications/ibutton/scenes/ibutton_scene_read_not_key_error.c b/applications/ibutton/scenes/ibutton_scene_read_not_key_error.c new file mode 100644 index 000000000..76f14daed --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_read_not_key_error.c @@ -0,0 +1,72 @@ +#include "../ibutton_i.h" +#include + +static void + ibutton_scene_read_not_key_error_dialog_ex_callback(DialogExResult result, void* context) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, result); +} + +void ibutton_scene_read_not_key_error_on_enter(void* context) { + iButton* ibutton = context; + DialogEx* dialog_ex = ibutton->dialog_ex; + iButtonKey* key = ibutton->key; + const uint8_t* key_data = ibutton_key_get_data_p(key); + + ibutton_text_store_set( + ibutton, + "THIS IS NOT A KEY\n%02X %02X %02X %02X %02X %02X %02X %02X", + key_data[0], + key_data[1], + key_data[2], + key_data[3], + key_data[4], + key_data[5], + key_data[6], + key_data[7], + maxim_crc8(key_data, 7, MAXIM_CRC8_INIT)); + + dialog_ex_set_header(dialog_ex, "CRC ERROR", 64, 10, AlignCenter, AlignCenter); + dialog_ex_set_text(dialog_ex, ibutton->text_store, 64, 19, AlignCenter, AlignTop); + dialog_ex_set_left_button_text(dialog_ex, "Retry"); + dialog_ex_set_right_button_text(dialog_ex, "More"); + dialog_ex_set_result_callback(dialog_ex, ibutton_scene_read_not_key_error_dialog_ex_callback); + dialog_ex_set_context(dialog_ex, ibutton); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewDialogEx); + + ibutton_notification_message(ibutton, iButtonNotificationMessageError); + ibutton_notification_message(ibutton, iButtonNotificationMessageRedOn); +} + +bool ibutton_scene_read_not_key_error_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + SceneManager* scene_manager = ibutton->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == DialogExResultRight) { + scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu); + } else if(event.event == DialogExResultLeft) { + scene_manager_previous_scene(scene_manager); + } + } + + return consumed; +} + +void ibutton_scene_read_not_key_error_on_exit(void* context) { + iButton* ibutton = context; + DialogEx* dialog_ex = ibutton->dialog_ex; + + ibutton_text_store_clear(ibutton); + + dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); + dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); + dialog_ex_set_left_button_text(dialog_ex, NULL); + dialog_ex_set_result_callback(dialog_ex, NULL); + dialog_ex_set_context(dialog_ex, NULL); + + ibutton_notification_message(ibutton, iButtonNotificationMessageRedOff); +} diff --git a/applications/ibutton/scenes/ibutton_scene_read_success.c b/applications/ibutton/scenes/ibutton_scene_read_success.c new file mode 100644 index 000000000..c3a134787 --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_read_success.c @@ -0,0 +1,87 @@ +#include "../ibutton_i.h" +#include + +static void ibutton_scene_read_success_dialog_ex_callback(DialogExResult result, void* context) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, result); +} + +void ibutton_scene_read_success_on_enter(void* context) { + iButton* ibutton = context; + DialogEx* dialog_ex = ibutton->dialog_ex; + iButtonKey* key = ibutton->key; + const uint8_t* key_data = ibutton_key_get_data_p(key); + + switch(ibutton_key_get_type(key)) { + case iButtonKeyDS1990: + ibutton_text_store_set( + ibutton, + "Dallas\n%02X %02X %02X %02X\n%02X %02X %02X %02X", + key_data[0], + key_data[1], + key_data[2], + key_data[3], + key_data[4], + key_data[5], + key_data[6], + key_data[7]); + break; + case iButtonKeyCyfral: + ibutton_text_store_set(ibutton, "Cyfral\n%02X %02X", key_data[0], key_data[1]); + break; + case iButtonKeyMetakom: + ibutton_text_store_set( + ibutton, + "Metakom\n%02X %02X %02X %02X", + key_data[0], + key_data[1], + key_data[2], + key_data[3]); + break; + } + + dialog_ex_set_text(dialog_ex, ibutton->text_store, 95, 30, AlignCenter, AlignCenter); + dialog_ex_set_left_button_text(dialog_ex, "Retry"); + dialog_ex_set_right_button_text(dialog_ex, "More"); + dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinReadingSuccess_59x63); + dialog_ex_set_result_callback(dialog_ex, ibutton_scene_read_success_dialog_ex_callback); + dialog_ex_set_context(dialog_ex, ibutton); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewDialogEx); +} + +bool ibutton_scene_read_success_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + SceneManager* scene_manager = ibutton->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; + scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm); + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == DialogExResultRight) { + scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu); + } else if(event.event == DialogExResultLeft) { + scene_manager_next_scene(scene_manager, iButtonSceneRetryConfirm); + } + } + + return consumed; +} + +void ibutton_scene_read_success_on_exit(void* context) { + iButton* ibutton = context; + DialogEx* dialog_ex = ibutton->dialog_ex; + + ibutton_text_store_clear(ibutton); + + dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); + dialog_ex_set_left_button_text(dialog_ex, NULL); + dialog_ex_set_right_button_text(dialog_ex, NULL); + dialog_ex_set_result_callback(dialog_ex, NULL); + dialog_ex_set_context(dialog_ex, NULL); + dialog_ex_set_icon(dialog_ex, 0, 0, NULL); + + ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOff); +} diff --git a/applications/ibutton/scenes/ibutton_scene_retry_confirm.c b/applications/ibutton/scenes/ibutton_scene_retry_confirm.c new file mode 100644 index 000000000..d2778ac15 --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_retry_confirm.c @@ -0,0 +1,51 @@ +#include "../ibutton_i.h" + +static void ibutton_scene_retry_confirm_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + iButton* ibutton = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(ibutton->view_dispatcher, result); + } +} + +void ibutton_scene_retry_confirm_on_enter(void* context) { + iButton* ibutton = context; + Widget* widget = ibutton->widget; + + widget_add_button_element( + widget, GuiButtonTypeLeft, "Exit", ibutton_scene_retry_confirm_widget_callback, ibutton); + widget_add_button_element( + widget, GuiButtonTypeRight, "Stay", ibutton_scene_retry_confirm_widget_callback, ibutton); + widget_add_string_element( + widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?"); + widget_add_string_element( + widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost"); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); +} + +bool ibutton_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + SceneManager* scene_manager = ibutton->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = true; // Ignore Back button presses + } else if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(scene_manager, iButtonSceneRead); + } else if(event.event == GuiButtonTypeRight) { + scene_manager_previous_scene(scene_manager); + } + } + + return consumed; +} + +void ibutton_scene_retry_confirm_on_exit(void* context) { + iButton* ibutton = context; + widget_reset(ibutton->widget); +} diff --git a/applications/ibutton/scenes/ibutton_scene_save_name.c b/applications/ibutton/scenes/ibutton_scene_save_name.c new file mode 100644 index 000000000..b1baf6afc --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_save_name.c @@ -0,0 +1,68 @@ +#include "../ibutton_i.h" +#include + +static void ibutton_scene_save_name_text_input_callback(void* context) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventTextEditResult); +} + +void ibutton_scene_save_name_on_enter(void* context) { + iButton* ibutton = context; + TextInput* text_input = ibutton->text_input; + + const char* key_name = ibutton_key_get_name_p(ibutton->key); + const bool key_name_is_empty = !strcmp(key_name, ""); + + if(key_name_is_empty) { + set_random_name(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE); + } else { + ibutton_text_store_set(ibutton, "%s", key_name); + } + + text_input_set_header_text(text_input, "Name the key"); + text_input_set_result_callback( + text_input, + ibutton_scene_save_name_text_input_callback, + ibutton, + ibutton->text_store, + IBUTTON_KEY_NAME_SIZE, + key_name_is_empty); + + ValidatorIsFile* validator_is_file = + validator_is_file_alloc_init(IBUTTON_APP_FOLDER, IBUTTON_APP_EXTENSION, key_name); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewTextInput); +} + +bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == iButtonCustomEventTextEditResult) { + if(ibutton_save_key(ibutton, ibutton->text_store)) { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveSuccess); + } else { + const uint32_t possible_scenes[] = { + iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType}; + ibutton_switch_to_previous_scene_one_of( + ibutton, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); + } + } + } + + return consumed; +} + +void ibutton_scene_save_name_on_exit(void* context) { + iButton* ibutton = context; + TextInput* text_input = ibutton->text_input; + + void* validator_context = text_input_get_validator_callback_context(text_input); + text_input_set_validator(text_input, NULL, NULL); + validator_is_file_free((ValidatorIsFile*)validator_context); + + text_input_reset(text_input); +} diff --git a/applications/ibutton/scenes/ibutton_scene_save_success.c b/applications/ibutton/scenes/ibutton_scene_save_success.c new file mode 100644 index 000000000..dffda6a0f --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_save_success.c @@ -0,0 +1,52 @@ +#include "../ibutton_i.h" +#include + +static void ibutton_scene_save_success_popup_callback(void* context) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventBack); +} + +void ibutton_scene_save_success_on_enter(void* context) { + iButton* ibutton = context; + Popup* popup = ibutton->popup; + DOLPHIN_DEED(DolphinDeedIbuttonSave); + + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); + + popup_set_callback(popup, ibutton_scene_save_success_popup_callback); + popup_set_context(popup, ibutton); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); +} + +bool ibutton_scene_save_success_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == iButtonCustomEventBack) { + const uint32_t possible_scenes[] = { + iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType}; + ibutton_switch_to_previous_scene_one_of( + ibutton, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); + } + } + + return consumed; +} + +void ibutton_scene_save_success_on_exit(void* context) { + iButton* ibutton = context; + Popup* popup = ibutton->popup; + + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); + + popup_disable_timeout(popup); + popup_set_context(popup, NULL); + popup_set_callback(popup, NULL); +} diff --git a/applications/ibutton/scenes/ibutton_scene_saved_key_menu.c b/applications/ibutton/scenes/ibutton_scene_saved_key_menu.c new file mode 100644 index 000000000..365297721 --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_saved_key_menu.c @@ -0,0 +1,75 @@ +#include "../ibutton_i.h" + +enum SubmenuIndex { + SubmenuIndexEmulate, + SubmenuIndexWrite, + SubmenuIndexEdit, + SubmenuIndexDelete, + SubmenuIndexInfo, +}; + +void ibutton_scene_saved_key_menu_submenu_callback(void* context, uint32_t index) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, index); +} + +void ibutton_scene_saved_key_menu_on_enter(void* context) { + iButton* ibutton = context; + Submenu* submenu = ibutton->submenu; + + submenu_add_item( + submenu, + "Emulate", + SubmenuIndexEmulate, + ibutton_scene_saved_key_menu_submenu_callback, + ibutton); + if(ibutton_key_get_type(ibutton->key) == iButtonKeyDS1990) { + submenu_add_item( + submenu, + "Write", + SubmenuIndexWrite, + ibutton_scene_saved_key_menu_submenu_callback, + ibutton); + } + submenu_add_item( + submenu, "Edit", SubmenuIndexEdit, ibutton_scene_saved_key_menu_submenu_callback, ibutton); + submenu_add_item( + submenu, + "Delete", + SubmenuIndexDelete, + ibutton_scene_saved_key_menu_submenu_callback, + ibutton); + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, ibutton_scene_saved_key_menu_submenu_callback, ibutton); + + submenu_set_selected_item(submenu, SubmenuIndexEmulate); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu); +} + +bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == SubmenuIndexEmulate) { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); + } else if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite); + } else if(event.event == SubmenuIndexEdit) { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue); + } else if(event.event == SubmenuIndexDelete) { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneDeleteConfirm); + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneInfo); + } + } + + return consumed; +} + +void ibutton_scene_saved_key_menu_on_exit(void* context) { + iButton* ibutton = context; + submenu_reset(ibutton->submenu); +} diff --git a/applications/ibutton/scenes/ibutton_scene_select_key.c b/applications/ibutton/scenes/ibutton_scene_select_key.c new file mode 100644 index 000000000..32169a9c0 --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_select_key.c @@ -0,0 +1,22 @@ +#include "../ibutton_i.h" + +void ibutton_scene_select_key_on_enter(void* context) { + iButton* ibutton = context; + + if(!ibutton_file_select(ibutton)) { + scene_manager_search_and_switch_to_previous_scene( + ibutton->scene_manager, iButtonSceneStart); + } else { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSavedKeyMenu); + } +} + +bool ibutton_scene_select_key_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void ibutton_scene_select_key_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/ibutton/scenes/ibutton_scene_start.c b/applications/ibutton/scenes/ibutton_scene_start.c new file mode 100644 index 000000000..a3141f5ad --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_start.c @@ -0,0 +1,51 @@ +#include "../ibutton_i.h" + +enum SubmenuIndex { + SubmenuIndexRead, + SubmenuIndexSaved, + SubmenuIndexAdd, +}; + +void ibutton_scene_start_submenu_callback(void* context, uint32_t index) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, index); +} + +void ibutton_scene_start_on_enter(void* context) { + iButton* ibutton = context; + Submenu* submenu = ibutton->submenu; + + submenu_add_item( + submenu, "Read", SubmenuIndexRead, ibutton_scene_start_submenu_callback, ibutton); + submenu_add_item( + submenu, "Saved", SubmenuIndexSaved, ibutton_scene_start_submenu_callback, ibutton); + submenu_add_item( + submenu, "Add Manually", SubmenuIndexAdd, ibutton_scene_start_submenu_callback, ibutton); + + submenu_set_selected_item(submenu, SubmenuIndexRead); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu); +} + +bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == SubmenuIndexRead) { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead); + } else if(event.event == SubmenuIndexSaved) { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey); + } else if(event.event == SubmenuIndexAdd) { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddType); + } + } + + return consumed; +} + +void ibutton_scene_start_on_exit(void* context) { + iButton* ibutton = context; + submenu_reset(ibutton->submenu); +} diff --git a/applications/ibutton/scenes/ibutton_scene_write.c b/applications/ibutton/scenes/ibutton_scene_write.c new file mode 100644 index 000000000..35e45d83b --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_write.c @@ -0,0 +1,121 @@ +#include "../ibutton_i.h" + +typedef enum { + iButtonSceneWriteStateDefault, + iButtonSceneWriteStateBlinkYellow, +} iButtonSceneWriteState; + +static void ibutton_scene_write_callback(void* context, iButtonWorkerWriteResult result) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, result); +} + +void ibutton_scene_write_on_enter(void* context) { + iButton* ibutton = context; + Popup* popup = ibutton->popup; + iButtonKey* key = ibutton->key; + iButtonWorker* worker = ibutton->key_worker; + + const uint8_t* key_data = ibutton_key_get_data_p(key); + const char* key_name = ibutton_key_get_name_p(key); + + uint8_t line_count = 2; + + // check that stored key has name + if(strcmp(key_name, "") != 0) { + ibutton_text_store_set(ibutton, "writing\n%s", key_name); + line_count = 2; + } else { + // if not, show key data + switch(ibutton_key_get_type(key)) { + case iButtonKeyDS1990: + ibutton_text_store_set( + ibutton, + "writing\n%02X %02X %02X %02X\n%02X %02X %02X %02X", + key_data[0], + key_data[1], + key_data[2], + key_data[3], + key_data[4], + key_data[5], + key_data[6], + key_data[7]); + line_count = 3; + break; + case iButtonKeyCyfral: + ibutton_text_store_set(ibutton, "writing\n%02X %02X", key_data[0], key_data[1]); + line_count = 2; + break; + case iButtonKeyMetakom: + ibutton_text_store_set( + ibutton, + "writing\n%02X %02X %02X %02X", + key_data[0], + key_data[1], + key_data[2], + key_data[3]); + line_count = 2; + break; + } + } + + switch(line_count) { + case 3: + popup_set_header(popup, "iButton", 82, 18, AlignCenter, AlignBottom); + popup_set_text(popup, ibutton->text_store, 82, 22, AlignCenter, AlignTop); + break; + + default: + popup_set_header(popup, "iButton", 82, 24, AlignCenter, AlignBottom); + popup_set_text(popup, ibutton->text_store, 82, 28, AlignCenter, AlignTop); + break; + } + + popup_set_icon(popup, 2, 10, &I_iButtonKey_49x44); + + scene_manager_set_scene_state( + ibutton->scene_manager, iButtonSceneWrite, iButtonSceneWriteStateDefault); + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); + + ibutton_worker_write_set_callback(worker, ibutton_scene_write_callback, ibutton); + ibutton_worker_write_start(worker, key); +} + +bool ibutton_scene_write_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + SceneManager* scene_manager = ibutton->scene_manager; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if((event.event == iButtonWorkerWriteOK) || (event.event == iButtonWorkerWriteSameKey)) { + scene_manager_next_scene(scene_manager, iButtonSceneWriteSuccess); + } else if(event.event == iButtonWorkerWriteNoDetect) { + scene_manager_set_scene_state( + scene_manager, iButtonSceneWrite, iButtonSceneWriteStateDefault); + } else if(event.event == iButtonWorkerWriteCannotWrite) { + scene_manager_set_scene_state( + scene_manager, iButtonSceneWrite, iButtonSceneWriteStateBlinkYellow); + } + + } else if(event.type == SceneManagerEventTypeTick) { + consumed = true; + if(scene_manager_get_scene_state(scene_manager, iButtonSceneWrite) == + iButtonSceneWriteStateBlinkYellow) { + ibutton_notification_message(ibutton, iButtonNotificationMessageYellowBlink); + } else { + ibutton_notification_message(ibutton, iButtonNotificationMessageEmulate); + } + } + + return consumed; +} + +void ibutton_scene_write_on_exit(void* context) { + iButton* ibutton = context; + Popup* popup = ibutton->popup; + ibutton_worker_stop(ibutton->key_worker); + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); +} diff --git a/applications/ibutton/scenes/ibutton_scene_write_success.c b/applications/ibutton/scenes/ibutton_scene_write_success.c new file mode 100644 index 000000000..6abafbb37 --- /dev/null +++ b/applications/ibutton/scenes/ibutton_scene_write_success.c @@ -0,0 +1,52 @@ +#include "../ibutton_i.h" + +static void ibutton_scene_write_success_popup_callback(void* context) { + iButton* ibutton = context; + view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventBack); + ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOff); +} + +void ibutton_scene_write_success_on_enter(void* context) { + iButton* ibutton = context; + Popup* popup = ibutton->popup; + + popup_set_icon(popup, 0, 12, &I_iButtonDolphinVerySuccess_108x52); + popup_set_text(popup, "Successfully written!", 40, 12, AlignLeft, AlignBottom); + + popup_set_callback(popup, ibutton_scene_write_success_popup_callback); + popup_set_context(popup, ibutton); + popup_set_timeout(popup, 1500); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); + ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess); + ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOn); +} + +bool ibutton_scene_write_success_on_event(void* context, SceneManagerEvent event) { + iButton* ibutton = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == iButtonCustomEventBack) { + const uint32_t possible_scenes[] = {iButtonSceneReadKeyMenu, iButtonSceneStart}; + ibutton_switch_to_previous_scene_one_of( + ibutton, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t)); + } + } + + return consumed; +} + +void ibutton_scene_write_success_on_exit(void* context) { + iButton* ibutton = context; + Popup* popup = ibutton->popup; + + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); + + popup_disable_timeout(popup); + popup_set_context(popup, NULL); + popup_set_callback(popup, NULL); +} diff --git a/applications/power/power_service/power_api.c b/applications/power/power_service/power_api.c index b290cb831..865c21c80 100644 --- a/applications/power/power_service/power_api.c +++ b/applications/power/power_service/power_api.c @@ -2,6 +2,7 @@ #include #include +#include void power_off(Power* power) { furi_hal_power_off(); @@ -14,7 +15,7 @@ void power_off(Power* power) { void power_reboot(PowerBootMode mode) { if(mode == PowerBootModeNormal) { - furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal); + update_operation_disarm(); } else if(mode == PowerBootModeDfu) { furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeDfu); } else if(mode == PowerBootModeUpdateStart) { diff --git a/applications/updater/cli/updater_cli.c b/applications/updater/cli/updater_cli.c index 000ff56cd..dfc7fbcef 100644 --- a/applications/updater/cli/updater_cli.c +++ b/applications/updater/cli/updater_cli.c @@ -134,4 +134,4 @@ void updater_on_system_start() { #else UNUSED(updater_start_app); #endif -} +} \ No newline at end of file diff --git a/applications/updater/scenes/updater_scene_main.c b/applications/updater/scenes/updater_scene_main.c index c5fc99ffb..5f7aeaca4 100644 --- a/applications/updater/scenes/updater_scene_main.c +++ b/applications/updater/scenes/updater_scene_main.c @@ -45,8 +45,8 @@ void updater_scene_main_on_enter(void* context) { view_dispatcher_switch_to_view(updater->view_dispatcher, UpdaterViewMain); } -static void updater_scene_restart_to_postupdate() { - furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate); +static void updater_scene_cancel_update() { + update_operation_disarm(); furi_hal_power_reset(); } @@ -57,7 +57,7 @@ bool updater_scene_main_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeTick) { if(!update_task_is_running(updater->update_task)) { if(updater->idle_ticks++ >= (UPDATE_DELAY_OPERATION_ERROR / UPDATER_APP_TICK)) { - updater_scene_restart_to_postupdate(); + updater_scene_cancel_update(); } } else { updater->idle_ticks = 0; @@ -74,7 +74,7 @@ bool updater_scene_main_on_event(void* context, SceneManagerEvent event) { case UpdaterCustomEventCancelUpdate: if(!update_task_is_running(updater->update_task)) { - updater_scene_restart_to_postupdate(); + updater_scene_cancel_update(); } consumed = true; break; diff --git a/applications/updater/updater.c b/applications/updater/updater.c index b58c8daa0..4c9fe41f9 100644 --- a/applications/updater/updater.c +++ b/applications/updater/updater.c @@ -26,15 +26,10 @@ static bool updater_back_event_callback(void* context) { return scene_manager_handle_back_event(updater->scene_manager); } -static void status_update_cb( - const char* message, - const uint8_t progress, - const uint8_t idx_stage, - const uint8_t total_stages, - bool failed, - void* context) { +static void + status_update_cb(const char* message, const uint8_t progress, bool failed, void* context) { UpdaterMainView* main_view = context; - updater_main_model_set_state(main_view, message, progress, idx_stage, total_stages, failed); + updater_main_model_set_state(main_view, message, progress, failed); } Updater* updater_alloc(const char* arg) { @@ -64,9 +59,7 @@ Updater* updater_alloc(const char* arg) { updater->view_dispatcher, updater_tick_event_callback, UPDATER_APP_TICK); view_dispatcher_attach_to_gui( - updater->view_dispatcher, - updater->gui, - arg ? ViewDispatcherTypeFullscreen : ViewDispatcherTypeWindow); + updater->view_dispatcher, updater->gui, ViewDispatcherTypeFullscreen); updater->main_view = updater_main_alloc(); view_dispatcher_add_view( diff --git a/applications/updater/util/update_task.c b/applications/updater/util/update_task.c index 6ff61700a..373f680a9 100644 --- a/applications/updater/util/update_task.c +++ b/applications/updater/util/update_task.c @@ -14,54 +14,139 @@ static const char* update_task_stage_descr[] = { [UpdateTaskStageReadManifest] = "Loading update manifest", [UpdateTaskStageValidateDFUImage] = "Checking DFU file", [UpdateTaskStageFlashWrite] = "Writing flash", - [UpdateTaskStageFlashValidate] = "Validating", - [UpdateTaskStageRadioImageValidate] = "Checking radio image", - [UpdateTaskStageRadioErase] = "Removing radio stack", - [UpdateTaskStageRadioWrite] = "Writing radio stack", - [UpdateTaskStageRadioInstall] = "Installing radio stack", - [UpdateTaskStageRadioBusy] = "Core2 is updating", + [UpdateTaskStageFlashValidate] = "Validating flash", + [UpdateTaskStageRadioImageValidate] = "Checking radio FW", + [UpdateTaskStageRadioErase] = "Uninstalling radio FW", + [UpdateTaskStageRadioWrite] = "Writing radio FW", + [UpdateTaskStageRadioInstall] = "Installing radio FW", + [UpdateTaskStageRadioBusy] = "Radio is updating", [UpdateTaskStageOBValidation] = "Validating opt. bytes", [UpdateTaskStageLfsBackup] = "Backing up LFS", [UpdateTaskStageLfsRestore] = "Restoring LFS", [UpdateTaskStageResourcesUpdate] = "Updating resources", - [UpdateTaskStageCompleted] = "Completed!", + [UpdateTaskStageCompleted] = "Restarting...", [UpdateTaskStageError] = "Error", - [UpdateTaskStageOBError] = "OB error, pls report", + [UpdateTaskStageOBError] = "OB Err, report", }; -static void update_task_set_status(UpdateTask* update_task, const char* status) { - if(!status) { - if(update_task->state.stage >= COUNT_OF(update_task_stage_descr)) { - status = "..."; - } else { - status = update_task_stage_descr[update_task->state.stage]; - } +typedef struct { + UpdateTaskStageGroup group; + uint8_t weight; +} UpdateTaskStageGroupMap; + +#define STAGE_DEF(GROUP, WEIGHT) \ + { .group = (GROUP), .weight = (WEIGHT), } + +static const UpdateTaskStageGroupMap update_task_stage_progress[] = { + [UpdateTaskStageProgress] = STAGE_DEF(UpdateTaskStageGroupMisc, 0), + + [UpdateTaskStageReadManifest] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 5), + [UpdateTaskStageLfsBackup] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 30), + + [UpdateTaskStageRadioImageValidate] = STAGE_DEF(UpdateTaskStageGroupRadio, 30), + [UpdateTaskStageRadioErase] = STAGE_DEF(UpdateTaskStageGroupRadio, 50), + [UpdateTaskStageRadioWrite] = STAGE_DEF(UpdateTaskStageGroupRadio, 100), + [UpdateTaskStageRadioInstall] = STAGE_DEF(UpdateTaskStageGroupRadio, 5), + [UpdateTaskStageRadioBusy] = STAGE_DEF(UpdateTaskStageGroupRadio, 70), + + [UpdateTaskStageOBValidation] = STAGE_DEF(UpdateTaskStageGroupOptionBytes, 10), + + [UpdateTaskStageValidateDFUImage] = STAGE_DEF(UpdateTaskStageGroupFirmware, 100), + [UpdateTaskStageFlashWrite] = STAGE_DEF(UpdateTaskStageGroupFirmware, 200), + [UpdateTaskStageFlashValidate] = STAGE_DEF(UpdateTaskStageGroupFirmware, 50), + + [UpdateTaskStageLfsRestore] = STAGE_DEF(UpdateTaskStageGroupPostUpdate, 30), + + [UpdateTaskStageResourcesUpdate] = STAGE_DEF(UpdateTaskStageGroupResources, 255), + + [UpdateTaskStageCompleted] = STAGE_DEF(UpdateTaskStageGroupMisc, 1), + [UpdateTaskStageError] = STAGE_DEF(UpdateTaskStageGroupMisc, 1), + [UpdateTaskStageOBError] = STAGE_DEF(UpdateTaskStageGroupMisc, 1), +}; + +static UpdateTaskStageGroup update_task_get_task_groups(UpdateTask* update_task) { + UpdateTaskStageGroup ret = UpdateTaskStageGroupPreUpdate | UpdateTaskStageGroupPostUpdate; + UpdateManifest* manifest = update_task->manifest; + if(!string_empty_p(manifest->radio_image)) { + ret |= UpdateTaskStageGroupRadio; } - string_set_str(update_task->state.status, status); + if(update_manifest_has_obdata(manifest)) { + ret |= UpdateTaskStageGroupOptionBytes; + } + if(!string_empty_p(manifest->firmware_dfu_image)) { + ret |= UpdateTaskStageGroupFirmware; + } + if(!string_empty_p(manifest->resource_bundle)) { + ret |= UpdateTaskStageGroupResources; + } + return ret; +} + +static void update_task_calc_completed_stages(UpdateTask* update_task) { + uint32_t completed_stages_points = 0; + for(UpdateTaskStage past_stage = UpdateTaskStageProgress; + past_stage < update_task->state.stage; + ++past_stage) { + const UpdateTaskStageGroupMap* grp_descr = &update_task_stage_progress[past_stage]; + if((grp_descr->group & update_task->state.groups) == 0) { + continue; + } + completed_stages_points += grp_descr->weight; + } + update_task->state.completed_stages_points = completed_stages_points; } void update_task_set_progress(UpdateTask* update_task, UpdateTaskStage stage, uint8_t progress) { if(stage != UpdateTaskStageProgress) { - // do not override more specific error states - if((update_task->state.stage < UpdateTaskStageError) || (stage < UpdateTaskStageError)) { - update_task->state.stage = stage; + /* do not override more specific error states */ + if((stage >= UpdateTaskStageError) && (update_task->state.stage >= UpdateTaskStageError)) { + return; + } + /* Build error message with code "[stage_idx-stage_percent]" */ + if(stage >= UpdateTaskStageError) { + string_printf( + update_task->state.status, + "%s #[%d-%d]", + update_task_stage_descr[stage], + update_task->state.stage, + update_task->state.stage_progress); + } else { + string_set_str(update_task->state.status, update_task_stage_descr[stage]); + } + /* Store stage update */ + update_task->state.stage = stage; + /* If we are still alive, sum completed stages weights */ + if((stage > UpdateTaskStageProgress) && (stage < UpdateTaskStageCompleted)) { + update_task_calc_completed_stages(update_task); } - update_task->state.current_stage_idx++; - update_task_set_status(update_task, NULL); } - if(progress > 100) { - progress = 100; + /* Store stage progress for all non-error updates - to provide details on error state */ + if(!update_stage_is_error(stage)) { + update_task->state.stage_progress = progress; } - update_task->state.progress = progress; + /* Calculate "overall" progress, based on stage weights */ + uint32_t adapted_progress = 1; + if(update_task->state.total_progress_points != 0) { + if(stage < UpdateTaskStageCompleted) { + adapted_progress = MIN( + (update_task->state.completed_stages_points + + (update_task_stage_progress[update_task->state.stage].weight * progress / 100)) * + 100 / (update_task->state.total_progress_points), + 100u); + + } else { + adapted_progress = update_task->state.overall_progress; + } + } + update_task->state.overall_progress = adapted_progress; + if(update_task->status_change_cb) { (update_task->status_change_cb)( string_get_cstr(update_task->state.status), - progress, - update_task->state.current_stage_idx, - update_task->state.total_stages, - update_task->state.stage >= UpdateTaskStageError, + adapted_progress, + update_stage_is_error(update_task->state.stage), update_task->status_change_cb_state); } } @@ -106,8 +191,7 @@ static void update_task_worker_thread_cb(FuriThreadState state, void* context) { return; } - int32_t op_result = furi_thread_get_return_code(update_task->thread); - if(op_result == UPDATE_TASK_NOERR) { + if(furi_thread_get_return_code(update_task->thread) == UPDATE_TASK_NOERR) { osDelay(UPDATE_DELAY_OPERATION_OK); furi_hal_power_reset(); } @@ -117,7 +201,8 @@ UpdateTask* update_task_alloc() { UpdateTask* update_task = malloc(sizeof(UpdateTask)); update_task->state.stage = UpdateTaskStageProgress; - update_task->state.progress = 0; + update_task->state.stage_progress = 0; + update_task->state.overall_progress = 0; string_init(update_task->state.status); update_task->manifest = update_manifest_alloc(); @@ -163,6 +248,12 @@ void update_task_free(UpdateTask* update_task) { bool update_task_parse_manifest(UpdateTask* update_task) { furi_assert(update_task); + update_task->state.stage_progress = 0; + update_task->state.overall_progress = 0; + update_task->state.total_progress_points = 0; + update_task->state.completed_stages_points = 0; + update_task->state.groups = 0; + update_task_set_progress(update_task, UpdateTaskStageReadManifest, 0); bool result = false; string_t manifest_path; @@ -180,19 +271,31 @@ bool update_task_parse_manifest(UpdateTask* update_task) { UPDATE_MANIFEST_DEFAULT_NAME, manifest_path); update_task_set_progress(update_task, UpdateTaskStageProgress, 30); - if(!update_manifest_init(update_task->manifest, string_get_cstr(manifest_path))) { + + UpdateManifest* manifest = update_task->manifest; + if(!update_manifest_init(manifest, string_get_cstr(manifest_path))) { break; } + update_task->state.groups = update_task_get_task_groups(update_task); + for(size_t stage_counter = 0; stage_counter < COUNT_OF(update_task_stage_progress); + ++stage_counter) { + const UpdateTaskStageGroupMap* grp_descr = &update_task_stage_progress[stage_counter]; + if((grp_descr->group & update_task->state.groups) != 0) { + update_task->state.total_progress_points += grp_descr->weight; + } + } + update_task_set_progress(update_task, UpdateTaskStageProgress, 50); - if(!string_empty_p(update_task->manifest->firmware_dfu_image) && - !update_task_check_file_exists(update_task, update_task->manifest->firmware_dfu_image)) { + if((update_task->state.groups & UpdateTaskStageGroupFirmware) && + !update_task_check_file_exists(update_task, manifest->firmware_dfu_image)) { break; } update_task_set_progress(update_task, UpdateTaskStageProgress, 70); - if(!string_empty_p(update_task->manifest->radio_image) && - !update_task_check_file_exists(update_task, update_task->manifest->radio_image)) { + if((update_task->state.groups & UpdateTaskStageGroupRadio) && + (!update_task_check_file_exists(update_task, manifest->radio_image) || + (manifest->radio_version.version.type == 0))) { break; } diff --git a/applications/updater/util/update_task.h b/applications/updater/util/update_task.h index 3197c8c19..cfbbb8500 100644 --- a/applications/updater/util/update_task.h +++ b/applications/updater/util/update_task.h @@ -10,46 +10,63 @@ extern "C" { #include #include -#define UPDATE_DELAY_OPERATION_OK 600 +#define UPDATE_DELAY_OPERATION_OK 300 #define UPDATE_DELAY_OPERATION_ERROR INT_MAX typedef enum { - UpdateTaskStageProgress, + UpdateTaskStageProgress = 0, + UpdateTaskStageReadManifest, - UpdateTaskStageValidateDFUImage, - UpdateTaskStageFlashWrite, - UpdateTaskStageFlashValidate, + UpdateTaskStageLfsBackup, + UpdateTaskStageRadioImageValidate, UpdateTaskStageRadioErase, UpdateTaskStageRadioWrite, UpdateTaskStageRadioInstall, UpdateTaskStageRadioBusy, + UpdateTaskStageOBValidation, - UpdateTaskStageLfsBackup, + + UpdateTaskStageValidateDFUImage, + UpdateTaskStageFlashWrite, + UpdateTaskStageFlashValidate, + UpdateTaskStageLfsRestore, UpdateTaskStageResourcesUpdate, + UpdateTaskStageCompleted, UpdateTaskStageError, - UpdateTaskStageOBError + UpdateTaskStageOBError, + UpdateTaskStageMAX } UpdateTaskStage; +inline bool update_stage_is_error(const UpdateTaskStage stage) { + return stage >= UpdateTaskStageError; +} + +typedef enum { + UpdateTaskStageGroupMisc = 0, + UpdateTaskStageGroupPreUpdate = 1 << 1, + UpdateTaskStageGroupFirmware = 1 << 2, + UpdateTaskStageGroupOptionBytes = 1 << 3, + UpdateTaskStageGroupRadio = 1 << 4, + UpdateTaskStageGroupPostUpdate = 1 << 5, + UpdateTaskStageGroupResources = 1 << 6, +} UpdateTaskStageGroup; + typedef struct { UpdateTaskStage stage; - uint8_t progress; - uint8_t current_stage_idx; - uint8_t total_stages; + uint8_t overall_progress, stage_progress; string_t status; + UpdateTaskStageGroup groups; + uint32_t total_progress_points; + uint32_t completed_stages_points; } UpdateTaskState; typedef struct UpdateTask UpdateTask; -typedef void (*updateProgressCb)( - const char* status, - const uint8_t stage_pct, - const uint8_t idx_stage, - const uint8_t total_stages, - bool failed, - void* state); +typedef void ( + *updateProgressCb)(const char* status, const uint8_t stage_pct, bool failed, void* state); UpdateTask* update_task_alloc(); diff --git a/applications/updater/util/update_task_worker_backup.c b/applications/updater/util/update_task_worker_backup.c index 38d71dfdd..485fdd48a 100644 --- a/applications/updater/util/update_task_worker_backup.c +++ b/applications/updater/util/update_task_worker_backup.c @@ -27,7 +27,6 @@ static bool update_task_pre_update(UpdateTask* update_task) { path_concat( string_get_cstr(update_task->update_path), LFS_BACKUP_DEFAULT_FILENAME, backup_file_path); - update_task->state.total_stages = 1; update_task_set_progress(update_task, UpdateTaskStageLfsBackup, 0); /* to avoid bootloops */ furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal); @@ -62,22 +61,18 @@ static bool update_task_post_update(UpdateTask* update_task) { string_t file_path; string_init(file_path); - /* status text is too long, too few stages to bother with a counter */ - update_task->state.total_stages = 0; - + TarArchive* archive = tar_archive_alloc(update_task->storage); do { CHECK_RESULT(update_task_parse_manifest(update_task)); path_concat( string_get_cstr(update_task->update_path), LFS_BACKUP_DEFAULT_FILENAME, file_path); - bool unpack_resources = !string_empty_p(update_task->manifest->resource_bundle); - update_task_set_progress(update_task, UpdateTaskStageLfsRestore, 0); - furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal); + update_operation_disarm(); CHECK_RESULT(lfs_backup_unpack(update_task->storage, string_get_cstr(file_path))); - if(unpack_resources) { + if(update_task->state.groups & UpdateTaskStageGroupResources) { TarUnpackProgress progress = { .update_task = update_task, .total_files = 0, @@ -90,20 +85,19 @@ static bool update_task_post_update(UpdateTask* update_task) { string_get_cstr(update_task->manifest->resource_bundle), file_path); - TarArchive* archive = tar_archive_alloc(update_task->storage); tar_archive_set_file_callback(archive, update_task_resource_unpack_cb, &progress); - success = tar_archive_open(archive, string_get_cstr(file_path), TAR_OPEN_MODE_READ); - if(success) { - progress.total_files = tar_archive_get_entries_count(archive); - if(progress.total_files > 0) { - tar_archive_unpack_to(archive, EXT_PATH); - } + CHECK_RESULT( + tar_archive_open(archive, string_get_cstr(file_path), TAR_OPEN_MODE_READ)); + + progress.total_files = tar_archive_get_entries_count(archive); + if(progress.total_files > 0) { + CHECK_RESULT(tar_archive_unpack_to(archive, EXT_PATH)); } - tar_archive_free(archive); } success = true; } while(false); + tar_archive_free(archive); string_clear(file_path); return success; } @@ -116,18 +110,17 @@ int32_t update_task_worker_backup_restore(void* context) { FuriHalRtcBootMode boot_mode = furi_hal_rtc_get_boot_mode(); if((boot_mode != FuriHalRtcBootModePreUpdate) && (boot_mode != FuriHalRtcBootModePostUpdate)) { /* no idea how we got here. Clear to normal boot */ - furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal); + update_operation_disarm(); return UPDATE_TASK_NOERR; } - update_task->state.current_stage_idx = 0; - if(!update_operation_get_current_package_path(update_task->storage, update_task->update_path)) { return UPDATE_TASK_FAILED; } - /* Waiting for BT service to 'start', so we don't race for boot mode */ + /* Waiting for BT service to 'start', so we don't race for boot mode flag */ furi_record_open("bt"); + furi_record_close("bt"); if(boot_mode == FuriHalRtcBootModePreUpdate) { success = update_task_pre_update(update_task); @@ -135,13 +128,11 @@ int32_t update_task_worker_backup_restore(void* context) { success = update_task_post_update(update_task); } - furi_record_close("bt"); - - if(success) { - update_task_set_progress(update_task, UpdateTaskStageCompleted, 100); - } else { - update_task_set_progress(update_task, UpdateTaskStageError, update_task->state.progress); + if(!success) { + update_task_set_progress(update_task, UpdateTaskStageError, 0); + return UPDATE_TASK_FAILED; } - return success ? UPDATE_TASK_NOERR : UPDATE_TASK_FAILED; + update_task_set_progress(update_task, UpdateTaskStageCompleted, 100); + return UPDATE_TASK_NOERR; } diff --git a/applications/updater/util/update_task_worker_flasher.c b/applications/updater/util/update_task_worker_flasher.c index 6b03439dd..1f22e2f72 100644 --- a/applications/updater/util/update_task_worker_flasher.c +++ b/applications/updater/util/update_task_worker_flasher.c @@ -111,19 +111,13 @@ static bool update_task_write_stack_data(UpdateTask* update_task) { } bytes_read = storage_file_read(update_task->file, fw_block, n_bytes_to_read); - if(bytes_read == 0) { - break; - } + CHECK_RESULT(bytes_read != 0); int16_t i_page = furi_hal_flash_get_page_number(update_task->manifest->radio_address + element_offs); - if(i_page < 0) { - break; - } + CHECK_RESULT(i_page >= 0); - if(!furi_hal_flash_program_page(i_page, fw_block, bytes_read)) { - break; - } + CHECK_RESULT(furi_hal_flash_program_page(i_page, fw_block, bytes_read)); element_offs += bytes_read; update_task_set_progress( @@ -142,19 +136,19 @@ static void update_task_wait_for_restart(UpdateTask* update_task) { static bool update_task_write_stack(UpdateTask* update_task) { bool success = false; + UpdateManifest* manifest = update_task->manifest; do { FURI_LOG_W(TAG, "Writing stack"); update_task_set_progress(update_task, UpdateTaskStageRadioImageValidate, 0); - CHECK_RESULT(update_task_open_file(update_task, update_task->manifest->radio_image)); + CHECK_RESULT(update_task_open_file(update_task, manifest->radio_image)); CHECK_RESULT( crc32_calc_file(update_task->file, &update_task_file_progress, update_task) == - update_task->manifest->radio_crc); + manifest->radio_crc); CHECK_RESULT(update_task_write_stack_data(update_task)); update_task_set_progress(update_task, UpdateTaskStageRadioInstall, 0); CHECK_RESULT( - ble_glue_fus_stack_install(update_task->manifest->radio_address, 0) != - BleGlueCommandResultError); + ble_glue_fus_stack_install(manifest->radio_address, 0) != BleGlueCommandResultError); update_task_set_progress(update_task, UpdateTaskStageRadioInstall, 80); CHECK_RESULT(ble_glue_fus_wait_operation() == BleGlueCommandResultOK); update_task_set_progress(update_task, UpdateTaskStageRadioInstall, 100); @@ -280,7 +274,6 @@ bool update_task_validate_optionbytes(UpdateTask* update_task) { manifest->ob_write_mask.obs[idx].values.base) != 0; if(can_patch) { - /* patch & restart loop */ const uint32_t patched_value = /* take all non-writable bits from real value */ (device_ob_value & ~(manifest->ob_write_mask.obs[idx].values.base)) | @@ -297,8 +290,7 @@ bool update_task_validate_optionbytes(UpdateTask* update_task) { if(!is_fixed) { /* Things are so bad that fixing what we are allowed to still doesn't match - * reference value - */ + * reference value */ FURI_LOG_W( TAG, "OB #%d is FUBAR (fixed&masked %08X, not %08X)", @@ -317,11 +309,11 @@ bool update_task_validate_optionbytes(UpdateTask* update_task) { } } if(!match) { - update_task_set_progress(update_task, UpdateTaskStageOBError, 95); + update_task_set_progress(update_task, UpdateTaskStageOBError, 0); } if(ob_dirty) { - FURI_LOG_W(TAG, "OB were changed, applying"); + FURI_LOG_W(TAG, "OBs were changed, applying"); furi_hal_flash_ob_apply(); } return match; @@ -332,24 +324,18 @@ int32_t update_task_worker_flash_writer(void* context) { UpdateTask* update_task = context; bool success = false; - update_task->state.current_stage_idx = 0; - update_task->state.total_stages = 0; - do { CHECK_RESULT(update_task_parse_manifest(update_task)); - if(!string_empty_p(update_task->manifest->radio_image)) { + if(update_task->state.groups & UpdateTaskStageGroupRadio) { CHECK_RESULT(update_task_manage_radiostack(update_task)); } - bool check_ob = update_manifest_has_obdata(update_task->manifest); - if(check_ob) { - update_task->state.total_stages++; + if(update_task->state.groups & UpdateTaskStageGroupOptionBytes) { CHECK_RESULT(update_task_validate_optionbytes(update_task)); } - if(!string_empty_p(update_task->manifest->firmware_dfu_image)) { - update_task->state.total_stages += 4; + if(update_task->state.groups & UpdateTaskStageGroupFirmware) { CHECK_RESULT(update_task_write_dfu(update_task)); } @@ -359,5 +345,10 @@ int32_t update_task_worker_flash_writer(void* context) { success = true; } while(false); - return success ? UPDATE_TASK_NOERR : UPDATE_TASK_FAILED; + if(!success) { + update_task_set_progress(update_task, UpdateTaskStageError, 0); + return UPDATE_TASK_FAILED; + } + + return UPDATE_TASK_NOERR; } diff --git a/applications/updater/views/updater_main.c b/applications/updater/views/updater_main.c index 8d9b3e953..72541b9ab 100644 --- a/applications/updater/views/updater_main.c +++ b/applications/updater/views/updater_main.c @@ -15,12 +15,11 @@ struct UpdaterMainView { void* context; }; -static const uint8_t PROGRESS_RENDER_STEP = 3; /* percent, to limit rendering rate */ +static const uint8_t PROGRESS_RENDER_STEP = 1; /* percent, to limit rendering rate */ typedef struct { string_t status; uint8_t progress, rendered_progress; - uint8_t idx_stage, total_stages; bool failed; } UpdaterProgressModel; @@ -28,14 +27,10 @@ void updater_main_model_set_state( UpdaterMainView* main_view, const char* message, uint8_t progress, - uint8_t idx_stage, - uint8_t total_stages, bool failed) { with_view_model( main_view->view, (UpdaterProgressModel * model) { model->failed = failed; - model->idx_stage = idx_stage; - model->total_stages = total_stages; model->progress = progress; if(string_cmp_str(model->status, message)) { string_set(model->status, message); @@ -65,14 +60,10 @@ bool updater_main_input(InputEvent* event, void* context) { return true; } - if(event->type != InputTypeShort) { - return true; - } - - if(event->key == InputKeyOk) { + if((event->type == InputTypeShort) && (event->key == InputKeyOk)) { view_dispatcher_send_custom_event( main_view->view_dispatcher, UpdaterCustomEventRetryUpdate); - } else if(event->key == InputKeyBack) { + } else if((event->type == InputTypeLong) && (event->key == InputKeyBack)) { view_dispatcher_send_custom_event( main_view->view_dispatcher, UpdaterCustomEventCancelUpdate); } @@ -85,27 +76,25 @@ static void updater_main_draw_callback(Canvas* canvas, void* _model) { canvas_set_font(canvas, FontPrimary); - uint16_t y_offset = model->failed ? 5 : 13; - string_t status_text; - if(!model->failed && (model->idx_stage != 0) && (model->idx_stage <= model->total_stages)) { - string_init_printf( - status_text, - "[%d/%d] %s", - model->idx_stage, - model->total_stages, - string_get_cstr(model->status)); - } else { - string_init_set(status_text, model->status); - } - canvas_draw_str_aligned( - canvas, 128 / 2, y_offset, AlignCenter, AlignTop, string_get_cstr(status_text)); - string_clear(status_text); if(model->failed) { + canvas_draw_str_aligned(canvas, 42, 16, AlignLeft, AlignTop, "Update Failed!"); canvas_set_font(canvas, FontSecondary); canvas_draw_str_aligned( - canvas, 128 / 2, 20, AlignCenter, AlignTop, "[OK] to retry, [Back] to abort"); + canvas, 42, 32, AlignLeft, AlignTop, string_get_cstr(model->status)); + + canvas_draw_icon(canvas, 7, 16, &I_Warning_30x23); + canvas_draw_str_aligned( + canvas, 18, 51, AlignLeft, AlignTop, "to retry, hold to abort"); + canvas_draw_icon(canvas, 7, 50, &I_Ok_btn_9x9); + canvas_draw_icon(canvas, 75, 51, &I_Pin_back_arrow_10x8); + } else { + canvas_draw_str_aligned(canvas, 55, 14, AlignLeft, AlignTop, "UPDATING"); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, 64, 51, AlignCenter, AlignTop, string_get_cstr(model->status)); + canvas_draw_icon(canvas, 4, 5, &I_Updating_32x40); + elements_progress_bar(canvas, 42, 29, 80, (float)model->progress / 100); } - elements_progress_bar(canvas, 14, 35, 100, (float)model->progress / 100); } UpdaterMainView* updater_main_alloc() { @@ -116,7 +105,7 @@ UpdaterMainView* updater_main_alloc() { with_view_model( main_view->view, (UpdaterProgressModel * model) { - string_init_set(model->status, "Waiting for storage"); + string_init_set(model->status, "Waiting for SD card"); return true; }); diff --git a/applications/updater/views/updater_main.h b/applications/updater/views/updater_main.h index d78729569..81a0e86c9 100644 --- a/applications/updater/views/updater_main.h +++ b/applications/updater/views/updater_main.h @@ -17,8 +17,6 @@ void updater_main_model_set_state( UpdaterMainView* main_view, const char* message, uint8_t progress, - uint8_t idx_stage, - uint8_t total_stages, bool failed); void updater_main_set_storage_pubsub(UpdaterMainView* main_view, FuriPubSubSubscription* sub); diff --git a/assets/compiled/assets_icons.c b/assets/compiled/assets_icons.c index 8b17d0780..709fab457 100644 --- a/assets/compiled/assets_icons.c +++ b/assets/compiled/assets_icons.c @@ -642,6 +642,9 @@ const uint8_t* const _I_Drive_112x35[] = {_I_Drive_112x35_0}; const uint8_t _I_Error_62x31_0[] = {0x01,0x00,0x9e,0x00,0x00,0x47,0xc2,0xfe,0x07,0x58,0x66,0x02,0x02,0x07,0x48,0x1c,0x02,0x0c,0x06,0x3c,0x00,0x08,0x61,0x00,0x73,0xa0,0x00,0x86,0x20,0x07,0x39,0x00,0x09,0x01,0x88,0x07,0x70,0xd1,0x09,0x0b,0xe0,0x07,0x38,0x1c,0x62,0x11,0x08,0x80,0x8c,0x8a,0x0f,0x1c,0x82,0x7d,0x20,0x58,0x0b,0xe4,0x02,0x1d,0x0e,0x82,0x6e,0xa0,0xb8,0x0c,0x1c,0x02,0x39,0x07,0x82,0x4e,0xa0,0xb7,0x08,0x04,0x07,0x71,0x03,0x82,0x7e,0xa0,0xb0,0xe8,0x04,0x0b,0xe1,0x01,0x81,0x01,0xc6,0x01,0xc0,0x81,0xf8,0x01,0x42,0x27,0x18,0x04,0xc0,0x1e,0x63,0x71,0x3d,0x0c,0x08,0x3e,0x20,0xa1,0x22,0x94,0x08,0x5e,0x21,0x51,0x0f,0x08,0xbc,0x47,0xe2,0x07,0x29,0x81,0x40,0x49,0xe2,0x07,0x28,0x61,0x80,0x4b,0xe2,0x07,0x28,0x19,0xe0,0xc0,0xe2,0x0d,0x18,0xc0,0x1d,0x00,0x02,0xa8,0x30,0x39,0x2e,0x10,0x0e,0x5e,0x00,0x3b,0x7e,0x00,0xec,0x46,0x10,0x3f,0x80,0xc8,}; const uint8_t* const _I_Error_62x31[] = {_I_Error_62x31_0}; +const uint8_t _I_Updating_32x40_0[] = {0x01,0x00,0x56,0x00,0xc0,0x7f,0xc0,0x03,0xc0,0x01,0x97,0x82,0x07,0x00,0xe0,0x5c,0x00,0x65,0x38,0x01,0x94,0x70,0x06,0x50,0xe0,0x19,0x41,0xc0,0x65,0xff,0x01,0xb4,0x0c,0x02,0x7e,0x08,0x38,0x0c,0x7c,0xd6,0x70,0x18,0xfb,0xfe,0xfc,0x0c,0x18,0xc8,0x78,0x20,0x33,0x81,0x8f,0x8a,0x07,0x3e,0xbe,0x70,0x38,0x71,0xff,0xc7,0x0f,0xc7,0x0f,0xf8,0x71,0xc0,0x76,0x13,0x30,0xd9,0x88,0xcc,0x5f,0x03,0xb2,0x21,0xa1,0x2c,0xc0,0x26,0x82,0x10,0x1f,0x80,0xd1,0x24,0x40,0x04,}; +const uint8_t* const _I_Updating_32x40[] = {_I_Updating_32x40_0}; + const uint8_t _I_DolphinExcited_64x63_0[] = {0x01,0x00,0x36,0x01,0x00,0x25,0x00,0x0f,0xd2,0x00,0x3b,0xe0,0x00,0xeb,0x10,0x0c,0x34,0x40,0x30,0xd0,0x88,0x80,0x1d,0xa1,0x00,0x42,0xfc,0x7f,0xc0,0x63,0x04,0x01,0x0e,0x02,0x0f,0x00,0x00,0x8c,0x08,0x0e,0x37,0x00,0x10,0xc6,0x20,0x10,0x10,0xd9,0x11,0x92,0x1c,0x1a,0x3e,0x00,0x04,0x42,0x02,0x1a,0x20,0xb0,0xce,0x00,0x64,0x07,0x20,0x59,0x16,0x50,0x36,0x45,0x94,0x84,0x78,0x20,0x60,0x75,0x8e,0x43,0x06,0x63,0x3c,0x33,0x94,0x0c,0xd2,0x5c,0x30,0x38,0xe4,0x08,0x43,0x10,0xc0,0x5e,0x06,0x22,0x53,0x1a,0x02,0x08,0x7f,0xd0,0x32,0xc1,0x50,0x21,0x14,0x0e,0x70,0x1c,0x46,0xe2,0x07,0x19,0x06,0x3c,0xdc,0x20,0x91,0xae,0x01,0xcc,0xbe,0x30,0x09,0xfc,0x12,0x41,0xff,0x83,0xcc,0x0a,0xa3,0x1f,0x03,0x99,0xe8,0x7c,0x10,0xf8,0x25,0xa0,0x5e,0x50,0x0f,0x84,0x1e,0x09,0x54,0x03,0x9f,0xf2,0x07,0x02,0xd5,0x11,0xca,0x01,0xfe,0x80,0xc0,0xaa,0x9f,0xf0,0x39,0x5f,0xd0,0x43,0xaa,0x83,0x41,0x92,0xc3,0x1f,0x03,0x8d,0x52,0x02,0x2e,0x25,0xc9,0x6a,0x99,0x46,0xa6,0x2a,0xa0,0x1c,0xaf,0xca,0x62,0x94,0x28,0xcb,0x7e,0x0f,0x15,0x71,0xf8,0x3c,0x22,0x71,0x03,0x8a,0x84,0x67,0x18,0x0f,0xac,0x1c,0x0e,0x38,0x08,0x0c,0x3e,0x01,0xae,0xbd,0x13,0x0c,0x0e,0x35,0x8e,0xa8,0x1c,0xb0,0x1f,0xf8,0x06,0x83,0xf4,0x27,0x38,0x07,0xff,0xff,0x8f,0x03,0xa0,0x4c,0x80,0xed,0x60,0x03,0xb4,0x60,0x0e,0xd0,0x60,0x3a,0x87,0x84,0x0e,0xb7,0xc2,0xfa,0x18,0x05,0x44,0x20,0x73,0xff,0xf7,0xce,0xe4,0x07,0x2d,0x52,0x2c,0x80,0xe7,0x54,0xea,0x81,0xd7,0x50,0x0f,0x7a,0xaa,0x3d,0x41,0xe2,0x07,0x5a,0x80,0x3c,0xa0,0x40,0x72,0xd0,0x6a,0x80,0xa2,0x07,0x3a,0x05,0x54,0x8e,0x20,0x73,0xc0,0x03,0xd8,0x60,0x30,0x40,0x3a,0xc0,0x00,0xee,0xea,0x10,0x3b,0x80,}; const uint8_t* const _I_DolphinExcited_64x63[] = {_I_DolphinExcited_64x63_0}; @@ -835,6 +838,7 @@ const Icon I_Connect_me_62x31 = {.width=62,.height=31,.frame_count=1,.frame_rate const Icon I_Connected_62x31 = {.width=62,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_Connected_62x31}; const Icon I_Drive_112x35 = {.width=112,.height=35,.frame_count=1,.frame_rate=0,.frames=_I_Drive_112x35}; const Icon I_Error_62x31 = {.width=62,.height=31,.frame_count=1,.frame_rate=0,.frames=_I_Error_62x31}; +const Icon I_Updating_32x40 = {.width=32,.height=40,.frame_count=1,.frame_rate=0,.frames=_I_Updating_32x40}; const Icon I_DolphinExcited_64x63 = {.width=64,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinExcited_64x63}; const Icon I_DolphinMafia_115x62 = {.width=115,.height=62,.frame_count=1,.frame_rate=0,.frames=_I_DolphinMafia_115x62}; const Icon I_DolphinNice_96x59 = {.width=96,.height=59,.frame_count=1,.frame_rate=0,.frames=_I_DolphinNice_96x59}; diff --git a/assets/compiled/assets_icons.h b/assets/compiled/assets_icons.h index be1023f65..12ddb78e9 100644 --- a/assets/compiled/assets_icons.h +++ b/assets/compiled/assets_icons.h @@ -173,6 +173,7 @@ extern const Icon I_Connect_me_62x31; extern const Icon I_Connected_62x31; extern const Icon I_Drive_112x35; extern const Icon I_Error_62x31; +extern const Icon I_Updating_32x40; extern const Icon I_DolphinExcited_64x63; extern const Icon I_DolphinMafia_115x62; extern const Icon I_DolphinNice_96x59; diff --git a/assets/icons/Update/Updating_32x40.png b/assets/icons/Update/Updating_32x40.png new file mode 100644 index 000000000..d8f7654b8 Binary files /dev/null and b/assets/icons/Update/Updating_32x40.png differ diff --git a/firmware/targets/f7/Src/main.c b/firmware/targets/f7/Src/main.c index 629c154ed..2c28265f7 100644 --- a/firmware/targets/f7/Src/main.c +++ b/firmware/targets/f7/Src/main.c @@ -3,6 +3,7 @@ #include #include #include +#include #define TAG "Main" @@ -47,7 +48,7 @@ int main() { flipper_boot_update_exec(); // if things go nice, we shouldn't reach this point. // But if we do, abandon to avoid bootloops - furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal); + update_operation_disarm(); furi_hal_power_reset(); } else { furi_hal_light_sequence("rgb G"); diff --git a/firmware/targets/f7/Src/update.c b/firmware/targets/f7/Src/update.c index 4b3ee3ad5..f4a434b11 100644 --- a/firmware/targets/f7/Src/update.c +++ b/firmware/targets/f7/Src/update.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -101,7 +102,7 @@ static bool flipper_update_load_stage(const string_t work_dir, UpdateManifest* m static bool flipper_update_get_work_directory(string_t out_dir) { const uint32_t update_index = furi_hal_rtc_get_register(FuriHalRtcRegisterUpdateFolderFSIndex); - if(update_index == 0) { + if(update_index == UPDATE_OPERATION_ROOT_DIR_PACKAGE_MAGIC) { string_set(out_dir, UPDATE_DIR_DEFAULT_REL_PATH); return true; } diff --git a/lib/update_util/update_manifest.h b/lib/update_util/update_manifest.h index 75871e1d3..2893be5a0 100644 --- a/lib/update_util/update_manifest.h +++ b/lib/update_util/update_manifest.h @@ -12,7 +12,6 @@ extern "C" { /* Paths don't include /ext -- because at startup SD card is mounted as root */ #define UPDATE_DIR_DEFAULT_REL_PATH "/update" #define UPDATE_MANIFEST_DEFAULT_NAME "update.fuf" -#define UPDATE_MAINFEST_DEFAULT_PATH UPDATE_DIR_DEFAULT_REL_PATH "/" UPDATE_MANIFEST_DEFAULT_NAME typedef union { uint8_t raw[6]; diff --git a/lib/update_util/update_operation.c b/lib/update_util/update_operation.c index cf72dd0c8..c9a7cd187 100644 --- a/lib/update_util/update_operation.c +++ b/lib/update_util/update_operation.c @@ -9,10 +9,10 @@ #include #include -static const char* UPDATE_ROOT_DIR = "/ext" UPDATE_DIR_DEFAULT_REL_PATH; -static const char* UPDATE_PREFIX = "/ext" UPDATE_DIR_DEFAULT_REL_PATH "/"; -static const char* UPDATE_SUFFIX = "/" UPDATE_MANIFEST_DEFAULT_NAME; -static const uint32_t MAX_DIR_NAME_LEN = 250; +#define UPDATE_ROOT_DIR "/ext" UPDATE_DIR_DEFAULT_REL_PATH +#define UPDATE_PREFIX "/ext" UPDATE_DIR_DEFAULT_REL_PATH "/" +#define UPDATE_SUFFIX "/" UPDATE_MANIFEST_DEFAULT_NAME +#define MAX_DIR_NAME_LEN 250 static const char* update_prepare_result_descr[] = { [UpdatePrepareResultOK] = "OK", @@ -59,7 +59,7 @@ int32_t update_operation_get_package_index(Storage* storage, const char* update_ furi_assert(update_package_dir); if(strlen(update_package_dir) == 0) { - return 0; + return UPDATE_OPERATION_ROOT_DIR_PACKAGE_MAGIC; } bool found = false; @@ -90,9 +90,9 @@ int32_t update_operation_get_package_index(Storage* storage, const char* update_ } bool update_operation_get_current_package_path(Storage* storage, string_t out_path) { - uint32_t update_index = furi_hal_rtc_get_register(FuriHalRtcRegisterUpdateFolderFSIndex); + const uint32_t update_index = furi_hal_rtc_get_register(FuriHalRtcRegisterUpdateFolderFSIndex); string_set_str(out_path, UPDATE_ROOT_DIR); - if(update_index == 0) { + if(update_index == UPDATE_OPERATION_ROOT_DIR_PACKAGE_MAGIC) { return true; } @@ -184,14 +184,19 @@ UpdatePrepareResult update_operation_prepare(const char* manifest_file_path) { } bool update_operation_is_armed() { - return furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModePreUpdate; + FuriHalRtcBootMode boot_mode = furi_hal_rtc_get_boot_mode(); + return (boot_mode >= FuriHalRtcBootModePreUpdate) && + (boot_mode <= FuriHalRtcBootModePostUpdate) && + (furi_hal_rtc_get_register(FuriHalRtcRegisterUpdateFolderFSIndex) > 0); } void update_operation_disarm() { furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal); - furi_hal_rtc_set_register(FuriHalRtcRegisterUpdateFolderFSIndex, 0); + furi_hal_rtc_set_register( + FuriHalRtcRegisterUpdateFolderFSIndex, INT_MAX); } -void update_operation_persist_package_index(uint32_t index) { +void update_operation_persist_package_index(int32_t index) { + furi_check(index >= 0); furi_hal_rtc_set_register(FuriHalRtcRegisterUpdateFolderFSIndex, index); } diff --git a/lib/update_util/update_operation.h b/lib/update_util/update_operation.h index 10f3c6b41..c11f2754a 100644 --- a/lib/update_util/update_operation.h +++ b/lib/update_util/update_operation.h @@ -8,6 +8,8 @@ extern "C" { #endif +#define UPDATE_OPERATION_ROOT_DIR_PACKAGE_MAGIC 0 + /* * Checks if supplied full manifest path is valid * @param full_path Full path to manifest file. Must be named UPDATE_MANIFEST_DEFAULT_NAME @@ -39,7 +41,7 @@ UpdatePrepareResult update_operation_prepare(const char* manifest_file_path); * Gets update package index to pass in RTC registers * @param storage Storage API * @param update_package_dir Package directory name - * @return int32_t <0 - error, >= 0 - update index value + * @return int32_t <=0 - error, >0 - update index value */ int32_t update_operation_get_package_index(Storage* storage, const char* update_package_dir); @@ -55,10 +57,10 @@ bool update_operation_get_current_package_path(Storage* storage, string_t out_pa * Stores given update index in RTC registers * @param index Value to store */ -void update_operation_persist_package_index(uint32_t index); +void update_operation_persist_package_index(int32_t index); /* - * Sets up update operation to be performed on reset + * Checks if an update operation step is pending after reset */ bool update_operation_is_armed();