diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e4794461..c8490d23 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,4 +1,4 @@ -# Who owns all the code by default +# Who owns all the fish by default * @skotopes @DrZlo13 @@ -8,7 +8,7 @@ applications/accessor/** @skotopes @DrZlo13 applications/loader/** @skotopes @DrZlo13 @gornekich applications/bt/** @skotopes @DrZlo13 applications/cli/** @skotopes @DrZlo13 -applications/dolphin/** @skotopes @DrZlo13 @itsyourbedtime +applications/dolphin/** @skotopes @DrZlo13 applications/gpio-tester/** @skotopes @DrZlo13 applications/gui/** @skotopes @DrZlo13 applications/gui-test/** @skotopes @DrZlo13 diff --git a/applications/about/about.c b/applications/about/about.c index b153841e..22b8a3a3 100644 --- a/applications/about/about.c +++ b/applications/about/about.c @@ -89,6 +89,12 @@ static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage* furi_hal_version_get_hw_connect(), my_name ? my_name : "Unknown"); + string_cat_printf(buffer, "Serial number:\n"); + const uint8_t* uid = furi_hal_version_uid(); + for(size_t i = 0; i < furi_hal_version_uid_size(); i++) { + string_cat_printf(buffer, "%02X", uid[i]); + } + dialog_message_set_header(message, "HW Version info:", 0, 0, AlignLeft, AlignTop); dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop); result = dialog_message_show(dialogs, message); diff --git a/applications/archive/archive_i.h b/applications/archive/archive_i.h index ba95ac4b..b450bb9c 100644 --- a/applications/archive/archive_i.h +++ b/applications/archive/archive_i.h @@ -25,4 +25,5 @@ struct ArchiveApp { ArchiveBrowserView* browser; TextInput* text_input; char text_store[MAX_NAME_LEN]; + char file_extension[MAX_EXT_LEN + 1]; }; diff --git a/applications/archive/helpers/archive_browser.c b/applications/archive/helpers/archive_browser.c index d52475cc..eb316c1e 100644 --- a/applications/archive/helpers/archive_browser.c +++ b/applications/archive/helpers/archive_browser.c @@ -272,7 +272,6 @@ void archive_enter_dir(ArchiveBrowserView* browser, string_t name) { with_view_model( browser->view, (ArchiveBrowserViewModel * model) { model->last_idx = model->idx; - model->last_offset = model->list_offset; model->idx = 0; model->depth = CLAMP(model->depth + 1, MAX_DEPTH, 0); return false; diff --git a/applications/archive/helpers/archive_favorites.c b/applications/archive/helpers/archive_favorites.c index 1e581502..b622e76f 100644 --- a/applications/archive/helpers/archive_favorites.c +++ b/applications/archive/helpers/archive_favorites.c @@ -31,6 +31,40 @@ uint16_t archive_favorites_count(void* context) { return lines; } +static bool archive_favourites_rescan() { + string_t buffer; + string_init(buffer); + FileWorker* file_worker = file_worker_alloc(true); + + bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); + if(result) { + while(1) { + if(!file_worker_read_until(file_worker, buffer, '\n')) { + break; + } + if(!string_size(buffer)) { + break; + } + + bool file_exists = false; + file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists); + if(file_exists) { + archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); + } + } + } + + string_clear(buffer); + + file_worker_close(file_worker); + file_worker_remove(file_worker, ARCHIVE_FAV_PATH); + file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); + + file_worker_free(file_worker); + + return result; +} + bool archive_favorites_read(void* context) { furi_assert(context); @@ -41,6 +75,8 @@ bool archive_favorites_read(void* context) { FileInfo file_info; string_init(buffer); + bool need_refresh = false; + bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); if(result) { @@ -52,13 +88,24 @@ bool archive_favorites_read(void* context) { break; } - archive_add_item(browser, &file_info, string_get_cstr(buffer)); + bool file_exists = false; + file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists); + + if(file_exists) + archive_add_item(browser, &file_info, string_get_cstr(buffer)); + else + need_refresh = true; string_reset(buffer); } } string_clear(buffer); file_worker_close(file_worker); file_worker_free(file_worker); + + if(need_refresh) { + archive_favourites_rescan(); + } + return result; } diff --git a/applications/archive/helpers/archive_files.c b/applications/archive/helpers/archive_files.c index 83b67a5b..a5bd2eb9 100644 --- a/applications/archive/helpers/archive_files.c +++ b/applications/archive/helpers/archive_files.c @@ -30,6 +30,14 @@ void archive_trim_file_path(char* name, bool ext) { } } +void archive_get_file_extension(char* name, char* ext) { + char* dot = strrchr(name, '.'); + if(dot == NULL) + *ext = '\0'; + else + strncpy(ext, dot, MAX_EXT_LEN); +} + void set_file_type(ArchiveFile_t* file, FileInfo* file_info) { furi_assert(file); furi_assert(file_info); diff --git a/applications/archive/helpers/archive_files.h b/applications/archive/helpers/archive_files.h index dd86a201..12fde2fb 100644 --- a/applications/archive/helpers/archive_files.h +++ b/applications/archive/helpers/archive_files.h @@ -50,6 +50,7 @@ ARRAY_DEF( bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name); void set_file_type(ArchiveFile_t* file, FileInfo* file_info); void archive_trim_file_path(char* name, bool ext); +void archive_get_file_extension(char* name, char* ext); bool archive_get_filenames(void* context, const char* path); bool archive_dir_empty(void* context, const char* path); bool archive_read_dir(void* context, const char* path); diff --git a/applications/archive/scenes/archive_scene_rename.c b/applications/archive/scenes/archive_scene_rename.c index ad7669bc..8f32eb8a 100644 --- a/applications/archive/scenes/archive_scene_rename.c +++ b/applications/archive/scenes/archive_scene_rename.c @@ -18,6 +18,7 @@ void archive_scene_rename_on_enter(void* context) { ArchiveFile_t* current = archive_get_current_file(archive->browser); strlcpy(archive->text_store, string_get_cstr(current->name), MAX_NAME_LEN); + archive_get_file_extension(archive->text_store, archive->file_extension); archive_trim_file_path(archive->text_store, true); text_input_set_header_text(text_input, "Rename:"); @@ -30,6 +31,10 @@ void archive_scene_rename_on_enter(void* context) { MAX_TEXT_INPUT_LEN, false); + ValidatorIsFile* validator_is_file = + validator_is_file_alloc_init(archive_get_path(archive->browser), archive->file_extension); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput); } @@ -74,6 +79,11 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) { void archive_scene_rename_on_exit(void* context) { ArchiveApp* archive = (ArchiveApp*)context; + // Clear view - text_input_clean(archive->text_input); + void* validator_context = text_input_get_validator_callback_context(archive->text_input); + text_input_set_validator(archive->text_input, NULL, NULL); + validator_is_file_free(validator_context); + + text_input_reset(archive->text_input); } diff --git a/applications/archive/views/archive_browser_view.h b/applications/archive/views/archive_browser_view.h index 91ce9ccc..634dec44 100644 --- a/applications/archive/views/archive_browser_view.h +++ b/applications/archive/views/archive_browser_view.h @@ -11,6 +11,7 @@ #define MAX_LEN_PX 110 #define MAX_NAME_LEN 255 +#define MAX_EXT_LEN 6 #define FRAME_HEIGHT 12 #define MENU_ITEMS 4 #define MAX_DEPTH 32 diff --git a/applications/bad_usb/bad_usb_app.c b/applications/bad_usb/bad_usb_app.c index 58af3d7c..4f94598e 100644 --- a/applications/bad_usb/bad_usb_app.c +++ b/applications/bad_usb/bad_usb_app.c @@ -71,7 +71,7 @@ void bad_usb_app_free(BadUsbApp* app) { } int32_t bad_usb_app(void* p) { - UsbInterface* usb_mode_prev = furi_hal_usb_get_config(); + FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); furi_hal_usb_set_config(&usb_hid); BadUsbApp* bad_usb_app = bad_usb_app_alloc(); diff --git a/applications/bad_usb/bad_usb_script.c b/applications/bad_usb/bad_usb_script.c index 1ce87bf0..6cf460df 100644 --- a/applications/bad_usb/bad_usb_script.c +++ b/applications/bad_usb/bad_usb_script.c @@ -6,6 +6,7 @@ #include #include #include "bad_usb_script.h" +#include #define TAG "BadUSB" #define WORKER_TAG TAG "Worker" @@ -442,6 +443,7 @@ static int32_t bad_usb_worker(void* context) { if(flags & WorkerEvtEnd) { break; } else if(flags & WorkerEvtToggle) { // Start executing script + DOLPHIN_DEED(DolphinDeedBadUsbPlayScript); delay_val = 0; bad_usb->buf_len = 0; bad_usb->st.line_cur = 0; diff --git a/applications/bt/bt_service/bt.c b/applications/bt/bt_service/bt.c index 5448c81b..32008f52 100755 --- a/applications/bt/bt_service/bt.c +++ b/applications/bt/bt_service/bt.c @@ -2,7 +2,8 @@ #include "battery_service.h" #include "bt_keys_storage.h" -#include +#include +#include #define TAG "BtSrv" @@ -29,17 +30,46 @@ static ViewPort* bt_statusbar_view_port_alloc(Bt* bt) { return statusbar_view_port; } -static void bt_pin_code_show_event_handler(Bt* bt, uint32_t pin) { - furi_assert(bt); +static void bt_pin_code_view_port_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + Bt* bt = context; + char pin_code_info[24]; + canvas_draw_icon(canvas, 0, 0, &I_BLE_Pairing_128x64); + snprintf(pin_code_info, sizeof(pin_code_info), "Pairing code\n%06ld", bt->pin_code); + elements_multiline_text_aligned(canvas, 64, 4, AlignCenter, AlignTop, pin_code_info); + elements_button_left(canvas, "Quit"); +} + +static void bt_pin_code_view_port_input_callback(InputEvent* event, void* context) { + furi_assert(context); + Bt* bt = context; + if(event->type == InputTypeShort) { + if(event->key == InputKeyLeft || event->key == InputKeyBack) { + view_port_enabled_set(bt->pin_code_view_port, false); + } + } +} + +static ViewPort* bt_pin_code_view_port_alloc(Bt* bt) { + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, bt_pin_code_view_port_draw_callback, bt); + view_port_input_callback_set(view_port, bt_pin_code_view_port_input_callback, bt); + view_port_enabled_set(view_port, false); + return view_port; +} + +static void bt_pin_code_show(Bt* bt, uint32_t pin_code) { + bt->pin_code = pin_code; notification_message(bt->notification, &sequence_display_on); - string_t pin_str; - dialog_message_set_icon(bt->dialog_message, &I_BLE_Pairing_128x64, 0, 0); - string_init_printf(pin_str, "Pairing code\n%06d", pin); - dialog_message_set_text( - bt->dialog_message, string_get_cstr(pin_str), 64, 4, AlignCenter, AlignTop); - dialog_message_set_buttons(bt->dialog_message, "Quit", NULL, NULL); - dialog_message_show(bt->dialogs, bt->dialog_message); - string_clear(pin_str); + gui_view_port_send_to_front(bt->gui, bt->pin_code_view_port); + view_port_enabled_set(bt->pin_code_view_port, true); +} + +static void bt_pin_code_hide(Bt* bt) { + bt->pin_code = 0; + if(view_port_is_enabled(bt->pin_code_view_port)) { + view_port_enabled_set(bt->pin_code_view_port, false); + } } static bool bt_pin_code_verify_event_handler(Bt* bt, uint32_t pin) { @@ -84,11 +114,14 @@ Bt* bt_alloc() { // Setup statusbar view port bt->statusbar_view_port = bt_statusbar_view_port_alloc(bt); + // Pin code view port + bt->pin_code_view_port = bt_pin_code_view_port_alloc(bt); // Notification bt->notification = furi_record_open("notification"); // Gui bt->gui = furi_record_open("gui"); gui_add_view_port(bt->gui, bt->statusbar_view_port, GuiLayerStatusBarLeft); + gui_add_view_port(bt->gui, bt->pin_code_view_port, GuiLayerFullscreen); // Dialogs bt->dialogs = furi_record_open("dialogs"); @@ -162,7 +195,7 @@ static bool bt_on_gap_event_callback(GapEvent event, void* context) { if(event.type == GapEventTypeConnected) { // Update status bar bt->status = BtStatusConnected; - BtMessage message = {.type = BtMessageTypeUpdateStatusbar}; + BtMessage message = {.type = BtMessageTypeUpdateStatus}; furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); if(bt->profile == BtProfileSerial) { // Open RPC session @@ -192,12 +225,12 @@ static bool bt_on_gap_event_callback(GapEvent event, void* context) { ret = true; } else if(event.type == GapEventTypeStartAdvertising) { bt->status = BtStatusAdvertising; - BtMessage message = {.type = BtMessageTypeUpdateStatusbar}; + BtMessage message = {.type = BtMessageTypeUpdateStatus}; furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); ret = true; } else if(event.type == GapEventTypeStopAdvertising) { bt->status = BtStatusOff; - BtMessage message = {.type = BtMessageTypeUpdateStatusbar}; + BtMessage message = {.type = BtMessageTypeUpdateStatus}; furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); ret = true; } else if(event.type == GapEventTypePinCodeShow) { @@ -313,9 +346,10 @@ int32_t bt_srv() { BtMessage message; while(1) { furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK); - if(message.type == BtMessageTypeUpdateStatusbar) { - // Update statusbar + if(message.type == BtMessageTypeUpdateStatus) { + // Update view ports bt_statusbar_update(bt); + bt_pin_code_hide(bt); if(bt->status_changed_cb) { bt->status_changed_cb(bt->status, bt->status_changed_ctx); } @@ -324,11 +358,13 @@ int32_t bt_srv() { furi_hal_bt_update_battery_level(message.data.battery_level); } else if(message.type == BtMessageTypePinCodeShow) { // Display PIN code - bt_pin_code_show_event_handler(bt, message.data.pin_code); + bt_pin_code_show(bt, message.data.pin_code); } else if(message.type == BtMessageTypeKeysStorageUpdated) { bt_save_key_storage(bt); } else if(message.type == BtMessageTypeSetProfile) { bt_change_profile(bt, &message); + } else if(message.type == BtMessageTypeForgetBondedDevices) { + bt_delete_key_storage(bt); } } return 0; diff --git a/applications/bt/bt_service/bt.h b/applications/bt/bt_service/bt.h index d928f8b1..e39717d6 100644 --- a/applications/bt/bt_service/bt.h +++ b/applications/bt/bt_service/bt.h @@ -41,6 +41,13 @@ bool bt_set_profile(Bt* bt, BtProfile profile); */ void bt_set_status_changed_callback(Bt* bt, BtStatusChangedCallback callback, void* context); +/** Forget bonded devices + * @note Leads to wipe ble key storage and deleting bt.keys + * + * @param bt Bt instance + */ +void bt_forget_bonded_devices(Bt* bt); + #ifdef __cplusplus } #endif diff --git a/applications/bt/bt_service/bt_api.c b/applications/bt/bt_service/bt_api.c index a4f67e04..96d72e63 100755 --- a/applications/bt/bt_service/bt_api.c +++ b/applications/bt/bt_service/bt_api.c @@ -20,3 +20,9 @@ void bt_set_status_changed_callback(Bt* bt, BtStatusChangedCallback callback, vo bt->status_changed_cb = callback; bt->status_changed_ctx = context; } + +void bt_forget_bonded_devices(Bt* bt) { + furi_assert(bt); + BtMessage message = {.type = BtMessageTypeForgetBondedDevices}; + furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); +} diff --git a/applications/bt/bt_service/bt_i.h b/applications/bt/bt_service/bt_i.h index bb81e92f..610c0905 100644 --- a/applications/bt/bt_service/bt_i.h +++ b/applications/bt/bt_service/bt_i.h @@ -19,11 +19,12 @@ #define BT_API_UNLOCK_EVENT (1UL << 0) typedef enum { - BtMessageTypeUpdateStatusbar, + BtMessageTypeUpdateStatus, BtMessageTypeUpdateBatteryLevel, BtMessageTypePinCodeShow, BtMessageTypeKeysStorageUpdated, BtMessageTypeSetProfile, + BtMessageTypeForgetBondedDevices, } BtMessageType; typedef union { @@ -49,6 +50,8 @@ struct Bt { NotificationApp* notification; Gui* gui; ViewPort* statusbar_view_port; + ViewPort* pin_code_view_port; + uint32_t pin_code; DialogsApp* dialogs; DialogMessage* dialog_message; Power* power; diff --git a/applications/bt/bt_service/bt_keys_storage.c b/applications/bt/bt_service/bt_keys_storage.c index acd32339..c712b65b 100644 --- a/applications/bt/bt_service/bt_keys_storage.c +++ b/applications/bt/bt_service/bt_keys_storage.c @@ -39,3 +39,16 @@ bool bt_save_key_storage(Bt* bt) { file_worker_free(file_worker); return file_saved; } + +bool bt_delete_key_storage(Bt* bt) { + furi_assert(bt); + bool delete_succeed = false; + + furi_hal_bt_stop_advertising(); + delete_succeed = furi_hal_bt_clear_white_list(); + if(bt->bt_settings.enabled) { + furi_hal_bt_start_advertising(); + } + + return delete_succeed; +} diff --git a/applications/bt/bt_service/bt_keys_storage.h b/applications/bt/bt_service/bt_keys_storage.h index 4b09d7f2..e763e6a7 100644 --- a/applications/bt/bt_service/bt_keys_storage.h +++ b/applications/bt/bt_service/bt_keys_storage.h @@ -5,3 +5,5 @@ bool bt_load_key_storage(Bt* bt); bool bt_save_key_storage(Bt* bt); + +bool bt_delete_key_storage(Bt* bt); diff --git a/applications/bt/bt_settings_app/bt_settings_app.c b/applications/bt/bt_settings_app/bt_settings_app.c index f3e60937..be57223e 100755 --- a/applications/bt/bt_settings_app/bt_settings_app.c +++ b/applications/bt/bt_settings_app/bt_settings_app.c @@ -18,7 +18,9 @@ BtSettingsApp* bt_settings_app_alloc() { // Load settings bt_settings_load(&app->settings); app->gui = furi_record_open("gui"); + app->bt = furi_record_open("bt"); + // View Dispatcher and Scene Manager app->view_dispatcher = view_dispatcher_alloc(); app->scene_manager = scene_manager_alloc(&bt_settings_scene_handlers, app); view_dispatcher_enable_queue(app->view_dispatcher); @@ -31,26 +33,45 @@ BtSettingsApp* bt_settings_app_alloc() { view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + // Gui Modules app->var_item_list = variable_item_list_alloc(); view_dispatcher_add_view( app->view_dispatcher, BtSettingsAppViewVarItemList, variable_item_list_get_view(app->var_item_list)); + app->dialog = dialog_ex_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, BtSettingsAppViewDialog, dialog_ex_get_view(app->dialog)); + + app->popup = popup_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, BtSettingsAppViewPopup, popup_get_view(app->popup)); + + // Set first scene scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneStart); return app; } void bt_settings_app_free(BtSettingsApp* app) { furi_assert(app); - // Variable item list + // Gui modules view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewVarItemList); variable_item_list_free(app->var_item_list); - // View dispatcher + + view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewDialog); + dialog_ex_free(app->dialog); + + view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewPopup); + popup_free(app->popup); + + // View Dispatcher and Scene Manager view_dispatcher_free(app->view_dispatcher); scene_manager_free(app->scene_manager); + // Records furi_record_close("gui"); + furi_record_close("bt"); free(app); } diff --git a/applications/bt/bt_settings_app/bt_settings_app.h b/applications/bt/bt_settings_app/bt_settings_app.h index 9f262a46..5b4a8d13 100755 --- a/applications/bt/bt_settings_app/bt_settings_app.h +++ b/applications/bt/bt_settings_app/bt_settings_app.h @@ -1,22 +1,41 @@ #pragma once #include +#include #include #include #include #include #include +#include +#include #include "../bt_settings.h" #include "scenes/bt_settings_scene.h" +enum BtSettingsCustomEvent { + // Keep first 10 events reserved for button types and indexes + BtSettingsCustomEventReserved = 10, + + BtSettingsCustomEventForgetDevices, + BtSettingsCustomEventExitView, +}; + typedef struct { BtSettings settings; + Bt* bt; Gui* gui; SceneManager* scene_manager; ViewDispatcher* view_dispatcher; + VariableItemList* var_item_list; + DialogEx* dialog; + Popup* popup; } BtSettingsApp; -typedef enum { BtSettingsAppViewVarItemList } BtSettingsAppView; +typedef enum { + BtSettingsAppViewVarItemList, + BtSettingsAppViewDialog, + BtSettingsAppViewPopup, +} BtSettingsAppView; diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene_config.h b/applications/bt/bt_settings_app/scenes/bt_settings_scene_config.h old mode 100644 new mode 100755 index 6aa23850..f78dd0c2 --- a/applications/bt/bt_settings_app/scenes/bt_settings_scene_config.h +++ b/applications/bt/bt_settings_app/scenes/bt_settings_scene_config.h @@ -1 +1,3 @@ ADD_SCENE(bt_settings, start, Start) +ADD_SCENE(bt_settings, forget_dev_confirm, ForgetDevConfirm) +ADD_SCENE(bt_settings, forget_dev_success, ForgetDevSuccess) diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c b/applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c new file mode 100755 index 00000000..be9a7196 --- /dev/null +++ b/applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c @@ -0,0 +1,44 @@ +#include "../bt_settings_app.h" +#include "furi_hal_bt.h" + +void bt_settings_scene_forget_dev_confirm_dialog_callback(DialogExResult result, void* context) { + furi_assert(context); + BtSettingsApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, result); +} + +void bt_settings_scene_forget_dev_confirm_on_enter(void* context) { + BtSettingsApp* app = context; + DialogEx* dialog = app->dialog; + dialog_ex_set_header(dialog, "Unpair all devices?", 64, 3, AlignCenter, AlignTop); + dialog_ex_set_text( + dialog, "All previous pairings\nwill be lost.", 64, 22, AlignCenter, AlignTop); + dialog_ex_set_left_button_text(dialog, "Back"); + dialog_ex_set_right_button_text(dialog, "Unpair"); + dialog_ex_set_context(dialog, app); + dialog_ex_set_result_callback(dialog, bt_settings_scene_forget_dev_confirm_dialog_callback); + + view_dispatcher_switch_to_view(app->view_dispatcher, BtSettingsAppViewDialog); +} + +bool bt_settings_scene_forget_dev_confirm_on_event(void* context, SceneManagerEvent event) { + BtSettingsApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultLeft) { + consumed = scene_manager_previous_scene(app->scene_manager); + } else if(event.event == DialogExResultRight) { + bt_forget_bonded_devices(app->bt); + scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneForgetDevSuccess); + consumed = true; + } + } + + return consumed; +} + +void bt_settings_scene_forget_dev_confirm_on_exit(void* context) { + BtSettingsApp* app = context; + dialog_ex_reset(app->dialog); +} diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c b/applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c new file mode 100755 index 00000000..c0b0c80a --- /dev/null +++ b/applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c @@ -0,0 +1,41 @@ +#include "../bt_settings_app.h" +#include "furi_hal_bt.h" + +void bt_settings_app_scene_forget_dev_success_popup_callback(void* context) { + BtSettingsApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, BtSettingsCustomEventExitView); +} + +void bt_settings_scene_forget_dev_success_on_enter(void* context) { + BtSettingsApp* app = context; + Popup* popup = app->popup; + + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Done", 14, 15, AlignLeft, AlignTop); + popup_set_timeout(popup, 1500); + popup_set_context(popup, app); + popup_set_callback(popup, bt_settings_app_scene_forget_dev_success_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(app->view_dispatcher, BtSettingsAppViewPopup); +} + +bool bt_settings_scene_forget_dev_success_on_event(void* context, SceneManagerEvent event) { + BtSettingsApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == BtSettingsCustomEventExitView) { + if(scene_manager_has_previous_scene(app->scene_manager, BtSettingsAppSceneStart)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, BtSettingsAppSceneStart); + } + } + } + + return consumed; +} + +void bt_settings_scene_forget_dev_success_on_exit(void* context) { + BtSettingsApp* app = context; + popup_reset(app->popup); +} diff --git a/applications/bt/bt_settings_app/scenes/bt_settings_scene_start.c b/applications/bt/bt_settings_app/scenes/bt_settings_scene_start.c index 0c809965..9dd0b1e7 100755 --- a/applications/bt/bt_settings_app/scenes/bt_settings_scene_start.c +++ b/applications/bt/bt_settings_app/scenes/bt_settings_scene_start.c @@ -7,9 +7,14 @@ enum BtSetting { BtSettingNum, }; +enum BtSettingIndex { + BtSettingIndexSwitchBt, + BtSettingIndexForgetDev, +}; + const char* const bt_settings_text[BtSettingNum] = { - "Off", - "On", + "OFF", + "ON", }; static void bt_settings_scene_start_var_list_change_callback(VariableItem* item) { @@ -20,6 +25,15 @@ static void bt_settings_scene_start_var_list_change_callback(VariableItem* item) view_dispatcher_send_custom_event(app->view_dispatcher, index); } +static void bt_settings_scene_start_var_list_enter_callback(void* context, uint32_t index) { + furi_assert(context); + BtSettingsApp* app = context; + if(index == BtSettingIndexForgetDev) { + view_dispatcher_send_custom_event( + app->view_dispatcher, BtSettingsCustomEventForgetDevices); + } +} + void bt_settings_scene_start_on_enter(void* context) { BtSettingsApp* app = context; VariableItemList* var_item_list = app->var_item_list; @@ -40,6 +54,9 @@ void bt_settings_scene_start_on_enter(void* context) { variable_item_set_current_value_index(item, BtSettingOff); variable_item_set_current_value_text(item, bt_settings_text[BtSettingOff]); } + variable_item_list_add(var_item_list, "Forget all paired devices", 1, NULL, NULL); + variable_item_list_set_enter_callback( + var_item_list, bt_settings_scene_start_var_list_enter_callback, app); } else { item = variable_item_list_add(var_item_list, "Bluetooth", 1, NULL, NULL); variable_item_set_current_value_text(item, "Broken"); @@ -56,16 +73,20 @@ bool bt_settings_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.event == BtSettingOn) { furi_hal_bt_start_advertising(); app->settings.enabled = true; + consumed = true; } else if(event.event == BtSettingOff) { app->settings.enabled = false; furi_hal_bt_stop_advertising(); + consumed = true; + } else if(event.event == BtSettingsCustomEventForgetDevices) { + scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneForgetDevConfirm); + consumed = true; } - consumed = true; } return consumed; } void bt_settings_scene_start_on_exit(void* context) { BtSettingsApp* app = context; - variable_item_list_clean(app->var_item_list); + variable_item_list_reset(app->var_item_list); } diff --git a/applications/debug_tools/usb_mouse.c b/applications/debug_tools/usb_mouse.c index edbd1e4a..9321b806 100644 --- a/applications/debug_tools/usb_mouse.c +++ b/applications/debug_tools/usb_mouse.c @@ -41,7 +41,7 @@ int32_t usb_mouse_app(void* p) { furi_check(event_queue); ViewPort* view_port = view_port_alloc(); - UsbInterface* usb_mode_prev = furi_hal_usb_get_config(); + FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); furi_hal_usb_set_config(&usb_hid); view_port_draw_callback_set(view_port, usb_mouse_render_callback, NULL); diff --git a/applications/debug_tools/usb_test.c b/applications/debug_tools/usb_test.c index 4f390d6a..ff32198a 100644 --- a/applications/debug_tools/usb_test.c +++ b/applications/debug_tools/usb_test.c @@ -15,6 +15,7 @@ typedef struct { typedef enum { UsbTestSubmenuIndexEnable, UsbTestSubmenuIndexDisable, + UsbTestSubmenuIndexRestart, UsbTestSubmenuIndexVcpSingle, UsbTestSubmenuIndexVcpDual, UsbTestSubmenuIndexHid, @@ -28,6 +29,8 @@ void usb_test_submenu_callback(void* context, uint32_t index) { furi_hal_usb_enable(); } else if(index == UsbTestSubmenuIndexDisable) { furi_hal_usb_disable(); + } else if(index == UsbTestSubmenuIndexRestart) { + furi_hal_usb_reinit(); } else if(index == UsbTestSubmenuIndexVcpSingle) { furi_hal_usb_set_config(&usb_cdc_single); } else if(index == UsbTestSubmenuIndexVcpDual) { @@ -60,6 +63,8 @@ UsbTestApp* usb_test_app_alloc() { app->submenu, "Enable", UsbTestSubmenuIndexEnable, usb_test_submenu_callback, app); submenu_add_item( app->submenu, "Disable", UsbTestSubmenuIndexDisable, usb_test_submenu_callback, app); + submenu_add_item( + app->submenu, "Restart", UsbTestSubmenuIndexRestart, usb_test_submenu_callback, app); submenu_add_item( app->submenu, "Single VCP", UsbTestSubmenuIndexVcpSingle, usb_test_submenu_callback, app); submenu_add_item( diff --git a/applications/desktop/animations/animation_manager.c b/applications/desktop/animations/animation_manager.c index c123dcaa..e9d97b04 100644 --- a/applications/desktop/animations/animation_manager.c +++ b/applications/desktop/animations/animation_manager.c @@ -1,23 +1,30 @@ -#include "animation_manager.h" -#include "furi_hal_delay.h" -#include "portmacro.h" -#include "views/bubble_animation_view.h" -#include "animation_storage.h" - -#include -#include -#include -#include -#include -#include -#include +#include #include +#include +#include +#include +#include +#include #include -#include -#include +#include + +#include "views/bubble_animation_view.h" +#include "views/one_shot_animation_view.h" +#include "animation_storage.h" +#include "animation_manager.h" #define TAG "AnimationManager" +#define HARDCODED_ANIMATION_NAME "L1_Tv_128x47" +#define NO_SD_ANIMATION_NAME "L1_NoSd_128x49" +#define BAD_BATTERY_ANIMATION_NAME "L1_BadBattery_128x47" + +#define NO_DB_ANIMATION_NAME "L0_NoDb_128x51" +#define BAD_SD_ANIMATION_NAME "L0_SdBad_128x51" +#define SD_OK_ANIMATION_NAME "L0_SdOk_128x51" +#define URL_ANIMATION_NAME "L0_Url_128x51" +#define NEW_MAIL_ANIMATION_NAME "L0_NewMail_128x51" + typedef enum { AnimationManagerStateIdle, AnimationManagerStateBlocked, @@ -29,10 +36,13 @@ struct AnimationManager { bool sd_show_url; bool sd_shown_no_db; bool sd_shown_sd_ok; + bool levelup_pending; + bool levelup_active; AnimationManagerState state; FuriPubSubSubscription* pubsub_subscription_storage; FuriPubSubSubscription* pubsub_subscription_dolphin; BubbleAnimationView* animation_view; + OneShotView* one_shot_view; osTimerId_t idle_animation_timer; StorageAnimation* current_animation; AnimationManagerInteractCallback interact_callback; @@ -41,6 +51,7 @@ struct AnimationManager { void* context; string_t freezed_animation_name; int32_t freezed_animation_time_left; + ViewStack* view_stack; }; static StorageAnimation* @@ -50,6 +61,11 @@ static void animation_manager_replace_current_animation( StorageAnimation* storage_animation); static void animation_manager_start_new_idle(AnimationManager* animation_manager); static bool animation_manager_check_blocking(AnimationManager* animation_manager); +static bool animation_manager_is_valid_idle_animation( + const StorageAnimationManifestInfo* info, + const DolphinStats* stats); +static void animation_manager_switch_to_one_shot_view(AnimationManager* animation_manager); +static void animation_manager_switch_to_animation_view(AnimationManager* animation_manager); void animation_manager_set_context(AnimationManager* animation_manager, void* context) { furi_assert(animation_manager); @@ -101,12 +117,26 @@ static void animation_manager_interact_callback(void* context) { } } -/* reaction to animation_manager->interact_callback() */ +/* reaction to animation_manager->check_blocking_callback() */ void animation_manager_check_blocking_process(AnimationManager* animation_manager) { furi_assert(animation_manager); if(animation_manager->state == AnimationManagerStateIdle) { - animation_manager_check_blocking(animation_manager); + bool blocked = animation_manager_check_blocking(animation_manager); + + if(!blocked) { + Dolphin* dolphin = furi_record_open("dolphin"); + DolphinStats stats = dolphin_stats(dolphin); + furi_record_close("dolphin"); + + const StorageAnimationManifestInfo* manifest_info = + animation_storage_get_meta(animation_manager->current_animation); + bool valid = animation_manager_is_valid_idle_animation(manifest_info, &stats); + + if(!valid) { + animation_manager_start_new_idle(animation_manager); + } + } } } @@ -119,13 +149,24 @@ void animation_manager_new_idle_process(AnimationManager* animation_manager) { } } -/* reaction to animation_manager->check_blocking_callback() */ +/* reaction to animation_manager->interact_callback() */ void animation_manager_interact_process(AnimationManager* animation_manager) { furi_assert(animation_manager); - if(animation_manager->state == AnimationManagerStateBlocked) { - /* check if new blocking animation has to be displayed */ + if(animation_manager->levelup_pending) { + animation_manager->levelup_pending = false; + animation_manager->levelup_active = true; + animation_manager_switch_to_one_shot_view(animation_manager); + Dolphin* dolphin = furi_record_open("dolphin"); + dolphin_upgrade_level(dolphin); + furi_record_close("dolphin"); + } else if(animation_manager->levelup_active) { + animation_manager->levelup_active = false; + animation_manager_start_new_idle(animation_manager); + animation_manager_switch_to_animation_view(animation_manager); + } else if(animation_manager->state == AnimationManagerStateBlocked) { bool blocked = animation_manager_check_blocking(animation_manager); + if(!blocked) { animation_manager_start_new_idle(animation_manager); } @@ -152,22 +193,26 @@ static bool animation_manager_check_blocking(AnimationManager* animation_manager if(sd_status == FSE_INTERNAL) { blocking_animation = animation_storage_find_animation(BAD_SD_ANIMATION_NAME); + furi_assert(blocking_animation); } else if(sd_status == FSE_NOT_READY) { animation_manager->sd_shown_sd_ok = false; animation_manager->sd_shown_no_db = false; } else if(sd_status == FSE_OK) { if(!animation_manager->sd_shown_sd_ok) { blocking_animation = animation_storage_find_animation(SD_OK_ANIMATION_NAME); + furi_assert(blocking_animation); animation_manager->sd_shown_sd_ok = true; } else if(!animation_manager->sd_shown_no_db) { bool db_exists = storage_common_stat(storage, "/ext/Manifest", NULL) == FSE_OK; if(!db_exists) { blocking_animation = animation_storage_find_animation(NO_DB_ANIMATION_NAME); + furi_assert(blocking_animation); animation_manager->sd_shown_no_db = true; animation_manager->sd_show_url = true; } } else if(animation_manager->sd_show_url) { blocking_animation = animation_storage_find_animation(URL_ANIMATION_NAME); + furi_assert(blocking_animation); animation_manager->sd_show_url = false; } } @@ -176,13 +221,17 @@ static bool animation_manager_check_blocking(AnimationManager* animation_manager DolphinStats stats = dolphin_stats(dolphin); furi_record_close("dolphin"); if(!blocking_animation && stats.level_up_is_pending) { - blocking_animation = animation_storage_find_animation(LEVELUP_ANIMATION_NAME); + blocking_animation = animation_storage_find_animation(NEW_MAIL_ANIMATION_NAME); + furi_assert(blocking_animation); + if(blocking_animation) { + animation_manager->levelup_pending = true; + } } if(blocking_animation) { osTimerStop(animation_manager->idle_animation_timer); animation_manager_replace_current_animation(animation_manager, blocking_animation); - /* no starting timer because its blocking animation */ + /* no timer starting because this is blocking animation */ animation_manager->state = AnimationManagerStateBlocked; } @@ -199,7 +248,7 @@ static void animation_manager_replace_current_animation( const BubbleAnimation* animation = animation_storage_get_bubble_animation(storage_animation); bubble_animation_view_set_animation(animation_manager->animation_view, animation); - const char* new_name = string_get_cstr(animation_storage_get_meta(storage_animation)->name); + const char* new_name = animation_storage_get_meta(storage_animation)->name; FURI_LOG_I(TAG, "Select \'%s\' animation", new_name); animation_manager->current_animation = storage_animation; @@ -209,9 +258,11 @@ static void animation_manager_replace_current_animation( } AnimationManager* animation_manager_alloc(void) { - animation_storage_initialize_internal_animations(); AnimationManager* animation_manager = furi_alloc(sizeof(AnimationManager)); animation_manager->animation_view = bubble_animation_view_alloc(); + animation_manager->view_stack = view_stack_alloc(); + View* animation_view = bubble_animation_get_view(animation_manager->animation_view); + view_stack_add_view(animation_manager->view_stack, animation_view); string_init(animation_manager->freezed_animation_name); animation_manager->idle_animation_timer = @@ -251,6 +302,8 @@ void animation_manager_free(AnimationManager* animation_manager) { furi_record_close("storage"); string_clear(animation_manager->freezed_animation_name); + View* animation_view = bubble_animation_get_view(animation_manager->animation_view); + view_stack_remove_view(animation_manager->view_stack, animation_view); bubble_animation_view_free(animation_manager->animation_view); osTimerDelete(animation_manager->idle_animation_timer); } @@ -258,7 +311,39 @@ void animation_manager_free(AnimationManager* animation_manager) { View* animation_manager_get_animation_view(AnimationManager* animation_manager) { furi_assert(animation_manager); - return bubble_animation_get_view(animation_manager->animation_view); + return view_stack_get_view(animation_manager->view_stack); +} + +static bool animation_manager_is_valid_idle_animation( + const StorageAnimationManifestInfo* info, + const DolphinStats* stats) { + furi_assert(info); + furi_assert(info->name); + + bool result = true; + + if(!strcmp(info->name, BAD_BATTERY_ANIMATION_NAME)) { + Power* power = furi_record_open("power"); + bool battery_is_well = power_is_battery_healthy(power); + furi_record_close("power"); + + result = !battery_is_well; + } + if(!strcmp(info->name, NO_SD_ANIMATION_NAME)) { + Storage* storage = furi_record_open("storage"); + FS_Error sd_status = storage_sd_status(storage); + furi_record_close("storage"); + + result = (sd_status == FSE_NOT_READY); + } + if((stats->butthurt < info->min_butthurt) || (stats->butthurt > info->max_butthurt)) { + result = false; + } + if((stats->level < info->min_level) || (stats->level > info->max_level)) { + result = false; + } + + return result; } static StorageAnimation* @@ -267,40 +352,25 @@ static StorageAnimation* StorageAnimationList_init(animation_list); animation_storage_fill_animation_list(&animation_list); - Power* power = furi_record_open("power"); - bool battery_is_well = power_is_battery_healthy(power); - furi_record_close("power"); - - Storage* storage = furi_record_open("storage"); - FS_Error sd_status = storage_sd_status(storage); - furi_record_close("storage"); - Dolphin* dolphin = furi_record_open("dolphin"); DolphinStats stats = dolphin_stats(dolphin); + furi_record_close("dolphin"); uint32_t whole_weight = 0; StorageAnimationList_it_t it; for(StorageAnimationList_it(it, animation_list); !StorageAnimationList_end_p(it);) { StorageAnimation* storage_animation = *StorageAnimationList_ref(it); - const StorageAnimationMeta* meta = animation_storage_get_meta(storage_animation); - bool skip_animation = false; - if(battery_is_well && !string_cmp_str(meta->name, BAD_BATTERY_ANIMATION_NAME)) { - skip_animation = true; - } else if((sd_status != FSE_NOT_READY) && !string_cmp_str(meta->name, NO_SD_ANIMATION_NAME)) { - skip_animation = true; - } else if((stats.butthurt < meta->min_butthurt) || (stats.butthurt > meta->max_butthurt)) { - skip_animation = true; - } else if((stats.level < meta->min_level) || (stats.level > meta->max_level)) { - skip_animation = true; - } + const StorageAnimationManifestInfo* manifest_info = + animation_storage_get_meta(storage_animation); + bool valid = animation_manager_is_valid_idle_animation(manifest_info, &stats); - if(skip_animation) { + if(valid) { + whole_weight += manifest_info->weight; + StorageAnimationList_next(it); + } else { animation_storage_free_storage_animation(&storage_animation); /* remove and increase iterator */ StorageAnimationList_remove(animation_list, it); - } else { - whole_weight += meta->weight; - StorageAnimationList_next(it); } } @@ -325,11 +395,10 @@ static StorageAnimation* } StorageAnimationList_clear(animation_list); - furi_record_close("dolphin"); /* cache animation, if failed - choose reliable animation */ if(!animation_storage_get_bubble_animation(selected)) { - const char* name = string_get_cstr(animation_storage_get_meta(selected)->name); + const char* name = animation_storage_get_meta(selected)->name; FURI_LOG_E(TAG, "Can't upload animation described in manifest: \'%s\'", name); animation_storage_free_storage_animation(&selected); selected = animation_storage_find_animation(HARDCODED_ANIMATION_NAME); @@ -362,9 +431,15 @@ void animation_manager_unload_and_stall_animation(AnimationManager* animation_ma furi_assert(0); } - StorageAnimationMeta* meta = animation_storage_get_meta(animation_manager->current_animation); + FURI_LOG_I( + TAG, + "Unload animation \'%s\'", + animation_storage_get_meta(animation_manager->current_animation)->name); + + StorageAnimationManifestInfo* meta = + animation_storage_get_meta(animation_manager->current_animation); /* copy str, not move, because it can be internal animation */ - string_set(animation_manager->freezed_animation_name, meta->name); + string_set_str(animation_manager->freezed_animation_name, meta->name); bubble_animation_freeze(animation_manager->animation_view); animation_storage_free_storage_animation(&animation_manager->current_animation); @@ -394,18 +469,27 @@ void animation_manager_load_and_continue_animation(AnimationManager* animation_m StorageAnimation* restore_animation = animation_storage_find_animation( string_get_cstr(animation_manager->freezed_animation_name)); if(restore_animation) { - animation_manager_replace_current_animation(animation_manager, restore_animation); - animation_manager->state = AnimationManagerStateIdle; + Dolphin* dolphin = furi_record_open("dolphin"); + DolphinStats stats = dolphin_stats(dolphin); + furi_record_close("dolphin"); + const StorageAnimationManifestInfo* manifest_info = + animation_storage_get_meta(restore_animation); + bool valid = animation_manager_is_valid_idle_animation(manifest_info, &stats); + if(valid) { + animation_manager_replace_current_animation( + animation_manager, restore_animation); + animation_manager->state = AnimationManagerStateIdle; - if(animation_manager->freezed_animation_time_left) { - osTimerStart( - animation_manager->idle_animation_timer, - animation_manager->freezed_animation_time_left); - } else { - const BubbleAnimation* animation = animation_storage_get_bubble_animation( - animation_manager->current_animation); - osTimerStart( - animation_manager->idle_animation_timer, animation->duration * 1000); + if(animation_manager->freezed_animation_time_left) { + osTimerStart( + animation_manager->idle_animation_timer, + animation_manager->freezed_animation_time_left); + } else { + const BubbleAnimation* animation = animation_storage_get_bubble_animation( + animation_manager->current_animation); + osTimerStart( + animation_manager->idle_animation_timer, animation->duration * 1000); + } } } else { FURI_LOG_E( @@ -423,12 +507,47 @@ void animation_manager_load_and_continue_animation(AnimationManager* animation_m if(!animation_manager->current_animation) { animation_manager_start_new_idle(animation_manager); } - FURI_LOG_D( + FURI_LOG_I( TAG, - "Load & Continue with \'%s\'", - string_get_cstr(animation_storage_get_meta(animation_manager->current_animation)->name)); + "Load animation \'%s\'", + animation_storage_get_meta(animation_manager->current_animation)->name); bubble_animation_unfreeze(animation_manager->animation_view); string_reset(animation_manager->freezed_animation_name); furi_assert(animation_manager->current_animation); } + +static void animation_manager_switch_to_one_shot_view(AnimationManager* animation_manager) { + furi_assert(animation_manager); + furi_assert(!animation_manager->one_shot_view); + Dolphin* dolphin = furi_record_open("dolphin"); + DolphinStats stats = dolphin_stats(dolphin); + furi_record_close("dolphin"); + + animation_manager->one_shot_view = one_shot_view_alloc(); + one_shot_view_set_interact_callback( + animation_manager->one_shot_view, animation_manager_interact_callback, animation_manager); + View* prev_view = bubble_animation_get_view(animation_manager->animation_view); + View* next_view = one_shot_view_get_view(animation_manager->one_shot_view); + view_stack_remove_view(animation_manager->view_stack, prev_view); + view_stack_add_view(animation_manager->view_stack, next_view); + if(stats.level == 1) { + one_shot_view_start_animation(animation_manager->one_shot_view, &A_Levelup1_128x64); + } else if(stats.level == 2) { + one_shot_view_start_animation(animation_manager->one_shot_view, &A_Levelup2_128x64); + } else { + furi_assert(0); + } +} + +static void animation_manager_switch_to_animation_view(AnimationManager* animation_manager) { + furi_assert(animation_manager); + furi_assert(animation_manager->one_shot_view); + + View* prev_view = one_shot_view_get_view(animation_manager->one_shot_view); + View* next_view = bubble_animation_get_view(animation_manager->animation_view); + view_stack_remove_view(animation_manager->view_stack, prev_view); + view_stack_add_view(animation_manager->view_stack, next_view); + one_shot_view_free(animation_manager->one_shot_view); + animation_manager->one_shot_view = NULL; +} diff --git a/applications/desktop/animations/animation_manager.h b/applications/desktop/animations/animation_manager.h index 1ffaee3a..74f31b8a 100644 --- a/applications/desktop/animations/animation_manager.h +++ b/applications/desktop/animations/animation_manager.h @@ -1,34 +1,35 @@ #pragma once -#include "dolphin/dolphin.h" #include +#include #include +#include typedef struct AnimationManager AnimationManager; typedef struct { uint8_t x; uint8_t y; - const char* str; - Align horizontal; - Align vertical; + const char* text; + Align align_h; + Align align_v; } Bubble; typedef struct FrameBubble { Bubble bubble; - uint8_t starts_at_frame; - uint8_t ends_at_frame; - struct FrameBubble* next_bubble; + uint8_t start_frame; + uint8_t end_frame; + const struct FrameBubble* next_bubble; } FrameBubble; typedef struct { - FrameBubble** frame_bubbles; - uint8_t frame_bubbles_count; - const Icon** icons; + const FrameBubble* const* frame_bubble_sequences; + uint8_t frame_bubble_sequences_count; + const Icon icon_animation; + const uint8_t* frame_order; uint8_t passive_frames; uint8_t active_frames; uint8_t active_cycles; - uint8_t frame_rate; uint16_t duration; uint16_t active_cooldown; } BubbleAnimation; diff --git a/applications/desktop/animations/animation_storage.c b/applications/desktop/animations/animation_storage.c index 04ea4249..f9a76959 100644 --- a/applications/desktop/animations/animation_storage.c +++ b/applications/desktop/animations/animation_storage.c @@ -1,34 +1,86 @@ -#include "animation_manager.h" -#include "file_worker.h" -#include "flipper_file.h" -#include "furi/common_defines.h" -#include "furi/memmgr.h" -#include "furi/record.h" -#include "animation_storage.h" -#include "gui/canvas.h" -#include "m-string.h" -#include "pb.h" -#include "pb_decode.h" -#include "storage/filesystem_api_defines.h" -#include "storage/storage.h" -#include "animation_storage_i.h" -#include -#include -// Read documentation before using it +#include +#include +#include #include +#include +#include +#include + +#include "animation_manager.h" +#include "animation_storage.h" +#include "animation_storage_i.h" +#include +#include #define ANIMATION_META_FILE "meta.txt" -#define ANIMATION_DIR "/ext/dolphin/animations" +#define ANIMATION_DIR "/ext/dolphin" #define ANIMATION_MANIFEST_FILE ANIMATION_DIR "/manifest.txt" #define TAG "AnimationStorage" -#define DEBUG_PB 0 static void animation_storage_free_bubbles(BubbleAnimation* animation); static void animation_storage_free_frames(BubbleAnimation* animation); static void animation_storage_free_animation(BubbleAnimation** storage_animation); static BubbleAnimation* animation_storage_load_animation(const char* name); +static bool animation_storage_load_single_manifest_info( + StorageAnimationManifestInfo* manifest_info, + const char* name) { + furi_assert(manifest_info); + + bool result = false; + Storage* storage = furi_record_open("storage"); + FlipperFile* file = flipper_file_alloc(storage); + flipper_file_set_strict_mode(file, true); + string_t read_string; + string_init(read_string); + + do { + uint32_t u32value; + if(FSE_OK != storage_sd_status(storage)) break; + if(!flipper_file_open_existing(file, ANIMATION_MANIFEST_FILE)) break; + + if(!flipper_file_read_header(file, read_string, &u32value)) break; + if(string_cmp_str(read_string, "Flipper Animation Manifest")) break; + + manifest_info->name = NULL; + + /* skip other animation names */ + flipper_file_set_strict_mode(file, false); + while(flipper_file_read_string(file, "Name", read_string) && + string_cmp_str(read_string, name)) + ; + if(string_cmp_str(read_string, name)) break; + flipper_file_set_strict_mode(file, true); + + manifest_info->name = furi_alloc(string_size(read_string) + 1); + strcpy((char*)manifest_info->name, string_get_cstr(read_string)); + + if(!flipper_file_read_uint32(file, "Min butthurt", &u32value, 1)) break; + manifest_info->min_butthurt = u32value; + if(!flipper_file_read_uint32(file, "Max butthurt", &u32value, 1)) break; + manifest_info->max_butthurt = u32value; + if(!flipper_file_read_uint32(file, "Min level", &u32value, 1)) break; + manifest_info->min_level = u32value; + if(!flipper_file_read_uint32(file, "Max level", &u32value, 1)) break; + manifest_info->max_level = u32value; + if(!flipper_file_read_uint32(file, "Weight", &u32value, 1)) break; + manifest_info->weight = u32value; + result = true; + } while(0); + + if(!result && manifest_info->name) { + free((void*)manifest_info->name); + } + string_clear(read_string); + flipper_file_close(file); + flipper_file_free(file); + + furi_record_close("storage"); + + return result; +} + void animation_storage_fill_animation_list(StorageAnimationList_t* animation_list) { furi_assert(sizeof(StorageAnimationList_t) == sizeof(void*)); furi_assert(!StorageAnimationList_size(*animation_list)); @@ -37,8 +89,8 @@ void animation_storage_fill_animation_list(StorageAnimationList_t* animation_lis FlipperFile* file = flipper_file_alloc(storage); /* Forbid skipping fields */ flipper_file_set_strict_mode(file, true); - string_t header; - string_init(header); + string_t read_string; + string_init(read_string); do { uint32_t u32value; @@ -46,24 +98,28 @@ void animation_storage_fill_animation_list(StorageAnimationList_t* animation_lis if(FSE_OK != storage_sd_status(storage)) break; if(!flipper_file_open_existing(file, ANIMATION_MANIFEST_FILE)) break; - if(!flipper_file_read_header(file, header, &u32value)) break; - if(string_cmp_str(header, "Flipper Animation Manifest")) break; + if(!flipper_file_read_header(file, read_string, &u32value)) break; + if(string_cmp_str(read_string, "Flipper Animation Manifest")) break; do { storage_animation = furi_alloc(sizeof(StorageAnimation)); storage_animation->external = true; storage_animation->animation = NULL; + storage_animation->manifest_info.name = NULL; + + if(!flipper_file_read_string(file, "Name", read_string)) break; + storage_animation->manifest_info.name = furi_alloc(string_size(read_string) + 1); + strcpy((char*)storage_animation->manifest_info.name, string_get_cstr(read_string)); - if(!flipper_file_read_string(file, "Name", storage_animation->meta.name)) break; if(!flipper_file_read_uint32(file, "Min butthurt", &u32value, 1)) break; - storage_animation->meta.min_butthurt = u32value; + storage_animation->manifest_info.min_butthurt = u32value; if(!flipper_file_read_uint32(file, "Max butthurt", &u32value, 1)) break; - storage_animation->meta.max_butthurt = u32value; + storage_animation->manifest_info.max_butthurt = u32value; if(!flipper_file_read_uint32(file, "Min level", &u32value, 1)) break; - storage_animation->meta.min_level = u32value; + storage_animation->manifest_info.min_level = u32value; if(!flipper_file_read_uint32(file, "Max level", &u32value, 1)) break; - storage_animation->meta.max_level = u32value; + storage_animation->manifest_info.max_level = u32value; if(!flipper_file_read_uint32(file, "Weight", &u32value, 1)) break; - storage_animation->meta.weight = u32value; + storage_animation->manifest_info.weight = u32value; StorageAnimationList_push_back(*animation_list, storage_animation); } while(1); @@ -71,13 +127,13 @@ void animation_storage_fill_animation_list(StorageAnimationList_t* animation_lis animation_storage_free_storage_animation(&storage_animation); } while(0); - string_clear(header); + string_clear(read_string); flipper_file_close(file); flipper_file_free(file); // add hard-coded animations - for(int i = 0; i < COUNT_OF(StorageAnimationInternal); ++i) { - StorageAnimationList_push_back(*animation_list, &StorageAnimationInternal[i]); + for(int i = 0; i < dolphin_internal_size; ++i) { + StorageAnimationList_push_back(*animation_list, (StorageAnimation*)&dolphin_internal[i]); } furi_record_close("storage"); @@ -88,41 +144,45 @@ StorageAnimation* animation_storage_find_animation(const char* name) { furi_assert(strlen(name)); StorageAnimation* storage_animation = NULL; - /* look through internal animations */ - for(int i = 0; i < COUNT_OF(StorageAnimationInternal); ++i) { - if(!string_cmp_str(StorageAnimationInternal[i].meta.name, name)) { - storage_animation = &StorageAnimationInternal[i]; + for(int i = 0; i < dolphin_blocking_size; ++i) { + if(!strcmp(dolphin_blocking[i].manifest_info.name, name)) { + storage_animation = (StorageAnimation*)&dolphin_blocking[i]; break; } } + if(!storage_animation) { + for(int i = 0; i < dolphin_internal_size; ++i) { + if(!strcmp(dolphin_internal[i].manifest_info.name, name)) { + storage_animation = (StorageAnimation*)&dolphin_internal[i]; + break; + } + } + } + /* look through external animations */ if(!storage_animation) { - BubbleAnimation* animation = animation_storage_load_animation(name); + storage_animation = furi_alloc(sizeof(StorageAnimation)); + storage_animation->external = true; - if(animation != NULL) { - storage_animation = furi_alloc(sizeof(StorageAnimation)); - storage_animation->animation = animation; - storage_animation->external = true; - /* meta data takes part in random animation selection, so it - * doesn't need here as we exactly know which animation we need, - * that's why we can ignore reading manifest.txt file - * filling meta data by zeroes */ - storage_animation->meta.min_butthurt = 0; - storage_animation->meta.max_butthurt = 0; - storage_animation->meta.min_level = 0; - storage_animation->meta.max_level = 0; - storage_animation->meta.weight = 0; - string_init_set_str(storage_animation->meta.name, name); + bool result = false; + result = + animation_storage_load_single_manifest_info(&storage_animation->manifest_info, name); + if(result) { + storage_animation->animation = animation_storage_load_animation(name); + result = !!storage_animation->animation; + } + if(!result) { + animation_storage_free_storage_animation(&storage_animation); } } return storage_animation; } -StorageAnimationMeta* animation_storage_get_meta(StorageAnimation* storage_animation) { +StorageAnimationManifestInfo* animation_storage_get_meta(StorageAnimation* storage_animation) { furi_assert(storage_animation); - return &storage_animation->meta; + return &storage_animation->manifest_info; } const BubbleAnimation* @@ -138,7 +198,7 @@ void animation_storage_cache_animation(StorageAnimation* storage_animation) { if(storage_animation->external) { if(!storage_animation->animation) { storage_animation->animation = - animation_storage_load_animation(string_get_cstr(storage_animation->meta.name)); + animation_storage_load_animation(storage_animation->manifest_info.name); } } } @@ -149,6 +209,9 @@ static void animation_storage_free_animation(BubbleAnimation** animation) { if(*animation) { animation_storage_free_bubbles(*animation); animation_storage_free_frames(*animation); + if((*animation)->frame_order) { + free((void*)(*animation)->frame_order); + } free(*animation); *animation = NULL; } @@ -161,7 +224,9 @@ void animation_storage_free_storage_animation(StorageAnimation** storage_animati if((*storage_animation)->external) { animation_storage_free_animation((BubbleAnimation**)&(*storage_animation)->animation); - string_clear((*storage_animation)->meta.name); + if((*storage_animation)->manifest_info.name) { + free((void*)(*storage_animation)->manifest_info.name); + } free(*storage_animation); } @@ -188,41 +253,15 @@ static bool animation_storage_cast_align(string_t align_str, Align* align) { static void animation_storage_free_frames(BubbleAnimation* animation) { furi_assert(animation); - furi_assert(animation->icons); - const Icon** icons = animation->icons; - uint16_t frames = animation->active_frames + animation->passive_frames; - furi_assert(frames > 0); - - for(int i = 0; i < frames; ++i) { - if(!icons[i]) continue; - - const Icon* icon = icons[i]; - free((void*)icon->frames[0]); - free(icon->frames); - free((void*)icon); - for(int j = i; j < frames; ++j) { - if(icons[j] == icon) { - icons[j] = NULL; - } + const Icon* icon = &animation->icon_animation; + for(int i = 0; i < icon->frame_count; ++i) { + if(icon->frames[i]) { + free((void*)icon->frames[i]); } } - free(animation->icons); - animation->icons = NULL; -} - -static Icon* animation_storage_alloc_icon(size_t frame_size) { - Icon* icon = furi_alloc(sizeof(Icon)); - icon->frames = furi_alloc(sizeof(const uint8_t*)); - icon->frames[0] = furi_alloc(frame_size); - return icon; -} - -static void animation_storage_free_icon(Icon* icon) { - free((void*)icon->frames[0]); free(icon->frames); - free(icon); } static bool animation_storage_load_frames( @@ -230,24 +269,37 @@ static bool animation_storage_load_frames( const char* name, BubbleAnimation* animation, uint32_t* frame_order, - uint32_t width, - uint32_t height) { - furi_assert(!animation->icons); - uint16_t frame_order_size = animation->passive_frames + animation->active_frames; + uint8_t width, + uint8_t height) { + uint16_t frame_order_count = animation->passive_frames + animation->active_frames; + + /* The frames should go in order (0...N), without omissions */ + size_t max_frame_count = 0; + for(int i = 0; i < frame_order_count; ++i) { + max_frame_count = MAX(max_frame_count, frame_order[i]); + } + + if((max_frame_count >= frame_order_count) || (max_frame_count >= 256 /* max uint8_t */)) { + return false; + } + + Icon* icon = (Icon*)&animation->icon_animation; + FURI_CONST_ASSIGN(icon->frame_count, max_frame_count + 1); + FURI_CONST_ASSIGN(icon->frame_rate, 0); + FURI_CONST_ASSIGN(icon->height, height); + FURI_CONST_ASSIGN(icon->width, width); + icon->frames = furi_alloc(sizeof(const uint8_t*) * icon->frame_count); bool frames_ok = false; - animation->icons = furi_alloc(sizeof(const Icon*) * frame_order_size); File* file = storage_file_alloc(storage); FileInfo file_info; string_t filename; string_init(filename); size_t max_filesize = ROUND_UP_TO(width, 8) * height + 1; - for(int i = 0; i < frame_order_size; ++i) { - if(animation->icons[i]) continue; - + for(int i = 0; i < icon->frame_count; ++i) { frames_ok = false; - string_printf(filename, ANIMATION_DIR "/%s/frame_%d.bm", name, frame_order[i]); + string_printf(filename, ANIMATION_DIR "/%s/frame_%d.bm", name, i); if(storage_common_stat(storage, string_get_cstr(filename), &file_info) != FSE_OK) break; if(file_info.size > max_filesize) { @@ -265,24 +317,12 @@ static bool animation_storage_load_frames( break; } - Icon* icon = animation_storage_alloc_icon(file_info.size); - if(storage_file_read(file, (void*)icon->frames[0], file_info.size) != file_info.size) { + icon->frames[i] = furi_alloc(file_info.size); + if(storage_file_read(file, (void*)icon->frames[i], file_info.size) != file_info.size) { FURI_LOG_E(TAG, "Read failed: \'%s\'", string_get_cstr(filename)); - animation_storage_free_icon(icon); break; } storage_file_close(file); - FURI_CONST_ASSIGN(icon->frame_count, 1); - FURI_CONST_ASSIGN(icon->frame_rate, 0); - FURI_CONST_ASSIGN(icon->height, height); - FURI_CONST_ASSIGN(icon->width, width); - - /* Claim 1 allocation for 1 files blob and several links to it */ - for(int j = i; j < frame_order_size; ++j) { - if(frame_order[i] == frame_order[j]) { - animation->icons[j] = icon; - } - } frames_ok = true; } @@ -295,11 +335,10 @@ static bool animation_storage_load_frames( height, file_info.size); animation_storage_free_frames(animation); - animation->icons = NULL; } else { - for(int i = 0; i < frame_order_size; ++i) { - furi_check(animation->icons[i]); - furi_check(animation->icons[i]->frames[0]); + furi_check(animation->icon_animation.frames); + for(int i = 0; i < animation->icon_animation.frame_count; ++i) { + furi_check(animation->icon_animation.frames[i]); } } @@ -314,72 +353,73 @@ static bool animation_storage_load_bubbles(BubbleAnimation* animation, FlipperFi string_t str; string_init(str); bool success = false; - furi_assert(!animation->frame_bubbles); + furi_assert(!animation->frame_bubble_sequences); do { if(!flipper_file_read_uint32(ff, "Bubble slots", &u32value, 1)) break; if(u32value > 20) break; - animation->frame_bubbles_count = u32value; - if(animation->frame_bubbles_count == 0) { - animation->frame_bubbles = NULL; + animation->frame_bubble_sequences_count = u32value; + if(animation->frame_bubble_sequences_count == 0) { + animation->frame_bubble_sequences = NULL; success = true; break; } - animation->frame_bubbles = - furi_alloc(sizeof(FrameBubble*) * animation->frame_bubbles_count); + animation->frame_bubble_sequences = + furi_alloc(sizeof(FrameBubble*) * animation->frame_bubble_sequences_count); uint32_t current_slot = 0; - for(int i = 0; i < animation->frame_bubbles_count; ++i) { - animation->frame_bubbles[i] = furi_alloc(sizeof(FrameBubble)); + for(int i = 0; i < animation->frame_bubble_sequences_count; ++i) { + FURI_CONST_ASSIGN_PTR( + animation->frame_bubble_sequences[i], furi_alloc(sizeof(FrameBubble))); } - FrameBubble* bubble = animation->frame_bubbles[0]; + const FrameBubble* bubble = animation->frame_bubble_sequences[0]; int8_t index = -1; for(;;) { if(!flipper_file_read_uint32(ff, "Slot", ¤t_slot, 1)) break; if((current_slot != 0) && (index == -1)) break; if(current_slot == index) { - bubble->next_bubble = furi_alloc(sizeof(FrameBubble)); + FURI_CONST_ASSIGN_PTR(bubble->next_bubble, furi_alloc(sizeof(FrameBubble))); bubble = bubble->next_bubble; } else if(current_slot == index + 1) { ++index; - bubble = animation->frame_bubbles[index]; + bubble = animation->frame_bubble_sequences[index]; } else { /* slots have to start from 0, be ascending sorted, and * have exact number of slots as specified in "Bubble slots" */ break; } - if(index >= animation->frame_bubbles_count) break; + if(index >= animation->frame_bubble_sequences_count) break; if(!flipper_file_read_uint32(ff, "X", &u32value, 1)) break; - bubble->bubble.x = u32value; + FURI_CONST_ASSIGN(bubble->bubble.x, u32value); if(!flipper_file_read_uint32(ff, "Y", &u32value, 1)) break; - bubble->bubble.y = u32value; + FURI_CONST_ASSIGN(bubble->bubble.y, u32value); if(!flipper_file_read_string(ff, "Text", str)) break; if(string_size(str) > 100) break; string_replace_all_str(str, "\\n", "\n"); - bubble->bubble.str = furi_alloc(string_size(str) + 1); - strcpy((char*)bubble->bubble.str, string_get_cstr(str)); + FURI_CONST_ASSIGN_PTR(bubble->bubble.text, furi_alloc(string_size(str) + 1)); + strcpy((char*)bubble->bubble.text, string_get_cstr(str)); if(!flipper_file_read_string(ff, "AlignH", str)) break; - if(!animation_storage_cast_align(str, &bubble->bubble.horizontal)) break; + if(!animation_storage_cast_align(str, (Align*)&bubble->bubble.align_h)) break; if(!flipper_file_read_string(ff, "AlignV", str)) break; - if(!animation_storage_cast_align(str, &bubble->bubble.vertical)) break; + if(!animation_storage_cast_align(str, (Align*)&bubble->bubble.align_v)) break; if(!flipper_file_read_uint32(ff, "StartFrame", &u32value, 1)) break; - bubble->starts_at_frame = u32value; + FURI_CONST_ASSIGN(bubble->start_frame, u32value); if(!flipper_file_read_uint32(ff, "EndFrame", &u32value, 1)) break; - bubble->ends_at_frame = u32value; + FURI_CONST_ASSIGN(bubble->end_frame, u32value); } - success = (index + 1) == animation->frame_bubbles_count; + success = (index + 1) == animation->frame_bubble_sequences_count; } while(0); if(!success) { - if(animation->frame_bubbles) { + if(animation->frame_bubble_sequences) { FURI_LOG_E(TAG, "Failed to load animation bubbles"); animation_storage_free_bubbles(animation); } @@ -402,7 +442,7 @@ static BubbleAnimation* animation_storage_load_animation(const char* name) { flipper_file_set_strict_mode(ff, true); string_t str; string_init(str); - animation->frame_bubbles = NULL; + animation->frame_bubble_sequences = NULL; bool success = false; do { @@ -424,8 +464,18 @@ static BubbleAnimation* animation_storage_load_animation(const char* name) { animation->active_frames = u32value; uint8_t frames = animation->passive_frames + animation->active_frames; + uint32_t count = 0; + if(!flipper_file_get_value_count(ff, "Frames order", &count)) break; + if(count != frames) { + FURI_LOG_E(TAG, "Error loading animation: frames order"); + break; + } u32array = furi_alloc(sizeof(uint32_t) * frames); if(!flipper_file_read_uint32(ff, "Frames order", u32array, frames)) break; + animation->frame_order = furi_alloc(sizeof(uint8_t) * frames); + for(int i = 0; i < frames; ++i) { + FURI_CONST_ASSIGN(animation->frame_order[i], u32array[i]); + } /* passive and active frames must be loaded up to this point */ if(!animation_storage_load_frames(storage, name, animation, u32array, width, height)) @@ -434,7 +484,7 @@ static BubbleAnimation* animation_storage_load_animation(const char* name) { if(!flipper_file_read_uint32(ff, "Active cycles", &u32value, 1)) break; animation->active_cycles = u32value; if(!flipper_file_read_uint32(ff, "Frame rate", &u32value, 1)) break; - animation->frame_rate = u32value; + FURI_CONST_ASSIGN(animation->icon_animation.frame_rate, u32value); if(!flipper_file_read_uint32(ff, "Duration", &u32value, 1)) break; animation->duration = u32value; if(!flipper_file_read_uint32(ff, "Active cooldown", &u32value, 1)) break; @@ -452,6 +502,9 @@ static BubbleAnimation* animation_storage_load_animation(const char* name) { } if(!success) { + if(animation->frame_order) { + free((void*)animation->frame_order); + } free(animation); animation = NULL; } @@ -460,10 +513,10 @@ static BubbleAnimation* animation_storage_load_animation(const char* name) { } static void animation_storage_free_bubbles(BubbleAnimation* animation) { - if(!animation->frame_bubbles) return; + if(!animation->frame_bubble_sequences) return; - for(int i = 0; i < animation->frame_bubbles_count;) { - FrameBubble** bubble = &animation->frame_bubbles[i]; + for(int i = 0; i < animation->frame_bubble_sequences_count;) { + const FrameBubble* const* bubble = &animation->frame_bubble_sequences[i]; if((*bubble) == NULL) break; @@ -471,15 +524,15 @@ static void animation_storage_free_bubbles(BubbleAnimation* animation) { bubble = &(*bubble)->next_bubble; } - if((*bubble)->bubble.str) { - free((void*)(*bubble)->bubble.str); + if((*bubble)->bubble.text) { + free((void*)(*bubble)->bubble.text); } - if((*bubble) == animation->frame_bubbles[i]) { + if((*bubble) == animation->frame_bubble_sequences[i]) { ++i; } - free(*bubble); - *bubble = NULL; + free((void*)*bubble); + FURI_CONST_ASSIGN_PTR(*bubble, NULL); } - free(animation->frame_bubbles); - animation->frame_bubbles = NULL; + free((void*)animation->frame_bubble_sequences); + animation->frame_bubble_sequences = NULL; } diff --git a/applications/desktop/animations/animation_storage.h b/applications/desktop/animations/animation_storage.h index f246129d..e53c1133 100644 --- a/applications/desktop/animations/animation_storage.h +++ b/applications/desktop/animations/animation_storage.h @@ -4,15 +4,6 @@ #include "views/bubble_animation_view.h" #include -#define HARDCODED_ANIMATION_NAME "tv" -#define NO_SD_ANIMATION_NAME "no_sd" -#define BAD_BATTERY_ANIMATION_NAME "bad_battery" -#define NO_DB_ANIMATION_NAME "no_db" -#define BAD_SD_ANIMATION_NAME "bad_sd" -#define SD_OK_ANIMATION_NAME "sd_ok" -#define URL_ANIMATION_NAME "url" -#define LEVELUP_ANIMATION_NAME "level" - /** Main structure to handle animation data. * Contains all, including animation playing data (BubbleAnimation), * data for random animation selection (StorageAnimationMeta) and @@ -20,13 +11,13 @@ typedef struct StorageAnimation StorageAnimation; typedef struct { - string_t name; + const char* name; uint8_t min_butthurt; uint8_t max_butthurt; uint8_t min_level; uint8_t max_level; uint8_t weight; -} StorageAnimationMeta; +} StorageAnimationManifestInfo; /** Container to return available animations list */ LIST_DEF(StorageAnimationList, StorageAnimation*, M_PTR_OPLIST) @@ -81,7 +72,7 @@ StorageAnimation* animation_storage_find_animation(const char* name); * @storage_animation item of whom we have to extract meta. * @return meta itself */ -StorageAnimationMeta* animation_storage_get_meta(StorageAnimation* storage_animation); +StorageAnimationManifestInfo* animation_storage_get_meta(StorageAnimation* storage_animation); /** * Free storage_animation, which previously acquired diff --git a/applications/desktop/animations/animation_storage_i.h b/applications/desktop/animations/animation_storage_i.h index c4f68039..cae9cad5 100644 --- a/applications/desktop/animations/animation_storage_i.h +++ b/applications/desktop/animations/animation_storage_i.h @@ -1,195 +1,9 @@ #pragma once #include "animation_storage.h" -#include "assets_icons.h" #include "animation_manager.h" -#include "gui/canvas.h" struct StorageAnimation { const BubbleAnimation* animation; bool external; - StorageAnimationMeta meta; + StorageAnimationManifestInfo manifest_info; }; - -// Hard-coded, always available idle animation -FrameBubble tv_bubble1 = { - .bubble = - {.x = 1, - .y = 23, - .str = "Take the red pill", - .horizontal = AlignRight, - .vertical = AlignBottom}, - .starts_at_frame = 7, - .ends_at_frame = 9, - .next_bubble = NULL, -}; -FrameBubble tv_bubble2 = { - .bubble = - {.x = 1, - .y = 23, - .str = "I can joke better", - .horizontal = AlignRight, - .vertical = AlignBottom}, - .starts_at_frame = 7, - .ends_at_frame = 9, - .next_bubble = NULL, -}; -FrameBubble* tv_bubbles[] = {&tv_bubble1, &tv_bubble2}; -const Icon* tv_icons[] = { - &I_tv1, - &I_tv2, - &I_tv3, - &I_tv4, - &I_tv5, - &I_tv6, - &I_tv7, - &I_tv8, -}; -const BubbleAnimation tv_bubble_animation = { - .icons = tv_icons, - .frame_bubbles = tv_bubbles, - .frame_bubbles_count = COUNT_OF(tv_bubbles), - .passive_frames = 6, - .active_frames = 2, - .active_cycles = 2, - .frame_rate = 2, - .duration = 3600, - .active_cooldown = 5, -}; - -// System animation - no SD card -const Icon* no_sd_icons[] = { - &I_no_sd1, - &I_no_sd2, - &I_no_sd1, - &I_no_sd2, - &I_no_sd1, - &I_no_sd3, - &I_no_sd4, - &I_no_sd5, - &I_no_sd4, - &I_no_sd6, -}; -FrameBubble no_sd_bubble = { - .bubble = - {.x = 40, - .y = 18, - .str = "Need an\nSD card", - .horizontal = AlignRight, - .vertical = AlignBottom}, - .starts_at_frame = 0, - .ends_at_frame = 9, - .next_bubble = NULL, -}; -FrameBubble* no_sd_bubbles[] = {&no_sd_bubble}; -const BubbleAnimation no_sd_bubble_animation = { - .icons = no_sd_icons, - .frame_bubbles = no_sd_bubbles, - .frame_bubbles_count = COUNT_OF(no_sd_bubbles), - .passive_frames = 10, - .active_frames = 0, - .frame_rate = 2, - .duration = 3600, - .active_cooldown = 0, - .active_cycles = 0, -}; - -// BLOCKING ANIMATION - no_db, bad_sd, sd_ok, url -const Icon* no_db_icons[] = { - &I_no_databases1, - &I_no_databases2, - &I_no_databases3, - &I_no_databases4, -}; -const BubbleAnimation no_db_bubble_animation = { - .icons = no_db_icons, - .passive_frames = COUNT_OF(no_db_icons), - .frame_rate = 2, -}; - -const Icon* bad_sd_icons[] = { - &I_card_bad1, - &I_card_bad2, -}; -const BubbleAnimation bad_sd_bubble_animation = { - .icons = bad_sd_icons, - .passive_frames = COUNT_OF(bad_sd_icons), - .frame_rate = 2, -}; - -const Icon* url_icons[] = { - &I_url1, - &I_url2, - &I_url3, - &I_url4, -}; -const BubbleAnimation url_bubble_animation = { - .icons = url_icons, - .passive_frames = COUNT_OF(url_icons), - .frame_rate = 2, -}; - -const Icon* sd_ok_icons[] = { - &I_card_ok1, - &I_card_ok2, - &I_card_ok3, - &I_card_ok4, -}; -const BubbleAnimation sd_ok_bubble_animation = { - .icons = sd_ok_icons, - .passive_frames = COUNT_OF(sd_ok_icons), - .frame_rate = 2, -}; - -static StorageAnimation StorageAnimationInternal[] = { - {.animation = &tv_bubble_animation, - .external = false, - .meta = - { - .min_butthurt = 0, - .max_butthurt = 11, - .min_level = 1, - .max_level = 3, - .weight = 3, - }}, - {.animation = &no_sd_bubble_animation, - .external = false, - .meta = - { - .min_butthurt = 0, - .max_butthurt = 14, - .min_level = 1, - .max_level = 3, - .weight = 6, - }}, - { - .animation = &no_db_bubble_animation, - .external = false, - }, - { - .animation = &bad_sd_bubble_animation, - .external = false, - }, - { - .animation = &sd_ok_bubble_animation, - .external = false, - }, - { - .animation = &url_bubble_animation, - .external = false, - }, -}; - -void animation_storage_initialize_internal_animations(void) { - /* not in constructor - no memory pool yet */ - /* called in 1 thread - no need in double check */ - static bool initialized = false; - if(!initialized) { - initialized = true; - string_init_set_str(StorageAnimationInternal[0].meta.name, HARDCODED_ANIMATION_NAME); - string_init_set_str(StorageAnimationInternal[1].meta.name, NO_SD_ANIMATION_NAME); - string_init_set_str(StorageAnimationInternal[2].meta.name, NO_DB_ANIMATION_NAME); - string_init_set_str(StorageAnimationInternal[3].meta.name, BAD_SD_ANIMATION_NAME); - string_init_set_str(StorageAnimationInternal[4].meta.name, SD_OK_ANIMATION_NAME); - string_init_set_str(StorageAnimationInternal[5].meta.name, URL_ANIMATION_NAME); - } -} diff --git a/applications/desktop/animations/views/bubble_animation_view.c b/applications/desktop/animations/views/bubble_animation_view.c index b18e7b75..aaffc4bc 100644 --- a/applications/desktop/animations/views/bubble_animation_view.c +++ b/applications/desktop/animations/views/bubble_animation_view.c @@ -1,23 +1,19 @@ -#include "cmsis_os2.h" #include "../animation_manager.h" #include "../animation_storage.h" -#include "furi_hal_delay.h" -#include "furi_hal_resources.h" -#include "furi/check.h" -#include "furi/memmgr.h" -#include "gui/canvas.h" -#include "gui/elements.h" -#include "gui/view.h" -#include "input/input.h" +#include "bubble_animation_view.h" + +#include #include -#include "portmacro.h" -#include +#include +#include +#include +#include +#include #include #include #include -#include "bubble_animation_view.h" -#include +#include #define ACTIVE_SHIFT 2 @@ -43,7 +39,7 @@ struct BubbleAnimationView { static void bubble_animation_activate(BubbleAnimationView* view, bool force); static void bubble_animation_activate_right_now(BubbleAnimationView* view); -static uint8_t bubble_animation_get_icon_index(BubbleAnimationViewModel* model) { +static uint8_t bubble_animation_get_frame_index(BubbleAnimationViewModel* model) { furi_assert(model); uint8_t icon_index = 0; const BubbleAnimation* animation = model->current; @@ -57,7 +53,7 @@ static uint8_t bubble_animation_get_icon_index(BubbleAnimationViewModel* model) } furi_assert(icon_index < (animation->passive_frames + animation->active_frames)); - return icon_index; + return animation->frame_order[icon_index]; } static void bubble_animation_draw_callback(Canvas* canvas, void* model_) { @@ -79,23 +75,26 @@ static void bubble_animation_draw_callback(Canvas* canvas, void* model_) { furi_assert(model->current_frame < 255); - const Icon* icon = animation->icons[bubble_animation_get_icon_index(model)]; - furi_assert(icon); - uint8_t y_offset = canvas_height(canvas) - icon_get_height(icon); - canvas_draw_icon(canvas, 0, y_offset, icon); + uint8_t index = bubble_animation_get_frame_index(model); + uint8_t width = icon_get_width(&animation->icon_animation); + uint8_t height = icon_get_height(&animation->icon_animation); + uint8_t y_offset = canvas_height(canvas) - height; + canvas_draw_bitmap( + canvas, 0, y_offset, width, height, animation->icon_animation.frames[index]); const FrameBubble* bubble = model->current_bubble; if(bubble) { - if((model->current_frame >= bubble->starts_at_frame) && - (model->current_frame <= bubble->ends_at_frame)) { + if((model->current_frame >= bubble->start_frame) && + (model->current_frame <= bubble->end_frame)) { const Bubble* b = &bubble->bubble; - elements_bubble_str(canvas, b->x, b->y, b->str, b->horizontal, b->vertical); + elements_bubble_str(canvas, b->x, b->y, b->text, b->align_h, b->align_v); } } } -static FrameBubble* bubble_animation_pick_bubble(BubbleAnimationViewModel* model, bool active) { - FrameBubble* bubble = NULL; +static const FrameBubble* + bubble_animation_pick_bubble(BubbleAnimationViewModel* model, bool active) { + const FrameBubble* bubble = NULL; if((model->active_bubbles == 0) && (model->passive_bubbles == 0)) { return NULL; @@ -104,10 +103,11 @@ static FrameBubble* bubble_animation_pick_bubble(BubbleAnimationViewModel* model uint8_t index = random() % (active ? model->active_bubbles : model->passive_bubbles); const BubbleAnimation* animation = model->current; - for(int i = 0; i < animation->frame_bubbles_count; ++i) { - if((animation->frame_bubbles[i]->starts_at_frame < animation->passive_frames) ^ active) { + for(int i = 0; i < animation->frame_bubble_sequences_count; ++i) { + if((animation->frame_bubble_sequences[i]->start_frame < animation->passive_frames) ^ + active) { if(!index) { - bubble = animation->frame_bubbles[i]; + bubble = animation->frame_bubble_sequences[i]; } --index; } @@ -135,10 +135,6 @@ static bool bubble_animation_input_callback(InputEvent* event, void* context) { animation_view->interact_callback(animation_view->interact_callback_context); } } - } else if(event->key == InputKeyBack) { - /* Prevent back button to fall down to common handler - leaving - * application, so consume */ - consumed = true; } return consumed; @@ -190,7 +186,7 @@ static void bubble_animation_activate_right_now(BubbleAnimationView* view) { if(model->current && (model->current->active_frames > 0) && (!model->freeze_frame)) { model->current_frame = model->current->passive_frames; model->current_bubble = bubble_animation_pick_bubble(model, true); - frame_rate = model->current->frame_rate; + frame_rate = model->current->icon_animation.frame_rate; } view_commit_model(view->view, true); @@ -222,7 +218,7 @@ static void bubble_animation_next_frame(BubbleAnimationViewModel* model) { } if(model->current_bubble) { - if(model->current_frame > model->current_bubble->ends_at_frame) { + if(model->current_frame > model->current_bubble->end_frame) { model->current_bubble = model->current_bubble->next_bubble; } } @@ -251,7 +247,11 @@ static void bubble_animation_timer_callback(void* context) { } } -static Icon* bubble_animation_clone_frame(const Icon* icon_orig) { +/* always freeze first passive frame, because + * animation is always activated at unfreezing and played + * passive frame first, and 2 frames after - active + */ +static Icon* bubble_animation_clone_first_frame(const Icon* icon_orig) { furi_assert(icon_orig); furi_assert(icon_orig->frames); furi_assert(icon_orig->frames[0]); @@ -268,6 +268,7 @@ static Icon* bubble_animation_clone_frame(const Icon* icon_orig) { size_t max_bitmap_size = ROUND_UP_TO(icon_orig->width, 8) * icon_orig->height + 1; icon_clone->frames[0] = furi_alloc(max_bitmap_size); memcpy((void*)icon_clone->frames[0], icon_orig->frames[0], max_bitmap_size); + FURI_CONST_ASSIGN(icon_clone->frame_count, 1); return icon_clone; } @@ -288,7 +289,7 @@ static void bubble_animation_enter(void* context) { bubble_animation_activate(view, false); BubbleAnimationViewModel* model = view_get_model(view->view); - uint8_t frame_rate = model->current->frame_rate; + uint8_t frame_rate = model->current->icon_animation.frame_rate; view_commit_model(view->view, false); if(frame_rate) { @@ -353,8 +354,8 @@ void bubble_animation_view_set_animation( model->active_ended_at = xTaskGetTickCount() - (model->current->active_cooldown * 1000); model->active_bubbles = 0; model->passive_bubbles = 0; - for(int i = 0; i < new_animation->frame_bubbles_count; ++i) { - if(new_animation->frame_bubbles[i]->starts_at_frame < new_animation->passive_frames) { + for(int i = 0; i < new_animation->frame_bubble_sequences_count; ++i) { + if(new_animation->frame_bubble_sequences[i]->start_frame < new_animation->passive_frames) { ++model->passive_bubbles; } else { ++model->active_bubbles; @@ -367,7 +368,7 @@ void bubble_animation_view_set_animation( model->active_cycle = 0; view_commit_model(view->view, true); - osTimerStart(view->timer, 1000 / new_animation->frame_rate); + osTimerStart(view->timer, 1000 / new_animation->icon_animation.frame_rate); } void bubble_animation_freeze(BubbleAnimationView* view) { @@ -376,12 +377,7 @@ void bubble_animation_freeze(BubbleAnimationView* view) { BubbleAnimationViewModel* model = view_get_model(view->view); furi_assert(model->current); furi_assert(!model->freeze_frame); - /* always freeze first passive frame, because - * animation is always activated at unfreezing and played - * passive frame first, and 2 frames after - active - */ - uint8_t icon_index = 0; - model->freeze_frame = bubble_animation_clone_frame(model->current->icons[icon_index]); + model->freeze_frame = bubble_animation_clone_first_frame(&model->current->icon_animation); model->current = NULL; view_commit_model(view->view, false); osTimerStop(view->timer); @@ -395,8 +391,7 @@ void bubble_animation_unfreeze(BubbleAnimationView* view) { furi_assert(model->freeze_frame); bubble_animation_release_frame(&model->freeze_frame); furi_assert(model->current); - furi_assert(model->current->icons); - frame_rate = model->current->frame_rate; + frame_rate = model->current->icon_animation.frame_rate; view_commit_model(view->view, true); osTimerStart(view->timer, 1000 / frame_rate); diff --git a/applications/desktop/animations/views/one_shot_animation_view.c b/applications/desktop/animations/views/one_shot_animation_view.c new file mode 100644 index 00000000..106cef55 --- /dev/null +++ b/applications/desktop/animations/views/one_shot_animation_view.c @@ -0,0 +1,130 @@ + +#include "one_shot_animation_view.h" +#include +#include +#include +#include +#include +#include + +typedef void (*OneShotInteractCallback)(void*); + +struct OneShotView { + View* view; + TimerHandle_t update_timer; + OneShotInteractCallback interact_callback; + void* interact_callback_context; +}; + +typedef struct { + const Icon* icon; + uint32_t index; + bool block_input; +} OneShotViewModel; + +static void one_shot_view_update_timer_callback(TimerHandle_t xTimer) { + OneShotView* view = (void*)pvTimerGetTimerID(xTimer); + + OneShotViewModel* model = view_get_model(view->view); + if((model->index + 1) < model->icon->frame_count) { + ++model->index; + } else { + model->block_input = false; + model->index = model->icon->frame_count - 2; + } + view_commit_model(view->view, true); +} + +static void one_shot_view_draw(Canvas* canvas, void* model_) { + furi_assert(canvas); + furi_assert(model_); + + OneShotViewModel* model = model_; + furi_check(model->index < model->icon->frame_count); + uint8_t y_offset = canvas_height(canvas) - model->icon->height; + canvas_draw_bitmap( + canvas, + 0, + y_offset, + model->icon->width, + model->icon->height, + model->icon->frames[model->index]); +} + +static bool one_shot_view_input(InputEvent* event, void* context) { + furi_assert(context); + furi_assert(event); + + OneShotView* view = context; + bool consumed = false; + + OneShotViewModel* model = view_get_model(view->view); + consumed = model->block_input; + view_commit_model(view->view, false); + + if(!consumed) { + if(event->key == InputKeyRight) { + /* Right button reserved for animation activation, so consume */ + consumed = true; + if(event->type == InputTypeShort) { + if(view->interact_callback) { + view->interact_callback(view->interact_callback_context); + } + } + } + } + + return consumed; +} + +OneShotView* one_shot_view_alloc(void) { + OneShotView* view = furi_alloc(sizeof(OneShotView)); + view->view = view_alloc(); + view->update_timer = + xTimerCreate("Update timer", 1000, pdTRUE, view, one_shot_view_update_timer_callback); + + view_allocate_model(view->view, ViewModelTypeLocking, sizeof(OneShotViewModel)); + view_set_context(view->view, view); + view_set_draw_callback(view->view, one_shot_view_draw); + view_set_input_callback(view->view, one_shot_view_input); + + return view; +} + +void one_shot_view_free(OneShotView* view) { + furi_assert(view); + + xTimerDelete(view->update_timer, portMAX_DELAY); + view_free(view->view); + view->view = NULL; + free(view); +} + +void one_shot_view_set_interact_callback( + OneShotView* view, + OneShotInteractCallback callback, + void* context) { + furi_assert(view); + + view->interact_callback_context = context; + view->interact_callback = callback; +} + +void one_shot_view_start_animation(OneShotView* view, const Icon* icon) { + furi_assert(view); + furi_assert(icon); + furi_check(icon->frame_count >= 2); + + OneShotViewModel* model = view_get_model(view->view); + model->index = 0; + model->icon = icon; + model->block_input = true; + view_commit_model(view->view, true); + xTimerChangePeriod(view->update_timer, 1000 / model->icon->frame_rate, portMAX_DELAY); +} + +View* one_shot_view_get_view(OneShotView* view) { + furi_assert(view); + + return view->view; +} diff --git a/applications/desktop/animations/views/one_shot_animation_view.h b/applications/desktop/animations/views/one_shot_animation_view.h new file mode 100644 index 00000000..3f78e603 --- /dev/null +++ b/applications/desktop/animations/views/one_shot_animation_view.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +typedef void (*OneShotInteractCallback)(void*); +typedef struct OneShotView OneShotView; + +OneShotView* one_shot_view_alloc(void); +void one_shot_view_free(OneShotView* view); +void one_shot_view_set_interact_callback( + OneShotView* view, + OneShotInteractCallback callback, + void* context); +void one_shot_view_start_animation(OneShotView* view, const Icon* icon); +View* one_shot_view_get_view(OneShotView* view); diff --git a/applications/desktop/desktop.c b/applications/desktop/desktop.c index 171322a9..5d9b7b80 100644 --- a/applications/desktop/desktop.c +++ b/applications/desktop/desktop.c @@ -1,17 +1,16 @@ -#include "assets_icons.h" -#include "cmsis_os2.h" -#include "desktop/desktop.h" -#include "desktop_i.h" -#include "gui/view_composed.h" -#include -#include -#include -#include "portmacro.h" -#include "storage/filesystem_api_defines.h" -#include "storage/storage.h" -#include -#include #include "animations/animation_manager.h" +#include "desktop/scenes/desktop_scene.h" +#include "desktop/scenes/desktop_scene_i.h" +#include "desktop/views/desktop_locked.h" +#include "desktop_i.h" + +#include +#include +#include +#include +#include +#include +#include static void desktop_lock_icon_callback(Canvas* canvas, void* context) { furi_assert(canvas); @@ -50,44 +49,27 @@ Desktop* desktop_alloc() { view_dispatcher_set_navigation_event_callback( desktop->view_dispatcher, desktop_back_event_callback); - desktop->dolphin_view = animation_manager_get_animation_view(desktop->animation_manager); - - desktop->main_view_composed = view_composed_alloc(); - desktop->main_view = desktop_main_alloc(); - view_composed_tie_views( - desktop->main_view_composed, - desktop->dolphin_view, - desktop_main_get_view(desktop->main_view)); - view_composed_top_enable(desktop->main_view_composed, true); - - desktop->locked_view_composed = view_composed_alloc(); desktop->locked_view = desktop_locked_alloc(); - view_composed_tie_views( - desktop->locked_view_composed, - desktop->dolphin_view, - desktop_locked_get_view(desktop->locked_view)); - view_composed_top_enable(desktop->locked_view_composed, true); - desktop->lock_menu = desktop_lock_menu_alloc(); desktop->debug_view = desktop_debug_alloc(); desktop->first_start_view = desktop_first_start_alloc(); desktop->hw_mismatch_popup = popup_alloc(); desktop->code_input = code_input_alloc(); + desktop->main_view_stack = view_stack_alloc(); + desktop->main_view = desktop_main_alloc(); + View* dolphin_view = animation_manager_get_animation_view(desktop->animation_manager); + view_stack_add_view(desktop->main_view_stack, desktop_main_get_view(desktop->main_view)); + view_stack_add_view(desktop->main_view_stack, dolphin_view); + view_stack_add_view(desktop->main_view_stack, desktop_locked_get_view(desktop->locked_view)); view_dispatcher_add_view( - desktop->view_dispatcher, - DesktopViewMain, - view_composed_get_view(desktop->main_view_composed)); + desktop->view_dispatcher, DesktopViewMain, view_stack_get_view(desktop->main_view_stack)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewLockMenu, desktop_lock_menu_get_view(desktop->lock_menu)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewDebug, desktop_debug_get_view(desktop->debug_view)); - view_dispatcher_add_view( - desktop->view_dispatcher, - DesktopViewLocked, - view_composed_get_view(desktop->locked_view_composed)); view_dispatcher_add_view( desktop->view_dispatcher, DesktopViewFirstStart, @@ -123,8 +105,8 @@ void desktop_free(Desktop* desktop) { scene_manager_free(desktop->scene_manager); animation_manager_free(desktop->animation_manager); - view_composed_free(desktop->main_view_composed); - view_composed_free(desktop->locked_view_composed); + view_stack_free(desktop->main_view_stack); + view_stack_free(desktop->locked_view_stack); desktop_main_free(desktop->main_view); desktop_lock_menu_free(desktop->lock_menu); desktop_locked_free(desktop->locked_view); @@ -163,15 +145,14 @@ int32_t desktop_srv(void* p) { SAVE_DESKTOP_SETTINGS(&desktop->settings); } - scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) { furi_hal_usb_disable(); scene_manager_set_scene_state( - desktop->scene_manager, DesktopSceneLocked, DesktopLockedWithPin); - scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); + desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateLockedWithPin); } + scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); + if(desktop_is_first_start()) { scene_manager_next_scene(desktop->scene_manager, DesktopSceneFirstStart); } diff --git a/applications/desktop/desktop_i.h b/applications/desktop/desktop_i.h index 8d74c00f..b6d0d923 100644 --- a/applications/desktop/desktop_i.h +++ b/applications/desktop/desktop_i.h @@ -1,31 +1,21 @@ #pragma once -#include "cmsis_os2.h" #include "desktop.h" - #include "animations/animation_manager.h" -#include "gui/view_composed.h" -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - #include "views/desktop_main.h" #include "views/desktop_first_start.h" #include "views/desktop_lock_menu.h" #include "views/desktop_locked.h" #include "views/desktop_debug.h" - -#include "scenes/desktop_scene.h" #include "desktop/desktop_settings/desktop_settings.h" -#include + +#include +#include +#include +#include +#include +#include +#include #define STATUS_BAR_Y_SHIFT 13 @@ -54,12 +44,11 @@ struct Desktop { DesktopDebugView* debug_view; CodeInput* code_input; - View* dolphin_view; DesktopMainView* main_view; DesktopLockedView* locked_view; - ViewComposed* main_view_composed; - ViewComposed* locked_view_composed; + ViewStack* main_view_stack; + ViewStack* locked_view_stack; DesktopSettings settings; PinCode pincode_buffer; @@ -69,8 +58,6 @@ struct Desktop { AnimationManager* animation_manager; osSemaphoreId_t unload_animation_semaphore; FuriPubSubSubscription* app_start_stop_subscription; - - char* text_buffer; }; Desktop* desktop_alloc(); diff --git a/applications/desktop/desktop_settings/desktop_settings_app.c b/applications/desktop/desktop_settings/desktop_settings_app.c index c8a5f2b7..1c65f58b 100644 --- a/applications/desktop/desktop_settings/desktop_settings_app.c +++ b/applications/desktop/desktop_settings/desktop_settings_app.c @@ -1,4 +1,6 @@ #include "desktop_settings_app.h" +#include +#include "scenes/desktop_settings_scene.h" static bool desktop_settings_custom_event_callback(void* context, uint32_t event) { furi_assert(context); diff --git a/applications/desktop/desktop_settings/desktop_settings_app.h b/applications/desktop/desktop_settings/desktop_settings_app.h index 8ec8e892..9c37a154 100644 --- a/applications/desktop/desktop_settings/desktop_settings_app.h +++ b/applications/desktop/desktop_settings/desktop_settings_app.h @@ -1,8 +1,6 @@ #pragma once -#include #include -#include #include #include #include @@ -10,8 +8,6 @@ #include "desktop_settings.h" -#include "scenes/desktop_settings_scene.h" - typedef enum { CodeEventsSetPin, CodeEventsChangePin, diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c index 0b9bb580..b1b576fc 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -1,6 +1,6 @@ #include "../desktop_settings_app.h" #include "applications.h" -#include "desktop/desktop_settings/desktop_settings.h" +#include "desktop_settings_scene.h" static void desktop_settings_scene_favorite_submenu_callback(void* context, uint32_t index) { DesktopSettingsApp* app = context; @@ -10,7 +10,7 @@ static void desktop_settings_scene_favorite_submenu_callback(void* context, uint void desktop_settings_scene_favorite_on_enter(void* context) { DesktopSettingsApp* app = context; Submenu* submenu = app->submenu; - submenu_clean(submenu); + submenu_reset(submenu); for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { submenu_add_item( @@ -45,5 +45,5 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e void desktop_settings_scene_favorite_on_exit(void* context) { DesktopSettingsApp* app = context; SAVE_DESKTOP_SETTINGS(&app->settings); - submenu_clean(app->submenu); + submenu_reset(app->submenu); } diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pincode_input.c b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pincode_input.c index 70b059a4..a24551c4 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pincode_input.c +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pincode_input.c @@ -1,5 +1,5 @@ #include "../desktop_settings_app.h" -#include "desktop/desktop_settings/desktop_settings.h" +#include "desktop_settings_scene.h" #define SCENE_EXIT_EVENT (0U) diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pincode_menu.c b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pincode_menu.c index 78c2eee9..9e72f52a 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pincode_menu.c +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pincode_menu.c @@ -1,5 +1,6 @@ #include "../desktop_settings_app.h" #include "applications.h" +#include "desktop_settings_scene.h" static void desktop_settings_scene_pincode_menu_submenu_callback(void* context, uint32_t index) { DesktopSettingsApp* app = context; @@ -9,7 +10,7 @@ static void desktop_settings_scene_pincode_menu_submenu_callback(void* context, void desktop_settings_scene_pincode_menu_on_enter(void* context) { DesktopSettingsApp* app = context; Submenu* submenu = app->submenu; - submenu_clean(submenu); + submenu_reset(submenu); if(!app->settings.pincode.length) { submenu_add_item( @@ -74,5 +75,5 @@ bool desktop_settings_scene_pincode_menu_on_event(void* context, SceneManagerEve void desktop_settings_scene_pincode_menu_on_exit(void* context) { DesktopSettingsApp* app = context; - submenu_clean(app->submenu); + submenu_reset(app->submenu); } diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c old mode 100755 new mode 100644 index 43b541ac..4ea7e0cc --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c @@ -1,5 +1,6 @@ #include "../desktop_settings_app.h" #include "applications.h" +#include "desktop_settings_scene.h" enum DesktopSettingsStartSubmenuIndex { DesktopSettingsStartSubmenuIndexFavorite, @@ -53,5 +54,5 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even void desktop_settings_scene_start_on_exit(void* context) { DesktopSettingsApp* app = context; - submenu_clean(app->submenu); + submenu_reset(app->submenu); } diff --git a/applications/desktop/scenes/desktop_scene_config.h b/applications/desktop/scenes/desktop_scene_config.h index ba0893aa..b4e39dd3 100644 --- a/applications/desktop/scenes/desktop_scene_config.h +++ b/applications/desktop/scenes/desktop_scene_config.h @@ -1,6 +1,5 @@ ADD_SCENE(desktop, main, Main) ADD_SCENE(desktop, lock_menu, LockMenu) -ADD_SCENE(desktop, locked, Locked) ADD_SCENE(desktop, debug, Debug) ADD_SCENE(desktop, first_start, FirstStart) ADD_SCENE(desktop, hw_mismatch, HwMismatch) diff --git a/applications/desktop/scenes/desktop_scene_debug.c b/applications/desktop/scenes/desktop_scene_debug.c index 08919283..bf8607f8 100644 --- a/applications/desktop/scenes/desktop_scene_debug.c +++ b/applications/desktop/scenes/desktop_scene_debug.c @@ -1,8 +1,11 @@ -#include "../desktop_i.h" -#include "../views/desktop_debug.h" + #include #include +#include "../desktop_i.h" +#include "../views/desktop_debug.h" +#include "desktop_scene.h" + void desktop_scene_debug_callback(DesktopEvent event, void* context) { Desktop* desktop = (Desktop*)context; view_dispatcher_send_custom_event(desktop->view_dispatcher, event); @@ -31,13 +34,13 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) { break; case DesktopDebugEventDeed: - dolphin_deed(dolphin, DolphinDeedIButtonEmulate); + dolphin_deed(dolphin, DolphinDeedIbuttonEmulate); desktop_debug_get_dolphin_data(desktop->debug_view); consumed = true; break; case DesktopDebugEventWrongDeed: - dolphin_deed(dolphin, DolphinDeedWrong); + dolphin_deed(dolphin, DolphinDeedIbuttonRead); desktop_debug_get_dolphin_data(desktop->debug_view); consumed = true; break; diff --git a/applications/desktop/scenes/desktop_scene_fault.c b/applications/desktop/scenes/desktop_scene_fault.c index eec27ec4..a2555e64 100644 --- a/applications/desktop/scenes/desktop_scene_fault.c +++ b/applications/desktop/scenes/desktop_scene_fault.c @@ -1,3 +1,5 @@ +#include + #include "../desktop_i.h" #define DesktopFaultEventExit 0x00FF00FF diff --git a/applications/desktop/scenes/desktop_scene_first_start.c b/applications/desktop/scenes/desktop_scene_first_start.c index db1b51dc..8dfc96dc 100644 --- a/applications/desktop/scenes/desktop_scene_first_start.c +++ b/applications/desktop/scenes/desktop_scene_first_start.c @@ -1,3 +1,6 @@ +#include +#include + #include "../desktop_i.h" #include "../views/desktop_first_start.h" #include "../views/desktop_events.h" diff --git a/applications/desktop/scenes/desktop_scene_hw_mismatch.c b/applications/desktop/scenes/desktop_scene_hw_mismatch.c index 892a0d84..7ca090b9 100644 --- a/applications/desktop/scenes/desktop_scene_hw_mismatch.c +++ b/applications/desktop/scenes/desktop_scene_hw_mismatch.c @@ -1,6 +1,9 @@ -#include "../desktop_i.h" +#include #include +#include "desktop_scene.h" +#include "../desktop_i.h" + #define HW_MISMATCH_BACK_EVENT (0UL) void desktop_scene_hw_mismatch_callback(void* context) { @@ -11,11 +14,14 @@ void desktop_scene_hw_mismatch_callback(void* context) { void desktop_scene_hw_mismatch_on_enter(void* context) { Desktop* desktop = (Desktop*)context; furi_assert(desktop); - furi_assert(!desktop->text_buffer); Popup* popup = desktop->hw_mismatch_popup; - desktop->text_buffer = furi_alloc(256); + + char* text_buffer = furi_alloc(256); + scene_manager_set_scene_state( + desktop->scene_manager, DesktopSceneHwMismatch, (uint32_t)text_buffer); + snprintf( - desktop->text_buffer, + text_buffer, 256, "HW target: %d\nFW target: %d", furi_hal_version_get_hw_target(), @@ -23,8 +29,7 @@ void desktop_scene_hw_mismatch_on_enter(void* context) { popup_set_context(popup, desktop); popup_set_header( popup, "!!!! HW Mismatch !!!!", 60, 14 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter); - popup_set_text( - popup, desktop->text_buffer, 60, 37 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter); + popup_set_text(popup, text_buffer, 60, 37 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter); popup_set_callback(popup, desktop_scene_hw_mismatch_callback); view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewHwMismatch); } @@ -50,12 +55,13 @@ bool desktop_scene_hw_mismatch_on_event(void* context, SceneManagerEvent event) void desktop_scene_hw_mismatch_on_exit(void* context) { Desktop* desktop = (Desktop*)context; furi_assert(desktop); - furi_assert(desktop->text_buffer); Popup* popup = desktop->hw_mismatch_popup; popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); popup_set_callback(popup, NULL); popup_set_context(popup, NULL); - free(desktop->text_buffer); - desktop->text_buffer = NULL; + char* text_buffer = + (char*)scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneHwMismatch); + free(text_buffer); + scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneHwMismatch, 0); } diff --git a/applications/desktop/scenes/desktop_scene_i.h b/applications/desktop/scenes/desktop_scene_i.h new file mode 100644 index 00000000..f459eb4a --- /dev/null +++ b/applications/desktop/scenes/desktop_scene_i.h @@ -0,0 +1,7 @@ +#pragma once + +typedef enum { + DesktopMainSceneStateUnlocked, + DesktopMainSceneStateLockedWithPin, + DesktopMainSceneStateLockedNoPin, +} DesktopMainSceneState; diff --git a/applications/desktop/scenes/desktop_scene_lock_menu.c b/applications/desktop/scenes/desktop_scene_lock_menu.c index 510ccecb..7a3d51bb 100644 --- a/applications/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/desktop/scenes/desktop_scene_lock_menu.c @@ -1,8 +1,11 @@ -#include "../desktop_i.h" -#include "../views/desktop_lock_menu.h" #include #include +#include "../desktop_i.h" +#include "../views/desktop_lock_menu.h" +#include "desktop_scene_i.h" +#include "desktop_scene.h" + void desktop_scene_lock_menu_callback(DesktopEvent event, void* context) { Desktop* desktop = (Desktop*)context; view_dispatcher_send_custom_event(desktop->view_dispatcher, event); @@ -15,6 +18,9 @@ void desktop_scene_lock_menu_on_enter(void* context) { desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop); desktop_lock_menu_pin_set(desktop->lock_menu, desktop->settings.pincode.length > 0); + + uint8_t idx = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLockMenu); + desktop_lock_menu_set_idx(desktop->lock_menu, idx); view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewLockMenu); } @@ -26,24 +32,25 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { switch(event.event) { case DesktopLockMenuEventLock: scene_manager_set_scene_state( - desktop->scene_manager, DesktopSceneLocked, DesktopLockedNoPin); - scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); + desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateLockedNoPin); + scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); + scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); consumed = true; break; case DesktopLockMenuEventPinLock: if(desktop->settings.pincode.length > 0) { - furi_hal_rtc_set_flag(FuriHalRtcFlagLock); - furi_hal_usb_disable(); scene_manager_set_scene_state( - desktop->scene_manager, DesktopSceneLocked, DesktopLockedWithPin); - scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); + desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateLockedWithPin); + scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); } else { + scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 1); scene_manager_next_scene(desktop->scene_manager, DesktopScenePinSetup); } consumed = true; break; case DesktopLockMenuEventExit: + scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); scene_manager_search_and_switch_to_previous_scene( desktop->scene_manager, DesktopSceneMain); consumed = true; @@ -56,6 +63,4 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { } void desktop_scene_lock_menu_on_exit(void* context) { - Desktop* desktop = (Desktop*)context; - desktop_lock_menu_reset_idx(desktop->lock_menu); } diff --git a/applications/desktop/scenes/desktop_scene_locked.c b/applications/desktop/scenes/desktop_scene_locked.c deleted file mode 100644 index e6c8aa4b..00000000 --- a/applications/desktop/scenes/desktop_scene_locked.c +++ /dev/null @@ -1,101 +0,0 @@ -#include "../desktop_i.h" -#include "../views/desktop_locked.h" -#include "desktop/views/desktop_main.h" - -void desktop_scene_locked_callback(DesktopEvent event, void* context) { - Desktop* desktop = (Desktop*)context; - view_dispatcher_send_custom_event(desktop->view_dispatcher, event); -} - -static void desktop_scene_locked_new_idle_animation_callback(void* context) { - furi_assert(context); - Desktop* desktop = context; - view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopLockedEventCheckAnimation); -} - -void desktop_scene_locked_on_enter(void* context) { - Desktop* desktop = (Desktop*)context; - DesktopLockedView* locked_view = desktop->locked_view; - - animation_manager_set_new_idle_callback( - desktop->animation_manager, desktop_scene_locked_new_idle_animation_callback); - desktop_locked_set_callback(locked_view, desktop_scene_locked_callback, desktop); - desktop_locked_reset_door_pos(locked_view); - desktop_locked_update_hint_timeout(locked_view); - - uint32_t state = scene_manager_get_scene_state(desktop->scene_manager, DesktopViewLocked); - - desktop_locked_with_pin(desktop->locked_view, state == DesktopLockedWithPin); - - view_port_enabled_set(desktop->lock_viewport, true); - osTimerStart(locked_view->timer, osKernelGetTickFreq() / 16); - - view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewLocked); -} - -static bool desktop_scene_locked_check_pin(Desktop* desktop, DesktopEvent event) { - bool match = false; - - size_t length = desktop->pincode_buffer.length; - length = code_input_push(desktop->pincode_buffer.data, length, event); - desktop->pincode_buffer.length = length; - - match = code_input_compare( - desktop->pincode_buffer.data, - length, - desktop->settings.pincode.data, - desktop->settings.pincode.length); - - if(match) { - desktop->pincode_buffer.length = 0; - furi_hal_usb_enable(); - furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); - desktop_main_unlocked(desktop->main_view); - } - - return match; -} - -bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) { - Desktop* desktop = (Desktop*)context; - - bool consumed = false; - if(event.type == SceneManagerEventTypeCustom) { - switch(event.event) { - case DesktopLockedEventUnlock: - scene_manager_set_scene_state( - desktop->scene_manager, DesktopSceneMain, DesktopMainEventUnlocked); - scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); - consumed = true; - break; - case DesktopLockedEventUpdate: - desktop_locked_manage_redraw(desktop->locked_view); - consumed = true; - break; - case DesktopLockedEventInputReset: - desktop->pincode_buffer.length = 0; - break; - case DesktopLockedEventCheckAnimation: - animation_manager_check_blocking_process(desktop->animation_manager); - consumed = true; - break; - default: - if(desktop_scene_locked_check_pin(desktop, event.event)) { - scene_manager_set_scene_state( - desktop->scene_manager, DesktopSceneMain, DesktopMainEventUnlocked); - scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); - consumed = true; - } - break; - } - } - - return consumed; -} - -void desktop_scene_locked_on_exit(void* context) { - Desktop* desktop = (Desktop*)context; - animation_manager_set_new_idle_callback(desktop->animation_manager, NULL); - desktop_locked_reset_counter(desktop->locked_view); - osTimerStop(desktop->locked_view->timer); -} diff --git a/applications/desktop/scenes/desktop_scene_main.c b/applications/desktop/scenes/desktop_scene_main.c index 08ddf606..7faa50fe 100644 --- a/applications/desktop/scenes/desktop_scene_main.c +++ b/applications/desktop/scenes/desktop_scene_main.c @@ -1,17 +1,14 @@ -#include "../desktop_i.h" -#include "../views/desktop_main.h" -#include "applications.h" -#include "assets_icons.h" -#include "cmsis_os2.h" -#include "desktop/desktop.h" -#include "desktop/views/desktop_events.h" -#include "dolphin/dolphin.h" -#include "furi/pubsub.h" -#include "furi/record.h" -#include "furi/thread.h" -#include "storage/storage_glue.h" +#include +#include +#include +#include #include -#include + +#include "desktop/desktop_i.h" +#include "desktop/views/desktop_main.h" +#include "desktop_scene.h" +#include "desktop_scene_i.h" + #define MAIN_VIEW_DEFAULT (0UL) static void desktop_scene_main_app_started_callback(const void* message, void* context) { @@ -81,17 +78,31 @@ void desktop_scene_main_on_enter(void* context) { desktop->animation_manager, desktop_scene_main_check_animation_callback); animation_manager_set_interact_callback( desktop->animation_manager, desktop_scene_main_interact_animation_callback); + desktop_locked_set_callback(desktop->locked_view, desktop_scene_main_callback, desktop); furi_assert(osSemaphoreGetCount(desktop->unload_animation_semaphore) == 0); + Loader* loader = furi_record_open("loader"); desktop->app_start_stop_subscription = furi_pubsub_subscribe( - loader_get_pubsub(), desktop_scene_main_app_started_callback, desktop); + loader_get_pubsub(loader), desktop_scene_main_app_started_callback, desktop); + furi_record_close("loader"); desktop_main_set_callback(main_view, desktop_scene_main_callback, desktop); - view_port_enabled_set(desktop->lock_viewport, false); - if(scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneMain) == - DesktopMainEventUnlocked) { - desktop_main_unlocked(desktop->main_view); + DesktopMainSceneState state = + scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneMain); + if(state == DesktopMainSceneStateLockedNoPin) { + desktop_locked_lock(desktop->locked_view); + view_port_enabled_set(desktop->lock_viewport, true); + } else if(state == DesktopMainSceneStateLockedWithPin) { + LOAD_DESKTOP_SETTINGS(&desktop->settings); + furi_assert(desktop->settings.pincode.length > 0); + desktop_locked_lock_pincode(desktop->locked_view, desktop->settings.pincode); + view_port_enabled_set(desktop->lock_viewport, true); + furi_hal_rtc_set_flag(FuriHalRtcFlagLock); + furi_hal_usb_disable(); + } else { + furi_assert(state == DesktopMainSceneStateUnlocked); + view_port_enabled_set(desktop->lock_viewport, false); } view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewMain); @@ -120,22 +131,22 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { case DesktopMainEventOpenArchive: #ifdef APP_ARCHIVE - animation_manager_unload_and_stall_animation(desktop->animation_manager); desktop_switch_to_app(desktop, &FLIPPER_ARCHIVE); - animation_manager_load_and_continue_animation(desktop->animation_manager); #endif consumed = true; break; case DesktopMainEventOpenFavorite: LOAD_DESKTOP_SETTINGS(&desktop->settings); - animation_manager_unload_and_stall_animation(desktop->animation_manager); if(desktop->settings.favorite < FLIPPER_APPS_COUNT) { - desktop_switch_to_app(desktop, &FLIPPER_APPS[desktop->settings.favorite]); + Loader* loader = furi_record_open("loader"); + LoaderStatus status = + loader_start(loader, FLIPPER_APPS[desktop->settings.favorite].name, NULL); + furi_check(status == LoaderStatusOk); + furi_record_close("loader"); } else { FURI_LOG_E("DesktopSrv", "Can't find favorite application"); } - animation_manager_load_and_continue_animation(desktop->animation_manager); consumed = true; break; @@ -160,6 +171,18 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { animation_manager_load_and_continue_animation(desktop->animation_manager); consumed = true; break; + case DesktopMainEventUnlocked: + consumed = true; + furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); + furi_hal_usb_enable(); + view_port_enabled_set(desktop->lock_viewport, false); + scene_manager_set_scene_state( + desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateUnlocked); + break; + case DesktopMainEventUpdate: + desktop_locked_update(desktop->locked_view); + consumed = true; + break; default: break; @@ -177,7 +200,9 @@ void desktop_scene_main_on_exit(void* context) { * is finished, that's why we can be sure there is no task waiting * for start/stop semaphore */ - furi_pubsub_unsubscribe(loader_get_pubsub(), desktop->app_start_stop_subscription); + Loader* loader = furi_record_open("loader"); + furi_pubsub_unsubscribe(loader_get_pubsub(loader), desktop->app_start_stop_subscription); + furi_record_close("loader"); furi_assert(osSemaphoreGetCount(desktop->unload_animation_semaphore) == 0); animation_manager_set_new_idle_callback(desktop->animation_manager, NULL); @@ -185,5 +210,4 @@ void desktop_scene_main_on_exit(void* context) { animation_manager_set_interact_callback(desktop->animation_manager, NULL); animation_manager_set_context(desktop->animation_manager, desktop); scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneMain, MAIN_VIEW_DEFAULT); - desktop_main_reset_hint(desktop->main_view); } diff --git a/applications/desktop/views/desktop_debug.c b/applications/desktop/views/desktop_debug.c index 91a32e95..0d793dca 100644 --- a/applications/desktop/views/desktop_debug.c +++ b/applications/desktop/views/desktop_debug.c @@ -1,7 +1,9 @@ +#include #include +#include + #include "../desktop_i.h" #include "desktop_debug.h" - #include "dolphin/helpers/dolphin_state.h" #include "dolphin/dolphin.h" diff --git a/applications/desktop/views/desktop_debug.h b/applications/desktop/views/desktop_debug.h index 0faca931..fecbb2aa 100644 --- a/applications/desktop/views/desktop_debug.h +++ b/applications/desktop/views/desktop_debug.h @@ -1,12 +1,7 @@ #pragma once -#include +#include #include -#include -#include -#include -#include -#include #include "desktop_events.h" typedef struct DesktopDebugView DesktopDebugView; diff --git a/applications/desktop/views/desktop_events.h b/applications/desktop/views/desktop_events.h index 38ee2107..56d9729f 100644 --- a/applications/desktop/views/desktop_events.h +++ b/applications/desktop/views/desktop_events.h @@ -6,6 +6,7 @@ typedef enum { DesktopMainEventOpenFavorite, DesktopMainEventOpenMenu, DesktopMainEventOpenDebug, + DesktopMainEventUpdate, DesktopMainEventUnlocked, DesktopMainEventRightShort, DesktopMainEventCheckAnimation, @@ -14,8 +15,6 @@ typedef enum { DesktopMainEventBeforeAppStarted, DesktopMainEventAfterAppFinished, DesktopLockedEventUnlock, - DesktopLockedEventUpdate, - DesktopLockedEventInputReset, DesktopLockedEventCheckAnimation, DesktopLockedEventMax, DesktopDebugEventDeed, diff --git a/applications/desktop/views/desktop_first_start.c b/applications/desktop/views/desktop_first_start.c index 21901c95..c0ef3a5f 100644 --- a/applications/desktop/views/desktop_first_start.c +++ b/applications/desktop/views/desktop_first_start.c @@ -1,4 +1,6 @@ #include +#include +#include #include "../desktop_i.h" #include "desktop_first_start.h" diff --git a/applications/desktop/views/desktop_first_start.h b/applications/desktop/views/desktop_first_start.h index 10414f2e..9b7b3c93 100644 --- a/applications/desktop/views/desktop_first_start.h +++ b/applications/desktop/views/desktop_first_start.h @@ -1,10 +1,7 @@ #pragma once -#include #include -#include -#include -#include + #include "desktop_events.h" typedef struct DesktopFirstStartView DesktopFirstStartView; diff --git a/applications/desktop/views/desktop_lock_menu.c b/applications/desktop/views/desktop_lock_menu.c index a9794417..d65aa30d 100644 --- a/applications/desktop/views/desktop_lock_menu.c +++ b/applications/desktop/views/desktop_lock_menu.c @@ -1,7 +1,11 @@ #include +#include + #include "../desktop_i.h" #include "desktop_lock_menu.h" +#define LOCK_MENU_ITEMS_NB 3 + void desktop_lock_menu_set_callback( DesktopLockMenuView* lock_menu, DesktopLockMenuViewCallback callback, @@ -20,10 +24,11 @@ void desktop_lock_menu_pin_set(DesktopLockMenuView* lock_menu, bool pin_is_set) }); } -void desktop_lock_menu_reset_idx(DesktopLockMenuView* lock_menu) { +void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) { + furi_assert(idx < LOCK_MENU_ITEMS_NB); with_view_model( lock_menu->view, (DesktopLockMenuViewModel * model) { - model->idx = 0; + model->idx = idx; return true; }); } @@ -49,7 +54,7 @@ static void lock_menu_callback(void* context, uint8_t index) { } void desktop_lock_menu_render(Canvas* canvas, void* model) { - const char* Lockmenu_Items[3] = {"Lock", "Lock with PIN", "DUMB mode"}; + const char* Lockmenu_Items[LOCK_MENU_ITEMS_NB] = {"Lock", "Lock with PIN", "DUMB mode"}; DesktopLockMenuViewModel* m = model; canvas_clear(canvas); @@ -58,14 +63,15 @@ void desktop_lock_menu_render(Canvas* canvas, void* model) { canvas_draw_icon(canvas, 116, 0 + STATUS_BAR_Y_SHIFT, &I_DoorRight_70x55); canvas_set_font(canvas, FontSecondary); - for(uint8_t i = 0; i < 3; ++i) { + for(uint8_t i = 0; i < LOCK_MENU_ITEMS_NB; ++i) { const char* str = Lockmenu_Items[i]; if(i == 1 && !m->pin_set) str = "Set PIN"; if(m->hint_timeout && m->idx == 2 && m->idx == i) str = "Not implemented"; - canvas_draw_str_aligned( - canvas, 64, 9 + (i * 17) + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter, str); + if(str != NULL) + canvas_draw_str_aligned( + canvas, 64, 9 + (i * 17) + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter, str); if(m->idx == i) elements_frame(canvas, 15, 1 + (i * 17) + STATUS_BAR_Y_SHIFT, 98, 15); } @@ -88,9 +94,9 @@ bool desktop_lock_menu_input(InputEvent* event, void* context) { lock_menu->view, (DesktopLockMenuViewModel * model) { model->hint_timeout = 0; // clear hint timeout if(event->key == InputKeyUp) { - model->idx = CLAMP(model->idx - 1, 2, 0); + model->idx = CLAMP(model->idx - 1, LOCK_MENU_ITEMS_NB - 1, 0); } else if(event->key == InputKeyDown) { - model->idx = CLAMP(model->idx + 1, 2, 0); + model->idx = CLAMP(model->idx + 1, LOCK_MENU_ITEMS_NB - 1, 0); } idx = model->idx; return true; diff --git a/applications/desktop/views/desktop_lock_menu.h b/applications/desktop/views/desktop_lock_menu.h index 3b0fffcc..e9928a38 100644 --- a/applications/desktop/views/desktop_lock_menu.h +++ b/applications/desktop/views/desktop_lock_menu.h @@ -1,10 +1,6 @@ #pragma once -#include #include -#include -#include -#include #include "desktop_events.h" #define HINT_TIMEOUT 2 @@ -32,6 +28,6 @@ void desktop_lock_menu_set_callback( View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu); void desktop_lock_menu_pin_set(DesktopLockMenuView* lock_menu, bool pin_is_set); -void desktop_lock_menu_reset_idx(DesktopLockMenuView* lock_menu); +void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx); DesktopLockMenuView* desktop_lock_menu_alloc(); void desktop_lock_menu_free(DesktopLockMenuView* lock_menu); diff --git a/applications/desktop/views/desktop_locked.c b/applications/desktop/views/desktop_locked.c index 5a9e7203..d8102f57 100644 --- a/applications/desktop/views/desktop_locked.c +++ b/applications/desktop/views/desktop_locked.c @@ -1,6 +1,42 @@ +#include "desktop/desktop_settings/desktop_settings.h" +#include "furi/check.h" +#include "gui/view.h" +#include "portmacro.h" #include +#include +#include #include "../desktop_i.h" #include "desktop_locked.h" +#include + +#define DOOR_MOVING_INTERVAL_MS (1000 / 16) +#define UNLOCKED_HINT_TIMEOUT_MS (2000) + +struct DesktopLockedView { + View* view; + DesktopLockedViewCallback callback; + void* context; + + TimerHandle_t timer; + uint8_t lock_count; + uint32_t lock_lastpress; + + PinCode pincode; + PinCode pincode_input; +}; + +typedef struct { + uint32_t hint_icon_expire_at; + bool unlocked_hint; + bool locked; + bool pin_locked; + + int8_t door_left_x; + int8_t door_right_x; + bool animation_seq_end; +} DesktopLockedViewModel; + +static void desktop_locked_unlock(DesktopLockedView* locked_view); void desktop_locked_set_callback( DesktopLockedView* locked_view, @@ -12,98 +48,69 @@ void desktop_locked_set_callback( locked_view->context = context; } -void locked_view_timer_callback(void* context) { - DesktopLockedView* locked_view = context; - locked_view->callback(DesktopLockedEventUpdate, locked_view->context); +void locked_view_timer_callback(TimerHandle_t timer) { + DesktopLockedView* locked_view = pvTimerGetTimerID(timer); + locked_view->callback(DesktopMainEventUpdate, locked_view->context); } -void desktop_locked_update_hint_timeout(DesktopLockedView* locked_view) { - with_view_model( - locked_view->view, (DesktopLockedViewModel * model) { - model->hint_expire_at = osKernelGetTickCount() + osKernelGetTickFreq(); - return true; - }); +static void desktop_locked_update_hint_icon_timeout(DesktopLockedView* locked_view) { + DesktopLockedViewModel* model = view_get_model(locked_view->view); + model->hint_icon_expire_at = osKernelGetTickCount() + osKernelGetTickFreq(); + view_commit_model(locked_view->view, true); } -void desktop_locked_reset_door_pos(DesktopLockedView* locked_view) { - with_view_model( - locked_view->view, (DesktopLockedViewModel * model) { - model->animation_seq_end = false; - model->door_left_x = DOOR_L_POS; - model->door_right_x = DOOR_R_POS; - return true; - }); +static void desktop_locked_reset_door_pos(DesktopLockedView* locked_view) { + DesktopLockedViewModel* model = view_get_model(locked_view->view); + model->animation_seq_end = false; + model->door_left_x = DOOR_L_POS; + model->door_right_x = DOOR_R_POS; + view_commit_model(locked_view->view, true); } -void desktop_locked_manage_redraw(DesktopLockedView* locked_view) { - bool animation_seq_end; +void desktop_locked_update(DesktopLockedView* locked_view) { + bool stop_timer = false; - with_view_model( - locked_view->view, (DesktopLockedViewModel * model) { - model->animation_seq_end = !model->door_left_x; - animation_seq_end = model->animation_seq_end; + DesktopLockedViewModel* model = view_get_model(locked_view->view); + if(model->locked) { + if(model->door_left_x != DOOR_L_POS_MAX) { + model->door_left_x = CLAMP(model->door_left_x + 5, DOOR_L_POS_MAX, DOOR_L_POS); + model->door_right_x = CLAMP(model->door_right_x - 5, DOOR_R_POS, DOOR_R_POS_MIN); + } else { + model->animation_seq_end = true; + } + stop_timer = model->animation_seq_end; + } else { + model->unlocked_hint = false; + stop_timer = true; + } + view_commit_model(locked_view->view, true); - if(!model->animation_seq_end) { - model->door_left_x = CLAMP(model->door_left_x + 5, DOOR_L_POS_MAX, DOOR_L_POS); - model->door_right_x = CLAMP(model->door_right_x - 5, DOOR_R_POS, DOOR_R_POS_MIN); - } else { - model->hint_expire_at = !model->hint_expire_at; - } - - return true; - }); - - if(animation_seq_end) { - osTimerStop(locked_view->timer); + if(stop_timer) { + xTimerStop(locked_view->timer, portMAX_DELAY); } } -void desktop_locked_reset_counter(DesktopLockedView* locked_view) { - locked_view->lock_count = 0; - locked_view->lock_lastpress = 0; - - with_view_model( - locked_view->view, (DesktopLockedViewModel * model) { - model->hint_expire_at = 0; - return true; - }); -} - -void desktop_locked_with_pin(DesktopLockedView* locked_view, bool locked) { - with_view_model( - locked_view->view, (DesktopLockedViewModel * model) { - model->pin_lock = locked; - return true; - }); -} - -void desktop_locked_render(Canvas* canvas, void* model) { +void desktop_locked_draw(Canvas* canvas, void* model) { DesktopLockedViewModel* m = model; uint32_t now = osKernelGetTickCount(); canvas_set_color(canvas, ColorBlack); - if(!m->animation_seq_end) { - canvas_draw_icon(canvas, m->door_left_x, 0 + STATUS_BAR_Y_SHIFT, &I_DoorLeft_70x55); - canvas_draw_icon(canvas, m->door_right_x, 0 + STATUS_BAR_Y_SHIFT, &I_DoorRight_70x55); - } - - if(m->animation && m->animation_seq_end) { - if(m->status_bar_background_black) { - canvas_draw_box(canvas, 0, 0, GUI_STATUS_BAR_WIDTH, GUI_STATUS_BAR_HEIGHT); - } - canvas_draw_icon_animation(canvas, 0, 0 + STATUS_BAR_Y_SHIFT, m->animation); - } - - if(now < m->hint_expire_at) { + if(m->locked) { if(!m->animation_seq_end) { + canvas_draw_icon(canvas, m->door_left_x, 0 + STATUS_BAR_Y_SHIFT, &I_DoorLeft_70x55); + canvas_draw_icon(canvas, m->door_right_x, 0 + STATUS_BAR_Y_SHIFT, &I_DoorRight_70x55); canvas_set_font(canvas, FontPrimary); elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked"); - - } else if(!m->pin_lock) { + } else if((now < m->hint_icon_expire_at) && !m->pin_locked) { canvas_set_font(canvas, FontSecondary); canvas_draw_icon(canvas, 13, 2 + STATUS_BAR_Y_SHIFT, &I_LockPopup_100x49); elements_multiline_text(canvas, 65, 20 + STATUS_BAR_Y_SHIFT, "To unlock\npress:"); } + } else { + if(m->unlocked_hint) { + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked"); + } } } @@ -116,85 +123,72 @@ bool desktop_locked_input(InputEvent* event, void* context) { furi_assert(event); furi_assert(context); DesktopLockedView* locked_view = context; - - uint32_t press_time = 0; + bool locked = false; bool locked_with_pin = false; + uint32_t press_time = xTaskGetTickCount(); - with_view_model( - locked_view->view, (DesktopLockedViewModel * model) { - locked_with_pin = model->pin_lock; - return false; - }); - - if(event->type == InputTypeShort) { - if(locked_with_pin) { - press_time = osKernelGetTickCount(); - - if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT * 3) { - locked_view->lock_lastpress = press_time; - locked_view->callback(DesktopLockedEventInputReset, locked_view->context); - } - - locked_view->callback(event->key, locked_view->context); - } else { - desktop_locked_update_hint_timeout(locked_view); - - if(event->key == InputKeyBack) { - press_time = osKernelGetTickCount(); - // check if pressed sequentially - if(press_time - locked_view->lock_lastpress < UNLOCK_RST_TIMEOUT) { - locked_view->lock_lastpress = press_time; - locked_view->lock_count++; - } - - if(locked_view->lock_count == UNLOCK_CNT) { - locked_view->lock_count = 0; - locked_view->callback(DesktopLockedEventUnlock, locked_view->context); - } - } + { + DesktopLockedViewModel* model = view_get_model(locked_view->view); + bool changed = false; + locked = model->locked; + locked_with_pin = model->pin_locked; + if(!locked && model->unlocked_hint && event->type == InputTypePress) { + model->unlocked_hint = false; + changed = true; } + view_commit_model(locked_view->view, changed); + } - if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) { + if(!locked || (event->type != InputTypeShort)) { + return locked; + } + + if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) { + locked_view->lock_lastpress = press_time; + locked_view->lock_count = 0; + locked_view->pincode_input.length = 0; + } + + if(locked_with_pin) { + locked_view->pincode_input.length = code_input_push( + locked_view->pincode_input.data, locked_view->pincode_input.length, event->key); + bool match = code_input_compare( + locked_view->pincode_input.data, + locked_view->pincode_input.length, + locked_view->pincode.data, + locked_view->pincode.length); + + if(match) { + desktop_locked_unlock(locked_view); + } + } else { + if(event->key == InputKeyBack) { locked_view->lock_lastpress = press_time; + locked_view->lock_count++; + if(locked_view->lock_count == UNLOCK_CNT) { + desktop_locked_unlock(locked_view); + } + } else { + desktop_locked_update_hint_icon_timeout(locked_view); locked_view->lock_count = 0; } } - // All events consumed - return true; -} -void desktop_locked_enter(void* context) { - DesktopLockedView* locked_view = context; + locked_view->lock_lastpress = press_time; - with_view_model( - locked_view->view, (DesktopLockedViewModel * model) { - if(model->animation) icon_animation_start(model->animation); - return false; - }); -} - -void desktop_locked_exit(void* context) { - DesktopLockedView* locked_view = context; - - with_view_model( - locked_view->view, (DesktopLockedViewModel * model) { - if(model->animation) icon_animation_stop(model->animation); - return false; - }); + return locked; } DesktopLockedView* desktop_locked_alloc() { DesktopLockedView* locked_view = furi_alloc(sizeof(DesktopLockedView)); locked_view->view = view_alloc(); locked_view->timer = - osTimerNew(locked_view_timer_callback, osTimerPeriodic, locked_view, NULL); + xTimerCreate("Locked view", 1000 / 16, pdTRUE, locked_view, locked_view_timer_callback); view_allocate_model(locked_view->view, ViewModelTypeLocking, sizeof(DesktopLockedViewModel)); view_set_context(locked_view->view, locked_view); - view_set_draw_callback(locked_view->view, (ViewDrawCallback)desktop_locked_render); + view_set_draw_callback(locked_view->view, (ViewDrawCallback)desktop_locked_draw); view_set_input_callback(locked_view->view, desktop_locked_input); - view_set_enter_callback(locked_view->view, desktop_locked_enter); - view_set_exit_callback(locked_view->view, desktop_locked_exit); return locked_view; } @@ -205,3 +199,49 @@ void desktop_locked_free(DesktopLockedView* locked_view) { view_free(locked_view->view); free(locked_view); } + +void desktop_locked_lock(DesktopLockedView* locked_view) { + locked_view->pincode.length = 0; + DesktopLockedViewModel* model = view_get_model(locked_view->view); + model->locked = true; + model->pin_locked = false; + view_commit_model(locked_view->view, true); + desktop_locked_reset_door_pos(locked_view); + xTimerChangePeriod(locked_view->timer, DOOR_MOVING_INTERVAL_MS, portMAX_DELAY); + + Gui* gui = furi_record_open("gui"); + gui_set_lockdown(gui, true); + furi_record_close("gui"); +} + +void desktop_locked_lock_pincode(DesktopLockedView* locked_view, PinCode pincode) { + locked_view->pincode = pincode; + locked_view->pincode_input.length = 0; + DesktopLockedViewModel* model = view_get_model(locked_view->view); + model->locked = true; + model->pin_locked = true; + view_commit_model(locked_view->view, true); + desktop_locked_reset_door_pos(locked_view); + xTimerChangePeriod(locked_view->timer, DOOR_MOVING_INTERVAL_MS, portMAX_DELAY); + + Gui* gui = furi_record_open("gui"); + gui_set_lockdown(gui, true); + furi_record_close("gui"); +} + +static void desktop_locked_unlock(DesktopLockedView* locked_view) { + furi_assert(locked_view); + + locked_view->lock_count = 0; + DesktopLockedViewModel* model = view_get_model(locked_view->view); + model->locked = false; + model->pin_locked = false; + model->unlocked_hint = true; + view_commit_model(locked_view->view, true); + locked_view->callback(DesktopMainEventUnlocked, locked_view->context); + xTimerChangePeriod(locked_view->timer, UNLOCKED_HINT_TIMEOUT_MS, portMAX_DELAY); + + Gui* gui = furi_record_open("gui"); + gui_set_lockdown(gui, false); + furi_record_close("gui"); +} diff --git a/applications/desktop/views/desktop_locked.h b/applications/desktop/views/desktop_locked.h index 81b75ef7..61e91e4e 100644 --- a/applications/desktop/views/desktop_locked.h +++ b/applications/desktop/views/desktop_locked.h @@ -1,14 +1,11 @@ #pragma once -#include +#include #include -#include -#include -#include #include "desktop_events.h" #define UNLOCK_RST_TIMEOUT 300 -#define UNLOCK_CNT 2 // 3 actually +#define UNLOCK_CNT 3 #define DOOR_L_POS -57 #define DOOR_L_POS_MAX 0 @@ -24,40 +21,16 @@ typedef struct DesktopLockedView DesktopLockedView; typedef void (*DesktopLockedViewCallback)(DesktopEvent event, void* context); -struct DesktopLockedView { - View* view; - DesktopLockedViewCallback callback; - void* context; - - osTimerId_t timer; - uint8_t lock_count; - uint32_t lock_lastpress; -}; - -typedef struct { - IconAnimation* animation; - uint32_t hint_expire_at; - - bool status_bar_background_black; - uint8_t scene_num; - int8_t door_left_x; - int8_t door_right_x; - bool animation_seq_end; - - bool pin_lock; -} DesktopLockedViewModel; - void desktop_locked_set_callback( DesktopLockedView* locked_view, DesktopLockedViewCallback callback, void* context); -void desktop_locked_update_hint_timeout(DesktopLockedView* locked_view); -void desktop_locked_reset_counter(DesktopLockedView* locked_view); -void desktop_locked_reset_door_pos(DesktopLockedView* locked_view); -void desktop_locked_manage_redraw(DesktopLockedView* locked_view); +void desktop_locked_update(DesktopLockedView* locked_view); View* desktop_locked_get_view(DesktopLockedView* locked_view); DesktopLockedView* desktop_locked_alloc(); void desktop_locked_free(DesktopLockedView* locked_view); -void desktop_locked_with_pin(DesktopLockedView* lock_menu, bool locked); + +void desktop_locked_lock_pincode(DesktopLockedView* locked_view, PinCode pincode); +void desktop_locked_lock(DesktopLockedView* locked_view); diff --git a/applications/desktop/views/desktop_main.c b/applications/desktop/views/desktop_main.c index 5da12d10..83d561df 100644 --- a/applications/desktop/views/desktop_main.c +++ b/applications/desktop/views/desktop_main.c @@ -1,13 +1,19 @@ -#include "dolphin/dolphin.h" -#include "furi/record.h" -#include "gui/canvas.h" -#include "gui/view.h" -#include "gui/view_composed.h" -#include "input/input.h" +#include +#include +#include +#include #include +#include +#include + #include "../desktop_i.h" #include "desktop_main.h" -//#include "../animations/views/bubble_animation_view.h" + +struct DesktopMainView { + View* view; + DesktopMainViewCallback callback; + void* context; +}; void desktop_main_set_callback( DesktopMainView* main_view, @@ -19,59 +25,6 @@ void desktop_main_set_callback( main_view->context = context; } -void desktop_main_reset_hint(DesktopMainView* main_view) { - with_view_model( - main_view->view, (DesktopMainViewModel * model) { - model->hint_expire_at = 0; - return true; - }); -} - -void desktop_main_switch_dolphin_animation( - DesktopMainView* main_view, - const Icon* icon, - bool status_bar_background_black) { - with_view_model( - main_view->view, (DesktopMainViewModel * model) { - if(model->animation) icon_animation_free(model->animation); - model->animation = icon_animation_alloc(icon); - view_tie_icon_animation(main_view->view, model->animation); - icon_animation_start(model->animation); - model->icon = NULL; - model->status_bar_background_black = status_bar_background_black; - return true; - }); -} - -void desktop_main_switch_dolphin_icon(DesktopMainView* main_view, const Icon* icon) { - with_view_model( - main_view->view, (DesktopMainViewModel * model) { - if(model->animation) icon_animation_free(model->animation); - model->animation = NULL; - model->icon = icon; - return true; - }); -} - -void desktop_main_render(Canvas* canvas, void* model) { - DesktopMainViewModel* m = model; - uint32_t now = osKernelGetTickCount(); - - if(m->status_bar_background_black) { - canvas_draw_box(canvas, 0, 0, GUI_STATUS_BAR_WIDTH, GUI_STATUS_BAR_HEIGHT); - } - if(m->icon) { - canvas_draw_icon(canvas, 0, 0 + STATUS_BAR_Y_SHIFT, m->icon); - } else if(m->animation) { - canvas_draw_icon_animation(canvas, 0, 0 + STATUS_BAR_Y_SHIFT, m->animation); - } - - if(now < m->hint_expire_at) { - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked"); - } -} - View* desktop_main_get_view(DesktopMainView* main_view) { furi_assert(main_view); return main_view->view; @@ -82,58 +35,35 @@ bool desktop_main_input(InputEvent* event, void* context) { furi_assert(context); DesktopMainView* main_view = context; - bool consumed = false; - if(event->key == InputKeyOk && event->type == InputTypeShort) { - main_view->callback(DesktopMainEventOpenMenu, main_view->context); - } else if(event->key == InputKeyDown && event->type == InputTypeLong) { - main_view->callback(DesktopMainEventOpenDebug, main_view->context); - } else if(event->key == InputKeyUp && event->type == InputTypeShort) { - main_view->callback(DesktopMainEventOpenLockMenu, main_view->context); - } else if(event->key == InputKeyDown && event->type == InputTypeShort) { - main_view->callback(DesktopMainEventOpenArchive, main_view->context); - } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { - main_view->callback(DesktopMainEventOpenFavorite, main_view->context); - } else if(event->key == InputKeyRight && event->type == InputTypeShort) { - main_view->callback(DesktopMainEventRightShort, main_view->context); - } else if(event->key == InputKeyBack && event->type == InputTypeShort) { - consumed = true; + if(event->type == InputTypeShort) { + if(event->key == InputKeyOk) { + main_view->callback(DesktopMainEventOpenMenu, main_view->context); + } else if(event->key == InputKeyUp) { + main_view->callback(DesktopMainEventOpenLockMenu, main_view->context); + } else if(event->key == InputKeyDown) { + main_view->callback(DesktopMainEventOpenArchive, main_view->context); + } else if(event->key == InputKeyLeft) { + main_view->callback(DesktopMainEventOpenFavorite, main_view->context); + } else if(event->key == InputKeyRight) { + main_view->callback(DesktopMainEventRightShort, main_view->context); + } + } else if(event->type == InputTypeLong) { + if(event->key == InputKeyDown) { + main_view->callback(DesktopMainEventOpenDebug, main_view->context); + } } - desktop_main_reset_hint(main_view); - - return consumed; -} - -void desktop_main_enter(void* context) { - DesktopMainView* main_view = context; - - with_view_model( - main_view->view, (DesktopMainViewModel * model) { - if(model->animation) icon_animation_start(model->animation); - return false; - }); -} - -void desktop_main_exit(void* context) { - DesktopMainView* main_view = context; - with_view_model( - main_view->view, (DesktopMainViewModel * model) { - if(model->animation) icon_animation_stop(model->animation); - return false; - }); + return true; } DesktopMainView* desktop_main_alloc() { DesktopMainView* main_view = furi_alloc(sizeof(DesktopMainView)); main_view->view = view_alloc(); - view_allocate_model(main_view->view, ViewModelTypeLocking, sizeof(DesktopMainViewModel)); + view_allocate_model(main_view->view, ViewModelTypeLockFree, 1); view_set_context(main_view->view, main_view); - view_set_draw_callback(main_view->view, (ViewDrawCallback)desktop_main_render); view_set_input_callback(main_view->view, desktop_main_input); - view_set_enter_callback(main_view->view, desktop_main_enter); - view_set_exit_callback(main_view->view, desktop_main_exit); return main_view; } @@ -143,11 +73,3 @@ void desktop_main_free(DesktopMainView* main_view) { view_free(main_view->view); free(main_view); } - -void desktop_main_unlocked(DesktopMainView* main_view) { - with_view_model( - main_view->view, (DesktopMainViewModel * model) { - model->hint_expire_at = osKernelGetTickCount() + osKernelGetTickFreq(); - return true; - }); -} diff --git a/applications/desktop/views/desktop_main.h b/applications/desktop/views/desktop_main.h index ea805507..329d9548 100644 --- a/applications/desktop/views/desktop_main.h +++ b/applications/desktop/views/desktop_main.h @@ -1,31 +1,12 @@ #pragma once -#include "gui/view_composed.h" -#include #include -#include -#include -#include #include "desktop_events.h" typedef struct DesktopMainView DesktopMainView; typedef void (*DesktopMainViewCallback)(DesktopEvent event, void* context); -struct DesktopMainView { - View* view; - DesktopMainViewCallback callback; - void* context; -}; - -typedef struct { - IconAnimation* animation; - const Icon* icon; - uint8_t scene_num; - bool status_bar_background_black; - uint32_t hint_expire_at; -} DesktopMainViewModel; - void desktop_main_set_callback( DesktopMainView* main_view, DesktopMainViewCallback callback, @@ -34,10 +15,3 @@ void desktop_main_set_callback( View* desktop_main_get_view(DesktopMainView* main_view); DesktopMainView* desktop_main_alloc(); void desktop_main_free(DesktopMainView* main_view); -void desktop_main_switch_dolphin_animation( - DesktopMainView* main_view, - const Icon* icon, - bool status_bar_background_black); -void desktop_main_unlocked(DesktopMainView* main_view); -void desktop_main_reset_hint(DesktopMainView* main_view); -void desktop_main_switch_dolphin_icon(DesktopMainView* main_view, const Icon* icon); diff --git a/applications/dolphin/dolphin.c b/applications/dolphin/dolphin.c index b401a217..2213ebb9 100644 --- a/applications/dolphin/dolphin.c +++ b/applications/dolphin/dolphin.c @@ -1,13 +1,18 @@ #include "dolphin/dolphin.h" -#include "desktop/desktop.h" #include "dolphin/helpers/dolphin_state.h" #include "dolphin_i.h" -#include "furi/pubsub.h" -#include "sys/_stdint.h" +#include "portmacro.h" +#include "projdefs.h" +#include +#include #include -#define DOLPHIN_TIMEGATE 86400 // one day #define DOLPHIN_LOCK_EVENT_FLAG (0x1) +#define TAG "Dolphin" +#define HOURS_IN_TICKS(x) ((x)*60 * 60 * 1000) + +static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin); + void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) { furi_assert(dolphin); DolphinEvent event; @@ -39,12 +44,51 @@ void dolphin_flush(Dolphin* dolphin) { dolphin_event_send_wait(dolphin, &event); } +void dolphin_butthurt_timer_callback(TimerHandle_t xTimer) { + Dolphin* dolphin = pvTimerGetTimerID(xTimer); + furi_assert(dolphin); + + DolphinEvent event; + event.type = DolphinEventTypeIncreaseButthurt; + dolphin_event_send_async(dolphin, &event); +} + +void dolphin_flush_timer_callback(TimerHandle_t xTimer) { + Dolphin* dolphin = pvTimerGetTimerID(xTimer); + furi_assert(dolphin); + + DolphinEvent event; + event.type = DolphinEventTypeFlush; + dolphin_event_send_async(dolphin, &event); +} + +void dolphin_clear_limits_timer_callback(TimerHandle_t xTimer) { + Dolphin* dolphin = pvTimerGetTimerID(xTimer); + furi_assert(dolphin); + + xTimerChangePeriod(dolphin->clear_limits_timer, HOURS_IN_TICKS(24), portMAX_DELAY); + + DolphinEvent event; + event.type = DolphinEventTypeClearLimits; + dolphin_event_send_async(dolphin, &event); +} + Dolphin* dolphin_alloc() { Dolphin* dolphin = furi_alloc(sizeof(Dolphin)); dolphin->state = dolphin_state_alloc(); dolphin->event_queue = osMessageQueueNew(8, sizeof(DolphinEvent), NULL); dolphin->pubsub = furi_pubsub_alloc(); + dolphin->butthurt_timer = xTimerCreate( + "Butthurt timer", HOURS_IN_TICKS(2 * 24), pdTRUE, dolphin, dolphin_butthurt_timer_callback); + dolphin->flush_timer = + xTimerCreate("Flush timer", 30 * 1000, pdFALSE, dolphin, dolphin_flush_timer_callback); + dolphin->clear_limits_timer = xTimerCreate( + "Clear limits timer", + HOURS_IN_TICKS(24), + pdTRUE, + dolphin, + dolphin_clear_limits_timer_callback); return dolphin; } @@ -83,50 +127,72 @@ void dolphin_event_release(Dolphin* dolphin, DolphinEvent* event) { } } -static void dolphin_check_butthurt(DolphinState* state) { - furi_assert(state); - float diff_time = difftime(state->data.timestamp, dolphin_state_timestamp()); - - if((fabs(diff_time)) > DOLPHIN_TIMEGATE) { - dolphin_state_butthurted(state); - } -} - FuriPubSub* dolphin_get_pubsub(Dolphin* dolphin) { return dolphin->pubsub; } +static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin) { + furi_assert(dolphin); + TickType_t now_ticks = xTaskGetTickCount(); + TickType_t timer_expires_at = xTimerGetExpiryTime(dolphin->clear_limits_timer); + + if((timer_expires_at - now_ticks) > HOURS_IN_TICKS(0.1)) { + FuriHalRtcDateTime date; + furi_hal_rtc_get_datetime(&date); + TickType_t now_time_in_ms = ((date.hour * 60 + date.minute) * 60 + date.second) * 1000; + TickType_t time_to_clear_limits = 0; + + if(date.hour < 5) { + time_to_clear_limits = HOURS_IN_TICKS(5) - now_time_in_ms; + } else { + time_to_clear_limits = HOURS_IN_TICKS(24 + 5) - now_time_in_ms; + } + + xTimerChangePeriod(dolphin->clear_limits_timer, time_to_clear_limits, portMAX_DELAY); + } +} + int32_t dolphin_srv(void* p) { Dolphin* dolphin = dolphin_alloc(); furi_record_create("dolphin", dolphin); dolphin_state_load(dolphin->state); + xTimerReset(dolphin->butthurt_timer, portMAX_DELAY); + dolphin_update_clear_limits_timer_period(dolphin); + xTimerReset(dolphin->clear_limits_timer, portMAX_DELAY); DolphinEvent event; while(1) { - if(osMessageQueueGet(dolphin->event_queue, &event, NULL, 60000) == osOK) { + if(osMessageQueueGet(dolphin->event_queue, &event, NULL, HOURS_IN_TICKS(1)) == osOK) { if(event.type == DolphinEventTypeDeed) { - if(dolphin_state_on_deed(dolphin->state, event.deed)) { - DolphinPubsubEvent event = DolphinPubsubEventUpdate; - furi_pubsub_publish(dolphin->pubsub, &event); - } + dolphin_state_on_deed(dolphin->state, event.deed); + DolphinPubsubEvent event = DolphinPubsubEventUpdate; + furi_pubsub_publish(dolphin->pubsub, &event); + xTimerReset(dolphin->butthurt_timer, portMAX_DELAY); + xTimerReset(dolphin->flush_timer, portMAX_DELAY); } else if(event.type == DolphinEventTypeStats) { - // TODO: correct icounter/butthurt changing, stub till then - event.stats->icounter = 0; - event.stats->butthurt = 0; + event.stats->icounter = dolphin->state->data.icounter; + event.stats->butthurt = dolphin->state->data.butthurt; event.stats->timestamp = dolphin->state->data.timestamp; - event.stats->level = 1; - event.stats->level_up_is_pending = 0; + event.stats->level = dolphin_get_level(dolphin->state->data.icounter); + event.stats->level_up_is_pending = + !dolphin_state_xp_to_levelup(dolphin->state->data.icounter); } else if(event.type == DolphinEventTypeFlush) { - // TODO: correct icounter/butthurt changing, stub till then - dolphin->state->data.butthurt = 0; - dolphin->state->data.icounter = 0; + FURI_LOG_I(TAG, "Flush stats"); + dolphin_state_save(dolphin->state); + } else if(event.type == DolphinEventTypeClearLimits) { + FURI_LOG_I(TAG, "Clear limits"); + dolphin_state_clear_limits(dolphin->state); + dolphin_state_save(dolphin->state); + } else if(event.type == DolphinEventTypeIncreaseButthurt) { + FURI_LOG_I(TAG, "Increase butthurt"); + dolphin_state_butthurted(dolphin->state); dolphin_state_save(dolphin->state); } dolphin_event_release(dolphin, &event); } else { - dolphin_check_butthurt(dolphin->state); - dolphin_state_save(dolphin->state); + /* once per hour check rtc time is not changed */ + dolphin_update_clear_limits_timer_period(dolphin); } } diff --git a/applications/dolphin/dolphin.h b/applications/dolphin/dolphin.h index 150b2de9..ca3bb4b3 100644 --- a/applications/dolphin/dolphin.h +++ b/applications/dolphin/dolphin.h @@ -5,6 +5,10 @@ #include "helpers/dolphin_deed.h" #include +#ifdef __cplusplus +extern "C" { +#endif + typedef struct Dolphin Dolphin; typedef struct { @@ -19,6 +23,13 @@ typedef enum { DolphinPubsubEventUpdate, } DolphinPubsubEvent; +#define DOLPHIN_DEED(deed) \ + do { \ + Dolphin* dolphin = (Dolphin*)furi_record_open("dolphin"); \ + dolphin_deed(dolphin, deed); \ + furi_record_close("dolphin"); \ + } while(0) + /** Deed complete notification. Call it on deed completion. * See dolphin_deed.h for available deeds. In futures it will become part of assets. * Thread safe, async @@ -38,3 +49,7 @@ void dolphin_flush(Dolphin* dolphin); void dolphin_upgrade_level(Dolphin* dolphin); FuriPubSub* dolphin_get_pubsub(Dolphin* dolphin); + +#ifdef __cplusplus +} +#endif diff --git a/applications/dolphin/dolphin_i.h b/applications/dolphin/dolphin_i.h index 1e761436..46f14915 100644 --- a/applications/dolphin/dolphin_i.h +++ b/applications/dolphin/dolphin_i.h @@ -11,9 +11,8 @@ typedef enum { DolphinEventTypeDeed, DolphinEventTypeStats, DolphinEventTypeFlush, - DolphinEventTypeAnimationStartNewIdle, - DolphinEventTypeAnimationCheckBlocking, - DolphinEventTypeAnimationInteract, + DolphinEventTypeIncreaseButthurt, + DolphinEventTypeClearLimits, } DolphinEventType; typedef struct { @@ -31,6 +30,9 @@ struct Dolphin { // Queue osMessageQueueId_t event_queue; FuriPubSub* pubsub; + TimerHandle_t butthurt_timer; + TimerHandle_t flush_timer; + TimerHandle_t clear_limits_timer; }; Dolphin* dolphin_alloc(); diff --git a/applications/dolphin/helpers/dolphin_deed.c b/applications/dolphin/helpers/dolphin_deed.c index c7b2305e..b112d82a 100644 --- a/applications/dolphin/helpers/dolphin_deed.c +++ b/applications/dolphin/helpers/dolphin_deed.c @@ -1,14 +1,65 @@ #include "dolphin_deed.h" #include -static const DolphinDeedWeight dolphin_deed_weights[DolphinDeedMax] = { - {1, -1, 60}, - {1, -1, 60}, - {1, -1, 60}, - {-1, 1, 60}, +static const DolphinDeedWeight dolphin_deed_weights[] = { + {1, DolphinAppSubGhz}, // DolphinDeedSubGhzReceiverInfo + {3, DolphinAppSubGhz}, // DolphinDeedSubGhzSave + {1, DolphinAppSubGhz}, // DolphinDeedSubGhzRawRec + {2, DolphinAppSubGhz}, // DolphinDeedSubGhzAddManually + {2, DolphinAppSubGhz}, // DolphinDeedSubGhzSend + {1, DolphinAppSubGhz}, // DolphinDeedSubGhzFrequencyAnalyzer + + {1, DolphinAppRfid}, // DolphinDeedRfidRead + {3, DolphinAppRfid}, // DolphinDeedRfidReadSuccess + {3, DolphinAppRfid}, // DolphinDeedRfidSave + {2, DolphinAppRfid}, // DolphinDeedRfidEmulate + {2, DolphinAppRfid}, // DolphinDeedRfidAdd + + {1, DolphinAppNfc}, // DolphinDeedNfcRead + {3, DolphinAppNfc}, // DolphinDeedNfcReadSuccess + {3, DolphinAppNfc}, // DolphinDeedNfcSave + {2, DolphinAppNfc}, // DolphinDeedNfcEmulate + {2, DolphinAppNfc}, // DolphinDeedNfcAdd + + {1, DolphinAppIr}, // DolphinDeedIrSend + {3, DolphinAppIr}, // DolphinDeedIrLearnSuccess + {3, DolphinAppIr}, // DolphinDeedIrSave + {2, DolphinAppIr}, // DolphinDeedIrBruteForce + + {1, DolphinAppIbutton}, // DolphinDeedIbuttonRead + {3, DolphinAppIbutton}, // DolphinDeedIbuttonReadSuccess + {3, DolphinAppIbutton}, // DolphinDeedIbuttonSave + {2, DolphinAppIbutton}, // DolphinDeedIbuttonEmulate + {2, DolphinAppIbutton}, // DolphinDeedIbuttonAdd + + {3, DolphinAppBadusb}, // DolphinDeedBadUsbPlayScript + {3, DolphinAppU2f}, // DolphinDeedU2fAuthorized }; -const DolphinDeedWeight* dolphin_deed_weight(DolphinDeed deed) { - furi_assert(deed < DolphinDeedMax); - return &dolphin_deed_weights[deed]; +static uint8_t dolphin_deed_limits[] = { + 15, // DolphinAppSubGhz + 15, // DolphinAppRfid + 15, // DolphinAppNfc + 15, // DolphinAppIr + 15, // DolphinAppIbutton + 15, // DolphinAppBadusb + 15, // DolphinAppU2f +}; + +_Static_assert(COUNT_OF(dolphin_deed_weights) == DolphinDeedMAX, "dolphin_deed_weights size error"); +_Static_assert(COUNT_OF(dolphin_deed_limits) == DolphinAppMAX, "dolphin_deed_limits size error"); + +uint8_t dolphin_deed_get_weight(DolphinDeed deed) { + furi_check(deed < DolphinDeedMAX); + return dolphin_deed_weights[deed].icounter; +} + +DolphinApp dolphin_deed_get_app(DolphinDeed deed) { + furi_check(deed < DolphinDeedMAX); + return dolphin_deed_weights[deed].app; +} + +uint8_t dolphin_deed_get_app_limit(DolphinApp app) { + furi_check(app < DolphinAppMAX); + return dolphin_deed_limits[app]; } diff --git a/applications/dolphin/helpers/dolphin_deed.h b/applications/dolphin/helpers/dolphin_deed.h index afbf94c2..20e18d70 100644 --- a/applications/dolphin/helpers/dolphin_deed.h +++ b/applications/dolphin/helpers/dolphin_deed.h @@ -2,23 +2,73 @@ #include -/* Countable deed that affects icounter*/ +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { - // iButton - DolphinDeedIButtonRead, - DolphinDeedIButtonWrite, - DolphinDeedIButtonEmulate, - // for debug - DolphinDeedWrong, - // Special value, do not use - DolphinDeedMax + DolphinAppSubGhz, + DolphinAppRfid, + DolphinAppNfc, + DolphinAppIr, + DolphinAppIbutton, + DolphinAppBadusb, + DolphinAppU2f, + DolphinAppMAX, +} DolphinApp; + +typedef enum { + DolphinDeedSubGhzReceiverInfo, + DolphinDeedSubGhzSave, + DolphinDeedSubGhzRawRec, + DolphinDeedSubGhzAddManually, + DolphinDeedSubGhzSend, + DolphinDeedSubGhzFrequencyAnalyzer, + + DolphinDeedRfidRead, + DolphinDeedRfidReadSuccess, + DolphinDeedRfidSave, + DolphinDeedRfidEmulate, + DolphinDeedRfidAdd, + + DolphinDeedNfcRead, + DolphinDeedNfcReadSuccess, + DolphinDeedNfcSave, + DolphinDeedNfcEmulate, + DolphinDeedNfcAdd, + + DolphinDeedIrSend, + DolphinDeedIrLearnSuccess, + DolphinDeedIrSave, + DolphinDeedIrBruteForce, + + DolphinDeedIbuttonRead, + DolphinDeedIbuttonReadSuccess, + DolphinDeedIbuttonSave, + DolphinDeedIbuttonEmulate, + DolphinDeedIbuttonAdd, + + DolphinDeedBadUsbPlayScript, + + DolphinDeedU2fAuthorized, + + DolphinDeedMAX } DolphinDeed; typedef struct { - int32_t icounter; // how many icounter get by Deed - int32_t butthurt; // how many icounter get by Deed - uint32_t limit_value; // how many deeds in limit interval - uint32_t limit_interval; // interval, in minutes + uint8_t icounter; + DolphinApp app; } DolphinDeedWeight; -const DolphinDeedWeight* dolphin_deed_weight(DolphinDeed deed); +typedef struct { + DolphinApp app; + uint8_t icounter_limit; +} DolphinDeedLimits; + +DolphinApp dolphin_deed_get_app(DolphinDeed deed); +uint8_t dolphin_deed_get_app_limit(DolphinApp app); +uint8_t dolphin_deed_get_weight(DolphinDeed deed); + +#ifdef __cplusplus +} +#endif diff --git a/applications/dolphin/helpers/dolphin_state.c b/applications/dolphin/helpers/dolphin_state.c index c57694ac..a14b106d 100644 --- a/applications/dolphin/helpers/dolphin_state.c +++ b/applications/dolphin/helpers/dolphin_state.c @@ -1,4 +1,5 @@ #include "dolphin_state.h" +#include "dolphin/helpers/dolphin_deed.h" #include #include #include @@ -10,9 +11,8 @@ #define DOLPHIN_STATE_PATH "/int/dolphin.state" #define DOLPHIN_STATE_HEADER_MAGIC 0xD0 #define DOLPHIN_STATE_HEADER_VERSION 0x01 -#define DOLPHIN_LVL_THRESHOLD 20.0f -#define LEVEL2_THRESHOLD 20 -#define LEVEL3_THRESHOLD 100 +#define LEVEL2_THRESHOLD 735 +#define LEVEL3_THRESHOLD 2940 #define BUTTHURT_MAX 14 #define BUTTHURT_MIN 0 @@ -125,50 +125,68 @@ uint32_t dolphin_state_xp_to_levelup(uint32_t icounter) { return threshold - icounter; } -bool dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed) { - const DolphinDeedWeight* deed_weight = dolphin_deed_weight(deed); - int32_t icounter = dolphin_state->data.icounter + deed_weight->icounter; - bool level_up = false; - bool mood_changed = false; - - if(icounter <= 0) { - icounter = 0; - if(dolphin_state->data.icounter == 0) { - return false; - } - } +void dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed) { + DolphinApp app = dolphin_deed_get_app(deed); + int8_t weight_limit = + dolphin_deed_get_app_limit(app) - dolphin_state->data.icounter_daily_limit[app]; + uint8_t deed_weight = CLAMP(dolphin_deed_get_weight(deed), weight_limit, 0); uint8_t xp_to_levelup = dolphin_state_xp_to_levelup(dolphin_state->data.icounter); if(xp_to_levelup) { - level_up = true; - dolphin_state->data.icounter += MIN(xp_to_levelup, deed_weight->icounter); + deed_weight = MIN(xp_to_levelup, deed_weight); + dolphin_state->data.icounter += deed_weight; + dolphin_state->data.icounter_daily_limit[app] += deed_weight; } - uint32_t new_butthurt = CLAMP( - ((int32_t)dolphin_state->data.butthurt) + deed_weight->butthurt, - BUTTHURT_MAX, - BUTTHURT_MIN); + /* decrease butthurt: + * 0 deeds accumulating --> 0 butthurt + * +1....+15 deeds accumulating --> -1 butthurt + * +16...+30 deeds accumulating --> -1 butthurt + * +31...+45 deeds accumulating --> -1 butthurt + * +46...... deeds accumulating --> -1 butthurt + * -4 butthurt per day is maximum + * */ + uint8_t butthurt_icounter_level_old = dolphin_state->data.butthurt_daily_limit / 15 + + !!(dolphin_state->data.butthurt_daily_limit % 15); + dolphin_state->data.butthurt_daily_limit = + CLAMP(dolphin_state->data.butthurt_daily_limit + deed_weight, 46, 0); + uint8_t butthurt_icounter_level_new = dolphin_state->data.butthurt_daily_limit / 15 + + !!(dolphin_state->data.butthurt_daily_limit % 15); + int32_t new_butthurt = ((int32_t)dolphin_state->data.butthurt) - + (butthurt_icounter_level_old != butthurt_icounter_level_new); + new_butthurt = CLAMP(new_butthurt, BUTTHURT_MAX, BUTTHURT_MIN); - if(!!dolphin_state->data.butthurt != !!new_butthurt) { - mood_changed = true; - } dolphin_state->data.butthurt = new_butthurt; dolphin_state->data.timestamp = dolphin_state_timestamp(); dolphin_state->dirty = true; - return level_up || mood_changed; + FURI_LOG_D( + TAG, + "icounter %d, butthurt %d", + dolphin_state->data.icounter, + dolphin_state->data.butthurt); } void dolphin_state_butthurted(DolphinState* dolphin_state) { if(dolphin_state->data.butthurt < BUTTHURT_MAX) { dolphin_state->data.butthurt++; - FURI_LOG_I("DolphinState", "Increasing butthurt"); dolphin_state->data.timestamp = dolphin_state_timestamp(); dolphin_state->dirty = true; } } void dolphin_state_increase_level(DolphinState* dolphin_state) { + furi_assert(dolphin_state_is_levelup(dolphin_state->data.icounter)); ++dolphin_state->data.icounter; dolphin_state->dirty = true; } + +void dolphin_state_clear_limits(DolphinState* dolphin_state) { + furi_assert(dolphin_state); + + for(int i = 0; i < DolphinAppMAX; ++i) { + dolphin_state->data.icounter_daily_limit[i] = 0; + } + dolphin_state->data.butthurt_daily_limit = 0; + dolphin_state->dirty = true; +} diff --git a/applications/dolphin/helpers/dolphin_state.h b/applications/dolphin/helpers/dolphin_state.h index 8c9f3aa9..07d0b427 100644 --- a/applications/dolphin/helpers/dolphin_state.h +++ b/applications/dolphin/helpers/dolphin_state.h @@ -7,10 +7,8 @@ typedef struct DolphinState DolphinState; typedef struct { - uint32_t limit_ibutton; - uint32_t limit_nfc; - uint32_t limit_ir; - uint32_t limit_rfid; + uint8_t icounter_daily_limit[DolphinAppMAX]; + uint8_t butthurt_daily_limit; uint32_t flags; uint32_t icounter; @@ -31,11 +29,11 @@ bool dolphin_state_save(DolphinState* dolphin_state); bool dolphin_state_load(DolphinState* dolphin_state); -void dolphin_state_clear(DolphinState* dolphin_state); +void dolphin_state_clear_limits(DolphinState* dolphin_state); uint64_t dolphin_state_timestamp(); -bool dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed); +void dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed); void dolphin_state_butthurted(DolphinState* dolphin_state); diff --git a/applications/gpio/scenes/gpio_scene_start.c b/applications/gpio/scenes/gpio_scene_start.c index dfa215e6..d0adb35e 100644 --- a/applications/gpio/scenes/gpio_scene_start.c +++ b/applications/gpio/scenes/gpio_scene_start.c @@ -95,5 +95,5 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) { void gpio_scene_start_on_exit(void* context) { GpioApp* app = context; - variable_item_list_clean(app->var_item_list); + variable_item_list_reset(app->var_item_list); } diff --git a/applications/gpio/scenes/gpio_scene_usb_uart_config.c b/applications/gpio/scenes/gpio_scene_usb_uart_config.c index 713e6bed..72f6db69 100644 --- a/applications/gpio/scenes/gpio_scene_usb_uart_config.c +++ b/applications/gpio/scenes/gpio_scene_usb_uart_config.c @@ -135,6 +135,6 @@ void gpio_scene_usb_uart_cfg_on_exit(void* context) { app->scene_manager, GpioAppViewUsbUartCfg, variable_item_list_get_selected_item_index(app->var_item_list)); - variable_item_list_clean(app->var_item_list); + variable_item_list_reset(app->var_item_list); free(cfg_set); } diff --git a/applications/gpio/usb_uart_bridge.c b/applications/gpio/usb_uart_bridge.c index 03706b8d..c9085af7 100644 --- a/applications/gpio/usb_uart_bridge.c +++ b/applications/gpio/usb_uart_bridge.c @@ -154,7 +154,7 @@ static int32_t usb_uart_worker(void* context) { furi_thread_set_context(usb_uart->tx_thread, usb_uart); furi_thread_set_callback(usb_uart->tx_thread, usb_uart_tx_thread); - UsbInterface* usb_mode_prev = furi_hal_usb_get_config(); + FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); usb_uart_vcp_init(usb_uart, usb_uart->cfg.vcp_ch); usb_uart_serial_init(usb_uart, usb_uart->cfg.uart_ch); usb_uart_set_baudrate(usb_uart, usb_uart->cfg.baudrate); diff --git a/applications/gui/canvas.c b/applications/gui/canvas.c old mode 100755 new mode 100644 index c69212ab..3706b176 --- a/applications/gui/canvas.c +++ b/applications/gui/canvas.c @@ -4,6 +4,7 @@ #include #include +#include #include const CanvasFontParameters canvas_font_params[FontTotalNumber] = { @@ -202,6 +203,22 @@ uint8_t canvas_glyph_width(Canvas* canvas, char symbol) { return u8g2_GetGlyphWidth(&canvas->fb, symbol); } +void canvas_draw_bitmap( + Canvas* canvas, + uint8_t x, + uint8_t y, + uint8_t width, + uint8_t height, + const uint8_t* compressed_bitmap_data) { + furi_assert(canvas); + + x += canvas->offset_x; + y += canvas->offset_y; + uint8_t* bitmap_data = NULL; + furi_hal_compress_icon_decode(compressed_bitmap_data, &bitmap_data); + u8g2_DrawXBM(&canvas->fb, x, y, width, height, bitmap_data); +} + void canvas_draw_icon_animation( Canvas* canvas, uint8_t x, diff --git a/applications/gui/canvas.h b/applications/gui/canvas.h index ec8cf433..4923e2e6 100755 --- a/applications/gui/canvas.h +++ b/applications/gui/canvas.h @@ -178,6 +178,23 @@ uint16_t canvas_string_width(Canvas* canvas, const char* str); */ uint8_t canvas_glyph_width(Canvas* canvas, char symbol); +/** Draw bitmap picture at position defined by x,y. + * + * @param canvas Canvas instance + * @param x x coordinate + * @param y y coordinate + * @param width width of bitmap + * @param height height of bitmap + * @param compressed_bitmap_data compressed bitmap data + */ +void canvas_draw_bitmap( + Canvas* canvas, + uint8_t x, + uint8_t y, + uint8_t width, + uint8_t height, + const uint8_t* compressed_bitmap_data); + /** Draw animation at position defined by x,y. * * @param canvas Canvas instance diff --git a/applications/gui/gui.c b/applications/gui/gui.c index 9d9b0900..bc333bb1 100644 --- a/applications/gui/gui.c +++ b/applications/gui/gui.c @@ -45,7 +45,7 @@ bool gui_redraw_fs(Gui* gui) { } } -void gui_redraw_status_bar(Gui* gui) { +static void gui_redraw_status_bar(Gui* gui, bool need_attention) { ViewPortArray_it_t it; uint8_t x; uint8_t x_used = 0; @@ -140,6 +140,30 @@ void gui_redraw_status_bar(Gui* gui) { } ViewPortArray_next(it); } + + if(need_attention) { + width = icon_get_width(&I_Attention_5x8); + canvas_frame_set(gui->canvas, 0, GUI_STATUS_BAR_Y, x + width + 5, GUI_STATUS_BAR_HEIGHT); + canvas_draw_rframe( + gui->canvas, 0, 0, canvas_width(gui->canvas), canvas_height(gui->canvas), 1); + canvas_draw_line(gui->canvas, 1, 1, 1, canvas_height(gui->canvas) - 2); + canvas_draw_line( + gui->canvas, + 2, + canvas_height(gui->canvas) - 2, + canvas_width(gui->canvas) - 2, + canvas_height(gui->canvas) - 2); + + canvas_frame_set(gui->canvas, x, GUI_STATUS_BAR_Y, width + 5, GUI_STATUS_BAR_HEIGHT); + + canvas_set_color(gui->canvas, ColorWhite); + canvas_draw_box(gui->canvas, 2, 1, width + 2, 10); + canvas_set_color(gui->canvas, ColorBlack); + + canvas_frame_set( + gui->canvas, x + 3, GUI_STATUS_BAR_Y + 2, width, GUI_STATUS_BAR_WORKAREA_HEIGHT); + canvas_draw_icon(gui->canvas, 0, 0, &I_Attention_5x8); + } } bool gui_redraw_window(Gui* gui) { @@ -171,11 +195,19 @@ void gui_redraw(Gui* gui) { canvas_reset(gui->canvas); - if(!gui_redraw_fs(gui)) { - if(!gui_redraw_window(gui)) { - gui_redraw_desktop(gui); + if(gui->lockdown) { + gui_redraw_desktop(gui); + bool need_attention = + (gui_view_port_find_enabled(gui->layers[GuiLayerWindow]) != 0 || + gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]) != 0); + gui_redraw_status_bar(gui, need_attention); + } else { + if(!gui_redraw_fs(gui)) { + if(!gui_redraw_window(gui)) { + gui_redraw_desktop(gui); + } + gui_redraw_status_bar(gui, false); } - gui_redraw_status_bar(gui); } canvas_commit(gui->canvas); @@ -210,9 +242,15 @@ void gui_input(Gui* gui, InputEvent* input_event) { gui_lock(gui); - ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]); - if(!view_port) view_port = gui_view_port_find_enabled(gui->layers[GuiLayerWindow]); - if(!view_port) view_port = gui_view_port_find_enabled(gui->layers[GuiLayerDesktop]); + ViewPort* view_port = NULL; + + if(gui->lockdown) { + view_port = gui_view_port_find_enabled(gui->layers[GuiLayerDesktop]); + } else { + view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]); + if(!view_port) view_port = gui_view_port_find_enabled(gui->layers[GuiLayerWindow]); + if(!view_port) view_port = gui_view_port_find_enabled(gui->layers[GuiLayerDesktop]); + } if(!(gui->ongoing_input & ~key_bit) && input_event->type == InputTypePress) { gui->ongoing_input_view_port = view_port; @@ -366,10 +404,18 @@ void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, vo gui_unlock(gui); if(callback != NULL) { - gui_redraw(gui); + gui_update(gui); } } +void gui_set_lockdown(Gui* gui, bool lockdown) { + furi_assert(gui); + gui_lock(gui); + gui->lockdown = lockdown; + gui_unlock(gui); + gui_update(gui); +} + Gui* gui_alloc() { Gui* gui = furi_alloc(sizeof(Gui)); // Thread ID diff --git a/applications/gui/gui.h b/applications/gui/gui.h index a5fb8a11..5c209362 100644 --- a/applications/gui/gui.h +++ b/applications/gui/gui.h @@ -79,6 +79,16 @@ void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port); */ void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context); +/** Set lockdown mode + * + * When lockdown mode is enabled, only GuiLayerDesktop is shown. + * This feature prevents services from showing sensitive information when flipper is locked. + * + * @param gui Gui instance + * @param lockdown bool, true if enabled + */ +void gui_set_lockdown(Gui* gui, bool lockdown); + #ifdef __cplusplus } #endif diff --git a/applications/gui/gui_i.h b/applications/gui/gui_i.h index 0046e85a..479b5592 100644 --- a/applications/gui/gui_i.h +++ b/applications/gui/gui_i.h @@ -49,6 +49,7 @@ struct Gui { osMutexId_t mutex; // Layers and Canvas + bool lockdown; ViewPortArray_t layers[GuiLayerMAX]; Canvas* canvas; GuiCanvasCommitCallback canvas_callback; diff --git a/applications/gui/icon_i.h b/applications/gui/icon_i.h index c01f5cce..63e9e94c 100644 --- a/applications/gui/icon_i.h +++ b/applications/gui/icon_i.h @@ -3,6 +3,7 @@ * GUI: internal Icon API */ +#pragma once #include "icon.h" struct Icon { diff --git a/applications/gui/modules/button_menu.c b/applications/gui/modules/button_menu.c index 0dbb1366..605e73eb 100644 --- a/applications/gui/modules/button_menu.c +++ b/applications/gui/modules/button_menu.c @@ -241,7 +241,7 @@ View* button_menu_get_view(ButtonMenu* button_menu) { return button_menu->view; } -void button_menu_clean(ButtonMenu* button_menu) { +void button_menu_reset(ButtonMenu* button_menu) { furi_assert(button_menu); with_view_model( diff --git a/applications/gui/modules/button_menu.h b/applications/gui/modules/button_menu.h index a662114b..bdf445d0 100644 --- a/applications/gui/modules/button_menu.h +++ b/applications/gui/modules/button_menu.h @@ -39,7 +39,7 @@ View* button_menu_get_view(ButtonMenu* button_menu); * * @param button_menu ButtonMenu instance */ -void button_menu_clean(ButtonMenu* button_menu); +void button_menu_reset(ButtonMenu* button_menu); /** Add item to button menu instance * diff --git a/applications/gui/modules/button_panel.c b/applications/gui/modules/button_panel.c index c3352d11..075e0c76 100644 --- a/applications/gui/modules/button_panel.c +++ b/applications/gui/modules/button_panel.c @@ -112,7 +112,7 @@ void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t re void button_panel_free(ButtonPanel* button_panel) { furi_assert(button_panel); - button_panel_clean(button_panel); + button_panel_reset(button_panel); with_view_model( button_panel->view, (ButtonPanelModel * model) { @@ -125,7 +125,7 @@ void button_panel_free(ButtonPanel* button_panel) { free(button_panel); } -void button_panel_clean(ButtonPanel* button_panel) { +void button_panel_reset(ButtonPanel* button_panel) { furi_assert(button_panel); with_view_model( diff --git a/applications/gui/modules/button_panel.h b/applications/gui/modules/button_panel.h index 479aeeaf..71ffdf3b 100644 --- a/applications/gui/modules/button_panel.h +++ b/applications/gui/modules/button_panel.h @@ -39,7 +39,7 @@ void button_panel_free(ButtonPanel* button_panel); * * @param button_panel ButtonPanel instance */ -void button_panel_clean(ButtonPanel* button_panel); +void button_panel_reset(ButtonPanel* button_panel); /** Reserve space for adding items. * diff --git a/applications/gui/modules/dialog_ex.c b/applications/gui/modules/dialog_ex.c index 71375030..5dd0e410 100755 --- a/applications/gui/modules/dialog_ex.c +++ b/applications/gui/modules/dialog_ex.c @@ -244,7 +244,7 @@ void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text) { }); } -void dialog_ex_clean(DialogEx* dialog_ex) { +void dialog_ex_reset(DialogEx* dialog_ex) { furi_assert(dialog_ex); TextElement clean_text_el = { .text = NULL, .x = 0, .y = 0, .horizontal = AlignLeft, .vertical = AlignLeft}; diff --git a/applications/gui/modules/dialog_ex.h b/applications/gui/modules/dialog_ex.h index 1420fe5f..871bb28a 100644 --- a/applications/gui/modules/dialog_ex.h +++ b/applications/gui/modules/dialog_ex.h @@ -143,8 +143,8 @@ void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text); * * @param dialog_ex DialogEx instance */ -void dialog_ex_clean(DialogEx* dialog_ex); +void dialog_ex_reset(DialogEx* dialog_ex); #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/applications/gui/modules/file_select.c b/applications/gui/modules/file_select.c index 449f3194..78ecd241 100644 --- a/applications/gui/modules/file_select.c +++ b/applications/gui/modules/file_select.c @@ -77,7 +77,7 @@ static bool file_select_input_callback(InputEvent* event, void* context) { FileSelect* file_select = (FileSelect*)context; bool consumed = false; - if(event->type == InputTypeShort) { + if((event->type == InputTypeShort) | (event->type == InputTypeRepeat)) { if(!file_select->init_completed) { if(!file_select_init_inner(file_select)) { file_select->callback(false, file_select->context); diff --git a/applications/gui/modules/menu.c b/applications/gui/modules/menu.c index 2b551d55..0fb95d70 100644 --- a/applications/gui/modules/menu.c +++ b/applications/gui/modules/menu.c @@ -87,6 +87,14 @@ static bool menu_input_callback(InputEvent* event, void* context) { consumed = true; menu_process_ok(menu); } + } else if(event->type == InputTypeRepeat) { + if(event->key == InputKeyUp) { + consumed = true; + menu_process_up(menu); + } else if(event->key == InputKeyDown) { + consumed = true; + menu_process_down(menu); + } } return consumed; @@ -138,7 +146,7 @@ Menu* menu_alloc() { void menu_free(Menu* menu) { furi_assert(menu); - menu_clean(menu); + menu_reset(menu); view_free(menu->view); free(menu); } @@ -172,7 +180,7 @@ void menu_add_item( }); } -void menu_clean(Menu* menu) { +void menu_reset(Menu* menu) { furi_assert(menu); with_view_model( menu->view, (MenuModel * model) { diff --git a/applications/gui/modules/menu.h b/applications/gui/modules/menu.h index b41930fd..f66514a7 100755 --- a/applications/gui/modules/menu.h +++ b/applications/gui/modules/menu.h @@ -59,7 +59,7 @@ void menu_add_item( * * @param menu Menu instance */ -void menu_clean(Menu* menu); +void menu_reset(Menu* menu); /** Set current menu item * diff --git a/applications/gui/modules/popup.c b/applications/gui/modules/popup.c index 766fdf67..0e3b3889 100644 --- a/applications/gui/modules/popup.c +++ b/applications/gui/modules/popup.c @@ -226,4 +226,20 @@ void popup_enable_timeout(Popup* popup) { void popup_disable_timeout(Popup* popup) { popup->timer_enabled = false; -} \ No newline at end of file +} + +void popup_reset(Popup* popup) { + furi_assert(popup); + + with_view_model( + popup->view, (PopupModel * model) { + memset(&model->header, 0, sizeof(model->header)); + memset(&model->text, 0, sizeof(model->text)); + memset(&model->icon, 0, sizeof(model->icon)); + return false; + }); + popup->callback = NULL; + popup->context = NULL; + popup->timer_enabled = false; + popup->timer_period_in_ms = 0; +} diff --git a/applications/gui/modules/popup.h b/applications/gui/modules/popup.h index 2b87f0ad..94f49a2b 100644 --- a/applications/gui/modules/popup.h +++ b/applications/gui/modules/popup.h @@ -123,6 +123,12 @@ void popup_enable_timeout(Popup* popup); */ void popup_disable_timeout(Popup* popup); +/** Reset popup instance state + * + * @param popup Popup instance + */ +void popup_reset(Popup* popup); + #ifdef __cplusplus } #endif diff --git a/applications/gui/modules/submenu.c b/applications/gui/modules/submenu.c index 60a1b092..e9e27203 100644 --- a/applications/gui/modules/submenu.c +++ b/applications/gui/modules/submenu.c @@ -106,6 +106,14 @@ static bool submenu_view_input_callback(InputEvent* event, void* context) { default: break; } + } else if(event->type == InputTypeRepeat) { + if(event->key == InputKeyUp) { + consumed = true; + submenu_process_up(submenu); + } else if(event->key == InputKeyDown) { + consumed = true; + submenu_process_down(submenu); + } } return consumed; @@ -169,7 +177,7 @@ void submenu_add_item( }); } -void submenu_clean(Submenu* submenu) { +void submenu_reset(Submenu* submenu) { furi_assert(submenu); with_view_model( diff --git a/applications/gui/modules/submenu.h b/applications/gui/modules/submenu.h index fac29e15..f68abe83 100644 --- a/applications/gui/modules/submenu.h +++ b/applications/gui/modules/submenu.h @@ -57,7 +57,7 @@ void submenu_add_item( * * @param submenu Submenu instance */ -void submenu_clean(Submenu* submenu); +void submenu_reset(Submenu* submenu); /** Set submenu item selector * diff --git a/applications/gui/modules/text_box.c b/applications/gui/modules/text_box.c index 67bb042c..40a8c382 100755 --- a/applications/gui/modules/text_box.c +++ b/applications/gui/modules/text_box.c @@ -164,7 +164,7 @@ View* text_box_get_view(TextBox* text_box) { return text_box->view; } -void text_box_clean(TextBox* text_box) { +void text_box_reset(TextBox* text_box) { furi_assert(text_box); with_view_model( diff --git a/applications/gui/modules/text_box.h b/applications/gui/modules/text_box.h index 9aaa0485..6928adcb 100644 --- a/applications/gui/modules/text_box.h +++ b/applications/gui/modules/text_box.h @@ -44,7 +44,7 @@ View* text_box_get_view(TextBox* text_box); * * @param text_box TextBox instance */ -void text_box_clean(TextBox* text_box); +void text_box_reset(TextBox* text_box); /** Set text for text_box * diff --git a/applications/gui/modules/text_input.c b/applications/gui/modules/text_input.c index 2b31f71b..bb200606 100755 --- a/applications/gui/modules/text_input.c +++ b/applications/gui/modules/text_input.c @@ -4,6 +4,7 @@ struct TextInput { View* view; + osTimerId_t timer; }; typedef struct { @@ -23,6 +24,11 @@ typedef struct { uint8_t selected_row; uint8_t selected_column; + + TextInputValidatorCallback validator_callback; + void* validator_callback_context; + string_t validator_text; + bool valadator_message_visible; } TextInputModel; static const uint8_t keyboard_origin_x = 1; @@ -236,6 +242,17 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) { } } } + if(model->valadator_message_visible) { + canvas_set_font(canvas, FontSecondary); + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 8, 10, 110, 48); + canvas_set_color(canvas, ColorBlack); + canvas_draw_icon(canvas, 10, 14, &I_WarningDolphin_45x42); + canvas_draw_rframe(canvas, 8, 8, 112, 50, 3); + canvas_draw_rframe(canvas, 9, 9, 110, 48, 2); + elements_multiline_text(canvas, 62, 20, string_get_cstr(model->validator_text)); + canvas_set_font(canvas, FontKeyboard); + } } static void text_input_handle_up(TextInput* text_input) { @@ -295,7 +312,13 @@ static void text_input_handle_ok(TextInput* text_input) { uint8_t text_length = strlen(model->text_buffer); if(selected == ENTER_KEY) { - if(model->callback != 0 && text_length > 0) { + if(model->validator_callback && (!model->validator_callback( + model->text_buffer, + model->validator_text, + model->validator_callback_context))) { + model->valadator_message_visible = true; + osTimerStart(text_input->timer, osKernelGetTickFreq() * 4); + } else if(model->callback != 0 && text_length > 0) { model->callback(model->callback_context); } } else if(selected == BACKSPACE_KEY) { @@ -321,6 +344,16 @@ static bool text_input_view_input_callback(InputEvent* event, void* context) { bool consumed = false; if(event->type == InputTypeShort || event->type == InputTypeRepeat) { + with_view_model( + text_input->view, (TextInputModel * model) { + if(model->valadator_message_visible) { + if(event->key == InputKeyBack) { + consumed = true; + } + } + model->valadator_message_visible = false; + return false; + }); switch(event->key) { case InputKeyUp: text_input_handle_up(text_input); @@ -351,7 +384,11 @@ static bool text_input_view_input_callback(InputEvent* event, void* context) { event->key == InputKeyBack) { with_view_model( text_input->view, (TextInputModel * model) { - text_input_backspace_cb(model); + if(model->valadator_message_visible) { + model->valadator_message_visible = false; + } else { + text_input_backspace_cb(model); + } return true; }); @@ -361,6 +398,17 @@ static bool text_input_view_input_callback(InputEvent* event, void* context) { return consumed; } +void text_input_timer_callback(void* context) { + furi_assert(context); + TextInput* text_input = context; + + with_view_model( + text_input->view, (TextInputModel * model) { + model->valadator_message_visible = false; + return true; + }); +} + TextInput* text_input_alloc() { TextInput* text_input = furi_alloc(sizeof(TextInput)); text_input->view = view_alloc(); @@ -369,18 +417,40 @@ TextInput* text_input_alloc() { view_set_draw_callback(text_input->view, text_input_view_draw_callback); view_set_input_callback(text_input->view, text_input_view_input_callback); - text_input_clean(text_input); + text_input->timer = osTimerNew(text_input_timer_callback, osTimerOnce, text_input, NULL); + + with_view_model( + text_input->view, (TextInputModel * model) { + string_init(model->validator_text); + return false; + }); + + text_input_reset(text_input); return text_input; } void text_input_free(TextInput* text_input) { furi_assert(text_input); + with_view_model( + text_input->view, (TextInputModel * model) { + string_clear(model->validator_text); + return false; + }); + + // Send stop command + osTimerStop(text_input->timer); + // Wait till timer stop + while(osTimerIsRunning(text_input->timer)) osDelay(1); + // Release allocated memory + osTimerDelete(text_input->timer); + view_free(text_input->view); + free(text_input); } -void text_input_clean(TextInput* text_input) { +void text_input_reset(TextInput* text_input) { furi_assert(text_input); with_view_model( text_input->view, (TextInputModel * model) { @@ -393,6 +463,10 @@ void text_input_clean(TextInput* text_input) { model->text_buffer_size = 0; model->callback = NULL; model->callback_context = NULL; + model->validator_callback = NULL; + model->validator_callback_context = NULL; + string_reset(model->validator_text); + model->valadator_message_visible = false; return true; }); } @@ -425,10 +499,42 @@ void text_input_set_result_callback( }); } +void text_input_set_validator( + TextInput* text_input, + TextInputValidatorCallback callback, + void* callback_context) { + with_view_model( + text_input->view, (TextInputModel * model) { + model->validator_callback = callback; + model->validator_callback_context = callback_context; + return true; + }); +} + +TextInputValidatorCallback text_input_get_validator_callback(TextInput* text_input) { + TextInputValidatorCallback validator_callback = NULL; + with_view_model( + text_input->view, (TextInputModel * model) { + validator_callback = model->validator_callback; + return false; + }); + return validator_callback; +} + +void* text_input_get_validator_callback_context(TextInput* text_input) { + void* validator_callback_context = NULL; + with_view_model( + text_input->view, (TextInputModel * model) { + validator_callback_context = model->validator_callback_context; + return false; + }); + return validator_callback_context; +} + void text_input_set_header_text(TextInput* text_input, const char* text) { with_view_model( text_input->view, (TextInputModel * model) { model->header = text; return true; }); -} \ No newline at end of file +} diff --git a/applications/gui/modules/text_input.h b/applications/gui/modules/text_input.h index d7b32def..d30fcd4c 100644 --- a/applications/gui/modules/text_input.h +++ b/applications/gui/modules/text_input.h @@ -6,6 +6,8 @@ #pragma once #include +#include "validators.h" +#include #ifdef __cplusplus extern "C" { @@ -14,6 +16,7 @@ extern "C" { /** Text input anonymous structure */ typedef struct TextInput TextInput; typedef void (*TextInputCallback)(void* context); +typedef bool (*TextInputValidatorCallback)(const char* text, string_t error, void* context); /** Allocate and initialize text input * @@ -33,7 +36,7 @@ void text_input_free(TextInput* text_input); * * @param text_input Text input instance */ -void text_input_clean(TextInput* text_input); +void text_input_reset(TextInput* text_input); /** Get text input view * @@ -63,6 +66,15 @@ void text_input_set_result_callback( size_t text_buffer_size, bool clear_default_text); +void text_input_set_validator( + TextInput* text_input, + TextInputValidatorCallback callback, + void* callback_context); + +TextInputValidatorCallback text_input_get_validator_callback(TextInput* text_input); + +void* text_input_get_validator_callback_context(TextInput* text_input); + /** Set text input header text * * @param text_input TextInput instance @@ -72,4 +84,4 @@ void text_input_set_header_text(TextInput* text_input, const char* text); #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/applications/gui/modules/validators.c b/applications/gui/modules/validators.c new file mode 100644 index 00000000..dc752e95 --- /dev/null +++ b/applications/gui/modules/validators.c @@ -0,0 +1,42 @@ +#include +#include "validators.h" +#include "applications/storage/storage.h" + +struct ValidatorIsFile { + const char* app_path_folder; + const char* app_extension; +}; + +bool validator_is_file_callback(const char* text, string_t error, void* context) { + furi_assert(context); + ValidatorIsFile* instance = context; + bool ret = true; + string_t path; + string_init_printf(path, "%s/%s%s", instance->app_path_folder, text, instance->app_extension); + Storage* storage = furi_record_open("storage"); + if(storage_common_stat(storage, string_get_cstr(path), NULL) == FSE_OK) { + ret = false; + string_printf(error, "This name\nexists!\nChoose\nanother one."); + } else { + ret = true; + } + string_clear(path); + furi_record_close("storage"); + + return ret; +} + +ValidatorIsFile* + validator_is_file_alloc_init(const char* app_path_folder, const char* app_extension) { + ValidatorIsFile* instance = furi_alloc(sizeof(ValidatorIsFile)); + + instance->app_path_folder = app_path_folder; + instance->app_extension = app_extension; + + return instance; +} + +void validator_is_file_free(ValidatorIsFile* instance) { + furi_assert(instance); + free(instance); +} diff --git a/applications/gui/modules/validators.h b/applications/gui/modules/validators.h new file mode 100644 index 00000000..f62064b6 --- /dev/null +++ b/applications/gui/modules/validators.h @@ -0,0 +1,20 @@ +#pragma once + +// #include +#include + +#ifdef __cplusplus +extern "C" { +#endif +typedef struct ValidatorIsFile ValidatorIsFile; + +ValidatorIsFile* + validator_is_file_alloc_init(const char* app_path_folder, const char* app_extension); + +void validator_is_file_free(ValidatorIsFile* instance); + +bool validator_is_file_callback(const char* text, string_t error, void* context); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/gui/modules/variable_item_list.c b/applications/gui/modules/variable_item_list.c index f5226afd..cf2b01a1 100644 --- a/applications/gui/modules/variable_item_list.c +++ b/applications/gui/modules/variable_item_list.c @@ -71,7 +71,13 @@ static void variable_item_list_draw_callback(Canvas* canvas, void* _model) { canvas_draw_str(canvas, 73, item_text_y, "<"); } - canvas_draw_str(canvas, 80, item_text_y, string_get_cstr(item->current_value_text)); + canvas_draw_str_aligned( + canvas, + (115 + 73) / 2 + 1, + item_text_y, + AlignCenter, + AlignBottom, + string_get_cstr(item->current_value_text)); if(item->current_value_index < (item->values_count - 1)) { canvas_draw_str(canvas, 115, item_text_y, ">"); @@ -147,6 +153,27 @@ static bool variable_item_list_input_callback(InputEvent* event, void* context) default: break; } + } else if(event->type == InputTypeRepeat) { + switch(event->key) { + case InputKeyUp: + consumed = true; + variable_item_list_process_up(variable_item_list); + break; + case InputKeyDown: + consumed = true; + variable_item_list_process_down(variable_item_list); + break; + case InputKeyLeft: + consumed = true; + variable_item_list_process_left(variable_item_list); + break; + case InputKeyRight: + consumed = true; + variable_item_list_process_right(variable_item_list); + break; + default: + break; + } } return consumed; @@ -285,7 +312,7 @@ void variable_item_list_free(VariableItemList* variable_item_list) { free(variable_item_list); } -void variable_item_list_clean(VariableItemList* variable_item_list) { +void variable_item_list_reset(VariableItemList* variable_item_list) { furi_assert(variable_item_list); with_view_model( diff --git a/applications/gui/modules/variable_item_list.h b/applications/gui/modules/variable_item_list.h index 86878273..78c7769c 100755 --- a/applications/gui/modules/variable_item_list.h +++ b/applications/gui/modules/variable_item_list.h @@ -32,7 +32,7 @@ void variable_item_list_free(VariableItemList* variable_item_list); * * @param variable_item_list VariableItemList instance */ -void variable_item_list_clean(VariableItemList* variable_item_list); +void variable_item_list_reset(VariableItemList* variable_item_list); /** Get VariableItemList View instance * diff --git a/applications/gui/view_composed.c b/applications/gui/view_composed.c deleted file mode 100644 index 5815d9dd..00000000 --- a/applications/gui/view_composed.c +++ /dev/null @@ -1,166 +0,0 @@ -#include "gui/view.h" -#include "furi/memmgr.h" -#include "view_composed.h" -#include "view_i.h" - -typedef struct { - View* bottom; - View* top; - bool top_enabled; -} ViewComposedModel; - -struct ViewComposed { - View* view; -}; - -static void view_composed_draw(Canvas* canvas, void* model); -static bool view_composed_input(InputEvent* event, void* context); - -static void view_composed_update_callback(View* view_top_or_bottom, void* context) { - furi_assert(view_top_or_bottom); - furi_assert(context); - - View* view_composed_view = context; - view_composed_view->update_callback( - view_composed_view, view_composed_view->update_callback_context); -} - -static void view_composed_enter(void* context) { - furi_assert(context); - - ViewComposed* view_composed = context; - ViewComposedModel* model = view_get_model(view_composed->view); - - /* if more than 1 composed views hold same view it has to reassign update_callback_context */ - if(model->bottom) { - view_set_update_callback_context(model->bottom, view_composed->view); - if(model->bottom->enter_callback) { - model->bottom->enter_callback(model->bottom->context); - } - } - if(model->top) { - view_set_update_callback_context(model->top, view_composed->view); - if(model->top->enter_callback) { - model->top->enter_callback(model->top->context); - } - } - - view_commit_model(view_composed->view, false); -} - -static void view_composed_exit(void* context) { - furi_assert(context); - - ViewComposed* view_composed = context; - ViewComposedModel* model = view_get_model(view_composed->view); - - if(model->bottom) { - if(model->bottom->exit_callback) { - model->bottom->exit_callback(model->bottom->context); - } - } - if(model->top) { - if(model->top->exit_callback) { - model->top->exit_callback(model->top->context); - } - } - - view_commit_model(view_composed->view, false); -} - -ViewComposed* view_composed_alloc(void) { - ViewComposed* view_composed = furi_alloc(sizeof(ViewComposed)); - view_composed->view = view_alloc(); - - view_allocate_model(view_composed->view, ViewModelTypeLocking, sizeof(ViewComposedModel)); - view_set_draw_callback(view_composed->view, view_composed_draw); - view_set_input_callback(view_composed->view, view_composed_input); - view_set_context(view_composed->view, view_composed); - view_set_enter_callback(view_composed->view, view_composed_enter); - view_set_exit_callback(view_composed->view, view_composed_exit); - return view_composed; -} - -void view_composed_free(ViewComposed* view_composed) { - furi_assert(view_composed); - - ViewComposedModel* view_composed_model = view_get_model(view_composed->view); - view_set_update_callback(view_composed_model->bottom, NULL); - view_set_update_callback_context(view_composed_model->bottom, NULL); - view_set_update_callback(view_composed_model->top, NULL); - view_set_update_callback_context(view_composed_model->top, NULL); - view_commit_model(view_composed->view, true); - - view_free(view_composed->view); - free(view_composed); -} - -static void view_composed_draw(Canvas* canvas, void* model) { - furi_assert(model); - - ViewComposedModel* view_composed_model = model; - - view_draw(view_composed_model->bottom, canvas); - if(view_composed_model->top_enabled && view_composed_model->top) { - view_draw(view_composed_model->top, canvas); - } -} - -static bool view_composed_input(InputEvent* event, void* context) { - furi_assert(event); - furi_assert(context); - - ViewComposed* view_composed = context; - ViewComposedModel* view_composed_model = view_get_model(view_composed->view); - bool consumed = false; - - if(view_composed_model->top_enabled && view_composed_model->top) { - consumed = view_input(view_composed_model->top, event); - } - if(!consumed) { - consumed = view_input(view_composed_model->bottom, event); - } - - view_commit_model(view_composed->view, false); - - return consumed; -} - -void view_composed_top_enable(ViewComposed* view_composed, bool enable) { - furi_assert(view_composed); - - ViewComposedModel* view_composed_model = view_get_model(view_composed->view); - bool update = (view_composed_model->top_enabled != enable); - view_composed_model->top_enabled = enable; - view_commit_model(view_composed->view, update); -} - -void view_composed_tie_views(ViewComposed* view_composed, View* view_bottom, View* view_top) { - furi_assert(view_composed); - furi_assert(view_bottom); - - ViewComposedModel* view_composed_model = view_get_model(view_composed->view); - - if(view_composed_model->bottom) { - view_set_update_callback(view_composed_model->bottom, NULL); - view_set_update_callback_context(view_composed_model->bottom, NULL); - } - if(view_composed_model->top) { - view_set_update_callback(view_composed_model->top, NULL); - view_set_update_callback_context(view_composed_model->top, NULL); - } - - view_composed_model->bottom = view_bottom; - view_set_update_callback(view_bottom, view_composed_update_callback); - view_set_update_callback_context(view_bottom, view_composed->view); - view_composed_model->top = view_top; - view_set_update_callback(view_top, view_composed_update_callback); - view_set_update_callback_context(view_top, view_composed->view); - - view_commit_model(view_composed->view, true); -} - -View* view_composed_get_view(ViewComposed* view_composed) { - furi_assert(view_composed); - return view_composed->view; -} diff --git a/applications/gui/view_composed.h b/applications/gui/view_composed.h deleted file mode 100644 index eaf82b5c..00000000 --- a/applications/gui/view_composed.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include "view.h" - -typedef struct ViewComposed ViewComposed; - -ViewComposed* view_composed_alloc(void); -void view_composed_free(ViewComposed* view_composed); -void view_composed_top_enable(ViewComposed* view_composed, bool enable); -void view_composed_tie_views(ViewComposed* view_composed, View* view_bottom, View* view_top); -View* view_composed_get_view(ViewComposed* view_composed); diff --git a/applications/gui/view_stack.c b/applications/gui/view_stack.c new file mode 100644 index 00000000..d790b801 --- /dev/null +++ b/applications/gui/view_stack.c @@ -0,0 +1,166 @@ +#include "gui/view.h" +#include "furi/memmgr.h" +#include "view_stack.h" +#include "view_i.h" + +#define MAX_VIEWS 3 + +typedef struct { + View* views[MAX_VIEWS]; +} ViewStackModel; + +struct ViewStack { + View* view; +}; + +static void view_stack_draw(Canvas* canvas, void* model); +static bool view_stack_input(InputEvent* event, void* context); + +static void view_stack_update_callback(View* view_top_or_bottom, void* context) { + furi_assert(view_top_or_bottom); + furi_assert(context); + + View* view_stack_view = context; + if(view_stack_view->update_callback) { + view_stack_view->update_callback( + view_stack_view, view_stack_view->update_callback_context); + } +} + +static void view_stack_enter(void* context) { + furi_assert(context); + + ViewStack* view_stack = context; + ViewStackModel* model = view_get_model(view_stack->view); + + /* if more than 1 composite views hold same view they have to reassign update_callback_context */ + for(int i = 0; i < MAX_VIEWS; ++i) { + if(model->views[i]) { + view_set_update_callback_context(model->views[i], view_stack->view); + if(model->views[i]->enter_callback) { + model->views[i]->enter_callback(model->views[i]->context); + } + } + } + + view_commit_model(view_stack->view, false); +} + +static void view_stack_exit(void* context) { + furi_assert(context); + + ViewStack* view_stack = context; + ViewStackModel* model = view_get_model(view_stack->view); + + for(int i = 0; i < MAX_VIEWS; ++i) { + if(model->views[i] && model->views[i]->exit_callback) { + model->views[i]->exit_callback(model->views[i]->context); + } + } + + view_commit_model(view_stack->view, false); +} + +ViewStack* view_stack_alloc(void) { + ViewStack* view_stack = furi_alloc(sizeof(ViewStack)); + view_stack->view = view_alloc(); + + view_allocate_model(view_stack->view, ViewModelTypeLocking, sizeof(ViewStackModel)); + view_set_draw_callback(view_stack->view, view_stack_draw); + view_set_input_callback(view_stack->view, view_stack_input); + view_set_context(view_stack->view, view_stack); + view_set_enter_callback(view_stack->view, view_stack_enter); + view_set_exit_callback(view_stack->view, view_stack_exit); + return view_stack; +} + +void view_stack_free(ViewStack* view_stack) { + furi_assert(view_stack); + + ViewStackModel* model = view_get_model(view_stack->view); + for(int i = 0; i < MAX_VIEWS; ++i) { + if(model->views[i]) { + view_set_update_callback(model->views[i], NULL); + view_set_update_callback_context(model->views[i], NULL); + } + } + view_commit_model(view_stack->view, false); + + view_free(view_stack->view); + free(view_stack); +} + +static void view_stack_draw(Canvas* canvas, void* _model) { + furi_assert(_model); + + ViewStackModel* model = _model; + for(int i = 0; i < MAX_VIEWS; ++i) { + if(model->views[i]) { + view_draw(model->views[i], canvas); + } + } +} + +static bool view_stack_input(InputEvent* event, void* context) { + furi_assert(event); + furi_assert(context); + + ViewStack* view_stack = context; + + bool consumed = false; + ViewStackModel* model = view_get_model(view_stack->view); + for(int i = MAX_VIEWS - 1; i >= 0; i--) { + if(model->views[i] && view_input(model->views[i], event)) { + consumed = true; + break; + } + } + view_commit_model(view_stack->view, false); + + return consumed; +} + +void view_stack_add_view(ViewStack* view_stack, View* view) { + furi_assert(view_stack); + furi_assert(view); + + bool result = false; + ViewStackModel* model = view_get_model(view_stack->view); + for(int i = 0; i < MAX_VIEWS; ++i) { + if(!model->views[i]) { + model->views[i] = view; + view_set_update_callback(model->views[i], view_stack_update_callback); + view_set_update_callback_context(model->views[i], view_stack->view); + result = true; + break; + } + } + view_commit_model(view_stack->view, result); + furi_assert(result); +} + +void view_stack_remove_view(ViewStack* view_stack, View* view) { + furi_assert(view_stack); + furi_assert(view); + + /* Removing view on-the-go is dangerous, but it is protected with + * Locking model, so system is consistent at any time. */ + bool result = false; + ViewStackModel* model = view_get_model(view_stack->view); + for(int i = 0; i < MAX_VIEWS; ++i) { + if(model->views[i] == view) { + view_set_update_callback(model->views[i], NULL); + view_set_update_callback_context(model->views[i], NULL); + model->views[i] = NULL; + result = true; + break; + } + } + view_commit_model(view_stack->view, result); + furi_assert(result); +} + +View* view_stack_get_view(ViewStack* view_stack) { + furi_assert(view_stack); + return view_stack->view; +} diff --git a/applications/gui/view_stack.h b/applications/gui/view_stack.h new file mode 100644 index 00000000..f733e6ad --- /dev/null +++ b/applications/gui/view_stack.h @@ -0,0 +1,53 @@ +/** + * @file view_stack.h + * GUI: ViewStack API + * + * ViewStack accumulates several Views in one stack. + * Draw callbacks are called sequenctially starting from + * first added. Input callbacks are called in reverse order. + * Consumed input is not passed on underlying layers. + */ + +#pragma once + +#include +#include "view.h" + +/** ViewStack, anonymous type. */ +typedef struct ViewStack ViewStack; + +/** Allocate and init ViewStack + * + * @return ViewStack instance + */ +ViewStack* view_stack_alloc(void); + +/** Free ViewStack instance + * + * @param view_stack instance + */ +void view_stack_free(ViewStack* view_stack); + +/** Get View of ViewStack. + * Should this View to any view manager such as + * ViewDispatcher or ViewHolder. + * + * @param view_stack instance + */ +View* view_stack_get_view(ViewStack* view_stack); + +/** Add View to ViewStack. + * Adds View on top of ViewStack. + * + * @param view_stack instance + * @view view view to add + */ +void view_stack_add_view(ViewStack* view_stack, View* view); + +/** Remove any View in ViewStack. + * If no View to remove found - ignore. + * + * @param view_stack instance + * @view view view to remove + */ +void view_stack_remove_view(ViewStack* view_stack, View* view); diff --git a/applications/ibutton/ibutton_app.h b/applications/ibutton/ibutton_app.h index 402d4cdf..fc2a32e7 100644 --- a/applications/ibutton/ibutton_app.h +++ b/applications/ibutton/ibutton_app.h @@ -64,6 +64,10 @@ public: 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); @@ -137,10 +141,6 @@ private: static const uint8_t text_store_size = 128; char text_store[text_store_size + 1]; - static const char* app_folder; - static const char* app_extension; - static const char* app_filetype; - bool load_key_data(string_t key_path); void make_app_folder(); }; \ No newline at end of file diff --git a/applications/ibutton/scene/ibutton_scene_add_type.cpp b/applications/ibutton/scene/ibutton_scene_add_type.cpp index 4414be85..0c573f41 100644 --- a/applications/ibutton/scene/ibutton_scene_add_type.cpp +++ b/applications/ibutton/scene/ibutton_scene_add_type.cpp @@ -52,7 +52,7 @@ void iButtonSceneAddType::on_exit(iButtonApp* app) { iButtonAppViewManager* view = app->get_view_manager(); Submenu* submenu = view->get_submenu(); - submenu_clean(submenu); + submenu_reset(submenu); } void iButtonSceneAddType::submenu_callback(void* context, uint32_t index) { @@ -63,4 +63,4 @@ void iButtonSceneAddType::submenu_callback(void* context, uint32_t index) { event.payload.menu_index = index; app->get_view_manager()->send_event(&event); -} \ No newline at end of file +} diff --git a/applications/ibutton/scene/ibutton_scene_add_value.cpp b/applications/ibutton/scene/ibutton_scene_add_value.cpp index 39a6aa4a..d91408b6 100755 --- a/applications/ibutton/scene/ibutton_scene_add_value.cpp +++ b/applications/ibutton/scene/ibutton_scene_add_value.cpp @@ -3,6 +3,7 @@ #include "../ibutton_view_manager.h" #include "../ibutton_event.h" #include +#include void iButtonSceneAddValue::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); @@ -20,6 +21,7 @@ bool iButtonSceneAddValue::on_event(iButtonApp* app, iButtonEvent* event) { bool consumed = false; if(event->type == iButtonEvent::Type::EventTypeByteEditResult) { + DOLPHIN_DEED(DolphinDeedIbuttonAdd); app->switch_to_next_scene(iButtonApp::Scene::SceneSaveName); consumed = true; } @@ -42,4 +44,4 @@ void iButtonSceneAddValue::byte_input_callback(void* context) { event.type = iButtonEvent::Type::EventTypeByteEditResult; memcpy(app->get_key()->get_data(), this->new_key_data, app->get_key()->get_type_data_size()); app->get_view_manager()->send_event(&event); -} \ No newline at end of file +} diff --git a/applications/ibutton/scene/ibutton_scene_emulate.cpp b/applications/ibutton/scene/ibutton_scene_emulate.cpp index 621c08d1..7fe6df28 100644 --- a/applications/ibutton/scene/ibutton_scene_emulate.cpp +++ b/applications/ibutton/scene/ibutton_scene_emulate.cpp @@ -3,6 +3,7 @@ #include "../ibutton_view_manager.h" #include "../ibutton_event.h" #include "../ibutton_key.h" +#include #include void iButtonSceneEmulate::on_enter(iButtonApp* app) { @@ -12,6 +13,7 @@ void iButtonSceneEmulate::on_enter(iButtonApp* app) { uint8_t* key_data = key->get_data(); const char* key_name = key->get_name(); uint8_t line_count = 2; + DOLPHIN_DEED(DolphinDeedIbuttonEmulate); // check that stored key has name if(strcmp(key_name, "") != 0) { @@ -90,4 +92,4 @@ void iButtonSceneEmulate::on_exit(iButtonApp* app) { 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); -} \ No newline at end of file +} diff --git a/applications/ibutton/scene/ibutton_scene_read.cpp b/applications/ibutton/scene/ibutton_scene_read.cpp index daf5446b..a16cb23d 100644 --- a/applications/ibutton/scene/ibutton_scene_read.cpp +++ b/applications/ibutton/scene/ibutton_scene_read.cpp @@ -2,10 +2,12 @@ #include "../ibutton_app.h" #include "../ibutton_view_manager.h" #include "../ibutton_event.h" +#include void iButtonSceneRead::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Popup* popup = view_manager->get_popup(); + DOLPHIN_DEED(DolphinDeedIbuttonRead); popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom); popup_set_text(popup, "waiting\nfor key ...", 95, 30, AlignCenter, AlignTop); @@ -50,4 +52,4 @@ void iButtonSceneRead::on_exit(iButtonApp* app) { 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); -} \ No newline at end of file +} diff --git a/applications/ibutton/scene/ibutton_scene_read_success.cpp b/applications/ibutton/scene/ibutton_scene_read_success.cpp index 1c6a5e64..afeb154f 100644 --- a/applications/ibutton/scene/ibutton_scene_read_success.cpp +++ b/applications/ibutton/scene/ibutton_scene_read_success.cpp @@ -2,12 +2,14 @@ #include "../ibutton_app.h" #include "../ibutton_view_manager.h" #include "../ibutton_event.h" +#include #include void iButtonSceneReadSuccess::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); DialogEx* dialog_ex = view_manager->get_dialog_ex(); auto callback = cbc::obtain_connector(this, &iButtonSceneReadSuccess::dialog_ex_callback); + DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); iButtonKey* key = app->get_key(); uint8_t* key_data = key->get_data(); @@ -87,4 +89,4 @@ void iButtonSceneReadSuccess::dialog_ex_callback(DialogExResult result, void* co event.payload.dialog_result = result; app->get_view_manager()->send_event(&event); -} \ No newline at end of file +} diff --git a/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp b/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp index 2a8ea36c..e832c7e6 100644 --- a/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp +++ b/applications/ibutton/scene/ibutton_scene_readed_key_menu.cpp @@ -57,7 +57,7 @@ void iButtonSceneReadedKeyMenu::on_exit(iButtonApp* app) { iButtonAppViewManager* view = app->get_view_manager(); Submenu* submenu = view->get_submenu(); - submenu_clean(submenu); + submenu_reset(submenu); } void iButtonSceneReadedKeyMenu::submenu_callback(void* context, uint32_t index) { @@ -68,4 +68,4 @@ void iButtonSceneReadedKeyMenu::submenu_callback(void* context, uint32_t index) event.payload.menu_index = index; app->get_view_manager()->send_event(&event); -} \ No newline at end of file +} diff --git a/applications/ibutton/scene/ibutton_scene_save_name.cpp b/applications/ibutton/scene/ibutton_scene_save_name.cpp index a59ee552..0d5c5900 100644 --- a/applications/ibutton/scene/ibutton_scene_save_name.cpp +++ b/applications/ibutton/scene/ibutton_scene_save_name.cpp @@ -25,6 +25,10 @@ void iButtonSceneSaveName::on_enter(iButtonApp* app) { text_input_set_result_callback( 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); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewTextInput); } @@ -48,7 +52,12 @@ bool iButtonSceneSaveName::on_event(iButtonApp* app, iButtonEvent* event) { void iButtonSceneSaveName::on_exit(iButtonApp* app) { TextInput* text_input = app->get_view_manager()->get_text_input(); - text_input_clean(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); } void iButtonSceneSaveName::text_input_callback(void* context) { @@ -58,4 +67,4 @@ void iButtonSceneSaveName::text_input_callback(void* context) { event.type = iButtonEvent::Type::EventTypeTextEditResult; app->get_view_manager()->send_event(&event); -} \ No newline at end of file +} diff --git a/applications/ibutton/scene/ibutton_scene_save_success.cpp b/applications/ibutton/scene/ibutton_scene_save_success.cpp index 04279052..c652e5d1 100644 --- a/applications/ibutton/scene/ibutton_scene_save_success.cpp +++ b/applications/ibutton/scene/ibutton_scene_save_success.cpp @@ -3,12 +3,14 @@ #include "../ibutton_view_manager.h" #include "../ibutton_event.h" #include "../ibutton_key.h" +#include #include void iButtonSceneSaveSuccess::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Popup* popup = view_manager->get_popup(); auto callback = cbc::obtain_connector(this, &iButtonSceneSaveSuccess::popup_callback); + DOLPHIN_DEED(DolphinDeedIbuttonSave); popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); popup_set_text(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); @@ -51,4 +53,4 @@ void iButtonSceneSaveSuccess::popup_callback(void* context) { iButtonEvent event; event.type = iButtonEvent::Type::EventTypeBack; app->get_view_manager()->send_event(&event); -} \ No newline at end of file +} diff --git a/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp b/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp index 80cf9565..8b797968 100644 --- a/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp +++ b/applications/ibutton/scene/ibutton_scene_saved_key_menu.cpp @@ -59,7 +59,7 @@ void iButtonSceneSavedKeyMenu::on_exit(iButtonApp* app) { iButtonAppViewManager* view = app->get_view_manager(); Submenu* submenu = view->get_submenu(); - submenu_clean(submenu); + submenu_reset(submenu); } void iButtonSceneSavedKeyMenu::submenu_callback(void* context, uint32_t index) { @@ -70,4 +70,4 @@ void iButtonSceneSavedKeyMenu::submenu_callback(void* context, uint32_t index) { event.payload.menu_index = index; app->get_view_manager()->send_event(&event); -} \ No newline at end of file +} diff --git a/applications/ibutton/scene/ibutton_scene_start.cpp b/applications/ibutton/scene/ibutton_scene_start.cpp index ccd2a90a..9d064aad 100644 --- a/applications/ibutton/scene/ibutton_scene_start.cpp +++ b/applications/ibutton/scene/ibutton_scene_start.cpp @@ -49,7 +49,7 @@ void iButtonSceneStart::on_exit(iButtonApp* app) { iButtonAppViewManager* view = app->get_view_manager(); Submenu* submenu = view->get_submenu(); - submenu_clean(submenu); + submenu_reset(submenu); } void iButtonSceneStart::submenu_callback(void* context, uint32_t index) { @@ -60,4 +60,4 @@ void iButtonSceneStart::submenu_callback(void* context, uint32_t index) { event.payload.menu_index = index; app->get_view_manager()->send_event(&event); -} \ No newline at end of file +} diff --git a/applications/irda/scene/irda_app_scene_edit.cpp b/applications/irda/scene/irda_app_scene_edit.cpp index a66bdc4b..bb26ca11 100644 --- a/applications/irda/scene/irda_app_scene_edit.cpp +++ b/applications/irda/scene/irda_app_scene_edit.cpp @@ -75,5 +75,5 @@ void IrdaAppSceneEdit::on_exit(IrdaApp* app) { IrdaAppViewManager* view_manager = app->get_view_manager(); Submenu* submenu = view_manager->get_submenu(); - submenu_clean(submenu); + submenu_reset(submenu); } diff --git a/applications/irda/scene/irda_app_scene_edit_key_select.cpp b/applications/irda/scene/irda_app_scene_edit_key_select.cpp index 33a74c8d..7d805cd6 100644 --- a/applications/irda/scene/irda_app_scene_edit_key_select.cpp +++ b/applications/irda/scene/irda_app_scene_edit_key_select.cpp @@ -53,5 +53,5 @@ void IrdaAppSceneEditKeySelect::on_exit(IrdaApp* app) { IrdaAppViewManager* view_manager = app->get_view_manager(); Submenu* submenu = view_manager->get_submenu(); - submenu_clean(submenu); + submenu_reset(submenu); } diff --git a/applications/irda/scene/irda_app_scene_edit_rename.cpp b/applications/irda/scene/irda_app_scene_edit_rename.cpp index f9253eaf..db6b8e4d 100644 --- a/applications/irda/scene/irda_app_scene_edit_rename.cpp +++ b/applications/irda/scene/irda_app_scene_edit_rename.cpp @@ -20,6 +20,10 @@ void IrdaAppSceneEditRename::on_enter(IrdaApp* app) { strncpy(app->get_text_store(0), remote_name.c_str(), app->get_text_store_size()); enter_name_length = IrdaAppRemoteManager::max_remote_name_length; text_input_set_header_text(text_input, "Name the remote"); + + ValidatorIsFile* validator_is_file = + validator_is_file_alloc_init(app->irda_directory, app->irda_extension); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); } text_input_set_result_callback( @@ -59,4 +63,10 @@ bool IrdaAppSceneEditRename::on_event(IrdaApp* app, IrdaAppEvent* event) { } void IrdaAppSceneEditRename::on_exit(IrdaApp* 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); + + if(validator_context != NULL) validator_is_file_free((ValidatorIsFile*)validator_context); } diff --git a/applications/irda/scene/irda_app_scene_learn_done.cpp b/applications/irda/scene/irda_app_scene_learn_done.cpp index 1ffebc56..c659b5ce 100644 --- a/applications/irda/scene/irda_app_scene_learn_done.cpp +++ b/applications/irda/scene/irda_app_scene_learn_done.cpp @@ -1,10 +1,12 @@ #include "../irda_app.h" +#include void IrdaAppSceneLearnDone::on_enter(IrdaApp* app) { IrdaAppViewManager* view_manager = app->get_view_manager(); Popup* popup = view_manager->get_popup(); popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + DOLPHIN_DEED(DolphinDeedIrSave); if(app->get_learn_new_remote()) { popup_set_text(popup, "New remote\ncreated!", 5, 7, AlignLeft, AlignTop); diff --git a/applications/irda/scene/irda_app_scene_learn_success.cpp b/applications/irda/scene/irda_app_scene_learn_success.cpp index f34d2774..d7bd85d2 100644 --- a/applications/irda/scene/irda_app_scene_learn_success.cpp +++ b/applications/irda/scene/irda_app_scene_learn_success.cpp @@ -2,6 +2,7 @@ #include #include "irda.h" #include +#include static void dialog_result_callback(DialogExResult result, void* context) { auto app = static_cast(context); @@ -17,6 +18,7 @@ void IrdaAppSceneLearnSuccess::on_enter(IrdaApp* app) { IrdaAppViewManager* view_manager = app->get_view_manager(); DialogEx* dialog_ex = view_manager->get_dialog_ex(); + DOLPHIN_DEED(DolphinDeedIrLearnSuccess); app->notify_green_on(); auto signal = app->get_received_signal(); diff --git a/applications/irda/scene/irda_app_scene_remote.cpp b/applications/irda/scene/irda_app_scene_remote.cpp index a19235cb..7138eb44 100644 --- a/applications/irda/scene/irda_app_scene_remote.cpp +++ b/applications/irda/scene/irda_app_scene_remote.cpp @@ -2,6 +2,7 @@ #include "gui/modules/button_menu.h" #include "input/input.h" #include "irda_worker.h" +#include typedef enum { ButtonIndexPlus = -2, @@ -106,6 +107,7 @@ bool IrdaAppSceneRemote::on_event(IrdaApp* app, IrdaAppEvent* event) { app->get_irda_worker(), &button_signal.get_message()); } + DOLPHIN_DEED(DolphinDeedIrSend); irda_worker_tx_start(app->get_irda_worker()); } else if(!pressed && button_pressed) { button_pressed = false; @@ -132,5 +134,5 @@ void IrdaAppSceneRemote::on_exit(IrdaApp* app) { IrdaAppViewManager* view_manager = app->get_view_manager(); ButtonMenu* button_menu = view_manager->get_button_menu(); - button_menu_clean(button_menu); + button_menu_reset(button_menu); } diff --git a/applications/irda/scene/irda_app_scene_start.cpp b/applications/irda/scene/irda_app_scene_start.cpp index be372d1b..62dcbbc5 100644 --- a/applications/irda/scene/irda_app_scene_start.cpp +++ b/applications/irda/scene/irda_app_scene_start.cpp @@ -62,5 +62,5 @@ void IrdaAppSceneStart::on_exit(IrdaApp* app) { Submenu* submenu = view_manager->get_submenu(); app->get_remote_manager()->reset_remote(); - submenu_clean(submenu); + submenu_reset(submenu); } diff --git a/applications/irda/scene/irda_app_scene_universal.cpp b/applications/irda/scene/irda_app_scene_universal.cpp index 65df44c6..01134400 100644 --- a/applications/irda/scene/irda_app_scene_universal.cpp +++ b/applications/irda/scene/irda_app_scene_universal.cpp @@ -53,5 +53,5 @@ void IrdaAppSceneUniversal::on_exit(IrdaApp* app) { IrdaAppViewManager* view_manager = app->get_view_manager(); Submenu* submenu = view_manager->get_submenu(); - submenu_clean(submenu); + submenu_reset(submenu); } diff --git a/applications/irda/scene/irda_app_scene_universal_common.cpp b/applications/irda/scene/irda_app_scene_universal_common.cpp index d61fb8ad..1b54791d 100644 --- a/applications/irda/scene/irda_app_scene_universal_common.cpp +++ b/applications/irda/scene/irda_app_scene_universal_common.cpp @@ -1,5 +1,6 @@ #include "../irda_app.h" #include "assets_icons.h" +#include #include "gui/modules/button_menu.h" #include "gui/modules/button_panel.h" #include "../view/irda_app_brut_view.h" @@ -84,6 +85,7 @@ bool IrdaAppSceneUniversalCommon::on_event(IrdaApp* app, IrdaAppEvent* event) { if(event->type == IrdaAppEvent::Type::ButtonPanelPressed) { int record_amount = 0; if(brute_force.start_bruteforce(event->payload.menu_index, record_amount)) { + DOLPHIN_DEED(DolphinDeedIrBruteForce); brute_force_started = true; show_popup(app, record_amount); } else { @@ -102,5 +104,5 @@ bool IrdaAppSceneUniversalCommon::on_event(IrdaApp* app, IrdaAppEvent* event) { void IrdaAppSceneUniversalCommon::on_exit(IrdaApp* app) { IrdaAppViewManager* view_manager = app->get_view_manager(); ButtonPanel* button_panel = view_manager->get_button_panel(); - button_panel_clean(button_panel); + button_panel_reset(button_panel); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp b/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp index c3d2621f..8f8fe9af 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp @@ -35,9 +35,9 @@ void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool need_restore) { string_printf(string_header, "Delete %s?", key.get_name()); line_1->set_text( - string_get_cstr(string_header), 64, 19, AlignCenter, AlignBottom, FontPrimary); + string_get_cstr(string_header), 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary); line_2->set_text( - string_get_cstr(string_data), 64, 29, AlignCenter, AlignBottom, FontSecondary); + string_get_cstr(string_data), 64, 29, 0, AlignCenter, AlignBottom, FontSecondary); switch(key.get_type()) { case LfrfidKeyType::KeyEM4100: @@ -52,12 +52,13 @@ void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool need_restore) { break; } line_3->set_text( - string_get_cstr(string_decrypted), 64, 39, AlignCenter, AlignBottom, FontSecondary); + string_get_cstr(string_decrypted), 64, 39, 0, AlignCenter, AlignBottom, FontSecondary); line_4->set_text( lfrfid_key_get_type_string(key.get_type()), 64, 49, + 0, AlignCenter, AlignBottom, FontSecondary); diff --git a/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp b/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp index 69b291cc..a46286d0 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp @@ -1,8 +1,10 @@ #include "lfrfid_app_scene_emulate.h" +#include void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool need_restore) { string_init(data_string); + DOLPHIN_DEED(DolphinDeedRfidEmulate); const uint8_t* data = app->worker.key.get_data(); for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read.cpp index eec1e0d9..f5608fe4 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_read.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_read.cpp @@ -1,8 +1,10 @@ #include "lfrfid_app_scene_read.h" +#include void LfRfidAppSceneRead::on_enter(LfRfidApp* app, bool need_restore) { auto popup = app->view_controller.get(); + DOLPHIN_DEED(DolphinDeedRfidRead); popup->set_header("Reading\nLF RFID", 89, 34, AlignCenter, AlignTop); popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61); @@ -15,6 +17,7 @@ bool LfRfidAppSceneRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) { if(event->type == LfRfidApp::EventType::Tick) { if(app->worker.read()) { + DOLPHIN_DEED(DolphinDeedRfidReadSuccess); notification_message(app->notification, &sequence_success); app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadSuccess); } else { diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp index 70dc208c..a86f77e6 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp @@ -22,7 +22,7 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool need_restore) { icon->set_icon(3, 12, &I_RFIDBigChip_37x36); auto header = container->add(); - header->set_text(app->worker.key.get_type_text(), 89, 3, AlignCenter); + header->set_text(app->worker.key.get_type_text(), 89, 3, 0, AlignCenter); auto line_1_text = container->add(); auto line_2_text = container->add(); @@ -36,9 +36,9 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool need_restore) { switch(app->worker.key.get_type()) { case LfrfidKeyType::KeyEM4100: - line_1_text->set_text("HEX:", 65, 23, AlignRight, AlignBottom, FontSecondary); - line_2_text->set_text("Mod:", 65, 35, AlignRight, AlignBottom, FontSecondary); - line_3_text->set_text("ID:", 65, 47, AlignRight, AlignBottom, FontSecondary); + line_1_text->set_text("HEX:", 65, 23, 0, AlignRight, AlignBottom, FontSecondary); + line_2_text->set_text("Mod:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary); + line_3_text->set_text("ID:", 65, 47, 0, AlignRight, AlignBottom, FontSecondary); for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { string_cat_printf(string[0], "%02X", data[i]); @@ -48,17 +48,17 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool need_restore) { string_printf(string[2], "%03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); line_1_value->set_text( - string_get_cstr(string[0]), 68, 23, AlignLeft, AlignBottom, FontSecondary); + string_get_cstr(string[0]), 68, 23, 0, AlignLeft, AlignBottom, FontSecondary); line_2_value->set_text( - string_get_cstr(string[1]), 68, 35, AlignLeft, AlignBottom, FontSecondary); + string_get_cstr(string[1]), 68, 35, 0, AlignLeft, AlignBottom, FontSecondary); line_3_value->set_text( - string_get_cstr(string[2]), 68, 47, AlignLeft, AlignBottom, FontSecondary); + string_get_cstr(string[2]), 68, 47, 0, AlignLeft, AlignBottom, FontSecondary); break; case LfrfidKeyType::KeyH10301: case LfrfidKeyType::KeyI40134: - line_1_text->set_text("HEX:", 65, 23, AlignRight, AlignBottom, FontSecondary); - line_2_text->set_text("FC:", 65, 35, AlignRight, AlignBottom, FontSecondary); - line_3_text->set_text("Card:", 65, 47, AlignRight, AlignBottom, FontSecondary); + line_1_text->set_text("HEX:", 65, 23, 0, AlignRight, AlignBottom, FontSecondary); + line_2_text->set_text("FC:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary); + line_3_text->set_text("Card:", 65, 47, 0, AlignRight, AlignBottom, FontSecondary); for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { string_cat_printf(string[0], "%02X", data[i]); @@ -68,11 +68,11 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool need_restore) { string_printf(string[2], "%u", (uint16_t)((data[1] << 8) | (data[2]))); line_1_value->set_text( - string_get_cstr(string[0]), 68, 23, AlignLeft, AlignBottom, FontSecondary); + string_get_cstr(string[0]), 68, 23, 0, AlignLeft, AlignBottom, FontSecondary); line_2_value->set_text( - string_get_cstr(string[1]), 68, 35, AlignLeft, AlignBottom, FontSecondary); + string_get_cstr(string[1]), 68, 35, 0, AlignLeft, AlignBottom, FontSecondary); line_3_value->set_text( - string_get_cstr(string[2]), 68, 47, AlignLeft, AlignBottom, FontSecondary); + string_get_cstr(string[2]), 68, 47, 0, AlignLeft, AlignBottom, FontSecondary); break; } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp index 14e8d89b..b36ff7e3 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp @@ -1,4 +1,5 @@ #include "lfrfid_app_scene_save_data.h" +#include static void print_buffer(const uint8_t* buffer) { for(uint8_t i = 0; i < LFRFID_KEY_SIZE; i++) { @@ -40,6 +41,7 @@ bool LfRfidAppSceneSaveData::on_event(LfRfidApp* app, LfRfidApp::Event* event) { if(event->type == LfRfidApp::EventType::Next) { key.set_data(new_key_data, key.get_type_data_count()); + DOLPHIN_DEED(DolphinDeedRfidAdd); app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp old mode 100755 new mode 100644 index 76165941..e5fee4fe --- a/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp @@ -21,6 +21,10 @@ void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool need_restore) { app->worker.key.get_name_length(), key_name_empty); + ValidatorIsFile* validator_is_file = + validator_is_file_alloc_init(app->app_folder, app->app_extension); + text_input->set_validator(validator_is_file_callback, validator_is_file); + app->view_controller.switch_to(); } @@ -46,6 +50,11 @@ bool LfRfidAppSceneSaveName::on_event(LfRfidApp* app, LfRfidApp::Event* event) { } void LfRfidAppSceneSaveName::on_exit(LfRfidApp* app) { + void* validator_context = + app->view_controller.get()->get_validator_callback_context(); + app->view_controller.get()->set_validator(NULL, NULL); + validator_is_file_free((ValidatorIsFile*)validator_context); + app->view_controller.get()->clean(); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_save_success.cpp index 6300edad..3a37da86 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_success.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_save_success.cpp @@ -1,8 +1,12 @@ #include "lfrfid_app_scene_save_success.h" +#include +#include +#include void LfRfidAppSceneSaveSuccess::on_enter(LfRfidApp* app, bool need_restore) { auto popup = app->view_controller.get(); + DOLPHIN_DEED(DolphinDeedRfidSave); popup->set_icon(32, 5, &I_DolphinNice_96x59); popup->set_text("Saved!", 13, 22, AlignLeft, AlignBottom); popup->set_context(app); @@ -43,4 +47,4 @@ void LfRfidAppSceneSaveSuccess::timeout_callback(void* context) { LfRfidApp::Event event; event.type = LfRfidApp::EventType::Back; app->view_controller.send_event(&event); -} \ No newline at end of file +} diff --git a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp b/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp index 45463d46..b054e141 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp @@ -28,8 +28,9 @@ void LfRfidAppSceneSavedInfo::on_enter(LfRfidApp* app, bool need_restore) { string_cat_printf(string_data, "%02X", data[i]); } - line_1->set_text(key.get_name(), 64, 17, AlignCenter, AlignBottom, FontSecondary); - line_2->set_text(string_get_cstr(string_data), 64, 29, AlignCenter, AlignBottom, FontPrimary); + line_1->set_text(key.get_name(), 64, 17, 128 - 2, AlignCenter, AlignBottom, FontSecondary); + line_2->set_text( + string_get_cstr(string_data), 64, 29, 0, AlignCenter, AlignBottom, FontPrimary); switch(key.get_type()) { case LfrfidKeyType::KeyEM4100: @@ -44,12 +45,13 @@ void LfRfidAppSceneSavedInfo::on_enter(LfRfidApp* app, bool need_restore) { break; } line_3->set_text( - string_get_cstr(string_decrypted), 64, 39, AlignCenter, AlignBottom, FontSecondary); + string_get_cstr(string_decrypted), 64, 39, 0, AlignCenter, AlignBottom, FontSecondary); line_4->set_text( lfrfid_key_get_type_string(key.get_type()), 64, 49, + 0, AlignCenter, AlignBottom, FontSecondary); diff --git a/applications/lfrfid/view/elements/string_element.cpp b/applications/lfrfid/view/elements/string_element.cpp index 92bb7abd..028bd7fd 100644 --- a/applications/lfrfid/view/elements/string_element.cpp +++ b/applications/lfrfid/view/elements/string_element.cpp @@ -9,8 +9,17 @@ StringElement::~StringElement() { void StringElement::draw(Canvas* canvas) { if(text) { + string_t line; + string_init(line); + string_set_str(line, text); + canvas_set_font(canvas, font); - elements_multiline_text_aligned(canvas, x, y, horizontal, vertical, text); + if(fit_width != 0) { + elements_string_fit_width(canvas, line, fit_width); + } + elements_multiline_text_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(line)); + + string_clear(line); } } @@ -22,6 +31,7 @@ void StringElement::set_text( const char* _text, uint8_t _x, uint8_t _y, + uint8_t _fit_w, Align _horizontal, Align _vertical, Font _font) { @@ -29,8 +39,9 @@ void StringElement::set_text( text = _text; x = _x; y = _y; + fit_width = _fit_w; horizontal = _horizontal; vertical = _vertical; font = _font; unlock_model(true); -} +} \ No newline at end of file diff --git a/applications/lfrfid/view/elements/string_element.h b/applications/lfrfid/view/elements/string_element.h index 4bc5364d..173fdd60 100644 --- a/applications/lfrfid/view/elements/string_element.h +++ b/applications/lfrfid/view/elements/string_element.h @@ -12,6 +12,7 @@ public: const char* text = NULL, uint8_t x = 0, uint8_t y = 0, + uint8_t fit_width = 0, Align horizontal = AlignLeft, Align vertical = AlignTop, Font font = FontPrimary); @@ -20,6 +21,7 @@ private: const char* text = NULL; uint8_t x = 0; uint8_t y = 0; + uint8_t fit_width = 0; Align horizontal = AlignLeft; Align vertical = AlignTop; Font font = FontPrimary; diff --git a/applications/loader/loader.c b/applications/loader/loader.c index 4cb2e209..d131de49 100644 --- a/applications/loader/loader.c +++ b/applications/loader/loader.c @@ -1,4 +1,4 @@ -#include +#include #include "loader/loader.h" #include "loader_i.h" @@ -429,7 +429,7 @@ void loader_show_menu() { } void loader_update_menu() { - menu_clean(loader_instance->primary_menu); + menu_reset(loader_instance->primary_menu); loader_build_menu(); } @@ -464,11 +464,12 @@ int32_t loader_srv(void* p) { } } + furi_record_destroy("loader"); loader_free(loader_instance); return 0; } -FuriPubSub* loader_get_pubsub() { - return loader_instance->pubsub; +FuriPubSub* loader_get_pubsub(Loader* instance) { + return instance->pubsub; } diff --git a/applications/loader/loader.h b/applications/loader/loader.h index edfa01b8..b65539fe 100644 --- a/applications/loader/loader.h +++ b/applications/loader/loader.h @@ -46,4 +46,4 @@ void loader_show_menu(); void loader_update_menu(); /** Show primary loader */ -FuriPubSub* loader_get_pubsub(); +FuriPubSub* loader_get_pubsub(Loader* instance); diff --git a/applications/nfc/nfc_device.c b/applications/nfc/nfc_device.c index cfd0db2d..d6996b3f 100755 --- a/applications/nfc/nfc_device.c +++ b/applications/nfc/nfc_device.c @@ -4,9 +4,6 @@ #include #include -static const char* nfc_app_folder = "/any/nfc"; -static const char* nfc_app_extension = ".nfc"; -static const char* nfc_app_shadow_extension = ".shd"; static const char* nfc_file_header = "Flipper NFC device"; static const uint32_t nfc_file_version = 2; @@ -243,7 +240,7 @@ static bool nfc_device_save_file( do { // Create nfc directory if necessary - if(!storage_simply_mkdir(dev->storage, nfc_app_folder)) break; + if(!storage_simply_mkdir(dev->storage, NFC_APP_FOLDER)) break; // First remove nfc device file if it was saved string_printf(temp_str, "%s/%s%s", folder, dev_name, extension); // Open file @@ -281,12 +278,12 @@ static bool nfc_device_save_file( } bool nfc_device_save(NfcDevice* dev, const char* dev_name) { - return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_extension); + return nfc_device_save_file(dev, dev_name, NFC_APP_FOLDER, NFC_APP_EXTENSION); } bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) { dev->shadow_file_exist = true; - return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_shadow_extension); + return nfc_device_save_file(dev, dev_name, NFC_APP_FOLDER, NFC_APP_SHADOW_EXTENSION); } static bool nfc_device_load_data(NfcDevice* dev, string_t path) { @@ -300,9 +297,9 @@ static bool nfc_device_load_data(NfcDevice* dev, string_t path) { do { // Check existance of shadow file - size_t ext_start = string_search_str(path, nfc_app_extension); + size_t ext_start = string_search_str(path, NFC_APP_EXTENSION); string_set_n(temp_str, path, 0, ext_start); - string_cat_printf(temp_str, "%s", nfc_app_shadow_extension); + string_cat_printf(temp_str, "%s", NFC_APP_SHADOW_EXTENSION); dev->shadow_file_exist = storage_common_stat(dev->storage, string_get_cstr(temp_str), NULL) == FSE_OK; // Open shadow file if it exists. If not - open original @@ -374,15 +371,15 @@ bool nfc_file_select(NfcDevice* dev) { // Input events and views are managed by file_select bool res = dialog_file_select_show( dev->dialogs, - nfc_app_folder, - nfc_app_extension, + NFC_APP_FOLDER, + NFC_APP_EXTENSION, dev->file_name, sizeof(dev->file_name), dev->dev_name); if(res) { string_t dev_str; // Get key file path - string_init_printf(dev_str, "%s/%s%s", nfc_app_folder, dev->file_name, nfc_app_extension); + string_init_printf(dev_str, "%s/%s%s", NFC_APP_FOLDER, dev->file_name, NFC_APP_EXTENSION); res = nfc_device_load_data(dev, dev_str); if(res) { nfc_device_set_name(dev, dev->file_name); @@ -409,12 +406,12 @@ bool nfc_device_delete(NfcDevice* dev) { do { // Delete original file - string_init_printf(file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension); + string_init_printf(file_path, "%s/%s%s", NFC_APP_FOLDER, dev->dev_name, NFC_APP_EXTENSION); if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break; // Delete shadow file if it exists if(dev->shadow_file_exist) { string_printf( - file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension); + file_path, "%s/%s%s", NFC_APP_FOLDER, dev->dev_name, NFC_APP_SHADOW_EXTENSION); if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break; } deleted = true; @@ -437,10 +434,10 @@ bool nfc_device_restore(NfcDevice* dev) { do { string_init_printf( - path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension); + path, "%s/%s%s", NFC_APP_FOLDER, dev->dev_name, NFC_APP_SHADOW_EXTENSION); if(!storage_simply_remove(dev->storage, string_get_cstr(path))) break; dev->shadow_file_exist = false; - string_printf(path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension); + string_printf(path, "%s/%s%s", NFC_APP_FOLDER, dev->dev_name, NFC_APP_EXTENSION); if(!nfc_device_load_data(dev, path)) break; restored = true; } while(0); diff --git a/applications/nfc/nfc_device.h b/applications/nfc/nfc_device.h index 888f0c2f..cf0c389c 100644 --- a/applications/nfc/nfc_device.h +++ b/applications/nfc/nfc_device.h @@ -10,6 +10,10 @@ #define NFC_DEV_NAME_MAX_LEN 22 #define NFC_FILE_NAME_MAX_LEN 120 +#define NFC_APP_FOLDER "/any/nfc" +#define NFC_APP_EXTENSION ".nfc" +#define NFC_APP_SHADOW_EXTENSION ".shd" + typedef enum { NfcDeviceNfca, NfcDeviceNfcb, diff --git a/applications/nfc/scenes/nfc_scene_card_menu.c b/applications/nfc/scenes/nfc_scene_card_menu.c index 5724abdb..638b7192 100755 --- a/applications/nfc/scenes/nfc_scene_card_menu.c +++ b/applications/nfc/scenes/nfc_scene_card_menu.c @@ -81,5 +81,5 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) { void nfc_scene_card_menu_on_exit(void* context) { Nfc* nfc = (Nfc*)context; - submenu_clean(nfc->submenu); + submenu_reset(nfc->submenu); } diff --git a/applications/nfc/scenes/nfc_scene_device_info.c b/applications/nfc/scenes/nfc_scene_device_info.c index 81708847..4aea026b 100755 --- a/applications/nfc/scenes/nfc_scene_device_info.c +++ b/applications/nfc/scenes/nfc_scene_device_info.c @@ -199,7 +199,7 @@ void nfc_scene_device_info_on_exit(void* context) { dialog_ex_set_context(dialog_ex, NULL); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { // Clear TextBox - text_box_clean(nfc->text_box); + text_box_reset(nfc->text_box); string_reset(nfc->text_box_store); } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { // Clear Bank Card diff --git a/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c b/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c index bacdd347..a712b03e 100755 --- a/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c +++ b/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include #define NFC_MF_UL_DATA_NOT_CHANGED (0UL) #define NFC_MF_UL_DATA_CHANGED (1UL) @@ -11,6 +12,7 @@ void nfc_emulate_mifare_ul_worker_callback(void* context) { void nfc_scene_emulate_mifare_ul_on_enter(void* context) { Nfc* nfc = (Nfc*)context; + DOLPHIN_DEED(DolphinDeedNfcEmulate); // Setup view Popup* popup = nfc->popup; diff --git a/applications/nfc/scenes/nfc_scene_emulate_uid.c b/applications/nfc/scenes/nfc_scene_emulate_uid.c index a8fff57b..a7af371c 100755 --- a/applications/nfc/scenes/nfc_scene_emulate_uid.c +++ b/applications/nfc/scenes/nfc_scene_emulate_uid.c @@ -1,7 +1,9 @@ #include "../nfc_i.h" +#include void nfc_scene_emulate_uid_on_enter(void* context) { Nfc* nfc = (Nfc*)context; + DOLPHIN_DEED(DolphinDeedNfcEmulate); // Setup view Popup* popup = nfc->popup; diff --git a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c index 344d4733..f8b4f2f1 100755 --- a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c +++ b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c @@ -54,5 +54,5 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) { void nfc_scene_mifare_ul_menu_on_exit(void* context) { Nfc* nfc = (Nfc*)context; - submenu_clean(nfc->submenu); + submenu_reset(nfc->submenu); } diff --git a/applications/nfc/scenes/nfc_scene_read_card.c b/applications/nfc/scenes/nfc_scene_read_card.c index d01fa75d..10cf74f2 100755 --- a/applications/nfc/scenes/nfc_scene_read_card.c +++ b/applications/nfc/scenes/nfc_scene_read_card.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include #define NFC_READ_CARD_CUSTOM_EVENT (10UL) @@ -9,6 +10,7 @@ void nfc_read_card_worker_callback(void* context) { void nfc_scene_read_card_on_enter(void* context) { Nfc* nfc = (Nfc*)context; + DOLPHIN_DEED(DolphinDeedNfcRead); // Setup view Popup* popup = nfc->popup; diff --git a/applications/nfc/scenes/nfc_scene_read_card_success.c b/applications/nfc/scenes/nfc_scene_read_card_success.c index ef6709ad..097cdd8d 100755 --- a/applications/nfc/scenes/nfc_scene_read_card_success.c +++ b/applications/nfc/scenes/nfc_scene_read_card_success.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include void nfc_scene_read_card_success_widget_callback( GuiButtonType result, @@ -17,6 +18,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { string_t uid_str; string_init(data_str); string_init(uid_str); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); // Send notification notification_message(nfc->notifications, &sequence_success); diff --git a/applications/nfc/scenes/nfc_scene_read_emv_app.c b/applications/nfc/scenes/nfc_scene_read_emv_app.c index 665a121b..c6eff352 100755 --- a/applications/nfc/scenes/nfc_scene_read_emv_app.c +++ b/applications/nfc/scenes/nfc_scene_read_emv_app.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include #define NFC_READ_EMV_APP_CUSTOM_EVENT (10UL) @@ -9,6 +10,7 @@ void nfc_read_emv_app_worker_callback(void* context) { void nfc_scene_read_emv_app_on_enter(void* context) { Nfc* nfc = (Nfc*)context; + DOLPHIN_DEED(DolphinDeedNfcRead); // Setup view Popup* popup = nfc->popup; diff --git a/applications/nfc/scenes/nfc_scene_read_emv_app_success.c b/applications/nfc/scenes/nfc_scene_read_emv_app_success.c index 3fe62f3f..057dd59e 100755 --- a/applications/nfc/scenes/nfc_scene_read_emv_app_success.c +++ b/applications/nfc/scenes/nfc_scene_read_emv_app_success.c @@ -1,5 +1,6 @@ #include "../nfc_i.h" #include "../helpers/nfc_emv_parser.h" +#include #define NFC_SCENE_READ_SUCCESS_SHIFT " " @@ -11,6 +12,7 @@ void nfc_scene_read_emv_app_success_dialog_callback(DialogExResult result, void* void nfc_scene_read_emv_app_success_on_enter(void* context) { Nfc* nfc = (Nfc*)context; + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); // Setup view NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data; diff --git a/applications/nfc/scenes/nfc_scene_read_emv_data.c b/applications/nfc/scenes/nfc_scene_read_emv_data.c index 4da1aaa7..36f525f1 100755 --- a/applications/nfc/scenes/nfc_scene_read_emv_data.c +++ b/applications/nfc/scenes/nfc_scene_read_emv_data.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include #define NFC_READ_EMV_DATA_CUSTOM_EVENT (10UL) @@ -9,6 +10,7 @@ void nfc_read_emv_data_worker_callback(void* context) { void nfc_scene_read_emv_data_on_enter(void* context) { Nfc* nfc = (Nfc*)context; + DOLPHIN_DEED(DolphinDeedNfcRead); // Setup view Popup* popup = nfc->popup; diff --git a/applications/nfc/scenes/nfc_scene_read_emv_data_success.c b/applications/nfc/scenes/nfc_scene_read_emv_data_success.c index 0867311f..99912450 100755 --- a/applications/nfc/scenes/nfc_scene_read_emv_data_success.c +++ b/applications/nfc/scenes/nfc_scene_read_emv_data_success.c @@ -1,5 +1,6 @@ #include "../nfc_i.h" #include "../helpers/nfc_emv_parser.h" +#include void nfc_scene_read_emv_data_success_widget_callback( GuiButtonType result, @@ -15,6 +16,7 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { Nfc* nfc = (Nfc*)context; NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data; + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); // Setup Custom Widget view // Add frame diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul.c index a0bd057d..c5b7c497 100755 --- a/applications/nfc/scenes/nfc_scene_read_mifare_ul.c +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include #define NFC_READ_MIFARE_UL_CUSTOM_EVENT (10UL) @@ -9,6 +10,7 @@ void nfc_read_mifare_ul_worker_callback(void* context) { void nfc_scene_read_mifare_ul_on_enter(void* context) { Nfc* nfc = (Nfc*)context; + DOLPHIN_DEED(DolphinDeedNfcRead); // Setup view Popup* popup = nfc->popup; diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c index a11af2b5..a7fcc2fc 100755 --- a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include #define NFC_SCENE_READ_SUCCESS_SHIFT " " #define NFC_SCENE_READ_MF_UL_CUSTOM_EVENT (0UL) @@ -22,6 +23,7 @@ void nfc_scene_read_mifare_ul_success_text_box_callback(void* context) { void nfc_scene_read_mifare_ul_success_on_enter(void* context) { Nfc* nfc = (Nfc*)context; + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); // Send notification notification_message(nfc->notifications, &sequence_success); @@ -126,6 +128,6 @@ void nfc_scene_read_mifare_ul_success_on_exit(void* context) { // Clean TextBox TextBox* text_box = nfc->text_box; - text_box_clean(text_box); + text_box_reset(text_box); string_reset(nfc->text_box_store); } diff --git a/applications/nfc/scenes/nfc_scene_save_name.c b/applications/nfc/scenes/nfc_scene_save_name.c index 44babcdd..c66484ff 100755 --- a/applications/nfc/scenes/nfc_scene_save_name.c +++ b/applications/nfc/scenes/nfc_scene_save_name.c @@ -1,5 +1,6 @@ #include "../nfc_i.h" #include +#include #define SCENE_SAVE_NAME_CUSTOM_EVENT (0UL) @@ -29,6 +30,11 @@ void nfc_scene_save_name_on_enter(void* context) { nfc->text_store, NFC_DEV_NAME_MAX_LEN, dev_name_empty); + + ValidatorIsFile* validator_is_file = + validator_is_file_alloc_init(NFC_APP_FOLDER, NFC_APP_EXTENSION); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput); } @@ -60,5 +66,9 @@ void nfc_scene_save_name_on_exit(void* context) { Nfc* nfc = (Nfc*)context; // Clear view - text_input_clean(nfc->text_input); + void* validator_context = text_input_get_validator_callback_context(nfc->text_input); + text_input_set_validator(nfc->text_input, NULL, NULL); + validator_is_file_free(validator_context); + + text_input_reset(nfc->text_input); } diff --git a/applications/nfc/scenes/nfc_scene_save_success.c b/applications/nfc/scenes/nfc_scene_save_success.c index 57b08b07..67599c24 100755 --- a/applications/nfc/scenes/nfc_scene_save_success.c +++ b/applications/nfc/scenes/nfc_scene_save_success.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include #define SCENE_SAVE_SUCCESS_CUSTOM_EVENT (0UL) @@ -9,6 +10,7 @@ void nfc_scene_save_success_popup_callback(void* context) { void nfc_scene_save_success_on_enter(void* context) { Nfc* nfc = (Nfc*)context; + DOLPHIN_DEED(DolphinDeedNfcSave); // Setup view Popup* popup = nfc->popup; diff --git a/applications/nfc/scenes/nfc_scene_saved_menu.c b/applications/nfc/scenes/nfc_scene_saved_menu.c index ea38ce3d..5da82572 100755 --- a/applications/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/nfc/scenes/nfc_scene_saved_menu.c @@ -81,5 +81,5 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { void nfc_scene_saved_menu_on_exit(void* context) { Nfc* nfc = (Nfc*)context; - submenu_clean(nfc->submenu); + submenu_reset(nfc->submenu); } diff --git a/applications/nfc/scenes/nfc_scene_scripts_menu.c b/applications/nfc/scenes/nfc_scene_scripts_menu.c index ffb856d3..367b5c05 100755 --- a/applications/nfc/scenes/nfc_scene_scripts_menu.c +++ b/applications/nfc/scenes/nfc_scene_scripts_menu.c @@ -55,5 +55,5 @@ bool nfc_scene_scripts_menu_on_event(void* context, SceneManagerEvent event) { void nfc_scene_scripts_menu_on_exit(void* context) { Nfc* nfc = (Nfc*)context; - submenu_clean(nfc->submenu); + submenu_reset(nfc->submenu); } diff --git a/applications/nfc/scenes/nfc_scene_set_type.c b/applications/nfc/scenes/nfc_scene_set_type.c index 66eafe83..0e6624bd 100755 --- a/applications/nfc/scenes/nfc_scene_set_type.c +++ b/applications/nfc/scenes/nfc_scene_set_type.c @@ -45,5 +45,5 @@ bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { void nfc_scene_set_type_on_exit(void* context) { Nfc* nfc = (Nfc*)context; - submenu_clean(nfc->submenu); + submenu_reset(nfc->submenu); } diff --git a/applications/nfc/scenes/nfc_scene_set_uid.c b/applications/nfc/scenes/nfc_scene_set_uid.c index 5d179f77..e23efe79 100755 --- a/applications/nfc/scenes/nfc_scene_set_uid.c +++ b/applications/nfc/scenes/nfc_scene_set_uid.c @@ -1,4 +1,5 @@ #include "../nfc_i.h" +#include #define SCENE_SET_UID_CUSTOM_EVENT (0UL) @@ -30,6 +31,7 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SCENE_SET_UID_CUSTOM_EVENT) { + DOLPHIN_DEED(DolphinDeedNfcAdd); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); return true; } diff --git a/applications/nfc/scenes/nfc_scene_start.c b/applications/nfc/scenes/nfc_scene_start.c index b99580d2..40f3a12e 100644 --- a/applications/nfc/scenes/nfc_scene_start.c +++ b/applications/nfc/scenes/nfc_scene_start.c @@ -78,5 +78,5 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { void nfc_scene_start_on_exit(void* context) { Nfc* nfc = (Nfc*)context; - submenu_clean(nfc->submenu); + submenu_reset(nfc->submenu); } diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_power_off.c b/applications/power/power_settings_app/scenes/power_settings_scene_power_off.c index a389778a..2c79bcfe 100755 --- a/applications/power/power_settings_app/scenes/power_settings_scene_power_off.c +++ b/applications/power/power_settings_app/scenes/power_settings_scene_power_off.c @@ -39,5 +39,5 @@ bool power_settings_scene_power_off_on_event(void* context, SceneManagerEvent ev void power_settings_scene_power_off_on_exit(void* context) { PowerSettingsApp* app = context; - dialog_ex_clean(app->dialog); + dialog_ex_reset(app->dialog); } diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_reboot.c b/applications/power/power_settings_app/scenes/power_settings_scene_reboot.c index d6ec2d04..8edc8138 100755 --- a/applications/power/power_settings_app/scenes/power_settings_scene_reboot.c +++ b/applications/power/power_settings_app/scenes/power_settings_scene_reboot.c @@ -48,5 +48,5 @@ bool power_settings_scene_reboot_on_event(void* context, SceneManagerEvent event void power_settings_scene_reboot_on_exit(void* context) { PowerSettingsApp* app = context; - submenu_clean(app->submenu); + submenu_reset(app->submenu); } diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_start.c b/applications/power/power_settings_app/scenes/power_settings_scene_start.c index c2ae256f..1b368dbc 100755 --- a/applications/power/power_settings_app/scenes/power_settings_scene_start.c +++ b/applications/power/power_settings_app/scenes/power_settings_scene_start.c @@ -60,5 +60,5 @@ bool power_settings_scene_start_on_event(void* context, SceneManagerEvent event) void power_settings_scene_start_on_exit(void* context) { PowerSettingsApp* app = context; - submenu_clean(app->submenu); + submenu_reset(app->submenu); } diff --git a/applications/power_observer/power_observer.c b/applications/power_observer/power_observer.c index 9f494d07..b32447f0 100644 --- a/applications/power_observer/power_observer.c +++ b/applications/power_observer/power_observer.c @@ -2,6 +2,11 @@ #include #include +typedef struct { + osThreadId_t thread; + +} PowerObserverSrv; + const NotificationMessage message_green_110 = { .type = NotificationMessageTypeLedGreen, .data.led.value = 110, @@ -14,20 +19,58 @@ static const NotificationSequence sequence_overconsumption = { NULL, }; +typedef enum { + EventReset = (1 << 0), + EventRequest = (1 << 1), +} UsbEvent; + +static void usb_state_callback(FuriHalUsbStateEvent state, void* context) { + PowerObserverSrv* srv = (PowerObserverSrv*)(context); + if(state == FuriHalUsbStateEventReset) { + osThreadFlagsSet(srv->thread, EventReset); + } else if(state == FuriHalUsbStateEventDescriptorRequest) { + osThreadFlagsSet(srv->thread, EventRequest); + } +} + int32_t power_observer_srv(void* p) { NotificationApp* notifications = furi_record_open("notification"); + PowerObserverSrv* srv = furi_alloc(sizeof(PowerObserverSrv)); + srv->thread = osThreadGetId(); const float overconsumption_limit = 0.03f; + bool usb_request_pending = false; + uint8_t usb_wait_time = 0; + + furi_hal_usb_set_state_callback(usb_state_callback, srv); while(true) { - float current = -furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge); - - if(current >= overconsumption_limit) { - notification_message_block(notifications, &sequence_overconsumption); + uint32_t flags = osThreadFlagsWait(EventReset | EventRequest, osFlagsWaitAny, 500); + if((flags & osFlagsError) == 0) { + if(flags & EventReset) { + usb_request_pending = true; + usb_wait_time = 0; + } + if(flags & EventRequest) { + usb_request_pending = false; + } + } else if(usb_request_pending) { + usb_wait_time++; + if(usb_wait_time > 4) { + furi_hal_usb_reinit(); + usb_request_pending = false; + } } - delay(1000); + float current = -furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge); + if(current > overconsumption_limit) { + notification_message_block(notifications, &sequence_overconsumption); + } + if(furi_hal_power_is_otg_enabled()) { + furi_hal_power_check_otg_status(); + } } + free(srv); return 0; -} \ No newline at end of file +} diff --git a/applications/storage_settings/scenes/storage_settings_scene_start.c b/applications/storage_settings/scenes/storage_settings_scene_start.c index 595c73f1..027a5998 100644 --- a/applications/storage_settings/scenes/storage_settings_scene_start.c +++ b/applications/storage_settings/scenes/storage_settings_scene_start.c @@ -115,5 +115,5 @@ bool storage_settings_scene_start_on_event(void* context, SceneManagerEvent even void storage_settings_scene_start_on_exit(void* context) { StorageSettings* app = context; - submenu_clean(app->submenu); + submenu_reset(app->submenu); } diff --git a/applications/subghz/scenes/subghz_scene_delete_raw.c b/applications/subghz/scenes/subghz_scene_delete_raw.c index 5c620989..8f3292c2 100644 --- a/applications/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/subghz/scenes/subghz_scene_delete_raw.c @@ -17,15 +17,14 @@ void subghz_scene_delete_raw_on_enter(void* context) { SubGhz* subghz = context; string_t frequency_str; string_t modulation_str; - string_t text; string_init(frequency_str); string_init(modulation_str); - string_init(text); - string_printf(text, "Delete\n%s?", subghz->file_name); - widget_add_string_multiline_element( - subghz->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, string_get_cstr(text)); + char delete_str[64]; + snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", subghz->file_name); + widget_add_text_box_element( + subghz->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str); widget_add_string_element( subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal"); @@ -44,7 +43,6 @@ void subghz_scene_delete_raw_on_enter(void* context) { string_clear(frequency_str); string_clear(modulation_str); - string_clear(text); widget_add_button_element( subghz->widget, GuiButtonTypeRight, "Delete", subghz_scene_delete_raw_callback, subghz); diff --git a/applications/subghz/scenes/subghz_scene_frequency_analyzer.c b/applications/subghz/scenes/subghz_scene_frequency_analyzer.c index 548a0f8f..554030ad 100644 --- a/applications/subghz/scenes/subghz_scene_frequency_analyzer.c +++ b/applications/subghz/scenes/subghz_scene_frequency_analyzer.c @@ -1,5 +1,6 @@ #include "../subghz_i.h" #include "../views/subghz_frequency_analyzer.h" +#include void subghz_scene_frequency_analyzer_callback(SubghzCustomEvent event, void* context) { furi_assert(context); @@ -9,6 +10,7 @@ void subghz_scene_frequency_analyzer_callback(SubghzCustomEvent event, void* con void subghz_scene_frequency_analyzer_on_enter(void* context) { SubGhz* subghz = context; + DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer); subghz_frequency_analyzer_set_callback( subghz->subghz_frequency_analyzer, subghz_scene_frequency_analyzer_callback, subghz); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewFrequencyAnalyzer); diff --git a/applications/subghz/scenes/subghz_scene_more_raw.c b/applications/subghz/scenes/subghz_scene_more_raw.c index 10e0aad4..70ea56db 100644 --- a/applications/subghz/scenes/subghz_scene_more_raw.c +++ b/applications/subghz/scenes/subghz_scene_more_raw.c @@ -45,6 +45,7 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW); return true; } else if(event.event == SubmenuIndexEdit) { + memset(subghz->file_name_tmp, 0, sizeof(subghz->file_name_tmp)); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); @@ -56,5 +57,5 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) { void subghz_scene_more_raw_on_exit(void* context) { SubGhz* subghz = context; - submenu_clean(subghz->submenu); + submenu_reset(subghz->submenu); } diff --git a/applications/subghz/scenes/subghz_scene_read_raw.c b/applications/subghz/scenes/subghz_scene_read_raw.c index aaa51c76..481138dc 100644 --- a/applications/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/subghz/scenes/subghz_scene_read_raw.c @@ -1,10 +1,11 @@ #include "../subghz_i.h" #include "../views/subghz_read_raw.h" +#include #include #include #include -#define RAW_FILE_NAME "Raw_temp" +#define RAW_FILE_NAME "Raw_signal_" bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { bool ret = false; @@ -199,6 +200,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { if(!subghz_tx_start(subghz)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); } else { + DOLPHIN_DEED(DolphinDeedSubGhzSend); subghz->state_notifications = SubGhzNotificationStateTX; } } @@ -240,6 +242,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { RAW_FILE_NAME, subghz->txrx->frequency, string_get_cstr(subghz->error_str))) { + DOLPHIN_DEED(DolphinDeedSubGhzRawRec); if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { subghz_begin(subghz, subghz->txrx->preset); diff --git a/applications/subghz/scenes/subghz_scene_receiver.c b/applications/subghz/scenes/subghz_scene_receiver.c index a2eb4af2..4ffa29fc 100644 --- a/applications/subghz/scenes/subghz_scene_receiver.c +++ b/applications/subghz/scenes/subghz_scene_receiver.c @@ -66,7 +66,7 @@ void subghz_scene_receiver_on_enter(void* context) { string_init(str_buff); if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { - subghz_history_clean(subghz->txrx->history); + subghz_history_reset(subghz->txrx->history); } //Load history to receiver diff --git a/applications/subghz/scenes/subghz_scene_receiver_config.c b/applications/subghz/scenes/subghz_scene_receiver_config.c index 4243b09b..28afc1fb 100644 --- a/applications/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/subghz/scenes/subghz_scene_receiver_config.c @@ -161,7 +161,7 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even void subghz_scene_receiver_config_on_exit(void* context) { SubGhz* subghz = context; - variable_item_list_clean(subghz->variable_item_list); + variable_item_list_reset(subghz->variable_item_list); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet); } diff --git a/applications/subghz/scenes/subghz_scene_receiver_info.c b/applications/subghz/scenes/subghz_scene_receiver_info.c index a8935a1c..64d3633c 100644 --- a/applications/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/subghz/scenes/subghz_scene_receiver_info.c @@ -1,5 +1,6 @@ #include "../subghz_i.h" #include "../helpers/subghz_custom_event.h" +#include void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); @@ -39,6 +40,7 @@ static bool subghz_scene_receiver_info_update_parser(void* context) { void subghz_scene_receiver_info_on_enter(void* context) { SubGhz* subghz = context; + DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo); if(subghz_scene_receiver_info_update_parser(subghz)) { string_t frequency_str; string_t modulation_str; diff --git a/applications/subghz/scenes/subghz_scene_save_name.c b/applications/subghz/scenes/subghz_scene_save_name.c index f688d20d..142ba7c9 100644 --- a/applications/subghz/scenes/subghz_scene_save_name.c +++ b/applications/subghz/scenes/subghz_scene_save_name.c @@ -1,10 +1,11 @@ #include "../subghz_i.h" #include -#include "file_worker.h" #include "../helpers/subghz_custom_event.h" #include +#include void subghz_scene_save_name_text_input_callback(void* context) { + furi_assert(context); SubGhz* subghz = context; view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneSaveName); } @@ -18,7 +19,8 @@ void subghz_scene_save_name_on_enter(void* context) { if(!strcmp(subghz->file_name, "")) { set_random_name(subghz->file_name, sizeof(subghz->file_name)); - + //highlighting the entire filename by default + dev_name_empty = true; } else { strcpy(subghz->file_name_tmp, subghz->file_name); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) == @@ -26,8 +28,6 @@ void subghz_scene_save_name_on_enter(void* context) { subghz_get_next_name_file(subghz); } } - //highlighting the entire filename by default - dev_name_empty = true; text_input_set_header_text(text_input, "Name signal"); text_input_set_result_callback( @@ -37,6 +37,11 @@ void subghz_scene_save_name_on_enter(void* context) { subghz->file_name, 22, //Max len name dev_name_empty); + + ValidatorIsFile* validator_is_file = + validator_is_file_alloc_init(SUBGHZ_APP_PATH_FOLDER, SUBGHZ_APP_EXTENSION); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTextInput); } @@ -50,7 +55,9 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(event.event == SubghzCustomEventSceneSaveName) { if(strcmp(subghz->file_name, "")) { if(strcmp(subghz->file_name_tmp, "")) { - subghz_rename_file(subghz); + if(!subghz_rename_file(subghz)) { + return false; + } } else { subghz_save_protocol_to_file(subghz, subghz->file_name); } @@ -59,6 +66,8 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { SubghzCustomEventManagerSet) { subghz_protocol_raw_set_last_file_name( (SubGhzProtocolRAW*)subghz->txrx->protocol_result, subghz->file_name); + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet); } else { subghz_file_name_clear(subghz); } @@ -78,8 +87,11 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { void subghz_scene_save_name_on_exit(void* context) { SubGhz* subghz = context; + // Clear validator + void* validator_context = text_input_get_validator_callback_context(subghz->text_input); + text_input_set_validator(subghz->text_input, NULL, NULL); + validator_is_file_free(validator_context); + // Clear view - text_input_clean(subghz->text_input); - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet); + text_input_reset(subghz->text_input); } diff --git a/applications/subghz/scenes/subghz_scene_save_success.c b/applications/subghz/scenes/subghz_scene_save_success.c index 923a06b6..3d9d28d1 100644 --- a/applications/subghz/scenes/subghz_scene_save_success.c +++ b/applications/subghz/scenes/subghz_scene_save_success.c @@ -1,5 +1,7 @@ #include "../subghz_i.h" #include "../helpers/subghz_custom_event.h" +#include "dolphin/helpers/dolphin_deed.h" +#include void subghz_scene_save_success_popup_callback(void* context) { SubGhz* subghz = context; @@ -8,6 +10,7 @@ void subghz_scene_save_success_popup_callback(void* context) { void subghz_scene_save_success_on_enter(void* context) { SubGhz* subghz = context; + DOLPHIN_DEED(DolphinDeedSubGhzSave); // Setup view Popup* popup = subghz->popup; diff --git a/applications/subghz/scenes/subghz_scene_saved_menu.c b/applications/subghz/scenes/subghz_scene_saved_menu.c index c6623c6b..833bdfd5 100644 --- a/applications/subghz/scenes/subghz_scene_saved_menu.c +++ b/applications/subghz/scenes/subghz_scene_saved_menu.c @@ -67,5 +67,5 @@ bool subghz_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { void subghz_scene_saved_menu_on_exit(void* context) { SubGhz* subghz = context; - submenu_clean(subghz->submenu); + submenu_reset(subghz->submenu); } diff --git a/applications/subghz/scenes/subghz_scene_set_type.c b/applications/subghz/scenes/subghz_scene_set_type.c index ea88baf8..0d8f0ad2 100644 --- a/applications/subghz/scenes/subghz_scene_set_type.c +++ b/applications/subghz/scenes/subghz_scene_set_type.c @@ -1,5 +1,6 @@ #include "../subghz_i.h" #include "../lib/subghz/protocols/subghz_protocol_keeloq.h" +#include enum SubmenuIndex { SubmenuIndexPricenton, @@ -192,6 +193,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; subghz_file_name_clear(subghz); + DOLPHIN_DEED(DolphinDeedSubGhzAddManually); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); return true; } @@ -202,5 +204,5 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { void subghz_scene_set_type_on_exit(void* context) { SubGhz* subghz = context; - submenu_clean(subghz->submenu); + submenu_reset(subghz->submenu); } diff --git a/applications/subghz/scenes/subghz_scene_start.c b/applications/subghz/scenes/subghz_scene_start.c index 454b39f1..14108e34 100644 --- a/applications/subghz/scenes/subghz_scene_start.c +++ b/applications/subghz/scenes/subghz_scene_start.c @@ -97,5 +97,5 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { void subghz_scene_start_on_exit(void* context) { SubGhz* subghz = context; - submenu_clean(subghz->submenu); + submenu_reset(subghz->submenu); } diff --git a/applications/subghz/scenes/subghz_scene_test.c b/applications/subghz/scenes/subghz_scene_test.c index bef7e1e4..48c49e0e 100644 --- a/applications/subghz/scenes/subghz_scene_test.c +++ b/applications/subghz/scenes/subghz_scene_test.c @@ -57,5 +57,5 @@ bool subghz_scene_test_on_event(void* context, SceneManagerEvent event) { void subghz_scene_test_on_exit(void* context) { SubGhz* subghz = context; - submenu_clean(subghz->submenu); + submenu_reset(subghz->submenu); } diff --git a/applications/subghz/scenes/subghz_scene_transmitter.c b/applications/subghz/scenes/subghz_scene_transmitter.c index 287e1afd..48ed0fd8 100644 --- a/applications/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/subghz/scenes/subghz_scene_transmitter.c @@ -1,6 +1,7 @@ #include "../subghz_i.h" #include "../views/subghz_transmitter.h" #include +#include void subghz_scene_transmitter_callback(SubghzCustomEvent event, void* context) { furi_assert(context); @@ -50,6 +51,7 @@ bool subghz_scene_transmitter_update_data_show(void* context) { void subghz_scene_transmitter_on_enter(void* context) { SubGhz* subghz = context; + DOLPHIN_DEED(DolphinDeedSubGhzSend); if(!subghz_scene_transmitter_update_data_show(subghz)) { view_dispatcher_send_custom_event( subghz->view_dispatcher, SubghzCustomEventViewTransmitterError); diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index 884bd4a3..f13c86d6 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -9,6 +9,7 @@ const char* const subghz_frequencies_text[] = { "348.00", "387.00", "433.08", + "433.42", "433.92", "434.42", "434.78", @@ -29,6 +30,7 @@ const uint32_t subghz_frequencies[] = { /* 387 - 464 */ 387000000, 433075000, /* LPD433 first */ + 433420000, 433920000, /* LPD433 mid */ 434420000, 434775000, /* LPD433 last channels */ @@ -51,7 +53,7 @@ const uint32_t subghz_hopper_frequencies[] = { const uint32_t subghz_frequencies_count = sizeof(subghz_frequencies) / sizeof(uint32_t); const uint32_t subghz_hopper_frequencies_count = sizeof(subghz_hopper_frequencies) / sizeof(uint32_t); -const uint32_t subghz_frequencies_433_92 = 5; +const uint32_t subghz_frequencies_433_92 = 6; bool subghz_custom_event_callback(void* context, uint32_t event) { furi_assert(context); diff --git a/applications/subghz/subghz_history.c b/applications/subghz/subghz_history.c index b9fb90e7..ad6c3d4c 100644 --- a/applications/subghz/subghz_history.c +++ b/applications/subghz/subghz_history.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -16,7 +17,7 @@ struct SubGhzHistoryStruct { uint8_t type_protocol; uint8_t code_count_bit; uint64_t code_found; - uint16_t te; + uint32_t data1; FuriHalSubGhzPreset preset; uint32_t real_frequency; }; @@ -60,7 +61,7 @@ FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t return instance->history[idx].preset; } -void subghz_history_clean(SubGhzHistory* instance) { +void subghz_history_reset(SubGhzHistory* instance) { furi_assert(instance); instance->last_index_write = 0; instance->code_last_found = 0; @@ -85,7 +86,7 @@ SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, u furi_assert(instance); instance->data.code_found = instance->history[idx].code_found; instance->data.code_count_bit = instance->history[idx].code_count_bit; - instance->data.param1 = instance->history[idx].te; + instance->data.param1 = instance->history[idx].data1; return &instance->data; } bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output) { @@ -149,7 +150,7 @@ bool subghz_history_add_to_history( instance->history[instance->last_index_write].real_frequency = frequency; instance->history[instance->last_index_write].preset = preset; - instance->history[instance->last_index_write].te = 0; + instance->history[instance->last_index_write].data1 = 0; instance->history[instance->last_index_write].manufacture_name = NULL; instance->history[instance->last_index_write].name = protocol->name; instance->history[instance->last_index_write].code_count_bit = protocol->code_last_count_bit; @@ -161,11 +162,15 @@ bool subghz_history_add_to_history( instance->history[instance->last_index_write].manufacture_name = subghz_protocol_star_line_find_and_get_manufacture_name(protocol); } else if(strcmp(protocol->name, "Princeton") == 0) { - instance->history[instance->last_index_write].te = + instance->history[instance->last_index_write].data1 = subghz_protocol_princeton_get_te(protocol); + } else if(strcmp(protocol->name, "Somfy Keytis") == 0) { + instance->history[instance->last_index_write].data1 = + subghz_protocol_somfy_keytis_get_press_duration(protocol); } + instance->history[instance->last_index_write].type_protocol = protocol->type_protocol; instance->last_index_write++; return true; -} \ No newline at end of file +} diff --git a/applications/subghz/subghz_history.h b/applications/subghz/subghz_history.h index 59655188..462a9f4e 100644 --- a/applications/subghz/subghz_history.h +++ b/applications/subghz/subghz_history.h @@ -21,7 +21,7 @@ void subghz_history_free(SubGhzHistory* instance); * * @param instance - SubGhzHistory instance */ -void subghz_history_clean(SubGhzHistory* instance); +void subghz_history_reset(SubGhzHistory* instance); /** Set frequency and preset to history[idx] * diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c index 2fce6f15..5a1f67fe 100644 --- a/applications/subghz/subghz_i.c +++ b/applications/subghz/subghz_i.c @@ -421,7 +421,7 @@ bool subghz_rename_file(SubGhz* subghz) { FS_Error fs_result = storage_common_rename(storage, string_get_cstr(old_path), string_get_cstr(new_path)); - if(fs_result != FSE_OK && fs_result != FSE_EXIST) { + if(fs_result != FSE_OK) { dialog_message_show_storage_error(subghz->dialogs, "Cannot rename\n file/directory"); ret = false; } diff --git a/applications/subghz/views/subghz_read_raw.c b/applications/subghz/views/subghz_read_raw.c index aacc2c7a..27d1c31f 100644 --- a/applications/subghz/views/subghz_read_raw.c +++ b/applications/subghz/views/subghz_read_raw.c @@ -237,8 +237,8 @@ void subghz_read_raw_draw(Canvas* canvas, SubghzReadRAWModel* model) { elements_button_left(canvas, "New"); elements_button_center(canvas, "Send"); elements_button_right(canvas, "More"); - canvas_draw_str_aligned( - canvas, 58, 28, AlignCenter, AlignTop, string_get_cstr(model->file_name)); + elements_text_box( + canvas, 4, 12, 110, 44, AlignCenter, AlignCenter, string_get_cstr(model->file_name)); break; case SubghzReadRAWStatusTX: diff --git a/applications/u2f/scenes/u2f_scene_main.c b/applications/u2f/scenes/u2f_scene_main.c index 5d2694d4..4ff5e601 100644 --- a/applications/u2f/scenes/u2f_scene_main.c +++ b/applications/u2f/scenes/u2f_scene_main.c @@ -1,5 +1,6 @@ #include "../u2f_app_i.h" #include "../views/u2f_view.h" +#include #include "furi_hal.h" #include "../u2f.h" @@ -63,6 +64,7 @@ bool u2f_scene_main_on_event(void* context, SceneManagerEvent event) { } else if(event.event == U2fCustomEventWink) { notification_message(app->notifications, &sequence_blink_green_10); } else if(event.event == U2fCustomEventAuthSuccess) { + DOLPHIN_DEED(DolphinDeedU2fAuthorized); osTimerStart(app->timer, U2F_SUCCESS_TIMEOUT); app->event_cur = U2fCustomEventNone; u2f_view_set_state(app->u2f_view, U2fMsgSuccess); diff --git a/applications/u2f/u2f_hid.c b/applications/u2f/u2f_hid.c index 7cc44dbe..1ddfecaf 100644 --- a/applications/u2f/u2f_hid.c +++ b/applications/u2f/u2f_hid.c @@ -190,7 +190,7 @@ static int32_t u2f_hid_worker(void* context) { FURI_LOG_D(WORKER_TAG, "Init"); - UsbInterface* usb_mode_prev = furi_hal_usb_get_config(); + FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); furi_hal_usb_set_config(&usb_hid_u2f); u2f_hid->lock_timer = osTimerNew(u2f_hid_lock_timeout_callback, osTimerOnce, u2f_hid, NULL); diff --git a/assets/Makefile b/assets/Makefile index 31b252b9..91cc0671 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -20,14 +20,18 @@ $(PROTOBUF) &: $(PROTOBUF_SOURCES) $(PROTOBUF_COMPILER) .PHONY: protobuf protobuf: $(PROTOBUF) -$(DOLPHIN_OUTPUT_DIR): $(DOLPHIN_SOURCE_DIR) - @echo "\tDOLPHIN" - @$(ASSETS_COMPILLER) dolphin "$(DOLPHIN_SOURCE_DIR)" "$(DOLPHIN_OUTPUT_DIR)" +$(DOLPHIN_EXTERNAL_OUTPUT_DIR): $(DOLPHIN_SOURCE_DIR) + @echo "\tDOLPHIN blocking" + @$(ASSETS_COMPILLER) dolphin -s dolphin_blocking "$(DOLPHIN_SOURCE_DIR)/blocking" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)" + @echo "\tDOLPHIN internal" + @$(ASSETS_COMPILLER) dolphin -s dolphin_internal "$(DOLPHIN_SOURCE_DIR)/internal" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)" + @echo "\tDOLPHIN external" + @$(ASSETS_COMPILLER) dolphin "$(DOLPHIN_SOURCE_DIR)/external" "$(DOLPHIN_EXTERNAL_OUTPUT_DIR)" .PHONY: dolphin -dolphin: $(DOLPHIN_OUTPUT_DIR) +dolphin: $(DOLPHIN_EXTERNAL_OUTPUT_DIR) clean: @echo "\tCLEAN\t" @$(RM) $(ASSETS_COMPILED_DIR)/* - @$(RM) -rf $(DOLPHIN_OUTPUT_DIR) + @$(RM) -rf $(DOLPHIN_EXTERNAL_OUTPUT_DIR) diff --git a/assets/assets.mk b/assets/assets.mk index 2d84f1d1..cd5a9b2e 100644 --- a/assets/assets.mk +++ b/assets/assets.mk @@ -6,8 +6,9 @@ ASSETS_SOURCE_DIR := $(ASSETS_DIR)/icons ASSETS_SOURCES += $(shell find $(ASSETS_SOURCE_DIR) -type f -iname '*.png' -or -iname 'frame_rate') ASSETS += $(ASSETS_COMPILED_DIR)/assets_icons.c -DOLPHIN_SOURCE_DIR := $(ASSETS_DIR)/dolphin -DOLPHIN_OUTPUT_DIR := $(ASSETS_DIR)/resources/dolphin +DOLPHIN_SOURCE_DIR := $(ASSETS_DIR)/dolphin +DOLPHIN_INTERNAL_OUTPUT_DIR := $(ASSETS_COMPILED_DIR) +DOLPHIN_EXTERNAL_OUTPUT_DIR := $(ASSETS_DIR)/resources/dolphin PROTOBUF_SOURCE_DIR := $(ASSETS_DIR)/protobuf PROTOBUF_COMPILER := $(PROJECT_ROOT)/lib/nanopb/generator/nanopb_generator.py diff --git a/assets/compiled/assets_dolphin_blocking.c b/assets/compiled/assets_dolphin_blocking.c new file mode 100644 index 00000000..9ea09e2f --- /dev/null +++ b/assets/compiled/assets_dolphin_blocking.c @@ -0,0 +1,330 @@ +#include +#include +#include +#include + + + +const uint8_t _A_L0_NoDb_128x51_0[] = { + 0x1,0x0,0x43,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xff,0x11,0x0,0x88,0x0,0x4,0x16,0x34,0x0,0x10,0xc1,0x1,0xf7,0x20,0x7,0xbe,0x62,0x19,0x9c,0x9d,0xdd,0xf3,0x91,0x99,0x1c,0x9a,0x3b,0x7,0x27,0xa6,0xa2,0x25,0x52,0xc9,0x65,0x2a,0x5a,0x4b,0x4,0xa7,0x4a,0x1f,0x10,0x79,0xf2,0x1,0xe7,0x92,0x9e,0x48,0x41,0xef,0x88,0x7,0x9c,0x4a,0xb,0x22,0x7,0xc0,0xfc,0x62,0x77,0x7e,0xe6,0x62,0x43,0xc6,0x92,0x8f,0xd5,0x3f,0xe0,0xff,0x7,0xf8,0x3f,0xc1,0xf9,0x7,0x7,0xbd,0xc2,0x3c,0xaf,0x2a,0x7,0xff,0xf3,0xfc,0x7,0xb6,0x22,0x44,0xf,0x2d,0x7,0xff,0x1d,0xfb,0x7,0xa6,0x2,0x73,0x8,0x91,0x63,0x27,0x70,0x7e,0x85,0xff,0xf7,0xf7,0x7,0xa5,0x2,0x95,0x70,0x91,0x54,0xb1,0x50,0x4f,0x86,0xff,0xfb,0xef,0x7,0xb6,0x2,0x45,0x42,0x7,0x9f,0xfc,0x1e,0xe3,0xf1,0xf,0x9f,0x7e,0x3f,0xdf,0x1f,0xad,0x24,0xbe,0x38,0xc8,0x5c,0x1c,0x1e,0x3e,0xfe,0xf1,0xfe,0xc1,0xe3,0xff,0x7,0xe7,0x0,0x5a,0x22,0xf5,0x7,0xc6,0xfc,0x1f,0xa5,0xf7,0x7,0xc6,0xfc,0x1e,0xff,0xe6,0xd1,0x40,0x68,0x17,0xff,0xff,0x9c,0x1e,0xb8,0x8,0x8,0x10,0xa0,0x4b,0xf1,0xff,0x70,0xc1,0xeb,0xc0,0x2,0x1c,0x13,0xa0,0xdf,0x1c,0x0,0x3e,0xfe,0xf,0xf1,0x83,0x83,0xda,0x11,0x2,0x80,0x42,0x1,0xe5,0xff,0x87,0xdf,0x81,0xeb,0x18,0x81,0xc0,0x23,0x0,0xf3,0x8f,0xdf,0x1,0xeb,0xa8,0x99,0x59,0xe7,0x0,0xf3,0x9f,0xde,0x1,0xeb,0x48,0xa5,0x64,0x6f,0x0,0xf3,0xbf,0x83,0xda,0x11,0x4a,0xf8,0x87,0xd3,0xfe,0xf,0x88,0x88,0xfd,0x4,0x2,0xf,0x69,0x95,0x84,0xbe,0x80,0xf7,0x3f,0xb0,0x3f,0xc1,0xf0,0xbf,0x40,0x7c,0xe0,0x1,0x24,0xdf,0x1f,0x0,0x10,0xa7,0xee,0xf5,0x7,0x98,0x25,0x40,0x1e,0x0,0xf0,0x7,0x80,0x28 +}; + +const uint8_t _A_L0_NoDb_128x51_1[] = { + 0x1,0x0,0x45,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xff,0x11,0x0,0x88,0x0,0x4,0x16,0x34,0x0,0x10,0xc1,0x1,0xf7,0x20,0x7,0xbe,0x62,0x19,0x9c,0x9d,0xdd,0xf3,0x91,0x99,0x1c,0x9a,0x3b,0x7,0x27,0xa6,0xa2,0x25,0x52,0xc9,0x65,0x2a,0x5a,0x4b,0x4,0xa7,0x4a,0x1f,0x10,0x79,0xf2,0x1,0xe7,0x92,0x9e,0x48,0x41,0xef,0x88,0x7,0x9c,0x4a,0xb,0x22,0x7,0xc0,0xfc,0x62,0x77,0x7e,0xe6,0x62,0x43,0xc6,0x92,0x8f,0xd5,0x3f,0xe0,0xff,0x7,0xf8,0x3f,0xc1,0xf9,0x1f,0xfe,0x3,0xda,0xe1,0x1e,0x57,0x95,0x3,0xff,0xe7,0xf9,0x83,0xdb,0x11,0x22,0x7,0x96,0x83,0xff,0x3b,0xf7,0x3,0xd3,0x1,0x39,0x84,0x48,0xb1,0x93,0xb8,0x3f,0x43,0xff,0xed,0xef,0x83,0xd2,0x81,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc3,0xff,0xf6,0xdf,0x83,0xdb,0x1,0x22,0xa1,0x3,0xcf,0xfc,0xf,0x71,0xf8,0x87,0xce,0xff,0x1f,0xbf,0x8f,0xd6,0x92,0x5f,0x1c,0x64,0x2e,0xe,0xf,0x1f,0x7d,0xf8,0xff,0x60,0xf1,0xff,0x83,0xf3,0x80,0x2d,0x11,0x7a,0x83,0xe0,0x9c,0x20,0xfc,0x2f,0xb8,0x3e,0x37,0xc0,0xf7,0xff,0x36,0x8a,0x2,0xbf,0x1f,0xee,0x7c,0x1e,0xb8,0x8,0x8,0x10,0xa0,0x4b,0xf1,0xfd,0xc3,0xc1,0xeb,0xc0,0x2,0x1c,0x11,0x7e,0x3e,0x78,0x1d,0xf8,0x1f,0x4a,0xf1,0x8f,0xc7,0x2f,0x80,0xf5,0x84,0x40,0xa0,0x10,0x80,0x79,0x7f,0xe7,0xf7,0x80,0x7a,0xc6,0x20,0x70,0x8,0xc0,0x3c,0xef,0xf7,0x0,0x7a,0xea,0x26,0x56,0x79,0xc0,0x3c,0xff,0xf6,0x0,0x7a,0xd2,0x29,0x59,0x1b,0xc0,0x3d,0x2c,0x23,0xf6,0xa5,0x7c,0x43,0xeb,0x63,0x7,0xbc,0x44,0x7e,0x84,0x1,0x7,0xb4,0xca,0xc2,0x5f,0x40,0x7b,0x9f,0xd8,0x1f,0xe0,0xf8,0x5f,0xa0,0x3e,0x70,0x0,0x92,0x6f,0x8f,0x80,0x8,0x53,0xf7,0x7a,0x83,0xcc,0x12,0xa0,0xf,0x0,0x78,0x3,0xc0,0x14 +}; + +const uint8_t _A_L0_NoDb_128x51_2[] = { + 0x1,0x0,0x43,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xff,0x11,0x0,0x88,0x0,0x4,0x16,0x34,0x0,0x10,0xc1,0x1,0xf7,0x20,0x7,0xbe,0x62,0x19,0x9c,0x9d,0xdd,0xf3,0x91,0x99,0x1c,0x9a,0x3b,0x7,0x27,0xa6,0xa2,0x25,0x52,0xc9,0x65,0x2a,0x5a,0x4b,0x4,0xa7,0x4a,0x1f,0x10,0x79,0xf2,0x1,0xe7,0x92,0x9e,0x48,0x41,0xef,0x88,0x7,0x9c,0x4a,0xb,0x22,0x7,0xc0,0xfc,0x62,0x77,0x7e,0xe6,0x62,0x43,0xc6,0x92,0x8f,0xd5,0x3f,0xe0,0xff,0x7,0xf8,0x3f,0xc1,0xfe,0xa,0x5b,0x84,0x79,0x5e,0x54,0x0,0x7c,0xe2,0x24,0x40,0xf2,0xd0,0x7f,0xe3,0xff,0xc0,0x7a,0x60,0x27,0x30,0x89,0x16,0x32,0x77,0x7,0xe8,0x7f,0xfc,0xff,0x30,0x7a,0x50,0x29,0x57,0x9,0x15,0x4b,0x15,0x4,0xf8,0x7f,0xe7,0x7e,0xe0,0x7b,0x60,0x24,0x54,0x20,0x79,0xfb,0x7b,0xe0,0xf6,0x1f,0x88,0x7d,0x22,0xdb,0xf1,0xfa,0xd2,0x4b,0xe3,0x8c,0x85,0xc1,0xc1,0xe3,0xee,0xdf,0x1f,0xef,0xe1,0x7f,0xff,0xdf,0x81,0xf7,0xc0,0xbf,0x80,0x8,0x1f,0x83,0xe1,0x7,0xea,0x78,0x43,0xfe,0xf,0x6f,0xf2,0xe8,0xa0,0x2b,0xf1,0xff,0x1b,0xd4,0xe0,0x30,0x10,0x21,0x40,0x97,0xe2,0xf,0x7e,0x0,0x10,0xe0,0x8b,0xf1,0xfe,0xe7,0xc1,0xf6,0x8f,0x1f,0xdc,0x3c,0x1e,0xd0,0x88,0x14,0x2,0x10,0xf,0x2f,0x3c,0xe,0xfc,0xf,0x58,0xc4,0xe,0x1,0x18,0x7,0x94,0x7e,0x39,0x7c,0x7,0xae,0xa2,0x65,0x67,0x9c,0x3,0xcb,0xff,0x3f,0xbc,0x3,0xd6,0x91,0x4a,0xc8,0xde,0x1,0xe7,0x7f,0xb8,0xf,0xda,0x95,0xf1,0xf,0xa7,0xfe,0xc0,0xf,0x78,0x88,0xfc,0xc0,0x3,0x61,0x7,0xb4,0xca,0xc2,0x5f,0x30,0x0,0xd8,0xcf,0xf8,0x40,0x20,0x7f,0x83,0xd5,0x7e,0x80,0xf9,0xc0,0x2,0x49,0xbe,0x3e,0x0,0x21,0x4f,0xdd,0xea,0xf,0x30,0x4a,0x80,0x3c,0x1,0xe0,0xf,0x0,0x50 +}; + +const uint8_t _A_L0_NoDb_128x51_3[] = { + 0x1,0x0,0x43,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xff,0x11,0x0,0x88,0x0,0x4,0x16,0x34,0x0,0x10,0xc1,0x1,0xf7,0x20,0x7,0xbe,0x62,0x19,0x9c,0x9d,0xdd,0xf3,0x91,0x99,0x1c,0x9a,0x3b,0x7,0x27,0xa6,0xa2,0x25,0x52,0xc9,0x65,0x2a,0x5a,0x4b,0x4,0xa7,0x4a,0x1f,0x10,0x79,0xf2,0x1,0xe7,0x92,0x9e,0x48,0x41,0xef,0x88,0x7,0x9c,0x4a,0xb,0x22,0x7,0xc0,0xfc,0x62,0x77,0x7e,0xe6,0x62,0x43,0xc6,0x92,0x8f,0xd5,0x3f,0xe0,0xff,0x7,0xf8,0x3f,0xc1,0xfe,0xa,0x5b,0x84,0x79,0x5e,0x54,0x0,0x7c,0xe2,0x24,0x40,0xf2,0xd0,0x7f,0xe0,0xe0,0xf5,0xc0,0x4e,0x61,0x12,0x2c,0x64,0xee,0xf,0xd0,0xff,0xfe,0x7f,0x80,0xf4,0xa0,0x52,0xae,0x12,0x2a,0x96,0x2a,0x9,0xf0,0xff,0xe3,0xbf,0x60,0xf6,0xc0,0x48,0xa8,0x40,0xf2,0xbf,0xfe,0xfe,0xe0,0xf6,0x1f,0x88,0x7c,0xf7,0xf1,0xdf,0x78,0xfd,0x69,0x25,0xf1,0xc6,0x42,0xe0,0xe0,0xf1,0xf7,0xfb,0x8f,0xf7,0xf0,0xef,0xff,0xfb,0xc0,0xfb,0xe0,0x77,0xef,0xe0,0x11,0x7,0xe6,0xfc,0x1f,0xdf,0xf0,0xff,0x83,0xdf,0xfc,0xba,0x28,0xd,0x3,0x7f,0xff,0x37,0xa9,0xc0,0x60,0x20,0x42,0x81,0x68,0x1,0xf1,0xc0,0x2,0x1c,0x13,0xa1,0x7f,0xff,0xf9,0xc1,0xf6,0xbf,0x1f,0xf7,0xc,0x1e,0xd0,0x88,0x14,0x2,0x10,0xf,0x2f,0xce,0x0,0x1e,0xd1,0x88,0x1c,0x2,0x30,0xf,0x28,0x3c,0x1c,0x1e,0xda,0x89,0x95,0x9e,0x70,0xf,0x2f,0xfc,0x3e,0xfc,0xf,0x5a,0x45,0x2b,0x23,0x78,0x7,0x9c,0x7e,0xf8,0x3f,0x6a,0x57,0xc4,0x3e,0x93,0xfb,0xc0,0x3d,0xe2,0x23,0xf3,0xff,0xdf,0xc1,0xef,0x32,0xb0,0x97,0xcc,0x0,0x20,0xf6,0x3f,0xb0,0x80,0x81,0xfe,0xf,0x55,0xfa,0x3,0xe7,0x0,0x9,0x26,0xf8,0xf8,0x0,0x85,0x3f,0x77,0xa8,0x3c,0xc1,0x2a,0x0,0xf0,0x7,0x80,0x3c,0x1,0x40 +}; + + +const uint8_t *_A_L0_NoDb_128x51[] = { + + _A_L0_NoDb_128x51_0, + + _A_L0_NoDb_128x51_1, + + _A_L0_NoDb_128x51_2, + + _A_L0_NoDb_128x51_3, + +}; + + + +const uint8_t L0_NoDb_128x51_frame_order[] = { 0, 1, 2, 3 }; + +const BubbleAnimation BA_L0_NoDb_128x51 = { + .icon_animation = { + .width = 128, + .height = 51, + .frame_count = 4, + .frame_rate = 2, + .frames = _A_L0_NoDb_128x51 + }, + .frame_order = L0_NoDb_128x51_frame_order, + .passive_frames = 4, + .active_frames = 0, + .active_cooldown = 0, + .active_cycles = 0, + .duration = 0, + + .frame_bubble_sequences = NULL, + .frame_bubble_sequences_count = 0, + +}; + + +const uint8_t _A_L0_SdBad_128x51_0[] = { + 0x1,0x0,0x1,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfe,0x1,0x82,0x4,0xc,0x4a,0x1,0x70,0x8f,0x1,0x46,0x8,0xf,0x5e,0x30,0x24,0x60,0x50,0xc,0x44,0x88,0x1f,0x1a,0xaa,0x64,0xeb,0xaf,0x71,0x84,0x48,0xb1,0x93,0xb8,0x39,0x3d,0x72,0x55,0x2a,0x50,0x4,0x6e,0x12,0x2a,0x96,0x28,0x3e,0x20,0xf4,0xc1,0x3,0xcf,0x1,0x22,0xa1,0x3,0xf0,0x7e,0x21,0xf9,0xc6,0x52,0xea,0x57,0x22,0xf8,0xe3,0x21,0x63,0xf6,0x0,0x1d,0x1,0x3f,0xd3,0x5,0x7f,0x83,0xfc,0x1f,0xe0,0xf5,0xcf,0xfc,0xee,0x77,0xe0,0x5b,0x7e,0x28,0x10,0x18,0x25,0x2,0x7f,0xf9,0x93,0x87,0xde,0x11,0x0,0x7,0x8e,0x82,0xff,0xfc,0xc7,0x83,0xe2,0xb9,0x19,0x83,0xf4,0x1,0xf5,0x78,0xa9,0x69,0x60,0x9f,0x1,0x7d,0xd4,0xb7,0xa0,0xf1,0x27,0xd0,0x3c,0x70,0xa0,0xf1,0x37,0xd0,0xfc,0xc1,0xf6,0x0,0x30,0x7f,0xf0,0x1,0xff,0xff,0x83,0xfe,0x1,0xfb,0xf9,0xf0,0x83,0xf6,0x19,0xc6,0x7,0xb0,0xe8,0xe0,0x34,0xf,0xfc,0x1b,0x90,0xf,0x69,0x80,0xc,0xa0,0x5a,0xf,0xfc,0xd8,0x1e,0xf1,0x80,0x19,0x41,0x3a,0x5,0xd1,0xfe,0x3,0xec,0xff,0x51,0x8b,0x84,0x8a,0x4,0xf,0xcc,0x44,0x4a,0xc,0xf,0xd8,0x54,0x38,0x1f,0xb0,0x68,0xf0,0x7f,0xc7,0xfe,0x5f,0xf0,0x7e,0x1f,0xfc,0x1f,0xd3,0x85,0xf9,0x83,0xe8,0x14,0x70,0x1f,0x0,0x10,0xa7,0xe0,0xf5,0x5,0x18,0x25,0x40,0x1e,0x0,0xf0,0x7,0x80,0x28 +}; + +const uint8_t _A_L0_SdBad_128x51_1[] = { + 0x1,0x0,0x12,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfe,0x1,0x82,0x4,0xc,0x4a,0x1,0x70,0x8f,0x1,0x46,0x8,0xf,0x5e,0x30,0x24,0x60,0x50,0xc,0x44,0x88,0x1f,0x1a,0xaa,0x64,0xeb,0xaf,0x71,0x84,0x48,0xb1,0x93,0xb8,0x39,0x3d,0x72,0x55,0x2a,0x50,0x4,0x6e,0x12,0x2a,0x96,0x28,0x3e,0x20,0xf4,0xc1,0x3,0xcf,0x1,0x22,0xa1,0x3,0xf0,0x7e,0x21,0xf9,0xc6,0x52,0xea,0x57,0x22,0xf8,0xe3,0x21,0x63,0xf6,0x0,0x1d,0x1,0x3f,0xd3,0x5,0x7f,0x83,0xfc,0x1f,0xe0,0xf5,0xcf,0xfc,0xee,0x77,0xe0,0x5b,0x7e,0x28,0x10,0x18,0x25,0x2,0x7f,0xf9,0x93,0x87,0xde,0x11,0x0,0x7,0x8e,0x82,0xff,0xfc,0xc7,0x83,0xe2,0xb9,0x19,0x83,0xf4,0x1,0xf5,0x78,0xa9,0x69,0x60,0x9f,0x1,0x7d,0xd4,0xb7,0xa0,0xf1,0x27,0xd0,0x3c,0x70,0xa0,0xf1,0x37,0xd0,0xfc,0xc1,0xf6,0x0,0x30,0x7f,0xf0,0x1,0xff,0xff,0x81,0xfc,0x1,0xfb,0xf8,0xe0,0x83,0xf2,0xff,0x4c,0xc3,0x3,0xd8,0x74,0x70,0x15,0xf8,0xe1,0xa1,0x0,0xf6,0x98,0x0,0xca,0x5,0xa0,0x9f,0xc5,0xa1,0x20,0xf6,0x8c,0x0,0xca,0x9,0xd0,0xbb,0xcf,0xb3,0x17,0xb0,0x7d,0x7c,0x3e,0xf3,0xff,0xc0,0x3d,0xee,0x12,0x28,0x10,0x3c,0x7d,0xee,0x1,0xbe,0x83,0xdb,0x11,0x12,0x83,0x2f,0xec,0x1e,0x30,0xa8,0x70,0x3f,0x60,0xd1,0xe0,0xff,0x83,0xf4,0x7f,0xc5,0xf4,0x7,0xd1,0xfd,0x1,0xfe,0xf,0x99,0xc2,0xfc,0xc1,0xf4,0xa,0x38,0xf,0x80,0x8,0x53,0xf0,0x7a,0x82,0x8c,0x12,0xa0,0xf,0x0,0x78,0x3,0xc0,0x14 +}; + + +const uint8_t *_A_L0_SdBad_128x51[] = { + + _A_L0_SdBad_128x51_0, + + _A_L0_SdBad_128x51_1, + +}; + + + +const uint8_t L0_SdBad_128x51_frame_order[] = { 0, 1 }; + +const BubbleAnimation BA_L0_SdBad_128x51 = { + .icon_animation = { + .width = 128, + .height = 51, + .frame_count = 2, + .frame_rate = 2, + .frames = _A_L0_SdBad_128x51 + }, + .frame_order = L0_SdBad_128x51_frame_order, + .passive_frames = 2, + .active_frames = 0, + .active_cooldown = 0, + .active_cycles = 0, + .duration = 0, + + .frame_bubble_sequences = NULL, + .frame_bubble_sequences_count = 0, + +}; + + +const uint8_t _A_L0_SdOk_128x51_0[] = { + 0x1,0x0,0x19,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0xe,0x54,0xec,0xe,0x0,0x8,0x35,0x48,0x20,0x3e,0x2a,0x20,0xf3,0xa8,0x3,0xeb,0xc3,0xdc,0x9c,0xc9,0x2a,0xb1,0xc8,0x19,0x3d,0xeb,0xf9,0x1c,0x94,0x90,0x1e,0x3a,0x48,0x20,0x3d,0xea,0x20,0xf5,0x83,0x83,0xf8,0xff,0x3,0xf1,0xce,0x4e,0x3b,0x15,0x41,0xfc,0xa7,0xfc,0x1f,0xe0,0xff,0x7,0xcc,0x1f,0xf8,0xf,0xdf,0xcf,0xcc,0x1e,0x8a,0xa1,0xb8,0x47,0x80,0xa5,0x40,0xff,0xff,0xbd,0xe0,0xf6,0xc4,0x48,0x80,0xa5,0xa0,0xbf,0xff,0xfb,0xe0,0xf1,0xb0,0x4b,0xa3,0x38,0x79,0xcc,0x22,0x45,0x8c,0x9d,0xc1,0xfa,0x1b,0xff,0xfe,0xfc,0x1e,0x31,0x9,0x4e,0x96,0x89,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc0,0x1e,0x92,0x9,0x4e,0xf4,0x1e,0x38,0x9,0x15,0x8,0x1e,0x5d,0xf3,0x70,0x83,0xc6,0x81,0x29,0xc2,0x83,0xc4,0x7e,0x21,0xf3,0x7,0xa4,0xc3,0x9d,0x18,0xc3,0xd2,0x4b,0xe3,0x8c,0x85,0xc1,0xc1,0xea,0x0,0x90,0x78,0x9f,0x84,0x1f,0x7c,0x0,0x7f,0xf7,0xfe,0xe0,0xfe,0x1f,0xef,0x0,0xfe,0x80,0xa5,0x75,0x14,0x6,0x80,0xf,0x99,0x80,0xc,0xa0,0x4b,0xf5,0x0,0x24,0x61,0xaa,0x7d,0x6,0xfb,0x83,0xdb,0xe0,0xff,0x70,0x79,0x34,0x6,0x4,0xf,0x28,0x3f,0xf0,0x1e,0xf8,0x88,0x94,0x18,0x1e,0x40,0x1,0x7,0xc4,0x2a,0x1c,0xf,0xd8,0x34,0x78,0x3f,0xe0,0xfd,0x1f,0xf1,0x7d,0x41,0xf2,0x7f,0x50,0x7f,0x83,0xe2,0x70,0xbf,0x30,0x7d,0x2,0x8e,0x3,0xe0,0x2,0x14,0xfc,0x1e,0xa0,0xa3,0x4,0xa8,0x3,0xc0,0x1e,0x0,0xf0,0x5,0x0 +}; + +const uint8_t _A_L0_SdOk_128x51_1[] = { + 0x1,0x0,0x1e,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0xe,0x54,0xec,0xe,0x0,0x8,0x35,0x48,0x20,0x3e,0x2a,0x20,0xf3,0xa8,0x3,0xeb,0xc3,0xdc,0x9c,0xc9,0x2a,0xb1,0xc8,0x19,0x3d,0xeb,0xf9,0x1c,0x94,0x90,0x1e,0x3a,0x48,0x20,0x3d,0xea,0x20,0xf5,0x83,0x83,0xf8,0xff,0x3,0xf1,0xce,0x4e,0x3b,0x15,0x41,0xfc,0xa7,0xfc,0x1f,0xe0,0xff,0x7,0xcc,0x1f,0xf8,0xf,0xdf,0xcf,0xcc,0x1e,0x8a,0xa1,0xb8,0x47,0x80,0xa5,0x40,0xff,0xff,0xbd,0xe0,0xf6,0xc4,0x48,0x80,0xa5,0xa0,0xbf,0xff,0xfb,0xe0,0xf1,0xb0,0x4b,0xa3,0x38,0x79,0xcc,0x22,0x45,0x8c,0x9d,0xc1,0xfa,0x1b,0xff,0xfe,0xfc,0x1e,0x31,0x9,0x4e,0x96,0x89,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc0,0x1e,0x92,0x9,0x4e,0xf4,0x1e,0x38,0x9,0x15,0x8,0x1e,0x5d,0xf3,0x70,0x83,0xc6,0x81,0x29,0xc2,0x83,0xc4,0x7e,0x21,0xf3,0x7,0xa4,0xc3,0x9d,0x18,0xc3,0xd2,0x4b,0xe3,0x8c,0x85,0xc1,0xc1,0xea,0x0,0x90,0x78,0x9f,0x84,0x1f,0x7c,0xe,0xff,0x8c,0x1f,0xd8,0x70,0x7f,0x63,0xc1,0xfb,0xbf,0xcf,0x9f,0xc8,0x14,0xae,0xa2,0x80,0xd0,0x11,0xe8,0x0,0x49,0x80,0xc,0xa0,0x4b,0xf5,0x0,0x24,0x61,0xaa,0x7d,0x6,0xfb,0x83,0xdb,0xe0,0xff,0x70,0x79,0x34,0x6,0x4,0xf,0x28,0x3f,0xf0,0x1e,0xf8,0x88,0x94,0x18,0x1e,0x40,0x1,0x7,0xc4,0x2a,0x1c,0xf,0xd8,0x34,0x78,0x3f,0xe0,0xfd,0x1f,0xf1,0x7d,0x41,0xf2,0x7f,0x50,0x7f,0x83,0xe2,0x70,0xbf,0x30,0x7d,0x2,0x8e,0x3,0xe0,0x2,0x14,0xfc,0x1e,0xa0,0xa3,0x4,0xa8,0x3,0xc0,0x1e,0x0,0xf0,0x5,0x0 +}; + +const uint8_t _A_L0_SdOk_128x51_2[] = { + 0x1,0x0,0x22,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0xe,0x54,0xec,0xe,0x0,0x8,0x35,0x48,0x20,0x3e,0x2a,0x20,0xf3,0xa8,0x3,0xeb,0xc3,0xdc,0x9c,0xc9,0x2a,0xb1,0xc8,0x19,0x3d,0xeb,0xf9,0x1c,0x94,0x90,0x1e,0x3a,0x48,0x20,0x3d,0xea,0x20,0xf5,0x83,0x83,0xf8,0xff,0x3,0xf1,0xce,0x4e,0x3b,0x15,0x41,0xfc,0xa7,0xfc,0x1f,0xe0,0xff,0x7,0xcc,0x1f,0xf8,0xf,0xdf,0xcf,0xcc,0x1e,0x8a,0xa1,0xb8,0x47,0x80,0xa5,0x40,0xff,0xff,0xbd,0xe0,0xf6,0xc4,0x48,0x80,0xa5,0xa0,0xbf,0xff,0xfb,0xe0,0xf1,0xb0,0x4b,0xa3,0x38,0x79,0xcc,0x22,0x45,0x8c,0x9d,0xc1,0xfa,0x1b,0xff,0xfe,0xfc,0x1e,0x31,0x9,0x4e,0x96,0x89,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc0,0x1e,0x92,0x9,0x4e,0xf4,0x1e,0x38,0x9,0x15,0x8,0x1e,0x5d,0xf3,0x70,0x83,0xc6,0x81,0x29,0xc2,0x83,0xc4,0x7e,0x21,0xf3,0x7,0xa4,0xc3,0x9d,0x18,0xc3,0xd2,0x4b,0xe3,0x8c,0x85,0xc1,0xc1,0xe5,0x7d,0x3f,0xd8,0x3c,0x7e,0x77,0xc0,0x7d,0xf0,0x3b,0xf6,0x30,0x7f,0x41,0xef,0xc0,0xfd,0x87,0x93,0xc8,0x1f,0x5b,0xfc,0xf9,0xfc,0x81,0x4a,0xea,0x28,0xd,0x1,0x1e,0x80,0x4,0x98,0x0,0xca,0x4,0xbf,0x50,0x2,0x46,0x1a,0xa7,0xd0,0x6f,0xb8,0x3d,0xbe,0xf,0xf7,0x7,0x93,0x40,0x60,0x40,0xf2,0x83,0xff,0x1,0xef,0x88,0x89,0x41,0x81,0xe4,0x0,0x10,0x7c,0x42,0xa1,0xc0,0xfd,0x83,0x47,0x83,0xfe,0xf,0xd1,0xff,0x17,0xd4,0x1f,0x27,0xf5,0x7,0xf8,0x3e,0x27,0xb,0xf3,0x7,0xd0,0x28,0xe0,0x3e,0x0,0x21,0x4f,0xc1,0xea,0xa,0x30,0x4a,0x80,0x3c,0x1,0xe0,0xf,0x0,0x50 +}; + +const uint8_t _A_L0_SdOk_128x51_3[] = { + 0x1,0x0,0x26,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0xe,0x54,0xec,0xe,0x0,0x8,0x35,0x48,0x20,0x3e,0x2a,0x20,0xf3,0xa8,0x3,0xeb,0xc3,0xdc,0x9c,0xc9,0x2a,0xb1,0xc8,0x19,0x3d,0xeb,0xf9,0x1c,0x94,0x90,0x1e,0x3a,0x48,0x20,0x3d,0xea,0x20,0xf5,0x83,0x83,0xf8,0xff,0x3,0xf1,0xce,0x4e,0x3b,0x15,0x41,0xfc,0xa7,0xfc,0x1f,0xe0,0xff,0x7,0xcc,0x1f,0xf8,0xf,0xdf,0xcf,0xcc,0x1e,0x8a,0xa1,0xb8,0x47,0x80,0xa5,0x40,0xff,0xff,0xbd,0xe0,0xf6,0xc4,0x48,0x80,0xa5,0xa0,0xbf,0xff,0xfb,0xe0,0xf1,0xb0,0x4b,0xa3,0x38,0x79,0xcc,0x22,0x45,0x8c,0x9d,0xc1,0xfa,0x1b,0xff,0xfe,0xfc,0x1e,0x31,0x9,0x4e,0x96,0x89,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc0,0x1e,0x92,0x9,0x4e,0xf4,0x1e,0x38,0x9,0x15,0x8,0x1e,0x5d,0xf3,0x70,0x83,0xc6,0x81,0x29,0xc2,0x83,0xc4,0x7e,0x21,0xf3,0x7,0x8d,0xcc,0x1e,0x33,0xe,0x74,0x63,0xf,0x49,0x2f,0x8e,0x32,0x17,0x7,0x7,0x95,0xc4,0xff,0x60,0xf1,0xf9,0xde,0x1,0xf7,0xc0,0xef,0xd8,0xef,0x80,0xfd,0x83,0xdf,0x81,0xfb,0xf,0x2f,0x90,0x3e,0xb7,0xf9,0xf3,0xf9,0x2,0x95,0xd4,0x50,0x1a,0x2,0x3d,0x0,0x9,0x30,0x1,0x94,0x9,0x7e,0xa0,0x4,0x8c,0x35,0x4f,0xa0,0xdf,0x70,0x7b,0x7c,0x1f,0xee,0xf,0x26,0x80,0xc0,0x81,0xe5,0x7,0xfe,0x3,0xdf,0x11,0x12,0x83,0x3,0xc8,0x0,0x20,0xf8,0x85,0x43,0x81,0xfb,0x6,0x8f,0x7,0xfc,0x1f,0xa3,0xfe,0x2f,0xa8,0x3e,0x4f,0xea,0xf,0xf0,0x7c,0x4e,0x17,0xe6,0xf,0xa0,0x51,0xc0,0x7c,0x0,0x42,0x9f,0x83,0xd4,0x14,0x60,0x95,0x0,0x78,0x3,0xc0,0x1e,0x0,0xa0 +}; + + +const uint8_t *_A_L0_SdOk_128x51[] = { + + _A_L0_SdOk_128x51_0, + + _A_L0_SdOk_128x51_1, + + _A_L0_SdOk_128x51_2, + + _A_L0_SdOk_128x51_3, + +}; + + + +const uint8_t L0_SdOk_128x51_frame_order[] = { 0, 1, 2, 3 }; + +const BubbleAnimation BA_L0_SdOk_128x51 = { + .icon_animation = { + .width = 128, + .height = 51, + .frame_count = 4, + .frame_rate = 2, + .frames = _A_L0_SdOk_128x51 + }, + .frame_order = L0_SdOk_128x51_frame_order, + .passive_frames = 4, + .active_frames = 0, + .active_cooldown = 0, + .active_cycles = 0, + .duration = 0, + + .frame_bubble_sequences = NULL, + .frame_bubble_sequences_count = 0, + +}; + + +const uint8_t _A_L0_Url_128x51_0[] = { + 0x1,0x0,0x33,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7f,0x83,0xd6,0xe,0xf,0x29,0xf0,0x20,0x60,0x30,0x1d,0x40,0x10,0x8e,0x63,0xff,0xfc,0xff,0x1,0xe3,0x47,0x7,0x9c,0x90,0x1e,0x7a,0xf,0xfe,0x3b,0xf7,0x7f,0xc0,0x6b,0xa9,0x1c,0x7d,0xcc,0xcf,0x49,0xce,0xe0,0xe6,0x60,0x9d,0xb,0xff,0xef,0xee,0xf,0x1d,0xe5,0x22,0x53,0x25,0xa4,0xeb,0x2a,0x52,0x2d,0x2c,0x13,0xe1,0xbf,0xfe,0xfb,0xc1,0xe3,0x8f,0x7,0x95,0xe7,0x48,0xf,0x1d,0xe8,0x3c,0xbf,0xe0,0xf2,0xcf,0x3,0xca,0x12,0xf,0x2c,0x28,0x3c,0x7b,0xf1,0xfe,0xf8,0x3c,0x7b,0xd7,0xe,0x3c,0xe6,0x63,0xa5,0xe7,0x72,0x63,0x30,0x30,0x78,0xfb,0xfb,0xc5,0xf1,0x0,0x89,0x64,0x40,0x3,0x42,0x1,0x90,0x3c,0x7f,0xe0,0xf2,0x3f,0x88,0x3d,0xf8,0x2,0xd1,0x0,0x8a,0x7e,0x81,0xe3,0xbf,0x7,0xe9,0x7c,0xc1,0xf9,0xbf,0x7,0xc7,0xe1,0xb4,0x30,0x1a,0x5,0xff,0xff,0xe7,0x7,0xbc,0x18,0x4,0x30,0x25,0xf8,0xff,0xb8,0x60,0xf7,0x81,0x80,0x85,0x7e,0x2d,0xf1,0xc0,0x3,0xef,0xe0,0xff,0x18,0x38,0x3d,0xf8,0x78,0x98,0x40,0x3c,0xbf,0xf0,0xfb,0xf0,0x3d,0xa4,0x74,0xa8,0xc0,0x3c,0xe3,0xf7,0xc0,0x7b,0xca,0xa7,0x0,0xf3,0x9f,0xde,0x1,0xef,0x1a,0xbc,0x3,0xce,0xfe,0xf,0x80,0xfa,0xff,0xc1,0xf0,0x3f,0x51,0x0,0x97,0xf4,0x1f,0x7,0xf5,0x7,0xf8,0x3e,0x60,0xeb,0xf2,0x7,0xdf,0xf9,0xbe,0x5e,0x0,0x79,0x4f,0xc1,0xed,0xfc,0x5,0x8,0x25,0x80,0x1e,0x0,0xf0,0x7,0x80,0x24 +}; + +const uint8_t _A_L0_Url_128x51_1[] = { + 0x1,0x0,0x33,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7f,0x83,0xd6,0x3f,0xfc,0x7,0x8c,0xf8,0x10,0x30,0x18,0xe,0xa0,0x8,0x47,0x31,0xff,0xf9,0xfe,0x60,0xf1,0xa3,0x83,0xce,0x48,0xf,0x3d,0x7,0xfe,0x77,0xee,0xbf,0xe0,0x35,0xd4,0x8e,0x3e,0xe6,0x67,0xa4,0xe7,0x70,0x73,0x30,0x4e,0x87,0xff,0xdb,0xdf,0x7,0x8e,0xf2,0x91,0x29,0x92,0xd2,0x75,0x95,0x29,0x16,0x96,0x9,0xf0,0xff,0xfd,0xb7,0xe0,0xf1,0xc7,0x83,0xca,0xf3,0xa4,0x7,0x8e,0xf4,0x1e,0x5f,0xe0,0x79,0x67,0x81,0xe5,0x9,0x7,0x96,0x14,0x1e,0x37,0xf8,0xfd,0xfc,0x1e,0x3d,0xeb,0x87,0x1e,0x73,0x31,0xd2,0xf3,0xb9,0x31,0x98,0x18,0x3c,0x7d,0xf7,0xe2,0xf8,0x80,0x44,0xb2,0x20,0x1,0xa1,0x0,0xc8,0x1e,0x3f,0xf0,0x79,0x1f,0xc4,0x1e,0xfc,0x1,0x68,0x80,0x5,0x3f,0x40,0xf1,0x27,0x8,0x3f,0xb,0xe6,0xf,0xcd,0xf0,0x3e,0x3f,0xd,0xa1,0x80,0xaf,0xc7,0xfb,0x9f,0x7,0xbc,0x18,0x4,0x30,0x25,0xf8,0xfe,0xe1,0xe0,0xf7,0x81,0x80,0x85,0x7e,0x5e,0x78,0x1d,0xf8,0x1f,0x4a,0xf1,0x8f,0xc7,0x2f,0x80,0xf6,0xe1,0xe2,0x61,0x0,0xf2,0xff,0xcf,0xef,0x0,0xf6,0x91,0xd2,0xa3,0x0,0xf3,0xbf,0xdc,0x1,0xef,0x2a,0x9c,0x3,0xcf,0xff,0x60,0x7,0xbc,0x6a,0xf0,0xf,0x4b,0x8,0x7f,0xac,0x63,0xfd,0x20,0x9,0x7f,0x41,0xf0,0x7f,0x50,0x7f,0x83,0xe6,0xe,0xbf,0x20,0x7d,0xff,0x9b,0xe5,0xe0,0x7,0x94,0xfc,0x1e,0xdf,0xc0,0x50,0x82,0x58,0x1,0xe0,0xf,0x0,0x78,0x2,0x40 +}; + +const uint8_t _A_L0_Url_128x51_2[] = { + 0x1,0x0,0x2e,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7f,0x83,0xe6,0x7c,0x8,0x18,0xc,0x7,0x50,0x4,0x23,0x98,0x83,0xd2,0x8e,0xf,0x39,0x20,0x3c,0xf4,0x1f,0xf8,0xff,0xf2,0xff,0x80,0xd7,0x52,0x38,0xfb,0x99,0x9e,0x93,0x9d,0xc1,0xcc,0xc1,0x3a,0x1f,0xff,0x3f,0xcc,0x1e,0x3b,0xca,0x44,0xa6,0x4b,0x49,0xd6,0x54,0xa4,0x5a,0x58,0x27,0xc3,0xff,0x3b,0xf7,0x3,0xc7,0x1e,0xf,0x2b,0xce,0x90,0x1e,0x3b,0xd0,0x79,0x7b,0x7b,0xe0,0xf1,0xcf,0x3,0xca,0x12,0xf,0x2c,0x28,0x3c,0xa2,0xdb,0xf0,0x78,0xf7,0xae,0x1c,0x79,0xcc,0xc7,0x4b,0xce,0xe4,0xc6,0x60,0x60,0xf1,0xf7,0x6f,0x8b,0xe2,0x1,0x12,0xc8,0x80,0x6,0x84,0x3,0x2f,0x85,0xff,0xff,0x7e,0x3f,0x98,0x3d,0xf8,0x17,0xf0,0x1,0x27,0xe8,0x1e,0x23,0xe1,0x7,0xea,0x78,0x43,0xfe,0xf,0x7f,0xc2,0xe8,0x60,0x2b,0xf1,0xff,0x4,0x4,0x1e,0xd0,0x60,0x10,0xc0,0x97,0xe2,0xf,0x98,0x18,0x8,0x57,0xe5,0xfd,0xcf,0x83,0xed,0x1e,0x3f,0xb8,0x78,0x3d,0xf8,0x78,0x98,0x40,0x3c,0xbc,0xf0,0x3b,0xf0,0x3d,0xa4,0x74,0xa8,0xc0,0x3c,0xa3,0xf1,0xcb,0xe0,0x3d,0xe5,0x53,0x80,0x79,0x7f,0xe7,0xf7,0x80,0x7b,0xc6,0xaf,0x0,0xf3,0xbf,0xdc,0x3,0xfb,0xff,0xb0,0xf,0xf0,0x0,0x36,0x12,0xfe,0x0,0x6,0xc6,0x7f,0xc2,0x1,0x3,0xfc,0x1e,0xd0,0x75,0xf9,0x3,0xef,0xfc,0xdf,0x2f,0x0,0x3c,0xa7,0xe0,0xf6,0xfe,0x2,0x84,0x12,0xc0,0xf,0x0,0x78,0x3,0xc0,0x12 +}; + +const uint8_t _A_L0_Url_128x51_3[] = { + 0x1,0x0,0x31,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7f,0x83,0xe6,0x7c,0x8,0x18,0xc,0x7,0x50,0x4,0x23,0x98,0x83,0xd2,0x8e,0xf,0x39,0x20,0x3c,0xf4,0x1f,0xf8,0x38,0x3c,0x70,0x1a,0xea,0x47,0x1f,0x73,0x33,0xd2,0x73,0xb8,0x39,0x98,0x27,0x43,0xff,0xf9,0xfe,0x3,0xc7,0x79,0x48,0x94,0xc9,0x69,0x3a,0xca,0x94,0x8b,0x4b,0x4,0xf8,0x7f,0xf1,0xdf,0xb0,0x78,0xe3,0xc1,0xe5,0x79,0xd2,0x3,0xc7,0x7a,0xf,0x1b,0xff,0xef,0xee,0xf,0x1c,0xf0,0x3c,0xa1,0x20,0xf2,0xc2,0x83,0xc7,0x7f,0x1d,0xf7,0x83,0xc7,0xbd,0x70,0xe3,0xce,0x66,0x3a,0x5e,0x77,0x26,0x33,0x3,0x7,0x8f,0xbf,0xdc,0x5f,0x10,0x8,0x96,0x44,0x0,0x34,0x20,0x19,0x7c,0x3b,0xff,0xfe,0xf1,0xfc,0xc1,0xef,0xc0,0xef,0xdf,0xc0,0x22,0x9f,0xa0,0x78,0xef,0xc1,0xfd,0xff,0xf,0xf8,0x3e,0x3f,0xb,0xa1,0x80,0xd0,0x37,0xff,0xf3,0x78,0x83,0xda,0xc,0x2,0x18,0x16,0x80,0x1f,0x50,0x30,0x10,0xaf,0xc6,0xff,0xff,0xf3,0x83,0xed,0x7e,0x3f,0xee,0x18,0x3d,0xf8,0x78,0x98,0x40,0x3c,0xbf,0x38,0x0,0x7b,0xc8,0xe9,0x51,0x80,0x79,0x41,0xe0,0xe0,0xf8,0x95,0x4e,0x1,0xe5,0xff,0x87,0xdf,0x81,0xef,0x1a,0xbc,0x3,0xce,0x3f,0x7c,0xf,0xec,0xfe,0xf0,0x3f,0xcf,0xfd,0xfc,0x1e,0xe5,0xf5,0x0,0x8,0x3d,0xcf,0xea,0x20,0x20,0x7f,0x83,0xda,0xe,0xbf,0x20,0x7d,0xff,0x9b,0xe5,0xe0,0x7,0x94,0xfc,0x1e,0xdf,0xc0,0x50,0x82,0x58,0x1,0xe0,0xf,0x0,0x78,0x2,0x40 +}; + + +const uint8_t *_A_L0_Url_128x51[] = { + + _A_L0_Url_128x51_0, + + _A_L0_Url_128x51_1, + + _A_L0_Url_128x51_2, + + _A_L0_Url_128x51_3, + +}; + + + +const uint8_t L0_Url_128x51_frame_order[] = { 0, 1, 2, 3 }; + +const BubbleAnimation BA_L0_Url_128x51 = { + .icon_animation = { + .width = 128, + .height = 51, + .frame_count = 4, + .frame_rate = 2, + .frames = _A_L0_Url_128x51 + }, + .frame_order = L0_Url_128x51_frame_order, + .passive_frames = 4, + .active_frames = 0, + .active_cooldown = 0, + .active_cycles = 0, + .duration = 0, + + .frame_bubble_sequences = NULL, + .frame_bubble_sequences_count = 0, + +}; + + +const uint8_t _A_L0_NewMail_128x51_0[] = { + 0x1,0x0,0x50,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf0,0x7,0x80,0x3c,0x1,0xe0,0x6,0xf8,0x40,0x40,0x63,0x30,0xfb,0x73,0x61,0x80,0xf7,0xfe,0x41,0xc0,0x63,0x70,0x9b,0x73,0x1,0xf1,0xfe,0x87,0x83,0xf7,0xff,0x1f,0x1,0x8e,0xc3,0xed,0xd9,0x83,0x3,0xdf,0x7e,0xf,0x39,0xb7,0x60,0x1e,0xf8,0xc,0xfc,0xfc,0x9e,0x53,0x7f,0xc1,0x14,0x81,0xeb,0xbf,0x7,0xa4,0xc2,0x6,0xa,0x2f,0xf8,0x0,0xc1,0xe9,0xf6,0x98,0x83,0xcb,0x80,0x1f,0x80,0x2,0xd0,0x11,0x24,0xf,0xc8,0x10,0x14,0xe1,0xf1,0xe0,0x7c,0x41,0xf,0xef,0xc,0xe3,0x6c,0x6c,0x20,0xf2,0x84,0x27,0xde,0x39,0xc7,0x7,0xa4,0x40,0x1e,0x7f,0xd3,0xc9,0x47,0x2c,0xfb,0x30,0x79,0xc8,0x9,0xe6,0xdf,0x3d,0xe0,0x3d,0x68,0x4,0x43,0x2,0x1e,0xb3,0xcd,0xb3,0x90,0x82,0x8b,0x0,0xa,0x29,0x0,0x3c,0xfd,0x93,0x6d,0xb0,0x3c,0xe0,0x2,0xa2,0x88,0x3,0xce,0x98,0xf,0x10,0x51,0x2,0x45,0x0,0x50,0x80,0x7b,0x5b,0xc1,0xe6,0x80,0x28,0x20,0x3c,0xd1,0xec,0x1c,0x10,0x20,0xc0,0x81,0xf6,0x80,0x28,0x8,0x3e,0xe6,0x7,0xe1,0x7,0xe5,0x21,0xa6,0x40,0xfb,0xc2,0x1f,0x84,0x9e,0x9f,0xef,0xf8,0x0,0x4e,0x2,0x6f,0x28,0xc,0x40,0xde,0x63,0x41,0x9,0x91,0xec,0x51,0xe5,0x2,0x84,0x23,0xcf,0x80,0x2d,0x33,0xd8,0xab,0xca,0x9,0x4,0x57,0x98,0x3d,0xc1,0x43,0xf8,0x81,0xb3,0xcf,0x81,0x8,0x16,0xc,0x20,0x1e,0x4e,0xf4,0x7,0x9c,0x62,0x7,0x0,0x8c,0x3,0xc9,0x1c,0x40,0x1,0xa0,0x83,0xcb,0x51,0x32,0xb3,0xce,0x1,0xe4,0xae,0x20,0x0,0xd0,0x81,0xe5,0x48,0xa5,0x64,0x6f,0x0,0xf2,0x67,0x10,0x0,0x68,0x83,0xf3,0xa5,0x7c,0x43,0xe6,0xee,0x20,0x0,0xa8,0xc4,0x1e,0x71,0x11,0xf9,0xa1,0x8e,0x1,0x50,0x7,0x9c,0xca,0xc2,0x5f,0x23,0xb2,0x40,0x2c,0x7,0xf8,0xc0,0x2d,0x48,0x0,0x33,0xf0,0x7c,0x0,0x23,0x80,0xbf,0x50,0x4,0xa,0x10,0x98,0x80,0x6,0x7,0x98,0x3a,0x80,0x1e,0x0,0xf0,0x7,0x80,0x14 +}; + +const uint8_t _A_L0_NewMail_128x51_1[] = { + 0x1,0x0,0x5d,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf0,0x7,0x80,0x3c,0x1,0xe0,0xa,0x98,0x7d,0xb9,0xb0,0xc0,0x7d,0xdc,0x26,0xdc,0xc0,0x7f,0x83,0xe3,0xe1,0x1,0x1,0x8e,0xc3,0xed,0xd9,0x83,0x3,0x13,0xfd,0xf,0x80,0x7f,0x20,0xe0,0xf2,0x9b,0x76,0x1,0xe9,0xc0,0x80,0xdc,0x2,0x46,0x4f,0x19,0xbf,0xe0,0x2a,0x40,0x1,0x9c,0x7f,0xb1,0xf0,0x3f,0xfc,0x7c,0x1e,0x73,0x8,0x18,0x38,0xb0,0x1c,0x7f,0xfd,0xfe,0x79,0xbf,0x7,0x9f,0xda,0x62,0xf,0x3b,0x87,0xf3,0xff,0xff,0xe3,0xe7,0xe7,0xe6,0x68,0xe7,0x3,0x84,0x0,0x3b,0xf0,0x7c,0x60,0x1,0xc6,0xf,0xae,0x0,0x3e,0x21,0x9c,0x6d,0x8d,0x84,0xa,0x34,0x0,0x7c,0x47,0x38,0xe0,0xf4,0x41,0xa4,0x3e,0x3c,0xf,0x2b,0x3e,0xcc,0x1e,0x70,0x40,0x79,0x9f,0xcf,0x78,0xf,0x58,0x42,0xc9,0xa0,0x1a,0xcf,0x36,0xce,0x42,0xf,0x28,0x80,0x3c,0xff,0xaa,0x92,0xf6,0x4d,0xb6,0xc0,0xf3,0xd0,0x13,0x8d,0xbe,0x74,0xc0,0x78,0x81,0x4a,0x81,0x40,0xf,0x10,0x11,0x1,0xe5,0x6f,0x5,0x16,0x0,0x14,0x52,0x0,0x79,0x80,0x14,0x12,0x22,0x42,0x88,0x3,0xef,0xfc,0x3f,0x18,0x78,0x3e,0xf0,0x82,0xe1,0x82,0x3,0xee,0x90,0x3,0x18,0x10,0x3e,0xe6,0xe,0x31,0x80,0x83,0xcc,0x6e,0x5f,0xf2,0x58,0x82,0x45,0x20,0x40,0xf3,0xa,0x8,0x4c,0xa0,0x40,0xf2,0x58,0x10,0xbc,0xf8,0x2,0xd3,0x66,0x8,0x24,0x5a,0x4,0x4f,0x30,0x7c,0x8,0xc4,0x44,0x20,0xf3,0x84,0x2,0x6,0x10,0xf,0x34,0x7b,0x70,0x23,0x10,0x38,0x4,0x60,0x1e,0x4a,0xf7,0xe0,0x6a,0x26,0x56,0x79,0xc0,0x3c,0x99,0xef,0xc0,0xa4,0x52,0xb2,0x37,0x80,0x79,0x48,0x1,0xe5,0x80,0x1f,0xa5,0x2b,0xe2,0x1f,0x33,0xf1,0x0,0x6,0x82,0xf,0x48,0x88,0xfc,0xcf,0xc4,0x0,0x1a,0x10,0x3c,0xe6,0x56,0x12,0xf9,0x9f,0x88,0x0,0x34,0x43,0xfc,0x9f,0x88,0x0,0x2d,0x31,0x7,0xc2,0xd8,0xe0,0x15,0x0,0x79,0x2f,0xd4,0x2c,0x90,0xb,0x1,0x8c,0x9b,0xc4,0xdf,0x20,0x32,0x7f,0xe7,0xe1,0x32,0x3,0x98,0x71,0x0,0x1e,0x0,0xf0,0x7,0x80,0x2c +}; + +const uint8_t _A_L0_NewMail_128x51_2[] = { + 0x1,0x0,0x79,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf0,0x1,0xfc,0x20,0x20,0xfd,0x84,0x40,0x81,0xfb,0xf6,0x86,0x83,0xf7,0xf3,0x13,0x3,0x24,0xc3,0xed,0xcd,0x86,0x1,0xcf,0x81,0xfe,0xb7,0x83,0xd2,0xe1,0x36,0xe6,0x3,0xd2,0x41,0xff,0xcf,0x83,0xf3,0xb1,0xff,0xbf,0xc0,0xc0,0xe7,0xb0,0xfb,0x76,0x60,0xc0,0x73,0xf2,0x7f,0xff,0xf0,0x40,0x7a,0x4d,0xbb,0x0,0xf4,0xfd,0x83,0xc6,0x36,0x82,0x39,0x84,0xdf,0xf1,0x7,0x7,0x16,0x3,0xf8,0xf,0x19,0x3f,0xf0,0x12,0x40,0xf1,0x98,0xd,0xcc,0x1c,0x40,0x2,0x87,0x9b,0xce,0x62,0xf,0x31,0xda,0x7f,0xe3,0xe8,0xd8,0x7,0xa6,0xfc,0x1f,0x25,0x33,0xc0,0x67,0xe7,0xe0,0xf8,0x82,0x83,0xcf,0x7e,0xf,0x28,0x67,0x1b,0x63,0x61,0x5,0x16,0x1c,0x9a,0x5b,0xf0,0x79,0xc7,0x38,0xe0,0xf3,0xe0,0x1c,0xd0,0x1e,0x96,0x7d,0x98,0x3c,0xa8,0x0,0xf8,0xde,0x3,0xd5,0x46,0x90,0xf8,0xf0,0xc,0x75,0x9e,0x6d,0x9c,0x84,0x1e,0x58,0x41,0xf9,0x4f,0xcf,0xe7,0xec,0x9b,0x6d,0x81,0xe7,0x8,0xf,0x9f,0xf9,0x3e,0x54,0xc0,0x78,0xb1,0x4a,0x81,0x10,0x7,0x9f,0xf4,0x8a,0x40,0xf2,0xb7,0x83,0xca,0x40,0x4f,0x36,0xf9,0x80,0x16,0x81,0xc0,0x1f,0x95,0xfe,0x80,0x9e,0x8a,0x6,0x0,0x8,0x52,0x0,0x7d,0x40,0x5,0x45,0x10,0x7,0xdc,0x8,0xd8,0x30,0x80,0x7d,0xff,0x20,0x1e,0x8,0x38,0x3c,0xff,0xc4,0x82,0x15,0x88,0x24,0x69,0x0,0x31,0x81,0x3,0xcb,0x0,0x62,0x38,0x10,0x3c,0xa6,0x0,0xa2,0x7,0x97,0x0,0x5a,0x70,0x40,0x79,0x24,0x8,0x1f,0x8b,0x2,0x17,0x9f,0x2,0x10,0x2c,0x18,0x40,0x3c,0xc0,0x62,0x2,0x10,0x79,0xc6,0x20,0x70,0x8,0xc0,0x3c,0xc2,0xc2,0x17,0x10,0x79,0xea,0x26,0x56,0x79,0xc0,0x3c,0xd1,0xed,0xc0,0xa4,0x52,0xb2,0x37,0x80,0x79,0x2b,0xdc,0x7e,0x34,0xaf,0x88,0x7c,0xd1,0x46,0x4,0x30,0x79,0x44,0x47,0xe6,0xef,0x40,0x7a,0x4c,0xac,0x25,0xf3,0x3f,0x10,0x0,0x68,0x27,0xf9,0x3f,0x10,0x0,0x68,0x40,0xf9,0x3f,0x10,0x0,0x68,0x80,0xf2,0x5f,0xb1,0xf8,0x80,0x2,0xd3,0x12,0x18,0xb7,0x89,0xbe,0x61,0x63,0x80,0x54,0x0,0x64,0xf,0x31,0xb3,0x40,0x2c,0x0,0x54,0x0,0x18,0x99,0x3f,0xf3,0xf0,0x7c,0x0,0x3c,0x1,0xc0 +}; + +const uint8_t _A_L0_NewMail_128x51_3[] = { + 0x1,0x0,0x77,0x1,0x0,0x1f,0xe2,0x6,0xf,0xd8,0x24,0x10,0x1f,0xbf,0xa8,0x58,0x3f,0x7f,0xb1,0x70,0x76,0x60,0x3f,0xd2,0xf0,0x7e,0x50,0x3f,0xf5,0xf0,0x7e,0x68,0x3f,0xfb,0xf0,0x7e,0x74,0x3f,0xf7,0xf8,0x8,0x1c,0xe6,0x1f,0x6e,0x6c,0x30,0xc,0x5f,0xcf,0xf8,0x0,0xa0,0xe0,0x82,0xb8,0x4d,0xb9,0x80,0xf3,0x3e,0x20,0x10,0xc1,0xff,0xb0,0xfb,0x76,0x60,0xc0,0xfc,0x9b,0x76,0x1,0xf9,0x30,0x9b,0xfe,0x8,0xc7,0x84,0x27,0x14,0xff,0xe8,0x61,0x20,0x78,0xcc,0x1b,0x6,0x1f,0x4f,0xe0,0x64,0x8d,0xe3,0x31,0x7,0xc7,0xfa,0x1e,0xed,0x90,0x21,0xff,0xe3,0xe0,0xf8,0x1f,0xa6,0xfc,0x1f,0x26,0x33,0xc0,0x67,0xe7,0xe0,0x41,0x86,0x71,0xb6,0x36,0x10,0x59,0x41,0x41,0xe7,0xbf,0x7,0x94,0x73,0x8e,0xf,0x3c,0x0,0x7d,0x1,0xe9,0x67,0xd9,0x83,0xcb,0x81,0x87,0x1f,0x96,0xfc,0x1e,0x7b,0xc0,0x7a,0x50,0x12,0x66,0x1f,0x4d,0x67,0x9b,0x67,0x21,0x7,0x90,0xbc,0xe0,0x10,0xf8,0xf0,0xc,0x7d,0x93,0x6d,0xb0,0x3c,0xcf,0xf1,0x4c,0x7,0x8a,0xd4,0xa8,0x18,0x83,0xf9,0xa7,0xcc,0x1e,0x56,0xf0,0x79,0x44,0x3,0xe7,0xfd,0x22,0x98,0x1,0x28,0x12,0x2,0x79,0xfc,0x5,0x24,0xf,0x6a,0x0,0x11,0xc1,0xed,0x80,0x1f,0x98,0x3e,0xa0,0x2,0xa2,0x88,0x3,0xee,0x4,0x6c,0x18,0x40,0x3c,0xff,0xc2,0x82,0xd,0x88,0x24,0x70,0x90,0x9,0x4,0x10,0x1e,0x58,0x2,0x91,0xc0,0x81,0xe5,0x48,0x1,0x8c,0x8,0x1e,0x5c,0x1,0x69,0xa7,0x4,0x12,0x33,0x0,0xd1,0x3,0xed,0x20,0x40,0xf4,0x84,0xb,0x6,0x10,0xf,0x38,0x40,0xd8,0x81,0xe7,0x18,0x81,0xc0,0x23,0x0,0xf3,0x68,0x11,0x3c,0xf8,0x1a,0x89,0x95,0x9e,0x70,0xf,0x31,0x30,0x88,0x84,0x1e,0x74,0x8a,0x56,0x46,0xf0,0xf,0x34,0x7b,0xf,0xc6,0x95,0xf1,0xf,0x9e,0x0,0xac,0x52,0x0,0x7a,0xc4,0x47,0xe6,0xcf,0x70,0x78,0xcc,0xac,0x25,0xf3,0x77,0xa1,0xfe,0x8f,0xc4,0x0,0x1a,0x8,0x3e,0x4f,0xc4,0x0,0x1a,0x10,0x3c,0x97,0xec,0x7e,0x20,0x0,0xd1,0x6,0x64,0xde,0x26,0xf9,0x9f,0x88,0x0,0x2d,0x31,0x0,0x8,0x3c,0xcb,0x44,0x26,0x38,0x5,0x40,0x8,0x60,0x4,0x23,0x24,0x2,0xc0,0xf,0x81,0xb2,0x7f,0xe7,0xe0,0xf8,0x0,0x70 +}; + + +const uint8_t *_A_L0_NewMail_128x51[] = { + + _A_L0_NewMail_128x51_0, + + _A_L0_NewMail_128x51_1, + + _A_L0_NewMail_128x51_2, + + _A_L0_NewMail_128x51_3, + +}; + + + +const uint8_t L0_NewMail_128x51_frame_order[] = { 0, 1, 2, 3, 2, 1 }; + +const BubbleAnimation BA_L0_NewMail_128x51 = { + .icon_animation = { + .width = 128, + .height = 51, + .frame_count = 4, + .frame_rate = 2, + .frames = _A_L0_NewMail_128x51 + }, + .frame_order = L0_NewMail_128x51_frame_order, + .passive_frames = 6, + .active_frames = 0, + .active_cooldown = 0, + .active_cycles = 0, + .duration = 0, + + .frame_bubble_sequences = NULL, + .frame_bubble_sequences_count = 0, + +}; + + +const StorageAnimation dolphin_blocking[] = { + + { + .animation = &BA_L0_NoDb_128x51, + .manifest_info = { + .name = "L0_NoDb_128x51", + .min_butthurt = 0, + .max_butthurt = 0, + .min_level = 0, + .max_level = 0, + .weight = 0, + } + }, + + { + .animation = &BA_L0_SdBad_128x51, + .manifest_info = { + .name = "L0_SdBad_128x51", + .min_butthurt = 0, + .max_butthurt = 0, + .min_level = 0, + .max_level = 0, + .weight = 0, + } + }, + + { + .animation = &BA_L0_SdOk_128x51, + .manifest_info = { + .name = "L0_SdOk_128x51", + .min_butthurt = 0, + .max_butthurt = 0, + .min_level = 0, + .max_level = 0, + .weight = 0, + } + }, + + { + .animation = &BA_L0_Url_128x51, + .manifest_info = { + .name = "L0_Url_128x51", + .min_butthurt = 0, + .max_butthurt = 0, + .min_level = 0, + .max_level = 0, + .weight = 0, + } + }, + + { + .animation = &BA_L0_NewMail_128x51, + .manifest_info = { + .name = "L0_NewMail_128x51", + .min_butthurt = 0, + .max_butthurt = 0, + .min_level = 0, + .max_level = 0, + .weight = 0, + } + }, + +}; + +const size_t dolphin_blocking_size = COUNT_OF(dolphin_blocking); diff --git a/assets/compiled/assets_dolphin_blocking.h b/assets/compiled/assets_dolphin_blocking.h new file mode 100644 index 00000000..ba3996ca --- /dev/null +++ b/assets/compiled/assets_dolphin_blocking.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +extern const StorageAnimation dolphin_blocking[]; +extern const size_t dolphin_blocking_size; diff --git a/assets/compiled/assets_dolphin_internal.c b/assets/compiled/assets_dolphin_internal.c new file mode 100644 index 00000000..373a2873 --- /dev/null +++ b/assets/compiled/assets_dolphin_internal.c @@ -0,0 +1,330 @@ +#include +#include +#include +#include + + + +const uint8_t _A_L1_Tv_128x47_0[] = { + 0x1,0x0,0xca,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x66,0x33,0x30,0x50,0x81,0x88,0x1e,0xd0,0x50,0x19,0xa,0x8a,0x8,0x24,0x21,0x31,0x40,0x38,0x0,0x81,0x2d,0x20,0x8,0x41,0xeb,0x38,0x7,0xc0,0xb4,0x46,0xc4,0x78,0x10,0x79,0x80,0xc8,0x64,0x20,0xf4,0x86,0x2,0xcc,0x1e,0xa6,0x21,0xe8,0x40,0x21,0xe5,0x61,0x82,0x60,0x2f,0xe0,0xf7,0xa8,0x78,0x66,0x7,0x61,0x81,0x58,0x11,0xa3,0x2,0xc0,0x43,0xce,0x47,0x48,0x8f,0x25,0x8a,0x5,0x30,0x80,0x41,0x90,0x64,0xf,0x43,0xf9,0xc0,0x7f,0x5,0xb1,0x81,0x78,0x27,0xe0,0xf1,0xff,0xff,0xc7,0x2,0xba,0x20,0x30,0xc0,0x7e,0x10,0x3f,0x4,0x9f,0xc1,0x1f,0x22,0x8e,0x10,0x1e,0x56,0x1,0x39,0x2,0xc6,0xc1,0x26,0xf0,0x48,0xc4,0xc3,0x82,0x7,0x94,0x78,0x1e,0x5c,0x8,0x1f,0x2,0x27,0xc0,0xa0,0x8d,0x8a,0x7,0x0,0xf0,0x38,0x8a,0x8,0x55,0x12,0xf8,0xf0,0x11,0xc3,0x10,0x80,0xa3,0x44,0xec,0x41,0x71,0x30,0x8b,0x1c,0x81,0xe7,0xf0,0x9f,0xae,0x48,0x1e,0x20,0x43,0x7,0x96,0x80,0xa,0x34,0x0,0x51,0xc4,0x16,0x46,0xf,0xa9,0x7,0xd0,0x1e,0xbf,0x2,0x58,0x83,0xd6,0x18,0x5f,0x10,0x79,0xff,0x20,0xe0,0xf1,0x27,0x9d,0x2,0x9,0x7c,0x63,0x88,0x3c,0xbf,0xd0,0xf0,0x7a,0xe0,0x21,0x6,0xe1,0x16,0xe,0xf,0xff,0xfd,0xfb,0xaa,0xc7,0xfe,0xa6,0x10,0x78,0x9b,0xce,0x19,0x9c,0xff,0xa3,0x4,0x1e,0x51,0xd0,0x59,0x70,0x52,0xe2,0xa4,0x1d,0xc0,0x30,0x80,0x3,0x3f,0xf,0x97,0xe0,0x54,0x22,0xf1,0x45,0x88,0x3d,0x39,0xe0,0xf1,0xc0,0x15,0x87,0xff,0x3,0x26,0x8f,0x81,0xf8,0x64,0x61,0x7,0x8d,0xc0,0xa,0x3f,0xc0,0xa0,0x8f,0x10,0x0,0x3f,0x30,0x78,0xc3,0x82,0xe7,0x40,0x7,0xb7,0xd2,0x7f,0xf0,0xe0,0x83,0xd7,0xf8,0xe,0x3b,0xff,0xdf,0xbf,0xf,0xd3,0x18,0x8c,0x1e,0x3c,0x30,0x79,0xe7,0xfe,0xf1,0xfd,0x85,0xe6,0xfc,0xb3,0x3c,0x6,0x0,0x1e,0x7e,0xf0,0x78,0xd3,0xe9,0x39,0x26,0x38,0x83,0xc6,0x80,0xf,0x4f,0x9f,0xdf,0x3e,0x5,0x23,0xe8,0x83,0xc4,0x40,0x24,0x63,0xfe,0x3,0xc4,0xa,0x51,0x80,0x7a,0x7,0xcd,0x84,0x31,0xf1,0x61,0x47,0x1,0xe5,0x10,0x7,0xbc,0x8,0x18,0x31,0xe0,0x10,0xd8,0x1,0xf1,0x4,0x6,0x8,0xfc,0xae,0xf,0x31,0xf3,0x83,0xd4,0x78,0x3c,0x6,0x99,0x6f,0x1,0xe3,0xc3,0xb,0xf,0xe0,0x1e,0x56,0x6,0x18,0xdf,0xc1,0xe3,0x3f,0x83,0x83,0xc7,0x5f,0x32,0xfd,0x83,0xc5,0x6a,0x8f,0x72,0x68,0x8f,0x9c,0x3e,0xae,0x64,0x80,0x4e,0x1,0xe2,0x4f,0x60,0x7a,0xc8,0x1,0xfe,0x2f,0x20,0x7f,0x0 +}; + +const uint8_t _A_L1_Tv_128x47_1[] = { + 0x1,0x0,0xcc,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x45,0x6,0x7,0x98,0x28,0x47,0x44,0xf,0x58,0x48,0x3c,0xc5,0x45,0x4,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0xa,0x20,0x7b,0xb,0x44,0x6c,0x53,0x80,0x7a,0xb,0x4,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x8,0x9c,0xaf,0xe0,0xf9,0x10,0x88,0x28,0x6c,0x8,0xd1,0x81,0x60,0x21,0xe7,0x23,0xd,0x88,0x44,0x41,0xe3,0x30,0x41,0x8a,0xdc,0x81,0xea,0x1,0x10,0x50,0xfe,0x0,0xa3,0x2,0xf0,0x4f,0xc1,0xe3,0xff,0x0,0x14,0x3e,0x1,0xfe,0x2,0xc,0x7,0xe1,0x3,0xf0,0x49,0xfc,0x11,0xf1,0x50,0xc1,0x3c,0xe,0x61,0x8,0x88,0x88,0x41,0x63,0x20,0x7,0x8c,0xfc,0x4c,0x30,0x68,0xe1,0x70,0x60,0x60,0xf2,0xe0,0x40,0xf8,0x11,0x3e,0x5,0x1c,0x1e,0x31,0xa0,0x60,0xf8,0xf,0xa6,0x75,0x12,0xf8,0xf0,0x30,0x65,0xc1,0xf2,0x82,0xc6,0xf0,0xad,0x33,0x8,0xae,0x8,0x1e,0x50,0x50,0x30,0xc7,0x81,0xe6,0xa3,0x30,0x79,0x68,0x12,0xc4,0x50,0x14,0xd1,0x1,0xc8,0x1e,0x81,0x72,0x27,0x12,0x28,0x7e,0x80,0xf5,0xf8,0x44,0x60,0x10,0xe0,0xf9,0xc8,0x21,0x85,0xf1,0x7,0x9f,0xf3,0xcf,0xc0,0x84,0xc1,0x81,0xe5,0x40,0x82,0x5f,0x26,0x10,0x10,0x79,0x7f,0xa1,0xf3,0xf8,0x80,0x3c,0xf0,0x10,0x83,0x70,0x8b,0x7,0x3f,0xff,0xfe,0xfd,0xd6,0x24,0xa6,0x10,0x78,0x9b,0xce,0x19,0xbc,0xff,0xa3,0x4,0x1e,0x51,0xd0,0x59,0x70,0x54,0x87,0xf8,0x67,0x9f,0xfe,0x7e,0x1f,0x2f,0xc6,0xc,0x4a,0x4d,0x41,0x7,0xa7,0x3c,0x12,0x38,0x3,0x18,0xff,0xe0,0xf8,0x5,0xca,0x0,0x7,0xe0,0xf,0x1b,0x80,0x14,0x7f,0x90,0x10,0x79,0x7,0xd3,0xe6,0xf,0x18,0x70,0x5c,0xe8,0x0,0xf6,0xfa,0x4f,0xfe,0x1c,0x10,0x7a,0xff,0x1,0xc7,0x7f,0xfb,0xf7,0xe1,0xfa,0x63,0x11,0x83,0xc4,0x3c,0x99,0xff,0xbc,0x7f,0x61,0x79,0xbf,0x2c,0xcf,0x1,0x87,0x7,0x9f,0xbc,0x1e,0x34,0xfa,0x4e,0x4a,0x2,0xf,0x2e,0x6,0x4,0x9c,0x9f,0x75,0x30,0x80,0x8,0x1e,0x5e,0x3,0x8,0x80,0xb,0xf8,0xf,0x10,0x29,0x7e,0x1,0xe5,0x60,0xc0,0x6,0xd,0x84,0x31,0xf1,0x61,0x7f,0x1,0xe5,0x30,0x7,0xbc,0x8,0x18,0x25,0x2,0xb0,0x3,0xe2,0x8,0xc,0x1b,0xf8,0x8,0x6e,0x11,0x8c,0x7,0x9c,0x1e,0xb1,0x88,0x7,0x0,0x9e,0x5b,0xc0,0x78,0xf0,0xe1,0xe4,0x81,0x7,0x95,0x81,0x86,0x3f,0xf7,0x78,0xcf,0xe1,0xe0,0xf1,0xd7,0xcc,0xbf,0x60,0xf1,0x4b,0x23,0xdc,0x9c,0xc3,0xe7,0xf,0xab,0x99,0x20,0x13,0x80,0x78,0x93,0xd8,0x1e,0xb2,0x0,0x7f,0x8b,0xc8,0x1f,0xc0 +}; + +const uint8_t _A_L1_Tv_128x47_2[] = { + 0x1,0x0,0xc1,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x66,0x33,0x30,0x50,0x81,0x88,0x1e,0xd0,0x50,0x19,0xa,0x8a,0x8,0x24,0x21,0x31,0x40,0x38,0x0,0x81,0x2d,0x20,0x8,0x41,0xeb,0x38,0x7,0xc0,0xb4,0x46,0xc4,0x78,0x10,0x79,0x80,0xc8,0x64,0x20,0xf4,0x86,0x2,0xcc,0x1e,0xa6,0x21,0xe8,0x40,0x21,0xe5,0x61,0x7,0xd5,0x43,0xc3,0x30,0x3b,0x9,0xbc,0xe0,0x58,0x8,0x79,0xc8,0xe9,0x11,0xe4,0xb1,0x3,0xd1,0x4,0xb4,0x83,0xf9,0xa8,0xce,0x5,0xe0,0x9f,0x83,0xc7,0xff,0xff,0xbf,0xae,0x8c,0xc,0x20,0x1,0x81,0xf8,0x24,0xfe,0x8,0xf9,0x14,0x70,0x80,0xf2,0xb0,0x8,0xce,0x3d,0x60,0x93,0x78,0x24,0x68,0x21,0xc1,0x2,0x8c,0x1e,0x70,0x3e,0x4,0x4f,0x81,0x41,0x7,0x8c,0xa,0x7,0x0,0xf0,0xf,0x8c,0xaa,0x25,0xf1,0xe0,0x23,0x86,0x21,0x1,0x46,0x89,0xd8,0x80,0x3,0x30,0x9,0x98,0x3c,0xfe,0x13,0xf5,0xc9,0x40,0x3f,0x10,0x90,0x7a,0xe8,0x0,0xa3,0x40,0x7,0x9c,0x1e,0xc,0xf,0xc1,0xe8,0xfd,0x1,0xeb,0xf0,0x25,0x88,0x3c,0xd1,0x23,0xfc,0x2f,0x88,0x3c,0xff,0x90,0x70,0x78,0x93,0xc8,0x4,0x3e,0xb,0xfb,0x1c,0x41,0xe5,0xfe,0x87,0x83,0xdb,0x81,0xe1,0x4,0x8f,0xc3,0x7,0xff,0xfe,0xfd,0xd5,0x44,0xa6,0x11,0x90,0xce,0x3e,0x1,0x51,0x86,0x67,0x3f,0xe2,0x71,0x7,0x94,0x74,0x1e,0x30,0x8f,0xe0,0x78,0x5a,0x43,0xb8,0x64,0x1f,0xfe,0x7e,0x1f,0x2f,0xc4,0x4e,0x1,0xe,0x73,0xf,0xc0,0x1e,0x9c,0xf0,0x79,0x44,0x3c,0x1c,0x8,0x19,0x34,0x7c,0xa,0x93,0x23,0x8,0x3c,0xdf,0x42,0xf,0x30,0xfa,0x7c,0xc1,0xe3,0x1e,0x40,0x9,0x3c,0x68,0x0,0xf6,0xfa,0x4f,0xfe,0x13,0x99,0x30,0x9c,0x81,0xe3,0xfc,0x7,0x1d,0xff,0xef,0xdf,0x87,0xfd,0xa7,0xe0,0xf4,0xe1,0x83,0xcf,0x3f,0xf7,0x8f,0xec,0x2f,0x37,0xe0,0x79,0x48,0x30,0x18,0x0,0x79,0xfb,0xc1,0xe3,0x4f,0xa4,0xe6,0x98,0xe2,0xf,0x1a,0x0,0x3d,0x3e,0x7f,0x7c,0xf8,0x14,0x91,0xc5,0x20,0x10,0x9,0xb8,0xff,0x80,0xf1,0x2,0x94,0x60,0x1e,0x81,0xf3,0x61,0xc,0x7c,0x58,0x51,0xc0,0x79,0x44,0x1,0xef,0x2,0x6,0xc,0x78,0x4,0x36,0x0,0x7c,0x41,0x1,0x82,0x3f,0x2b,0x84,0x23,0x1,0xe7,0x7,0xa8,0xf0,0x78,0xa,0x31,0x80,0x6f,0x1,0xe3,0xc3,0xb,0xf,0xe0,0x1e,0x56,0x5,0x68,0xdf,0xc1,0xe3,0x3f,0x83,0x83,0xc7,0x5f,0x32,0xfd,0x83,0xc5,0x6a,0x8f,0x72,0x80,0xb,0xc4,0x3e,0xae,0x64,0x80,0x4e,0x1,0xe2,0x4f,0x60,0x7a,0xb8,0xc4,0x1f,0xe5,0xf7,0x7,0xc0 +}; + +const uint8_t _A_L1_Tv_128x47_3[] = { + 0x1,0x0,0xc0,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x45,0x6,0x7,0x98,0x28,0x47,0x44,0xf,0x58,0x48,0x3c,0xc5,0x45,0x4,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0xa,0x20,0x7b,0xb,0x44,0x6c,0x53,0x80,0x7a,0xb,0x4,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x8,0x3f,0x44,0x22,0xa,0x23,0x61,0x60,0x21,0xe7,0x23,0xd,0x88,0x44,0x41,0xea,0x82,0x50,0x78,0x80,0x45,0x84,0x90,0x2f,0x4,0xfc,0x1e,0x3f,0xf0,0x1,0x43,0xe0,0x1f,0xe0,0x31,0xc0,0xfc,0x12,0x7f,0x4,0x7c,0x54,0x30,0x4f,0x3,0x98,0x42,0x22,0x0,0x28,0xf4,0x80,0x1e,0x33,0xf1,0x60,0xc1,0xa3,0x87,0x41,0x81,0x83,0xce,0x7,0xc0,0x89,0xf0,0x28,0xe0,0xf1,0x8d,0x3,0x7,0xc0,0xe,0x33,0xa8,0x97,0xc7,0x81,0x83,0x2e,0xf,0x94,0x14,0x37,0x80,0x79,0xcc,0x2,0x66,0xf,0x28,0x28,0xe4,0x97,0xcc,0xf,0x3d,0x1,0xec,0x8a,0x2,0x9e,0x43,0x68,0x83,0xcc,0x2e,0x44,0xe4,0xf2,0x2e,0x4c,0x1e,0x3f,0x8,0x8c,0x2,0x1c,0x1f,0x39,0xe5,0xf2,0xd,0x18,0x7,0x9f,0xf3,0xcf,0xc0,0x84,0xc1,0x81,0xe5,0xc2,0x87,0xf3,0x11,0x82,0xf,0x2f,0xf4,0x3e,0x7f,0x10,0x7,0x9c,0x4,0x42,0x22,0xf1,0xf8,0x67,0xff,0xff,0xdf,0xba,0xa8,0x83,0x23,0x80,0x8,0x8c,0x38,0x9e,0x30,0xcd,0xe7,0xfd,0x18,0x20,0xf2,0x8e,0x83,0xcc,0x8a,0x50,0x2f,0xc3,0x20,0xff,0xf3,0xf0,0xf9,0xe0,0x4,0xa5,0x1,0xf8,0x3,0xd3,0x9e,0xf,0x31,0x38,0xc1,0xc0,0x84,0x79,0x32,0x30,0x83,0xc6,0xe1,0x1,0xfe,0x7f,0x20,0x21,0x43,0x0,0x1f,0xcc,0x1e,0x30,0xef,0xf3,0xa8,0x60,0x14,0x0,0x7b,0x7d,0x27,0xff,0xe,0x8,0x9c,0xc1,0xe3,0xfc,0x7,0x1d,0xff,0xef,0xdf,0x87,0xe9,0x8c,0x42,0xf,0x30,0xf2,0x67,0xfe,0xf1,0xfd,0x85,0xe6,0xfc,0xf,0x29,0x6,0x3,0xe,0xf,0x3f,0x78,0x3c,0x69,0xf4,0x9c,0x92,0x80,0x41,0xe3,0xc0,0xc0,0x93,0x93,0xee,0xa6,0x10,0x1,0x3,0xcb,0xc0,0x96,0x20,0x0,0xff,0x1,0xe2,0x5,0x2f,0xc0,0x3c,0xac,0x9,0x41,0x0,0x13,0x8,0x63,0xe2,0xc2,0xfe,0x3,0xca,0x60,0xf,0x78,0x10,0x30,0x4a,0x5,0x60,0x7,0xc4,0x10,0x18,0x37,0xf0,0x10,0xdc,0x23,0x18,0xf,0x38,0x3d,0x63,0x10,0xe,0x1,0x3c,0xb7,0x80,0xf1,0xe1,0xc3,0xc9,0x2,0xf,0x2b,0x3,0xc,0x7f,0xf0,0x38,0x4,0xfe,0x1e,0xf,0x1d,0x7c,0xcb,0xf6,0xf,0x14,0xb2,0x3d,0xc9,0xcc,0x3e,0x70,0xfa,0xb9,0x92,0x1,0x38,0x7,0x89,0x3d,0x81,0xeb,0x20,0x7,0xf8,0xbc,0x81,0xfc +}; + +const uint8_t _A_L1_Tv_128x47_4[] = { + 0x1,0x0,0xcb,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x45,0x6,0x7,0x98,0x28,0x47,0x44,0xf,0x58,0x48,0x3c,0xc5,0x45,0x4,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0xa,0x20,0x7b,0xb,0x44,0x6c,0x53,0x80,0x7a,0xb,0x4,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x8,0x9c,0xaf,0xe0,0xf9,0x10,0x88,0x28,0x6c,0x8,0xd1,0x81,0x60,0x21,0xe7,0x23,0xd,0x88,0x44,0x41,0xe3,0x30,0x41,0x8a,0xdc,0x81,0xea,0x1,0x10,0x50,0xfe,0x0,0xa3,0x2,0xf0,0x4f,0xc1,0xe3,0xff,0x0,0x14,0x3e,0x1,0xfe,0x2,0xc,0x7,0xe1,0x3,0xf0,0x49,0xfc,0x11,0xf1,0x50,0xc1,0x3c,0xe,0x61,0x61,0x10,0x74,0x63,0xf6,0x9,0x37,0x82,0x46,0x26,0x18,0x34,0x71,0x64,0x90,0x2e,0x4,0xf,0x81,0x13,0xe0,0x50,0x41,0xe3,0x1a,0x81,0x97,0x4,0xfa,0x67,0x51,0x2f,0x8f,0x0,0x32,0x31,0xf,0x28,0x2c,0x63,0xa,0xd3,0x30,0x8a,0xe0,0x81,0xe5,0x5,0x77,0x2c,0x20,0xca,0x25,0xd1,0x7,0x96,0x81,0x2c,0x44,0xe2,0xb,0x88,0x1c,0x55,0x24,0xf,0x25,0xd9,0x3,0xce,0x41,0xf4,0x1b,0x10,0x3c,0xbe,0x11,0x18,0x4,0x38,0x1e,0x90,0xc8,0x7c,0x58,0x1e,0x7f,0xcf,0x3f,0x2,0x12,0xa9,0x28,0x5,0x2,0x8,0x19,0x20,0x79,0x7f,0xa1,0xf3,0xf8,0x80,0x3c,0xf0,0x4,0xf3,0xf8,0x60,0xff,0xff,0xdf,0xba,0xc4,0x94,0xc2,0xf,0x13,0x79,0xc3,0x33,0x9f,0xf8,0x7,0x80,0x1e,0x51,0xd0,0x59,0x70,0x52,0xe2,0xa4,0x1d,0xc3,0x3c,0xff,0xf3,0xf0,0xf9,0x7e,0x5,0x42,0xd7,0x16,0xa0,0x83,0xd3,0x9e,0xf,0x1c,0x3,0x50,0x7f,0xf0,0x32,0x68,0xf8,0x5,0x4,0x0,0x1f,0x80,0x3c,0x6e,0x0,0x51,0xfe,0x40,0x41,0xe4,0x1f,0x4f,0x98,0x3c,0x61,0xc1,0x73,0xa0,0x3,0xdb,0xe9,0x3f,0xf8,0x70,0x41,0xeb,0xfc,0x7,0x1d,0xff,0xef,0xdf,0x87,0xe9,0x8c,0x46,0xf,0x1e,0x18,0x3c,0xf3,0xff,0x78,0xfe,0xc2,0xf3,0x7e,0x59,0x9e,0x3,0x0,0xf,0x3f,0x78,0x3c,0x69,0xf4,0x9c,0x93,0x10,0xa4,0x14,0x0,0x7a,0x7c,0xfe,0xf9,0xf0,0x29,0x1f,0x44,0x1e,0x22,0x1,0x23,0x1f,0xf0,0x1e,0x20,0x52,0x76,0x88,0x3c,0xc3,0xe6,0xc2,0x18,0xf8,0xb0,0xa3,0x80,0xf2,0x88,0x3,0xdd,0xc2,0x51,0xe0,0x10,0xd8,0x1,0xf1,0x4,0x6,0x8,0xfc,0xae,0x10,0x8c,0x7,0x9c,0x1e,0xa3,0xc1,0xe0,0x34,0xcb,0x78,0xf,0x1e,0x18,0x58,0x7f,0x0,0xf2,0xb0,0x30,0xc6,0xfe,0xf,0x19,0xfc,0x1c,0x1e,0x3a,0xf9,0x97,0xec,0x1e,0x2b,0x54,0x7b,0x93,0x98,0x7c,0xe1,0xf5,0x73,0x24,0x2,0x70,0xf,0x12,0x7b,0x3,0xd6,0x40,0xf,0xf1,0x79,0x3,0xf8 +}; + +const uint8_t _A_L1_Tv_128x47_5[] = { + 0x1,0x0,0xd1,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x45,0x6,0x7,0x98,0x28,0x47,0x44,0xf,0x58,0x48,0x3c,0xc5,0x45,0x4,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0xa,0x20,0x7b,0xb,0x44,0x6c,0x53,0x80,0x7a,0xb,0x4,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x8,0x9c,0xaf,0xe0,0xf9,0x10,0x88,0x28,0x6c,0x8,0xd1,0x81,0x60,0x21,0xe7,0x23,0xd,0x88,0x44,0x41,0xe3,0x30,0x41,0x8a,0xdc,0x81,0xea,0x1,0x10,0x50,0xfe,0x0,0xa3,0x2,0xf0,0x4f,0xc1,0xe3,0xff,0x0,0x14,0x3e,0x1,0xfe,0x2,0xc,0x7,0xe1,0x3,0xf0,0x49,0xfc,0x11,0xf1,0x50,0xc1,0x3c,0xe,0x61,0x8,0x88,0x88,0x41,0x63,0x20,0x7,0x8c,0xfc,0x4c,0x30,0x68,0xe1,0x70,0x60,0x60,0xf2,0xe0,0x40,0xf8,0x11,0x3e,0x5,0x1c,0x1e,0x31,0xa0,0x60,0xf8,0xf,0xa6,0x75,0x12,0xf8,0xf0,0x30,0x65,0xc1,0xf2,0x82,0xc6,0xf0,0xad,0x33,0x8,0xae,0x8,0x1e,0x50,0x50,0x30,0xc7,0x81,0xe6,0xa3,0x30,0x79,0x68,0x12,0xc4,0x50,0x14,0xd1,0x1,0xc8,0x1e,0x81,0x72,0x27,0x12,0x28,0x7e,0x9f,0x3,0xe8,0x83,0xcb,0xe1,0x11,0x80,0x43,0x83,0xe7,0x20,0x86,0x43,0xe2,0x60,0xf3,0xfe,0x79,0xf8,0x10,0x98,0x30,0x3c,0xa8,0x2,0xf1,0x3c,0x8,0x3c,0xbf,0xd0,0xf9,0xfc,0x40,0x1e,0x78,0x6,0x39,0xfc,0x33,0xff,0xff,0xef,0xdd,0x62,0x4a,0x61,0x7,0x89,0xbc,0x41,0xe3,0xc,0xde,0x7f,0xd1,0x82,0xf,0x28,0xe8,0x80,0xb8,0x30,0x32,0x78,0xc0,0xbf,0xc,0xf3,0xff,0xcf,0xc3,0xe5,0xf8,0xc1,0x89,0x49,0xa8,0x20,0xf4,0xe7,0x82,0x47,0x0,0x63,0x1f,0xfc,0x1f,0x0,0xb9,0x40,0x0,0xfc,0x1,0xe3,0x70,0x2,0x8f,0xf2,0x2,0xf,0x20,0xfa,0x7c,0xc1,0xe3,0xe,0xb,0x9d,0x0,0x1e,0xdf,0x49,0xff,0xc3,0x82,0xf,0x5f,0xe0,0x38,0xef,0xff,0x7e,0xfc,0x3f,0x4c,0x62,0x30,0x78,0x87,0x93,0x3f,0xf7,0x8f,0xec,0x2f,0x37,0xe5,0x99,0xe0,0x30,0xe0,0xf3,0xf7,0x83,0xc6,0x9f,0x49,0xc9,0x40,0x41,0xe5,0xc0,0xc0,0x93,0x93,0xee,0xa6,0x10,0x1,0x3,0xcb,0xc0,0x61,0x10,0x1,0x7f,0x1,0xe2,0x5,0x2f,0xc0,0x3c,0xac,0x18,0x0,0xc1,0xb0,0x86,0x3e,0x2c,0x2f,0xe0,0x3c,0xa6,0x0,0xf7,0x81,0x3,0x4,0xa0,0x56,0x0,0x7c,0x3f,0x6,0x1,0x7f,0x1,0xd,0xc2,0x31,0x80,0xf3,0x83,0xd6,0x31,0x0,0xe0,0x13,0xcb,0x78,0xf,0x1e,0x1c,0x3c,0x90,0x20,0xf2,0xb0,0x30,0xc7,0xff,0x3,0x80,0x4f,0xe1,0xe0,0xf1,0xd7,0xcc,0xbf,0x60,0xf1,0x4b,0x23,0xdc,0x9c,0xc3,0xe7,0xf,0xab,0x99,0x20,0x13,0x80,0x78,0x93,0xd8,0x1e,0xb2,0x0,0x7f,0x8b,0xc8,0x1f,0xc0 +}; + +const uint8_t _A_L1_Tv_128x47_6[] = { + 0x1,0x0,0xc1,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x45,0x6,0x7,0x98,0x28,0x47,0x44,0xf,0x58,0x48,0x3c,0xc5,0x45,0x4,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0xa,0x20,0x7b,0xb,0x44,0x6c,0x53,0x80,0x7a,0xb,0x4,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x8,0x3f,0x44,0x22,0xa,0x23,0x61,0x60,0x21,0xe7,0x23,0xd,0x88,0x44,0x41,0xea,0x82,0x50,0x78,0x80,0x45,0x84,0x90,0x2f,0x4,0xfc,0x1e,0x3f,0xf0,0x1,0x43,0xe0,0x1f,0xe0,0x31,0xc0,0xfc,0x12,0x7f,0x4,0x7c,0x54,0x30,0x4f,0x3,0x98,0x58,0x49,0x1e,0xb0,0x49,0xbc,0x12,0x31,0x60,0xc1,0xa3,0x8b,0x24,0x0,0xc,0xf,0x81,0x13,0xe0,0x50,0x41,0xe3,0x1a,0x81,0xc0,0x2c,0x0,0xe3,0x3a,0x89,0x7c,0x78,0x1,0x91,0x88,0x79,0x41,0x43,0x18,0x7,0x9c,0xc0,0x26,0x60,0xf2,0x82,0xbb,0x8f,0xf0,0x41,0x14,0x99,0x83,0xcb,0x40,0x7b,0x20,0x60,0xc1,0x2f,0xc8,0x34,0x7,0x98,0x5c,0x81,0xe5,0x80,0x8f,0xfd,0x1,0xeb,0xf0,0x88,0xc0,0x21,0xc2,0xc3,0xf0,0x43,0xcf,0x62,0xf,0x3f,0xe7,0x9f,0x81,0x9,0x4f,0xb,0x20,0x90,0xe2,0x10,0x10,0x79,0x7f,0xa1,0xf3,0xf8,0x80,0x3c,0x57,0x4,0x22,0x10,0x20,0xfc,0x30,0x7f,0xff,0xef,0xdd,0x54,0x51,0xf3,0xe0,0x9b,0xd2,0x19,0x9c,0xff,0x8e,0x4,0x1e,0x51,0xd8,0x2,0xcc,0x78,0x9,0x71,0x69,0xe,0xe1,0x90,0x7f,0xf9,0xf8,0xe4,0x6f,0x1f,0x81,0x50,0xb5,0xc6,0x3,0xf0,0x7,0xa7,0x3c,0x1e,0x38,0x1,0x0,0xb8,0x4,0x9a,0x3e,0x6,0x4a,0x7c,0x1,0xe3,0x70,0x2,0x8f,0xf1,0xae,0x43,0xc3,0x0,0xf,0xcc,0x1e,0x30,0xe0,0xb9,0xd0,0x1,0xed,0xf4,0x9f,0xfc,0x38,0x20,0xf5,0xfe,0x3,0x8e,0xff,0xf7,0xef,0xc3,0xf4,0xc6,0x21,0x7,0x9f,0xc,0x1e,0x79,0xff,0xbc,0x7f,0x61,0x79,0x68,0x8,0x0,0x64,0x18,0xc,0x0,0x3c,0xfd,0xe0,0xf1,0xa7,0xd2,0x72,0x4c,0x41,0x7,0x8d,0x0,0x1e,0x9f,0x3f,0xbe,0x7c,0xa,0x47,0xd1,0x7,0x88,0x80,0x48,0xc7,0xfc,0x7,0x88,0x14,0xa3,0x0,0xf4,0xf,0x9b,0x8,0x63,0xe2,0xc2,0x8e,0x3,0xca,0x20,0xf,0x77,0x8,0xc0,0x23,0xc0,0x21,0xb0,0x3,0xe2,0x8,0xc,0x11,0xf9,0x5c,0x21,0x18,0xf,0x38,0x3d,0x47,0x83,0xc0,0x51,0x8c,0x3,0x78,0xf,0x1e,0x18,0x58,0x7f,0x0,0xf2,0xb0,0x30,0xc6,0xfe,0xf,0x19,0xfc,0x1c,0x1e,0x3a,0xf9,0x97,0xec,0x1e,0x2b,0x54,0x7b,0x93,0x44,0x7c,0xe1,0xf5,0x73,0x24,0x2,0x70,0xf,0x12,0x7b,0x3,0xd6,0x40,0xf,0xf1,0x79,0x3,0xf8 +}; + +const uint8_t _A_L1_Tv_128x47_7[] = { + 0x1,0x0,0xcd,0x1,0x84,0x0,0x86,0x4,0xb,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0xc,0x62,0x0,0x21,0x80,0x83,0x9b,0x1,0x1,0xe0,0x3,0xf2,0x80,0xa,0x39,0x0,0x58,0x41,0x45,0x6,0x7,0x98,0x28,0x47,0x44,0xf,0x58,0x48,0x3c,0xc5,0x45,0x4,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0xa,0x20,0x7b,0xb,0x44,0x6c,0x53,0x80,0x7a,0xb,0x4,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x8,0x3f,0x44,0x22,0xa,0x23,0x61,0x60,0x21,0xe7,0x23,0xd,0x88,0x44,0x41,0xea,0x82,0x50,0x78,0x80,0x45,0x84,0x7f,0x8,0x1f,0x82,0x7e,0xf,0x1f,0xf8,0x0,0xa1,0xf0,0xf,0xf0,0x14,0xe1,0xde,0x9,0x3f,0x82,0x3e,0x2a,0x18,0x27,0x81,0xcc,0x21,0x11,0x27,0x14,0xc2,0x40,0xf,0x19,0xf8,0xb0,0x60,0xd1,0xc3,0xa0,0xc0,0xc1,0xe5,0x74,0xe0,0x70,0x22,0x7c,0xa,0x38,0x3c,0x63,0x40,0xc1,0xf0,0x13,0x8f,0xf9,0x1,0x2f,0x8f,0x3,0x6,0x5c,0x1f,0x28,0x28,0x6f,0x0,0xf3,0xfc,0xd,0x85,0x12,0x20,0xf2,0x82,0x81,0x86,0x3c,0xc,0x17,0xc8,0x92,0xc8,0x1e,0x7a,0x3,0xd9,0x6,0x46,0x9,0x7e,0x22,0xd,0xfc,0x1e,0xaa,0xb2,0x20,0x8c,0x13,0x0,0x1d,0x1c,0x38,0x18,0x41,0xe5,0xf0,0x88,0xc0,0x21,0xc1,0xf1,0xa,0xf,0x83,0x1f,0x1,0x9,0x8,0x3c,0xbf,0x9e,0x7e,0x4,0x26,0xc,0xc8,0x3f,0xc7,0xfd,0x3a,0x20,0xf2,0xff,0x43,0xe7,0xf1,0x0,0x78,0xae,0x9,0xc6,0x7f,0xc,0xff,0xff,0xfb,0xf7,0x55,0x94,0x7d,0xe4,0x20,0xf4,0x86,0x6f,0x3f,0xe3,0x81,0x7,0x94,0x74,0xc4,0x53,0x7,0x11,0x8d,0x4,0x0,0x73,0xf2,0x48,0xde,0x3f,0x1c,0x31,0x28,0xc0,0x20,0x3f,0x0,0x7a,0x73,0xc1,0x23,0x80,0x83,0xe0,0x3f,0xe0,0x21,0x5c,0xa9,0x18,0x41,0xe3,0x70,0x2,0x8f,0xf9,0x80,0x23,0xc4,0x0,0xf,0xcc,0x1e,0x30,0xe0,0xb9,0xd0,0x1,0xed,0xf4,0x9f,0xfc,0x38,0x20,0xf5,0xfe,0x3,0x8e,0xff,0xf7,0xef,0xc3,0xf4,0xc6,0x21,0x7,0x98,0x79,0x33,0xff,0x78,0xfe,0xc2,0xf2,0xd0,0x10,0x0,0xc8,0x30,0x18,0x70,0x79,0xfb,0xc1,0xe3,0x4f,0xa4,0xe4,0x9e,0x22,0xf,0x1e,0x6,0x4,0x9c,0x9f,0x75,0x30,0x80,0x8,0x1e,0x5e,0x3,0x8,0x80,0xb,0xf8,0xf,0x10,0x29,0x7e,0x1,0xe5,0x60,0x42,0x8,0x0,0x98,0x43,0x1f,0x16,0x17,0xf0,0x1e,0x53,0x0,0x7b,0xc0,0x81,0x82,0x50,0x2b,0x0,0x3e,0x20,0x80,0xc1,0xbf,0x80,0x86,0xe1,0x18,0xc0,0x79,0xc1,0xeb,0x18,0x80,0x70,0x9,0xe5,0xbc,0x7,0x8f,0xe,0x1e,0x48,0x10,0x79,0x58,0x18,0x63,0xff,0x81,0xc0,0x27,0xf0,0xf0,0x78,0xeb,0xe6,0x5f,0xb0,0x78,0xa5,0x91,0xee,0x4e,0x61,0xf3,0x87,0xd5,0xcc,0x90,0x9,0xc0,0x3c,0x49,0xec,0xf,0x59,0x0,0x3f,0xc5,0xe4,0xf,0xe0 +}; + + +const uint8_t *_A_L1_Tv_128x47[] = { + + _A_L1_Tv_128x47_0, + + _A_L1_Tv_128x47_1, + + _A_L1_Tv_128x47_2, + + _A_L1_Tv_128x47_3, + + _A_L1_Tv_128x47_4, + + _A_L1_Tv_128x47_5, + + _A_L1_Tv_128x47_6, + + _A_L1_Tv_128x47_7, + +}; + + + +const FrameBubble L1_Tv_128x47_bubble_0_0; + +const FrameBubble L1_Tv_128x47_bubble_1_0; + + +const FrameBubble* const L1_Tv_128x47_bubble_sequences[] = { + + &L1_Tv_128x47_bubble_0_0, + + &L1_Tv_128x47_bubble_1_0, + +}; + + + +const FrameBubble L1_Tv_128x47_bubble_0_0 = { + .bubble = { + .x = 1, + .y = 23, + .text = "Take the red pill", + .align_h = AlignRight, + .align_v = AlignBottom, + }, + .start_frame = 7, + .end_frame = 9, + .next_bubble = NULL, +}; + + +const FrameBubble L1_Tv_128x47_bubble_1_0 = { + .bubble = { + .x = 1, + .y = 23, + .text = "I can joke better", + .align_h = AlignRight, + .align_v = AlignBottom, + }, + .start_frame = 7, + .end_frame = 9, + .next_bubble = NULL, +}; + + + +const uint8_t L1_Tv_128x47_frame_order[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + +const BubbleAnimation BA_L1_Tv_128x47 = { + .icon_animation = { + .width = 128, + .height = 47, + .frame_count = 8, + .frame_rate = 2, + .frames = _A_L1_Tv_128x47 + }, + .frame_order = L1_Tv_128x47_frame_order, + .passive_frames = 6, + .active_frames = 2, + .active_cooldown = 5, + .active_cycles = 2, + .duration = 3600, + + .frame_bubble_sequences = L1_Tv_128x47_bubble_sequences, + .frame_bubble_sequences_count = COUNT_OF(L1_Tv_128x47_bubble_sequences), + +}; + + +const uint8_t _A_L1_BadBattery_128x47_0[] = { + 0x1,0x0,0xb,0x1,0x0,0x47,0xfb,0xfe,0x0,0x2b,0x38,0x3e,0x60,0x40,0x43,0xbf,0x3,0xe7,0xa5,0xf3,0xff,0xf9,0x2f,0xf5,0x60,0xff,0x5a,0x81,0xf3,0xa,0x2,0x18,0x7e,0x81,0xe9,0xea,0x87,0x8b,0xf7,0xad,0x1d,0x7,0xef,0xaa,0x30,0x2f,0xd0,0xfd,0x62,0xa6,0x30,0x9,0x84,0x18,0x7f,0x50,0xa8,0xdc,0x2,0xc1,0x3,0x2f,0xdc,0x3a,0x1,0xc0,0x80,0x9f,0xec,0x1e,0x61,0xfb,0x17,0x98,0x7e,0x89,0xe8,0x9f,0xf5,0xff,0x87,0xfc,0xff,0x69,0xf4,0x8f,0x83,0xe3,0xc5,0x1,0xff,0x40,0xd7,0xf7,0xfa,0x83,0xfc,0x60,0xe1,0xfb,0x7,0x8f,0xfc,0x1e,0x23,0xfa,0xff,0x2,0x8c,0xbf,0x40,0xf4,0x3f,0xd0,0x7f,0xfe,0x5c,0xff,0xff,0xd2,0xa2,0x1f,0xaf,0x9,0x34,0x40,0x3,0x7e,0x7,0x46,0x3,0x8f,0xff,0x0,0x15,0x9c,0x1f,0x1c,0xe,0x7c,0x4,0x57,0x20,0x2,0xa0,0x4b,0xc1,0xd9,0x0,0x90,0x47,0x81,0xfb,0x10,0x87,0x3,0xf6,0x10,0x5e,0x30,0x5,0x61,0x20,0xa0,0xfd,0xa1,0x3,0xfa,0x4c,0xf,0x64,0x29,0x80,0xe,0x3e,0xf,0xe0,0x7,0x97,0x9f,0x8f,0x18,0xb3,0x62,0xe6,0xd6,0xed,0xc,0x6c,0x1e,0xfb,0x7e,0xb5,0x6f,0xbb,0xd4,0xa7,0xef,0x7d,0x70,0x78,0x84,0xe6,0x71,0xe6,0xf7,0x53,0xa0,0x21,0xf1,0xa1,0x77,0xaa,0x52,0xed,0xe,0x6a,0xf,0xb0,0x82,0xd2,0x29,0x32,0x4a,0x94,0x7,0x6f,0xda,0xf,0x8f,0x5a,0xdd,0xbd,0xbd,0x41,0xea,0x11,0x99,0xc5,0x3f,0xc9,0x8e,0x1f,0x8c,0x5a,0xb4,0x3f,0x1b,0x7d,0x87,0x1a,0x2f,0x19,0x8,0x7c,0xb1,0x46,0xf8,0x7,0x8e,0x76,0x71,0x49,0xf2,0x64,0x81,0xf2,0x5f,0x60,0x7f,0x80 +}; + +const uint8_t _A_L1_BadBattery_128x47_1[] = { + 0x1,0x0,0x11,0x1,0x0,0x47,0xfb,0xfe,0x0,0x2b,0x38,0x3e,0x60,0x40,0x43,0xbf,0x3,0xe7,0xa5,0xf3,0xff,0xf9,0x2f,0xf5,0x60,0xff,0x5a,0x81,0xf3,0xa,0x2,0x18,0x7e,0x81,0xe9,0xea,0x87,0x8b,0xf7,0xad,0x1d,0x7,0xef,0xaa,0x30,0x2f,0xd0,0xfd,0x62,0xa6,0x30,0x9,0x84,0x18,0x7f,0x50,0xa8,0xdc,0x2,0xc1,0x3,0x2f,0xdc,0x3a,0x1,0xc0,0x80,0x9f,0xec,0x1e,0x61,0xfb,0x17,0x98,0x7e,0x89,0xe8,0x9f,0xf5,0xff,0x87,0xfc,0xff,0x70,0xf,0xe4,0x5,0x3e,0x31,0xf0,0x7c,0x78,0xa0,0x3c,0x28,0x1a,0xfe,0xff,0x50,0x7f,0x8c,0x1c,0x3f,0x60,0xf1,0xfc,0x83,0xc4,0x7f,0x5f,0xe8,0x7f,0xfc,0x1e,0x25,0xfa,0x7,0x89,0xff,0x41,0xe8,0x1f,0xaf,0x97,0x3f,0xff,0xf4,0xa8,0x87,0xeb,0xc2,0x3d,0x10,0x0,0xdf,0x81,0xd1,0x80,0xe3,0xff,0xc0,0x5,0x67,0x7,0xc7,0x3,0x9e,0x9d,0x10,0x5,0xd0,0x25,0xe0,0xec,0x80,0x48,0x23,0xc0,0xfd,0x88,0x43,0x81,0xfb,0x8,0x2f,0x18,0x2,0xb0,0x90,0x50,0x7e,0xd0,0x81,0xfd,0x26,0x7,0xb2,0x14,0xc0,0x7,0x1f,0x7,0xf0,0x3,0xcb,0xcf,0xc7,0x8c,0x59,0xb1,0x73,0x6b,0x76,0x86,0x36,0xf,0x7d,0xbf,0x5a,0xb7,0xdd,0xea,0x53,0xf7,0xbe,0xb8,0x3c,0x42,0x73,0x38,0xf3,0x7b,0xa9,0xd0,0x10,0xf8,0xd0,0xbb,0xd5,0x29,0x76,0x87,0x35,0x7,0xd8,0x41,0x69,0x14,0x99,0x25,0x4a,0x3,0xb7,0xed,0x7,0xc7,0xad,0x6e,0xde,0xde,0xa0,0xf5,0x8,0xcc,0xe2,0x9f,0xe4,0xc7,0xf,0xc6,0x2d,0x5a,0x1f,0x8d,0xbe,0xc3,0x8d,0x17,0x8c,0x84,0x3e,0x58,0xa3,0x7c,0x3,0xc7,0x3b,0x38,0xa4,0xf9,0x32,0x40,0xf9,0x2f,0xb0,0x3f,0xc0 +}; + + +const uint8_t *_A_L1_BadBattery_128x47[] = { + + _A_L1_BadBattery_128x47_0, + + _A_L1_BadBattery_128x47_1, + +}; + + + +const FrameBubble L1_BadBattery_128x47_bubble_0_0; + + +const FrameBubble* const L1_BadBattery_128x47_bubble_sequences[] = { + + &L1_BadBattery_128x47_bubble_0_0, + +}; + + + +const FrameBubble L1_BadBattery_128x47_bubble_0_0 = { + .bubble = { + .x = 4, + .y = 21, + .text = "I feel so sick!\nI'm dying...", + .align_h = AlignRight, + .align_v = AlignCenter, + }, + .start_frame = 0, + .end_frame = 1, + .next_bubble = NULL, +}; + + + +const uint8_t L1_BadBattery_128x47_frame_order[] = { 0, 1 }; + +const BubbleAnimation BA_L1_BadBattery_128x47 = { + .icon_animation = { + .width = 128, + .height = 47, + .frame_count = 2, + .frame_rate = 2, + .frames = _A_L1_BadBattery_128x47 + }, + .frame_order = L1_BadBattery_128x47_frame_order, + .passive_frames = 2, + .active_frames = 0, + .active_cooldown = 0, + .active_cycles = 0, + .duration = 3600, + + .frame_bubble_sequences = L1_BadBattery_128x47_bubble_sequences, + .frame_bubble_sequences_count = COUNT_OF(L1_BadBattery_128x47_bubble_sequences), + +}; + + +const uint8_t _A_L1_NoSd_128x49_0[] = { + 0x1,0x0,0x49,0x1,0x0,0x5e,0x3,0xff,0x7,0x7,0xe5,0xc2,0x1,0x38,0x7,0xe4,0x32,0x1,0xc0,0x7,0xe4,0xc,0x4,0x5c,0xf,0xf8,0x0,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x0,0xf2,0x22,0xb5,0x0,0x6,0x50,0x8b,0x6,0x4a,0x49,0x49,0x83,0x3,0xd6,0x40,0x3,0x28,0x80,0x3e,0xa2,0x1,0x33,0x7,0xd4,0x20,0x1f,0xe4,0x33,0x7,0xd4,0x10,0x1e,0x65,0xfa,0x7,0x9e,0x0,0x1f,0x50,0x20,0x7f,0x81,0xc,0x1f,0xe0,0xfa,0x80,0x80,0x86,0x1e,0xf,0xde,0x4,0xf0,0x1f,0xb6,0xb,0xc0,0x3f,0xc1,0xfb,0x70,0xfc,0x40,0x3a,0x0,0xfc,0xec,0x40,0x3d,0x0,0xfb,0xf8,0x7f,0x20,0x1f,0x40,0x7d,0xec,0x35,0xf0,0xf,0xe7,0x26,0x4d,0xe7,0xf,0xce,0xf4,0x1e,0x38,0xd,0xdf,0x68,0x1f,0x1e,0xa,0xe8,0x3c,0x72,0x9b,0xae,0xd8,0x3d,0xa0,0xb0,0x9,0x5,0x1c,0x1e,0x5a,0x61,0x7b,0xc0,0xd3,0xe3,0x30,0x7,0x92,0xff,0x7e,0x19,0x48,0x1f,0x44,0x1e,0xb8,0x0,0x1a,0x3,0xc7,0xf3,0x2f,0x7,0xad,0x0,0x6,0x54,0x88,0x17,0xc3,0xff,0xc0,0x8f,0x83,0xd6,0x40,0x3,0x29,0x24,0x4,0x1e,0x38,0x18,0x78,0x3d,0x62,0x0,0x32,0xc9,0x2f,0xcb,0x1f,0x0,0x7,0xac,0x20,0x6,0x54,0x95,0xf8,0xdf,0xf0,0x18,0x8,0x3f,0x80,0x22,0x70,0x40,0x10,0xc1,0x80,0x43,0xf4,0x7,0x8f,0x2,0xf,0x10,0xec,0x4,0x8,0x1e,0x38,0x3,0x89,0x7f,0x19,0xe7,0x10,0x90,0xb,0x8,0x1e,0x37,0x81,0x29,0x3,0xd8,0x98,0x40,0xf1,0x1a,0x98,0x3d,0x2c,0x0,0xf3,0xf2,0x78,0x16,0x24,0xf,0x5c,0x4,0xff,0xc0,0x3a,0x18,0xc4,0x7c,0x8,0x40,0xf6,0x45,0x8c,0xf8,0xfe,0x5f,0xc0,0x7b,0xd0,0x28,0x10,0x4e,0x4,0x3e,0xc1,0x80,0xff,0x8f,0xdc,0x1e,0x4c,0x81,0x3,0x8c,0xfc,0x1f,0x1c,0x2,0x49,0x40,0x3f,0xce,0xd1,0x7,0xc2,0xc0,0xff,0xc1,0x43,0x7,0xd4,0x8,0x8,0x60,0xff,0xfc,0x3,0xca,0x7,0x80,0xb0,0x2,0x8c,0xda,0x40,0x7,0xb0,0x83,0xfb,0xfc,0xb,0x30,0x7a,0x0 +}; + +const uint8_t _A_L1_NoSd_128x49_1[] = { + 0x1,0x0,0x42,0x1,0x0,0x5e,0x3,0xff,0x7,0x7,0xe5,0xc2,0x1,0x38,0x7,0xe4,0x32,0x1,0xc0,0x7,0xe4,0xc,0x4,0x5c,0xf,0xf8,0x0,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x0,0xf2,0x22,0xb5,0x0,0x6,0x50,0x8b,0x6,0x4a,0x49,0x49,0x83,0x3,0xd6,0x40,0x3,0x28,0x80,0x3e,0xa2,0x1,0x33,0x7,0xd4,0x20,0x1f,0xe4,0x33,0x7,0xd4,0x10,0x1e,0x65,0xfa,0x7,0x9e,0x0,0x1f,0x50,0x20,0x7f,0x81,0xc,0x1f,0xe0,0xfa,0x80,0x80,0x86,0x1e,0xf,0xde,0x4,0xf0,0x1f,0xb6,0xb,0xc0,0x3f,0xc1,0xfb,0x70,0xfc,0x40,0x3a,0x0,0xfc,0xec,0x40,0x3d,0x0,0xfb,0xf8,0x7f,0x20,0x1f,0x40,0x7d,0xec,0x35,0xf0,0xf,0xe7,0x26,0x4d,0xe7,0xf,0xce,0xf4,0x1e,0x38,0xd,0xdf,0x68,0x1f,0x1e,0xa,0xe8,0x3c,0x72,0x9b,0xae,0xd8,0x3d,0xa0,0xb0,0x9,0x5,0x1c,0x1e,0x5a,0x61,0x7b,0xc0,0xd3,0xe3,0x30,0x7,0x92,0xff,0x7e,0x19,0x48,0x1f,0x44,0x1e,0xb8,0x0,0x1a,0x3,0xc7,0xf3,0x2f,0x7,0xad,0x0,0x6,0x54,0x88,0x17,0xc3,0xff,0xc0,0x8f,0x83,0xd6,0x40,0x3,0x29,0x24,0x4,0x1e,0x38,0x18,0x78,0x3d,0x62,0x0,0x32,0xc9,0x2f,0xcb,0x1f,0x0,0x7,0xac,0x20,0x6,0x54,0x95,0xf8,0xdf,0xf0,0x18,0x0,0x7a,0xc1,0x0,0x43,0x6,0x1,0xf,0xd0,0x1e,0x3c,0x0,0x78,0xf8,0x2,0x44,0xf,0x1c,0x1,0xc4,0xbf,0x8c,0xf4,0x88,0x76,0x0,0x62,0xf,0x1b,0xc0,0x94,0x81,0xed,0x20,0x1e,0x88,0x3c,0x46,0xe6,0xf,0x72,0xe8,0xf9,0x3c,0xb,0x12,0x7,0xb5,0x80,0x1e,0x51,0x88,0xff,0x80,0x7f,0x18,0x9,0xf8,0x2c,0x42,0x23,0xfc,0x7,0xca,0x70,0x67,0xd6,0xc,0x7,0xfc,0x7f,0x14,0xa,0x4,0x13,0x81,0x8f,0xff,0xcf,0xc1,0xf6,0xd9,0x1f,0xfb,0xb4,0x41,0xf1,0xc0,0x2d,0x17,0xf8,0x6,0x40,0xf8,0x5,0x14,0x9,0x6a,0x60,0xff,0xfc,0x3,0xc8,0x4e,0x20,0xf4,0x36,0x90,0x1,0xf0,0x16,0x0,0x7e,0xc0,0x2c,0x20,0xf7 +}; + +const uint8_t _A_L1_NoSd_128x49_2[] = { + 0x1,0x0,0x41,0x1,0x0,0x5e,0x3,0xff,0x7,0x7,0xe5,0xc2,0x1,0x38,0x7,0xe4,0x32,0x1,0xc0,0x7,0xe4,0xc,0x4,0x5c,0xf,0xf8,0x0,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x0,0xf2,0x22,0xb5,0x0,0x6,0x50,0x8b,0x6,0x4a,0x49,0x49,0x83,0x3,0xd6,0x40,0x3,0x28,0x80,0x3e,0xa2,0x1,0x33,0x7,0xd4,0x20,0x1f,0xe4,0x33,0x7,0xd4,0x10,0x1e,0x65,0xfa,0x7,0x9e,0x0,0x1f,0x50,0x20,0x7f,0x81,0xc,0x1f,0xe0,0xfa,0x80,0x83,0xfc,0x1f,0xe0,0xff,0x2e,0x8c,0xfc,0x1f,0xbe,0xb,0xc4,0x3,0xa0,0xf,0xbb,0x6,0xe2,0x1,0xe8,0x7,0xdf,0xc3,0xf9,0x0,0xfa,0x3,0xef,0x61,0xdf,0x80,0x7f,0x39,0x32,0x6f,0x38,0x7e,0x77,0x20,0xf1,0xc0,0x6e,0xfb,0x44,0xf9,0xac,0x83,0xc7,0x29,0xba,0xed,0x83,0xda,0xb,0x0,0xe0,0x1b,0xc4,0x1e,0x3a,0x61,0x7b,0xc0,0xc0,0x86,0xf,0x14,0xfd,0xe4,0x8,0x43,0x94,0x81,0xf4,0x41,0xeb,0x80,0x1,0x95,0x22,0x4,0xf,0x1f,0xcc,0xbc,0x1e,0xb4,0x0,0x91,0x49,0x20,0x3f,0xf,0xff,0x2,0x3e,0xf,0x59,0x0,0x48,0xb2,0x50,0x40,0x78,0xe0,0x61,0xe0,0xf5,0x88,0x4,0x8a,0x93,0x2,0x5f,0x8e,0x3e,0x0,0xf,0x58,0x40,0x8c,0xe1,0x3e,0x8b,0xfe,0x3,0x0,0xf,0x58,0x20,0x8,0x60,0xd8,0x8,0x27,0xd0,0x1e,0x3c,0x0,0x7b,0xe0,0xe,0x25,0xfc,0x67,0xc0,0x3c,0x5f,0xa2,0xf,0x7f,0xc0,0x64,0x81,0xe3,0x1f,0x7,0xc4,0x13,0xec,0x10,0x1f,0x27,0x80,0x4e,0x60,0xf6,0x84,0x40,0xa0,0x1d,0x8f,0xf8,0x90,0x81,0xf0,0x2d,0x1f,0x7,0xc5,0x62,0x60,0xf5,0x8c,0x3,0xce,0x3f,0x70,0x7,0xc7,0x82,0x1e,0x5b,0x15,0x78,0xcf,0x1,0xf1,0x20,0x84,0x60,0x21,0xe0,0xf1,0x2f,0xcc,0x42,0x20,0xd8,0x1a,0x1f,0x2,0x1e,0xf,0xb0,0x49,0x1b,0xe6,0x21,0xf0,0x5,0x17,0xf8,0xde,0x7f,0x80,0x79,0x40,0xc1,0xe3,0x30,0x5,0x15,0xf5,0x6c,0x8f,0xb5,0x7,0x98,0x78,0xc1,0xff,0x0 +}; + +const uint8_t _A_L1_NoSd_128x49_3[] = { + 0x1,0x0,0x45,0x1,0x0,0x5e,0x3,0xff,0x7,0x7,0xe5,0xc2,0x1,0x38,0x7,0xe4,0x32,0x1,0xc0,0x7,0xe4,0xc,0x4,0x5c,0xf,0xf8,0x0,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x0,0xf2,0x22,0xb5,0x0,0x6,0x50,0x8b,0x6,0x4a,0x49,0x49,0x83,0x3,0xd6,0x40,0x3,0x28,0x80,0x3e,0xa2,0x1,0x33,0x7,0xd4,0x20,0x1f,0xe4,0x33,0x7,0xd4,0x10,0x1e,0x65,0xfa,0x7,0x9e,0x0,0x1f,0x50,0x20,0x7f,0x81,0xc,0x1f,0xe0,0xfa,0x80,0x83,0xfc,0x1f,0xe0,0xff,0x2e,0x8c,0xfc,0x1f,0xbe,0xb,0xc4,0x3,0xa0,0xf,0xbb,0x6,0xe2,0x1,0xe8,0x7,0xdf,0xc3,0xf9,0x0,0xfa,0x3,0xef,0x61,0xdf,0x80,0x7f,0x39,0x32,0x6f,0x38,0x7e,0x77,0x20,0xf1,0xc0,0x6e,0xfb,0x44,0xf9,0xac,0x83,0xc7,0x29,0xba,0xed,0x83,0xda,0xb,0x0,0xe0,0x1b,0xc4,0x1e,0x3a,0x61,0x7b,0xc0,0xc0,0x86,0xf,0x14,0xfd,0xe4,0x8,0x43,0x94,0x81,0xf4,0x41,0xeb,0x80,0x1,0x95,0x22,0x4,0xf,0x1f,0xcc,0xbc,0x1e,0xb4,0x0,0x91,0x49,0x20,0x3f,0xf,0xff,0x2,0x3e,0xf,0x59,0x0,0x48,0xb2,0x50,0x40,0x78,0xe0,0x61,0xe0,0xf5,0x88,0x4,0x8a,0x93,0x2,0x5f,0x8e,0x3e,0x0,0xf,0x58,0x40,0x8c,0xe1,0x3e,0x8b,0xfe,0x3,0x0,0xf,0x58,0x20,0x8,0x60,0xd8,0x8,0x27,0xd0,0x1e,0x3c,0x0,0x7b,0xe0,0xe,0x25,0xfc,0x67,0xc0,0x3c,0x5f,0xa2,0xf,0x7f,0xc0,0x64,0x81,0xe2,0x17,0x30,0x7a,0xc1,0x3e,0xc1,0x1,0xf2,0x78,0x16,0x26,0xf,0x68,0x44,0xa,0x1,0x18,0x8f,0xf8,0x7,0xf0,0xf,0x11,0x68,0x9f,0xc7,0xf8,0xf,0x88,0xc0,0x3c,0xac,0x18,0xf,0xf8,0xfe,0x3c,0x10,0xf2,0xd8,0x83,0x85,0xfa,0x20,0xf7,0x90,0x42,0x30,0x10,0xf8,0x7,0xf8,0x4,0x20,0xf7,0x88,0x44,0x1b,0x3,0x3,0xff,0x17,0x88,0x1f,0x20,0x91,0x8f,0xa5,0x4c,0x1e,0xdf,0x0,0x51,0x1c,0x84,0x0,0x5f,0x80,0x79,0x9,0xc6,0x21,0x30,0x5,0x11,0xb4,0x80,0xe,0xf,0xf0,0x7c,0x80 +}; + +const uint8_t _A_L1_NoSd_128x49_4[] = { + 0x1,0x0,0x3d,0x1,0x0,0x5e,0x3,0xff,0x7,0x7,0xe5,0xc2,0x1,0x38,0x7,0xe4,0x32,0x1,0xc0,0x7,0xe4,0xc,0x4,0x5c,0xf,0xf8,0x0,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x0,0xf2,0x22,0xb5,0x0,0x6,0x50,0x8b,0x6,0x4a,0x49,0x49,0x83,0x3,0xd6,0x40,0x3,0x28,0x80,0x3e,0xa2,0x1,0x33,0x7,0xd4,0x20,0x1f,0xe4,0x33,0x7,0xd4,0x10,0x1e,0x65,0xfa,0x7,0x9e,0x0,0x1f,0x50,0x20,0x7f,0x81,0xc,0x1f,0xe0,0xfa,0x80,0x83,0xfc,0x1f,0xe0,0xff,0x7,0xf8,0x10,0xfa,0x0,0xfc,0xe0,0x40,0x3d,0x0,0xfc,0xf0,0x40,0x3e,0x80,0xfb,0x98,0x7c,0x20,0x1f,0xce,0x4c,0x9b,0xce,0xf,0x8f,0x85,0xfc,0x1e,0x38,0xd,0xdf,0x68,0x1f,0x1e,0x9,0xf8,0x3c,0x72,0x9b,0xae,0xd8,0x3d,0xa0,0xa4,0xe1,0x8f,0x83,0xcb,0x4c,0x2f,0x78,0x18,0x10,0xc1,0xe2,0x5f,0xbc,0x81,0x8,0x72,0x90,0x3e,0x88,0x3d,0x70,0x0,0x32,0xa4,0x40,0x81,0xe3,0xf9,0x97,0x83,0xd6,0x80,0x12,0x29,0x24,0x7,0xe1,0xff,0x22,0x8,0x3d,0x64,0x1,0x22,0xc9,0x41,0x1,0xe3,0x81,0x87,0x83,0xd6,0x20,0x12,0x2a,0x4c,0x9,0x7e,0x38,0xf8,0x0,0x3d,0x61,0x2,0x33,0x84,0xfa,0x2f,0xf8,0xc,0x0,0x3d,0x60,0x80,0x21,0x83,0x60,0x20,0x9f,0x40,0x78,0xf0,0x1,0xef,0x80,0x38,0x97,0xf1,0x9f,0x0,0xf1,0xbc,0x23,0xcc,0x1e,0x9f,0x80,0xc9,0x3,0xc5,0x5a,0x20,0xf7,0x82,0x7d,0x82,0x3,0xe4,0xf0,0x9,0xcc,0x1e,0xd0,0x88,0x14,0x3,0xb1,0xff,0x12,0x10,0x3e,0x5,0xa3,0xe0,0xf8,0xac,0x4c,0x1e,0xb1,0x80,0x79,0xc7,0xee,0x0,0xf8,0xf0,0x43,0xcb,0x62,0xaf,0x19,0xe0,0x3e,0x24,0x10,0x8c,0x4,0x3c,0x1e,0x25,0xf9,0x88,0x44,0x1b,0x3,0x43,0xe0,0x43,0xc1,0xf6,0x9,0x23,0x7c,0xc4,0x3e,0x0,0xa2,0xff,0x1b,0xcf,0xf0,0xf,0x28,0x18,0x3c,0x66,0x0,0xa2,0xbe,0xad,0x91,0xf6,0xa0,0xf3,0xf,0x18,0x3f,0xe0,0x0 +}; + +const uint8_t _A_L1_NoSd_128x49_5[] = { + 0x1,0x0,0x43,0x1,0x0,0x5e,0x3,0xff,0x7,0x7,0xe5,0xc2,0x1,0x38,0x7,0xe4,0x32,0x1,0xc0,0x7,0xe4,0xc,0x4,0x5c,0xf,0xf8,0x0,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x0,0xf2,0x22,0xb5,0x0,0x6,0x50,0x8b,0x6,0x4a,0x49,0x49,0x83,0x3,0xd6,0x40,0x3,0x28,0x80,0x3e,0xa2,0x1,0x33,0x7,0xd4,0x20,0x1f,0xe4,0x33,0x7,0xd4,0x10,0x1e,0x65,0xfa,0x7,0x9e,0x0,0x1f,0x50,0x20,0x7f,0x81,0xc,0x1f,0xe0,0xfa,0x80,0x80,0x86,0x1e,0xf,0xde,0x4,0xf0,0x1f,0xb6,0xb,0xc0,0x3f,0xc1,0xfb,0x70,0xfc,0x40,0x3a,0x0,0xfc,0xec,0x40,0x3d,0x0,0xfb,0xf8,0x7f,0x20,0x1f,0x40,0x7d,0xec,0x35,0xf0,0xf,0xe7,0x26,0x4d,0xe7,0xf,0xce,0xf4,0x1e,0x38,0xd,0xdf,0x68,0x1f,0x1e,0xa,0xe8,0x3c,0x72,0x9b,0xae,0xd8,0x3d,0xa0,0xb0,0x9,0x5,0x1c,0x1e,0x5a,0x61,0x7b,0xc0,0xd3,0xe3,0x30,0x7,0x92,0xff,0x7e,0x19,0x48,0x1f,0x44,0x1e,0xb8,0x0,0x1a,0x3,0xc7,0xf3,0x2f,0x7,0xad,0x0,0x6,0x54,0x88,0x17,0xc3,0xff,0xc0,0x8f,0x83,0xd6,0x40,0x3,0x29,0x24,0x4,0x1e,0x38,0x18,0x78,0x3d,0x62,0x0,0x32,0xc9,0x2f,0xcb,0x1f,0x0,0x7,0xac,0x20,0x6,0x54,0x95,0xf8,0xdf,0xf0,0x18,0x0,0x7a,0xc1,0x0,0x43,0x6,0x1,0xf,0xd0,0x1e,0x3c,0x0,0x7b,0xe0,0xe,0x25,0xfc,0x67,0xc0,0x3c,0x6f,0x0,0x52,0x7,0xaf,0xe0,0x32,0x40,0xf1,0x8f,0x83,0xe2,0x9,0xf6,0x8,0xf,0x93,0xc0,0x27,0x30,0x7b,0x42,0x20,0x50,0xe,0xc7,0xfc,0x48,0x40,0xf8,0x16,0x8f,0x83,0xe2,0xb1,0x30,0x7a,0xc6,0x1,0xe7,0x1f,0xb8,0x3,0xe3,0xc1,0xf,0x2d,0x8a,0xbc,0x67,0x80,0xf8,0x90,0x42,0x30,0x10,0xf0,0x78,0x97,0xe6,0x21,0x10,0x64,0xd,0xf,0x80,0xfd,0x10,0x7d,0x2,0x48,0xdf,0x31,0xf,0x80,0x28,0xbf,0xc6,0xf3,0xfc,0x3,0xca,0x6,0xf,0x19,0x80,0x28,0xaf,0xab,0x64,0x7d,0xa8,0x3c,0xc3,0xc6,0xf,0xf8,0x0 +}; + + +const uint8_t *_A_L1_NoSd_128x49[] = { + + _A_L1_NoSd_128x49_0, + + _A_L1_NoSd_128x49_1, + + _A_L1_NoSd_128x49_2, + + _A_L1_NoSd_128x49_3, + + _A_L1_NoSd_128x49_4, + + _A_L1_NoSd_128x49_5, + +}; + + + +const FrameBubble L1_NoSd_128x49_bubble_0_0; + + +const FrameBubble* const L1_NoSd_128x49_bubble_sequences[] = { + + &L1_NoSd_128x49_bubble_0_0, + +}; + + + +const FrameBubble L1_NoSd_128x49_bubble_0_0 = { + .bubble = { + .x = 40, + .y = 18, + .text = "Need an\nSD card", + .align_h = AlignRight, + .align_v = AlignBottom, + }, + .start_frame = 0, + .end_frame = 9, + .next_bubble = NULL, +}; + + + +const uint8_t L1_NoSd_128x49_frame_order[] = { 0, 1, 0, 1, 0, 2, 3, 4, 3, 5 }; + +const BubbleAnimation BA_L1_NoSd_128x49 = { + .icon_animation = { + .width = 128, + .height = 49, + .frame_count = 6, + .frame_rate = 2, + .frames = _A_L1_NoSd_128x49 + }, + .frame_order = L1_NoSd_128x49_frame_order, + .passive_frames = 10, + .active_frames = 0, + .active_cooldown = 0, + .active_cycles = 0, + .duration = 3600, + + .frame_bubble_sequences = L1_NoSd_128x49_bubble_sequences, + .frame_bubble_sequences_count = COUNT_OF(L1_NoSd_128x49_bubble_sequences), + +}; + + +const StorageAnimation dolphin_internal[] = { + + { + .animation = &BA_L1_Tv_128x47, + .manifest_info = { + .name = "L1_Tv_128x47", + .min_butthurt = 0, + .max_butthurt = 14, + .min_level = 1, + .max_level = 3, + .weight = 3, + } + }, + + { + .animation = &BA_L1_BadBattery_128x47, + .manifest_info = { + .name = "L1_BadBattery_128x47", + .min_butthurt = 0, + .max_butthurt = 14, + .min_level = 1, + .max_level = 3, + .weight = 3, + } + }, + + { + .animation = &BA_L1_NoSd_128x49, + .manifest_info = { + .name = "L1_NoSd_128x49", + .min_butthurt = 0, + .max_butthurt = 14, + .min_level = 1, + .max_level = 3, + .weight = 6, + } + }, + +}; + +const size_t dolphin_internal_size = COUNT_OF(dolphin_internal); diff --git a/assets/compiled/assets_dolphin_internal.h b/assets/compiled/assets_dolphin_internal.h new file mode 100644 index 00000000..f4f415fa --- /dev/null +++ b/assets/compiled/assets_dolphin_internal.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +extern const StorageAnimation dolphin_internal[]; +extern const size_t dolphin_internal_size; diff --git a/assets/compiled/assets_icons.c b/assets/compiled/assets_icons.c index f5f7a6d3..409f7034 100644 --- a/assets/compiled/assets_icons.c +++ b/assets/compiled/assets_icons.c @@ -8,89 +8,31 @@ const uint8_t *_I_Certification1_103x23[] = {_I_Certification1_103x23_0}; const uint8_t _I_Certification2_119x30_0[] = {0x01,0x00,0x3c,0x01,0x00,0x5c,0x06,0x01,0x40,0x07,0x5e,0x0b,0xff,0x20,0x07,0x5d,0x92,0x01,0x13,0x03,0xa4,0x70,0x06,0x5f,0xe0,0x10,0xc6,0x20,0x10,0xc8,0x1c,0xce,0x70,0x07,0x19,0xf0,0x08,0x70,0x10,0x18,0x1c,0x03,0xe1,0xff,0x83,0x83,0x84,0x34,0x57,0xf0,0x10,0xd8,0x03,0x23,0x00,0x1c,0x8c,0x08,0x1c,0x30,0xf0,0xc8,0xf8,0xc1,0xc3,0x10,0x00,0x90,0x48,0x60,0x70,0x3d,0x98,0x90,0x70,0x1c,0x10,0x70,0xc2,0x03,0x65,0xa0,0xc0,0x07,0x47,0xe6,0x6d,0x1e,0x07,0x04,0x06,0x20,0xe3,0x90,0x5f,0x41,0xc9,0xe0,0xc0,0x08,0x46,0x09,0x18,0x41,0x0c,0x82,0x44,0x0e,0x11,0x61,0x5c,0x27,0xd0,0x70,0x70,0xc5,0xc1,0xc3,0x40,0x8a,0x17,0x84,0x94,0x53,0x0a,0x0c,0x1a,0x01,0xe2,0x88,0x7e,0x01,0xc3,0x08,0x80,0xff,0xcd,0x05,0xb8,0x80,0x43,0xa0,0x11,0xe8,0x80,0x84,0x43,0xa5,0xfe,0x98,0xa1,0x86,0xb9,0x00,0x8e,0x9c,0x47,0xe0,0x5d,0x1a,0x04,0x88,0x8e,0x20,0x02,0x97,0x60,0x27,0x40,0xe1,0x03,0x95,0x02,0x82,0x0e,0x49,0x35,0x0a,0x65,0x00,0xe1,0x28,0x04,0xfe,0x38,0x05,0xc8,0xf8,0xe3,0xf0,0x09,0x3c,0x8a,0xe4,0x0e,0x4e,0x02,0xe0,0x7f,0xff,0x39,0xfe,0x02,0x47,0x14,0xf1,0x0b,0x13,0x41,0xc0,0x52,0x0c,0xc2,0x61,0xc0,0x90,0xc3,0x38,0x50,0x1e,0x27,0xfe,0x8f,0x00,0xc8,0x48,0x20,0xc0,0xe3,0x40,0x0e,0x04,0x1c,0x98,0x8d,0x04,0x28,0x1c,0x4a,0x31,0x00,0x0c,0x0e,0x11,0x38,0x59,0x8c,0x12,0x7f,0x12,0x81,0xfc,0x27,0xf7,0x08,0x05,0x06,0x01,0x07,0x07,0x1c,0x08,0x6c,0x20,0xe2,0x98,0x40,0x27,0xd0,0x08,0x34,0x42,0x70,0xef,0x13,0xa8,0xd0,0x05,0x84,0x1d,0x10,0x00,0xc1,0xdf,0x43,0x0c,0x41,0x1a,0xcc,0x47,0x63,0xff,0x00,0x0c,0x0c,0xe4,0x2d,0x91,0x00,0x17,0xf8,0x1c,0x3c,0x00,0x71,0x09,0xc7,0xfc,0x0d,0x30,0x06,0x7f,0x3f,0xea,0x11,0x07,0x78,0x3b,0xc1,0xd6,}; const uint8_t *_I_Certification2_119x30[] = {_I_Certification2_119x30_0}; -const uint8_t _I_card_bad1_0[] = {0x01,0x00,0x01,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xfe,0x01,0x82,0x04,0x0c,0x4a,0x01,0x70,0x8f,0x01,0x46,0x08,0x0f,0x5e,0x30,0x24,0x60,0x50,0x0c,0x44,0x88,0x1f,0x1a,0xaa,0x64,0xeb,0xaf,0x71,0x84,0x48,0xb1,0x93,0xb8,0x39,0x3d,0x72,0x55,0x2a,0x50,0x04,0x6e,0x12,0x2a,0x96,0x28,0x3e,0x20,0xf4,0xc1,0x03,0xcf,0x01,0x22,0xa1,0x03,0xf0,0x7e,0x21,0xf9,0xc6,0x52,0xea,0x57,0x22,0xf8,0xe3,0x21,0x63,0xf6,0x00,0x1d,0x01,0x3f,0xd3,0x05,0x7f,0x83,0xfc,0x1f,0xe0,0xf5,0xcf,0xfc,0xee,0x77,0xe0,0x5b,0x7e,0x28,0x10,0x18,0x25,0x02,0x7f,0xf9,0x93,0x87,0xde,0x11,0x00,0x07,0x8e,0x82,0xff,0xfc,0xc7,0x83,0xe2,0xb9,0x19,0x83,0xf4,0x01,0xf5,0x78,0xa9,0x69,0x60,0x9f,0x01,0x7d,0xd4,0xb7,0xa0,0xf1,0x27,0xd0,0x3c,0x70,0xa0,0xf1,0x37,0xd0,0xfc,0xc1,0xf6,0x00,0x30,0x7f,0xf0,0x01,0xff,0xff,0x83,0xfe,0x01,0xfb,0xf9,0xf0,0x83,0xf6,0x19,0xc6,0x07,0xb0,0xe8,0xe0,0x34,0x0f,0xfc,0x1b,0x90,0x0f,0x69,0x80,0x0c,0xa0,0x5a,0x0f,0xfc,0xd8,0x1e,0xf1,0x80,0x19,0x41,0x3a,0x05,0xd1,0xfe,0x03,0xec,0xff,0x51,0x8b,0x84,0x8a,0x04,0x0f,0xcc,0x44,0x4a,0x0c,0x0f,0xd8,0x54,0x38,0x1f,0xb0,0x68,0xf0,0x7f,0xc7,0xfe,0x5f,0xf0,0x7e,0x1f,0xfc,0x1f,0xd3,0x85,0xf9,0x83,0xe8,0x14,0x70,0x1f,0x00,0x10,0xa7,0xe0,0xf5,0x05,0x18,0x25,0x40,0x1e,0x00,0xf0,0x07,0x80,0x28,}; -const uint8_t *_I_card_bad1[] = {_I_card_bad1_0}; +const uint8_t _A_Levelup1_128x64_0[] = {0x01,0x00,0x22,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0x38,0x1f,0xe0,0x1d,0x97,0xff,0xe7,0x1c,0x1f,0x99,0xf8,0x1c,0xe0,0x1f,0x96,0x78,0x07,0x03,0xf8,0x0f,0xb8,0xdc,0x02,0x01,0xfb,0x07,0xdc,0x14,0x1e,0x3f,0x40,0x7d,0xc0,0x81,0xe3,0xe8,0x2f,0x5c,0x04,0x1e,0x3d,0x00,0x7d,0x6f,0xc1,0xc3,0x00,0xd0,0x03,0xea,0xbe,0x0f,0xf0,0x79,0x50,0x01,0xf5,0x2f,0x07,0xf8,0x38,0x63,0xf8,0x0f,0xf1,0x7a,0x62,0x10,0x0c,0x04,0x80,0x1f,0x59,0xf8,0xf8,0xb4,0x6f,0x80,0xfa,0xb7,0xcc,0x20,0x12,0x0f,0x34,0x03,0xfa,0x0f,0x88,0xbd,0x00,0x1e,0x3e,0x30,0x7d,0x42,0xf0,0x10,0x18,0x87,0x9c,0x1f,0x70,0x08,0x16,0x43,0xfe,0x0f,0xaf,0x5c,0x02,0x18,0x0f,0xc8,0xdc,0x0e,0x20,0x0f,0xc8,0x5c,0x31,0x7a,0x37,0xf0,0x7d,0xa3,0xc6,0x81,0x3f,0x37,0xdc,0x82,0x01,0xc0,0x49,0x09,0xff,0x61,0x00,0xfa,0x97,0x9f,0xc6,0x00,0x32,0x10,0x7d,0x40,0x20,0xc0,0xfc,0xaf,0xc0,0x23,0x0f,0x01,0x07,0xd6,0xfe,0x01,0xe0,0x07,0xe5,0xfc,0x7c,0x30,0xf0,0x7d,0xff,0xe0,0x41,0xe2,0x07,0xdc,0x14,0x1f,0xd0,0xd0,0x7f,0x45,0x45,0xfe,0x0f,0xf0,0x7f,0x17,0xd3,0xf4,0x7f,0x98,0x18,0x3f,0xc1,0xe7,0xf4,0x57,0xc8,0xbd,0x01,0xff,0xe8,0x6f,0xc8,0x3d,0x3a,0x0f,0xf9,0x67,0x88,0x00,0xb4,0x00,0xf8,0x8b,0x83,0xd2,0x80,0x0f,0x88,0x48,0x3d,0x30,0x1f,0xc0,0x6a,0xe3,0xef,0xf0,0x60,0x7a,0x40,0x3e,0x60,0xf5,0xbb,0xe0,0x20,0x20,0xf4,0x80,0xf3,0x01,0xeb,0x8b,0xbf,0x82,0x84,0x1e,0x93,0x0c,0x00,0x3d,0x21,0x60,0xa2,0x07,0xa7,0x02,0xfe,0x0f,0xd2,0x88,0xff,0x81,0xe6,}; +const uint8_t _A_Levelup1_128x64_1[] = {0x01,0x00,0x02,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x2f,0xf8,0x17,0x59,0xfe,0xf8,0x6b,0x37,0xf9,0xf0,0x32,0x7e,0xc1,0xac,0x02,0x19,0xff,0xfe,0x03,0xfc,0x11,0x5c,0xfe,0x7f,0xfe,0xf1,0x8c,0x2e,0x3d,0xce,0x80,0xe7,0x3e,0xff,0x90,0x7c,0xc3,0xe6,0x10,0x0b,0x07,0xfb,0xf0,0x61,0x8c,0x7c,0x3e,0x19,0x00,0xc0,0x43,0x6f,0xc1,0xe8,0xbf,0xe3,0xa0,0x50,0x08,0x04,0x0a,0xfe,0x83,0x7f,0xdf,0xf6,0x09,0x01,0x07,0x8e,0x11,0x25,0x1f,0x7f,0x7e,0x00,0x1c,0x30,0x09,0x41,0xfd,0xc0,0x03,0x1f,0xa0,0x03,0xca,0x21,0xfe,0x30,0x45,0xfe,0x90,0x0f,0x3f,0xe7,0xf4,0x1e,0xff,0x79,0x00,0x3c,0xa4,0x1b,0xc4,0xf4,0xca,0x01,0xe5,0xa0,0xfc,0x03,0xe6,0x20,0x0f,0x2a,0x00,0x3c,0x7c,0xef,0x96,0xbf,0xcc,0x81,0xc3,0xf8,0x07,0x93,0x0d,0xaf,0xbf,0xf5,0x70,0xc0,0x20,0x94,0x1d,0xc4,0x3f,0xf9,0xef,0x08,0x2f,0xf0,0x7e,0x5e,0x2c,0x17,0xf3,0xee,0x6f,0x89,0xc0,0x3c,0xb0,0x7f,0xc7,0x93,0x83,0x87,0xf1,0x07,0x80,0x79,0x70,0xbf,0x80,0x7b,0xc9,0xe0,0x13,0x86,0xf8,0xff,0x70,0xbc,0x0f,0x80,0x3d,0xb0,0xfa,0x18,0xe1,0x40,0x7f,0xb0,0x58,0x4f,0xf3,0xff,0xdf,0x08,0x2c,0x0e,0x18,0xc0,0x10,0x78,0xc0,0x7f,0xdb,0xfd,0xf8,0x3d,0x74,0x70,0x4c,0x04,0x07,0xfb,0x03,0x84,0xe3,0xfe,0xe0,0xf6,0x87,0xf9,0x20,0x10,0x6f,0xd4,0x0b,0x03,0xe7,0xf9,0xf7,0xce,0x47,0x7b,0xbf,0x67,0xe2,0x90,0x38,0x05,0xfe,0x03,0xc9,0xff,0xfe,0xfd,0xee,0x23,0x9f,0xff,0x27,0xd0,0xc2,0xf8,0xfc,0x20,0x18,0x16,0x6b,0xff,0xf3,0xf0,0xe6,0x81,0xca,0x7c,0x00,0xf5,0x22,0x0c,0x02,0x15,0x20,0x07,0x94,0x04,0x1e,0xd7,0xf8,0xfe,0x82,0x14,0x6f,0x10,0x00,0xea,0x51,0xe3,0xf3,0x08,0x26,0x7a,0x03,0x12,0x37,0x88,0x7c,0x91,0xe3,0xe7,0x3f,0xb4,0x48,0xde,0x21,0xf2,0xff,0x7f,0xf9,0xe7,0xf6,0x91,0x40,0x2f,0x01,0xf2,0x07,0xba,0x58,0x68,0x43,0xe2,0x0f,0x88,0xbc,0x7d,0xff,0xb0,0x79,0xf3,0xe1,0x78,0x20,0x79,0xc0,0x47,0xc2,0x8f,0x43,0xf0,0xe8,0xe0,0x44,0xe2,0x0f,0x8f,0xdf,0xc6,0xae,0x35,0x28,0xb7,0xc6,0x05,0x02,0x07,0x97,0x07,0xff,0xf1,0x17,0x20,0x10,0x74,0xe0,0xe3,0x80,0x72,0x67,0xff,0x82,0xf2,0xfc,0xe1,0xec,0xe1,0x00,0x15,0x0a,0x1e,0x60,0x12,0x72,0x70,0xe5,0xe0,0xf4,0x85,0x41,0x83,0xcb,0x37,0x83,0xe1,0xc5,0xe9,0x04,0x81,0x07,0xc7,0xde,0x0f,0x2a,0x5c,0x3b,0x40,0x0f,0x4d,0x24,0x83,0x3d,0xbf,0x30,0x1e,0x2e,0x39,0x40,0x07,0xa4,0x22,0x01,0x67,0xcf,0x8b,0xce,0x17,0x83,0x91,0x03,0xd2,0x61,0x2a,0xcc,0xf3,0x81,0xe9,0x1c,0x8c,0x03,0xd3,0x81,0x00,0xc3,0x18,0x12,0x2f,0xe0,0x83,0x83,0xd2,0x01,0xff,0xc0,0x83,0xd4,0x12,0x20,0xf5,0x80,0x60,0x01,0xe2,0x50,0x29,0x78,0x3d,0x98,0x63,0x40,0x48,0xa0,0x3e,0xac,0xc0,0xf3,0xa0,0x83,0xe2,0x41,0xc0,0x3f,0x9e,0x04,0x1f,0x3e,0x0f,0xc8,0x80,0xa0,0x60,0x81,0x07,0xb6,0x42,0x85,0xfc,0x0f,0x90,}; +const uint8_t _A_Levelup1_128x64_2[] = {0x01,0x00,0xc1,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x3f,0xe4,0x1f,0xdf,0x40,0x43,0xf3,0xc0,0xa9,0x7f,0xfb,0x03,0xdf,0x66,0x05,0x4d,0xff,0xbc,0x1e,0xf3,0xbf,0xf0,0x14,0xe3,0xf7,0x8f,0xf7,0xc4,0x1e,0xb1,0x3f,0xe0,0x14,0xe1,0xf9,0x02,0x0b,0xc5,0xc1,0xeb,0xcc,0xff,0x03,0xda,0x1e,0x0f,0x48,0x3f,0xbf,0xfd,0xf8,0x07,0xad,0xfc,0x1e,0x57,0xff,0xf4,0x0f,0xe7,0xff,0x07,0xaf,0x8e,0xff,0xf8,0xed,0xc7,0xee,0x1f,0xc8,0x18,0x34,0x41,0xeb,0xc3,0x9f,0xfc,0x3f,0x70,0xfe,0x07,0xfe,0x01,0x9c,0x0b,0x88,0x88,0x41,0xe7,0x1f,0xc8,0x5f,0xe0,0x7c,0x08,0x7c,0x03,0xf9,0x7f,0x9e,0x07,0xd3,0x8f,0x17,0x80,0x7e,0xe0,0x2f,0x71,0x85,0x7f,0xa7,0xf1,0xe0,0x7a,0x63,0xe7,0xf0,0x09,0x99,0x34,0x42,0x03,0xfb,0x9f,0xa5,0xd3,0xf1,0x3f,0xbf,0xc1,0x38,0x10,0x1c,0xe6,0xaa,0x04,0x1f,0x10,0xf2,0x7e,0x26,0xff,0x88,0x74,0xc2,0x01,0x60,0x0f,0x8d,0xfc,0x5c,0x2c,0x23,0xff,0x4c,0xed,0x18,0xe8,0x64,0x03,0x01,0xa9,0xc1,0x5e,0xf3,0xc1,0xf4,0x9f,0xcc,0xf8,0x10,0x48,0x10,0x74,0x60,0x58,0x0b,0xfe,0x32,0xfe,0xbe,0x50,0x78,0x97,0x8b,0x49,0xc0,0xf7,0xe0,0x14,0xc4,0xbe,0x3c,0x06,0x00,0x1c,0x30,0x08,0x46,0x02,0x78,0x0f,0x20,0x01,0xdf,0xb0,0x14,0x00,0x79,0x64,0x21,0x41,0x11,0x07,0x23,0x30,0x60,0x00,0xf3,0x88,0x00,0x87,0x81,0xbf,0x07,0x9e,0x73,0xdf,0x01,0x90,0x03,0xcb,0x40,0x53,0x19,0x02,0x3d,0x23,0x3f,0xf0,0x7a,0x00,0xc8,0x1e,0x5c,0x70,0x78,0xc6,0xb9,0xd0,0x11,0x59,0x0c,0xc7,0x51,0x0a,0x80,0x03,0x07,0x16,0x02,0x13,0xc0,0x83,0xd4,0x04,0x38,0xef,0xff,0x8f,0xfa,0x0f,0x18,0x3a,0x6c,0x43,0x22,0x00,0x1c,0x06,0xaa,0x14,0xd9,0x1f,0x38,0xfc,0xa1,0xa4,0x81,0x84,0x03,0xcc,0x02,0x3f,0xf0,0x71,0x80,0x06,0x02,0x1f,0x5d,0x14,0x2b,0xf0,0x0f,0x51,0x80,0xc1,0x01,0xe5,0x00,0x0b,0x0f,0xe7,0xf6,0x0f,0x5c,0x50,0x3d,0x35,0x3e,0x07,0x59,0x03,0x8a,0xff,0x0f,0x80,0x51,0x13,0xe7,0x01,0xf8,0x7b,0xff,0xa0,0xf2,0x87,0xff,0xe3,0xd2,0x8e,0x20,0x3c,0xa3,0x1a,0x9f,0x87,0x1e,0xff,0xde,0xc7,0x8b,0x47,0xd2,0x1f,0x10,0x7a,0x07,0xc7,0x8f,0x3f,0xff,0x61,0xff,0xff,0x7e,0xfc,0x1f,0x40,0x1f,0x5f,0x07,0x9d,0xfa,0x3e,0x37,0xf9,0x87,0xc6,0x02,0x0f,0x18,0xe4,0x07,0x80,0x0c,0x24,0xf9,0x14,0x04,0x3e,0x31,0xf7,0x58,0xc7,0xf5,0x38,0x0f,0x1b,0xbd,0x00,0x03,0x00,0xc2,0x03,0xca,0x1e,0x23,0x1f,0x80,0x28,0x73,0xe0,0x21,0xf9,0xff,0x70,0x30,0x41,0x90,0xe0,0x20,0xfa,0x98,0x17,0xf3,0xee,0x0f,0x2f,0xe7,0x83,0xdf,0x01,0x4f,0xac,0x03,0xfc,0x0f,0x10,0xe8,0xa4,0xc9,0x5e,0xba,0x96,0xf8,0x87,0x87,0xcf,0xf1,0xff,0xf1,0xe7,0x80,0xf1,0x88,0x3f,0x88,0x3e,0x3f,0xfe,0x7f,0x7f,0xcf,0xf9,0xff,0xc0,0xa3,0x1a,0x08,0x24,0x82,0x00,0x01,0x1d,0x4e,0x0b,0x3f,0xc7,0xf3,0xfc,0xff,0x9f,0xf9,0x08,0xa8,0x41,0xe8,0xdf,0x18,0x7f,0x07,0xcf,0x78,0x1e,0x8d,0xfe,0x00,0x1f,0x5c,0x0c,0x2a,0x0f,0xe0,0xbb,0xc7,0x0f,0xc7,0x00,0x83,0x0f,0x44,0x82,0x30,0x30,0x38,0xf8,0x22,0x78,0x00,0x70,0xf3,0xf0,0x1a,0xa0,0x7a,0x60,0xe1,0x50,0xaf,0x84,0x07,0xc0,0x0f,0x1d,0xb8,0x5c,0x60,0xbc,0x06,0x70,0x81,0x06,0x01,0x60,0xf0,0x28,0x85,0x64,0x34,0xad,0x46,0x2a,0x09,0x80,0xfc,0xc3,0x20,0x18,0x9d,0x56,0x48,0x32,0x3f,0x80,0xf8,0xe2,0xa0,0x36,0x00,0x78,0xc1,0xd6,0x23,0x31,0x80,0x63,0x01,0xe3,0xb8,0xfd,0xff,0xe1,0x10,0xe8,0xc2,0x7c,0x56,0x45,0xc1,0xc0,0x60,0xe0,0x52,0xae,0x41,0xb8,0x61,0x1f,0x08,0x38,0x30,0x60,0xc5,0xd1,0x80,0xdf,0xf0,0x06,0x12,0x17,0x89,0x64,0x57,0xe5,0xf8,0x60,0x9d,0x03,0x44,0x61,0x10,0x7b,0x00,0x10,0xea,0x25,0xf1,0x07,0x8a,0xbc,0xc1,0xeb,0xa0,0xd5,0x42,0x97,0xc3,0xff,0x54,0x88,0x3d,0xc1,0x25,0xfe,0x5f,0x88,0x94,0x80,0x0d,0x90,0xd5,0x4a,0x81,0xc3,0xfe,0xce,0x03,0xe2,0x10,0x1f,0x2f,0xff,0xe2,0x7f,0x01,0x06,0xa8,0x18,0x74,0x83,0xf1,0xfb,0x7f,0xff,0x33,0xf8,0x30,0xfd,0x41,0xe2,0xe1,0x25,0x79,0x41,0xcf,0x62,0x0f,0x5f,0xc6,0xa3,0x55,0x8a,0x07,0x90,}; +const uint8_t _A_Levelup1_128x64_3[] = {0x01,0x00,0x0a,0x03,0x8f,0xc0,0xb8,0x1f,0xfb,0xfd,0xe2,0x7f,0xf8,0x02,0x0f,0xff,0xff,0x03,0xff,0x00,0xc6,0xff,0x36,0xe0,0x47,0xfd,0xff,0x08,0xff,0xf3,0xff,0x3f,0x05,0x8f,0xf0,0x1e,0x5f,0xf8,0xfe,0x02,0xfb,0xff,0xf8,0x43,0xff,0x99,0xfd,0xf8,0x44,0x81,0xe7,0x17,0x88,0x7d,0x37,0xe0,0xf2,0x87,0xe7,0xff,0xe0,0x11,0xfe,0x83,0xca,0x1f,0x20,0xf8,0x0f,0x46,0x0f,0xfe,0x83,0xf6,0xff,0xfc,0xf0,0xfa,0x47,0xec,0x1e,0x08,0xf8,0x3c,0xa0,0x7c,0x3f,0xff,0x9c,0x1e,0x93,0xf8,0x06,0x02,0x1f,0xf8,0x2c,0x8c,0x07,0xc1,0xff,0xfd,0x83,0xdb,0xc1,0x07,0xfc,0x40,0x6f,0xda,0x0d,0x47,0xff,0xf2,0x0f,0x4b,0xf8,0x7c,0x60,0xda,0x88,0x0c,0x72,0x01,0xb0,0xff,0xe0,0x01,0xe9,0xff,0x80,0x68,0x21,0xff,0xa9,0x06,0x02,0x01,0xf2,0xbf,0x40,0x12,0x44,0x1f,0x2b,0x82,0xa1,0x7d,0x11,0xf8,0x05,0xf8,0x1e,0x74,0x7f,0x80,0xc0,0x75,0x50,0xa8,0x04,0x83,0xf0,0x0f,0x1b,0xe1,0x48,0x6f,0xfb,0x78,0x38,0x3c,0x40,0x09,0xfc,0x81,0x83,0xcb,0xfb,0xbf,0xbf,0xcb,0xbe,0x1a,0x8d,0x56,0xaa,0x55,0x80,0x85,0x18,0xc4,0x5e,0xb3,0xce,0x00,0x7d,0x7b,0x80,0x21,0xdf,0xcf,0xef,0xee,0x72,0x2f,0x8e,0xaa,0x01,0xa8,0xd1,0x62,0xa7,0xfa,0x0c,0x06,0x7d,0x82,0x33,0x8f,0x3d,0xfe,0x04,0x18,0x15,0x68,0xc0,0x1e,0xa2,0x02,0x1f,0x0f,0xff,0xbf,0x3f,0xe3,0xcf,0xc7,0x63,0xca,0xd5,0xe7,0xb5,0x58,0xa8,0x3e,0xa3,0x80,0x8e,0x29,0xfe,0x3c,0x2e,0x30,0x0b,0x85,0x56,0xea,0x73,0x11,0x10,0xd8,0x01,0xe5,0xcf,0x9f,0xcf,0xf5,0x50,0x2d,0x61,0x80,0x75,0x38,0xa2,0x28,0xda,0x09,0x63,0x9f,0x1f,0x0c,0xf8,0x3e,0x35,0x6a,0xad,0x54,0x3a,0x20,0x01,0xba,0x7f,0xf7,0xf9,0xff,0xbc,0xfe,0x7c,0x9c,0x1d,0x58,0x7c,0x74,0xd0,0xad,0x16,0xab,0x71,0xbf,0xef,0xfb,0xc1,0xe3,0x0c,0x1d,0x08,0x78,0x6a,0xb0,0xd0,0xf9,0x66,0x3f,0xbf,0xff,0x3f,0x9c,0x9c,0x3a,0x8e,0x50,0x78,0x75,0x59,0xa8,0x50,0x0c,0x7c,0x9f,0xff,0xcf,0x9f,0xe3,0x07,0x0b,0x8d,0x00,0x3e,0x51,0x50,0xf9,0x7c,0x3e,0x7f,0x99,0x3f,0xe2,0x0f,0x2a,0x5f,0x10,0x00,0xb1,0x4c,0x31,0xf8,0x7c,0x77,0x10,0x3f,0xe4,0x3c,0x2e,0x36,0x00,0xf9,0x4d,0x43,0xe5,0xe0,0x9c,0xfb,0xa0,0x7e,0x88,0x78,0x68,0x76,0x41,0xe2,0xb5,0x17,0x86,0x05,0xf8,0xcc,0x7f,0xe0,0x3f,0xc8,0x30,0x5c,0x6a,0x01,0xf2,0xaa,0x87,0xcb,0xf1,0xc2,0xff,0xc0,0x00,0x22,0x3e,0x50,0x01,0x42,0xaf,0x1d,0x09,0xfe,0x00,0x1e,0x20,0x01,0xac,0x07,0x8b,0xaa,0x07,0x29,0xe7,0x0a,0x1e,0x0f,0x20,0xfc,0x4a,0xa7,0x9e,0x85,0xa8,0xf0,0xc2,0xe5,0x54,0x1f,0x9c,0x04,0x3e,0x5e,0x00,0x18,0xf1,0xe0,0x3a,0x06,0xf1,0xb8,0x08,0x7e,0x33,0x8a,0x04,0x02,0x51,0xe3,0x4f,0x90,0x7d,0xc0,0x07,0xfa,0x80,0x68,0xe1,0x5e,0xc0,0xf1,0x6e,0x83,0xe4,0x0e,0x28,0x57,0xe3,0xce,0x18,0x1e,0xa0,0x78,0xab,0xa1,0xf6,0xfc,0x7f,0xf0,0x72,0xa0,0xfa,0xca,0xa5,0x50,0x08,0x46,0x01,0x46,0x3f,0xf3,0x18,0x87,0xf3,0xbf,0x00,0xd5,0x7b,0x37,0xfa,0xaf,0x56,0xff,0x53,0x82,0x0f,0x8c,0x83,0x51,0x02,0xff,0x5f,0xc2,0x63,0xd4,0xaf,0xa7,0x86,0xbe,0x1f,0x6d,0xf5,0xff,0x51,0x2a,0xd6,0x6b,0xc7,0xe3,0xaf,0xd4,0xe0,0x03,0xe2,0x06,0x18,0x17,0xf2,0xf6,0x7f,0xd2,0x78,0xea,0x21,0x49,0xf4,0x80,0xe0,0x35,0x40,0x11,0x0f,0x97,0xfc,0x30,0x21,0xfb,0xbf,0x43,0xc3,0xed,0x81,0x0e,0x90,0x7c,0xa7,0xd1,0xf1,0xf9,0x5d,0x6a,0xa0,0x11,0x0f,0xb4,0xf2,0x7c,0x57,0x16,0xfa,0xe2,0x80,0xa7,0x00,0x9c,0x07,0xca,0xac,0x3f,0x35,0x30,0x80,0x19,0x6e,0x3a,0xef,0x52,0xf8,0x75,0x5a,0xbd,0x10,0x80,0x90,0x43,0xe0,0x98,0x04,0x45,0x3a,0x2b,0xe1,0xaa,0xc1,0x60,0x16,0x00,0xe9,0xfd,0x2d,0x1a,0xac,0x56,0xbb,0x55,0xfb,0x01,0x0e,0x2f,0x45,0xb2,0x0f,0x8c,0x2a,0x01,0xfc,0xec,0x40,0x6c,0x01,0xf1,0xab,0xb0,0x46,0x6b,0x00,0xee,0x27,0xd3,0x51,0x0e,0xdc,0x07,0x07,0x56,0x02,0x1f,0x5e,0x03,0x56,0x1f,0x1d,0x04,0x2b,0xfd,0x59,0xfa,0xd5,0xcb,0x83,0x57,0x01,0x95,0xff,0xaa,0x1f,0x3f,0xfe,0xdc,0x2a,0x21,0xc1,0xfd,0x1e,0xce,0xd5,0x0a,0x85,0x10,0x06,0x7b,0x53,0x3e,0x18,0x01,0x43,0xe7,0xc0,0x7d,0x90,0x7c,0x40,0x09,0x2a,0x94,0x4a,0x17,0xe3,0xe3,0xb5,0x87,0xa0,0xc2,0x20,0x01,0xc0,0x78,0x7b,0xe1,0xc5,0x00,0x16,0x68,0x42,0x3a,0xae,0x17,0xc7,0x3e,0x1f,0x88,0x68,0xf8,0xfe,0x10,0x13,0xb1,0x00,0x0c,0x0c,0x3a,0x65,0x48,0x8f,0xc7,0xf0,0xdd,0x57,0x0c,0x7f,0x14,0x22,0x5f,0x5d,0x5f,0xeb,0x51,0xaa,0xd1,0x07,0xc7,0xf8,}; +const uint8_t _A_Levelup1_128x64_4[] = {0x01,0x00,0x7e,0x02,0xff,0x80,0x3c,0x01,0xf1,0xff,0xe0,0x3f,0x7d,0xff,0xd1,0x0f,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x2d,0xff,0xee,0x0f,0xef,0x47,0xff,0xfc,0x06,0x2d,0xf8,0x3d,0xe0,0x3e,0x49,0x3f,0xc0,0xfc,0x7f,0x8f,0xfc,0xed,0x02,0x37,0xff,0xc5,0xbe,0x01,0xf0,0xaf,0xe0,0xc1,0xe7,0xe0,0xff,0xc0,0xc2,0xe3,0x1f,0xf8,0x4f,0xe0,0x17,0x0b,0xf5,0x81,0x34,0x40,0xf1,0xb8,0xc1,0x38,0x1f,0xd8,0x3f,0xe2,0x73,0x00,0xf7,0xc7,0xe4,0x02,0xb1,0xff,0xcf,0xf0,0x02,0x81,0xc0,0x77,0xe0,0x37,0xf8,0x47,0x82,0xff,0x0e,0x6e,0x1c,0x1d,0xc4,0x3e,0x08,0x0d,0xfb,0x80,0x2e,0x1f,0x00,0x08,0x60,0x06,0x02,0xc3,0xc0,0x41,0x23,0x81,0x04,0x89,0x38,0x6c,0x11,0xfc,0x04,0x3c,0x1e,0x3f,0x78,0x3c,0x0e,0x01,0xc0,0x83,0xff,0xa0,0x60,0x52,0x8c,0x88,0x45,0x00,0x63,0x02,0xe2,0x6a,0xe3,0xc0,0x41,0x00,0x09,0xf8,0xd2,0x63,0x4f,0x04,0x1d,0xfc,0x1e,0x65,0xd2,0x01,0x09,0xc8,0x60,0xd0,0x0d,0x66,0xab,0x54,0x45,0x10,0x00,0xfb,0x3f,0xff,0x3f,0x8f,0xcf,0xd9,0xf9,0x87,0xd4,0x06,0xc5,0x03,0x8a,0x03,0xc7,0xf9,0xcf,0xf3,0xdf,0xfc,0xfc,0x4f,0xfc,0x2e,0x01,0xab,0x0f,0x88,0x90,0x45,0xe5,0x87,0x1f,0x94,0x02,0x9f,0x08,0xca,0x01,0x8a,0x9f,0x15,0x07,0x8d,0xe3,0x80,0x0f,0x30,0xc8,0xf0,0x03,0xc3,0xaa,0x8d,0x14,0x13,0x9f,0xfb,0x07,0x8c,0x02,0x21,0xd0,0x0b,0x15,0x7e,0x2a,0x51,0x1b,0x07,0xfb,0xcd,0xff,0xe1,0x9f,0x8b,0x40,0x1f,0x29,0x50,0x78,0xa7,0x93,0x9c,0x87,0xfe,0x03,0x1f,0x5f,0x90,0x7c,0xa7,0xf5,0x5a,0x84,0x07,0x7c,0x95,0x1f,0xbb,0x48,0x41,0xe3,0xb0,0x0f,0x95,0xa8,0x3e,0x51,0xe7,0x00,0xdf,0xe6,0x0a,0xf1,0x82,0x29,0xce,0xff,0x55,0xaa,0xc0,0x60,0x90,0x0c,0x04,0x7f,0xfd,0xfd,0x20,0x0e,0xa0,0x3e,0x5a,0xa2,0xf9,0x9a,0x47,0x8e,0x19,0x14,0xf0,0xfe,0x58,0xe7,0x54,0xaa,0x84,0x13,0xdf,0xfb,0x12,0x88,0x7e,0x4b,0x43,0xe3,0xb7,0xc0,0x2a,0x9f,0xd0,0xf9,0x8f,0xc5,0xe4,0x9c,0x38,0x18,0x10,0x5b,0xc4,0xe0,0x50,0x79,0x60,0x40,0x63,0x40,0x0f,0xbd,0x50,0x26,0xaf,0x71,0x0f,0x16,0xe8,0x16,0xd1,0xfb,0x85,0xc2,0x00,0x1f,0x50,0x80,0xd5,0x22,0x20,0xf1,0xff,0x7e,0x3f,0x01,0xfb,0xec,0x7f,0xef,0x12,0x08,0x07,0xf0,0x3e,0x71,0x58,0x24,0x16,0x28,0x1e,0x20,0x40,0xf8,0xe0,0x3e,0xcd,0xfe,0xab,0xd5,0xbf,0x0f,0xad,0x6d,0x3e,0x41,0xf5,0xa8,0xd5,0x60,0xa0,0x11,0x67,0x8e,0xfa,0xfe,0x0f,0x1d,0x66,0xbc,0x7e,0x3a,0xf0,0xfa,0xff,0xe3,0xe0,0x11,0x0f,0xad,0x56,0x8b,0x41,0xaa,0xc5,0x60,0x1f,0xb8,0x4e,0x5c,0x1e,0x29,0xf9,0xe0,0x7f,0xe1,0xb1,0xf8,0x7a,0xfd,0xc3,0xe3,0x05,0xb0,0x43,0xf8,0x17,0xf6,0xf8,0x87,0xe6,0x61,0x04,0xf0,0x46,0x20,0x15,0x50,0xfc,0x04,0xca,0xe4,0x15,0x26,0xfd,0x40,0x22,0x00,0x21,0xa8,0xa5,0x08,0x00,0x35,0x3a,0xad,0x50,0xbc,0x20,0x01,0xb0,0x00,0xcb,0x5d,0xea,0x5f,0x0e,0xaa,0x06,0x1f,0x5f,0xc4,0xc2,0x01,0x15,0x0f,0x1f,0xfe,0xaf,0x55,0xb2,0x9f,0xc8,0x1e,0x36,0x88,0x06,0x03,0x5d,0xaa,0xfd,0x80,0x86,0x17,0x00,0xd8,0x07,0xcf,0xdd,0xf9,0xa8,0xf9,0x43,0xe9,0x3f,0xaa,0xff,0x08,0x02,0x61,0x1f,0xf6,0xae,0x1d,0xb8,0x0e,0x0e,0xac,0x04,0x3e,0xbc,0x06,0xac,0x3c,0x58,0x0f,0xff,0xec,0x3a,0x80,0x04,0xaa,0x20,0xc7,0xc1,0x4f,0xd9,0x9e,0x84,0x38,0x3f,0xa4,0x09,0xda,0x87,0xe7,0x08,0xfb,0x87,0xa2,0xff,0x55,0xa8,0x18,0x0b,0x4e,0x1f,0x30,0x02,0x4a,0x90,0x09,0xef,0x0f,0xc1,0x84,0x60,0xb4,0x16,0xe0,0xf7,0x43,0x8a,0x00,0x28,0xd0,0x7d,0x0c,0x22,0x00,0x7a,0x79,0x78,0x55,0x62,0x10,0x1d,0x58,0x75,0x40,0xc3,0x06,0x60,0xab,0x75,0x1c,0x2b,0x55,0xa0,0xb0,0x4c,0xbe,0xba,0xbf,0xd0,0x79,0x40,}; +const uint8_t _A_Levelup1_128x64_5[] = {0x01,0x00,0x79,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1f,0xff,0xfb,0xcf,0xc0,0xc9,0xf0,0xf1,0x84,0x1e,0xff,0xfe,0x80,0xff,0x3f,0xb7,0xbf,0xe7,0x3c,0x1c,0xdb,0xff,0xfc,0xff,0xfc,0x1b,0x80,0x02,0x73,0xf5,0xf9,0xf8,0xff,0xff,0x8f,0x9f,0xfc,0x0b,0xde,0xe5,0xdd,0xba,0xf3,0xbe,0x3c,0x78,0x08,0xf5,0xe6,0x3a,0xcd,0x56,0xaa,0xc3,0xf0,0xa7,0xe0,0x3f,0xff,0xe1,0xf2,0x5f,0x20,0x15,0x6a,0xad,0x57,0x07,0xf3,0x87,0xf8,0x3f,0xfe,0x11,0x02,0x4d,0xe0,0x1a,0xbd,0x76,0xaf,0x0d,0xff,0x80,0x7c,0x3f,0xbc,0x70,0x7a,0x4f,0xf0,0x41,0xe1,0xaa,0xfb,0x67,0xf0,0x02,0x70,0x9c,0x4c,0x7c,0x33,0xfe,0x3e,0xa8,0x3e,0x31,0xa8,0x78,0x3c,0x89,0xc9,0xd0,0xff,0xd1,0xea,0xb5,0x7a,0xbc,0x56,0x01,0x00,0xfe,0x03,0xd4,0x2c,0x3a,0xf2,0xf0,0xea,0xa5,0x40,0xf1,0x9c,0x1f,0xdb,0x1f,0x67,0x0f,0x94,0xd6,0x01,0x04,0x80,0x18,0x07,0x7f,0xef,0x07,0x94,0x3f,0x64,0x1f,0x2b,0x50,0x7c,0x46,0x25,0xfd,0xef,0xb7,0x47,0x3f,0x0c,0xa8,0x07,0xc8,0xc2,0x30,0x10,0x78,0xfc,0x08,0x09,0x18,0xd4,0x6a,0x90,0x03,0xaa,0x06,0x8c,0x70,0x60,0x47,0xd2,0xff,0xcc,0xfb,0x01,0xd2,0xef,0xd5,0x20,0x37,0xf0,0x78,0xfe,0xc2,0x05,0xc7,0x83,0xfa,0x35,0x46,0x21,0xdd,0x40,0x30,0x10,0xfc,0x63,0xd4,0x5f,0x03,0xef,0x07,0x8d,0xd7,0xab,0x55,0xae,0xdd,0x6a,0xb8,0x58,0x7e,0xff,0xce,0x1d,0x12,0x10,0xfc,0xe0,0xfa,0xcf,0xd6,0xa8,0x02,0x24,0xe1,0x81,0xb7,0x84,0xdc,0x57,0xf9,0x7c,0x02,0xab,0x75,0x00,0x0d,0x56,0x82,0x10,0x10,0x78,0xc3,0xde,0x25,0x06,0x3b,0x0e,0xeb,0x55,0xea,0xfd,0x1b,0x8a,0xff,0x7f,0xbf,0x2c,0xc7,0xe7,0x0e,0x80,0x75,0x2a,0xb7,0x7a,0xbd,0x76,0x8b,0x05,0x80,0x06,0xc6,0xf8,0xb2,0x1b,0x1a,0x58,0x83,0xec,0x6e,0x41,0x70,0xd5,0x0b,0xc2,0x00,0x10,0xf9,0x08,0x04,0x7a,0x5f,0xf8,0x60,0x7c,0xb7,0xe1,0xf1,0xff,0x87,0xca,0x01,0xfd,0x07,0x96,0x26,0x07,0x40,0xfa,0xb1,0x47,0xbf,0x7f,0xa2,0xb0,0x0b,0xf1,0x7f,0x10,0x8f,0x82,0x0f,0x00,0xd6,0x7b,0xcf,0xe3,0xaf,0x0f,0x96,0x03,0xff,0x39,0xff,0x63,0x7f,0xf1,0xf3,0xf9,0x00,0x4a,0x82,0x01,0x1c,0x07,0x7c,0xc4,0x38,0x71,0x88,0xc0,0x75,0x83,0xf2,0x0f,0x9c,0x02,0x0c,0x21,0x17,0x01,0x41,0xea,0x85,0xf2,0x00,0x12,0x84,0xb0,0x0d,0x11,0xff,0xcf,0xa0,0xba,0xcd,0x50,0x00,0x83,0xe7,0x00,0xe0,0x7c,0x57,0xe3,0x78,0x9c,0x55,0x07,0xe7,0x55,0x8a,0xd0,0x02,0x43,0xe0,0xfe,0x7d,0xff,0xfe,0x9b,0xc0,0x7e,0x60,0x13,0x07,0x01,0x5e,0x2a,0xc3,0xd3,0x43,0x0a,0x04,0x42,0x05,0x8c,0xc1,0xc7,0xfe,0x1a,0xef,0x56,0xa9,0x82,0x30,0x30,0xfa,0x08,0x4a,0x1d,0x40,0xaa,0xb0,0x06,0xbb,0x55,0x82,0xd4,0x2c,0xa4,0x21,0x80,0x7c,0x20,0x76,0x83,0x20,0xeb,0xb5,0x5f,0xb0,0x10,0xc2,0xe0,0x1b,0x00,0xe9,0x2c,0x47,0xb1,0x01,0x0b,0x8f,0x56,0xaf,0x5f,0xaa,0xcd,0x6a,0x9d,0xca,0xa3,0x84,0xf5,0x10,0xed,0xc0,0x70,0x75,0x60,0x21,0xf5,0xe0,0x35,0x6c,0x13,0xbf,0x56,0xfe,0xb5,0x72,0xe0,0xd5,0xc0,0x65,0x7f,0xea,0xd1,0x20,0x14,0x0f,0x84,0xff,0x6e,0x7a,0x10,0xe0,0xfe,0x90,0x27,0x6a,0x1f,0x97,0x82,0x7e,0x19,0x20,0x03,0x8f,0x86,0x01,0xe7,0xbf,0xeb,0x43,0xe6,0x00,0x49,0x50,0x38,0x7f,0x9c,0xff,0xfd,0xbc,0x3d,0x13,0x5a,0xa9,0x38,0x78,0xf9,0xce,0xf0,0x71,0x40,0x05,0x1a,0x2f,0x0f,0x7f,0xff,0xf9,0xd8,0x07,0xe2,0x9b,0x50,0x80,0x33,0x47,0xc7,0x00,0xd5,0x87,0x54,0x0c,0x30,0x61,0xf8,0xdf,0xfe,0xc0,0xf1,0x6e,0xa3,0x85,0x0c,0x03,0x1c,0x10,0x0a,0xc8,0x4b,0xeb,0xab,0xfd,0x37,0x4e,0x77,0xfe,}; +const uint8_t _A_Levelup1_128x64_6[] = {0x01,0x00,0x38,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0x5f,0x78,0x37,0x20,0x3f,0xc0,0x7e,0x4f,0xff,0xde,0x3e,0x38,0xae,0xf9,0xf0,0x5c,0xe8,0x7e,0xf8,0xf3,0x3c,0x45,0x83,0xdc,0x1f,0xb8,0x6e,0x23,0x01,0xfd,0x1f,0xdc,0x0a,0x09,0x01,0xfd,0x03,0xaa,0xff,0x01,0x07,0x8f,0xd0,0x1f,0x5b,0xf8,0x00,0x3c,0x7d,0x00,0xfa,0xaf,0x83,0xcb,0xa0,0x0e,0x9f,0xb8,0x3c,0x60,0x50,0x20,0x7d,0xcb,0xc1,0xe5,0xa0,0xdb,0x83,0xe3,0xc6,0x0f,0x4d,0xff,0xdc,0x3f,0x11,0x70,0x79,0x50,0x23,0xe0,0xe7,0xfe,0x83,0xd7,0x7e,0x2f,0x8f,0xe4,0x2e,0x00,0x80,0x1c,0x06,0xf9,0x1b,0x1f,0xcc,0x5c,0x1c,0x1e,0x38,0xfd,0xf6,0x0f,0xbe,0xb3,0x5b,0xfd,0xf2,0x97,0x08,0xff,0xe1,0xf2,0x1e,0xec,0x38,0xfd,0xff,0x12,0x5c,0x84,0x06,0x99,0x20,0xfa,0xff,0x81,0xed,0xfb,0xfd,0xc9,0x6a,0x10,0x0a,0x84,0x80,0x58,0x9e,0xf3,0x7a,0x55,0x66,0x12,0x0b,0x05,0x40,0x1e,0x5f,0x11,0x0b,0x75,0x66,0x12,0x2b,0x15,0x63,0x7a,0x07,0x1f,0x80,0xf4,0xca,0x05,0xd5,0x88,0x48,0xa8,0x55,0x80,0x40,0xdf,0x3e,0x1f,0x30,0x60,0xff,0xb0,0xfe,0x3f,0xf0,0x3d,0x6e,0xf1,0xef,0xc7,0xec,0x40,0x58,0x7e,0x1f,0xbf,0xab,0x11,0x80,0x50,0x2b,0x81,0xf1,0x87,0xff,0x0c,0x49,0x07,0xc1,0xf5,0x63,0xf0,0x0e,0x05,0x7c,0x7e,0x30,0x70,0x71,0x35,0x0a,0x7f,0x02,0xd2,0xe7,0xff,0xfc,0xf9,0x78,0x7c,0x7c,0x7f,0xf8,0xf8,0x44,0xaf,0xb7,0xeb,0x14,0x92,0x9f,0x00,0xe8,0x49,0xf9,0xb3,0xdf,0x01,0x64,0x40,0x42,0x1e,0x1f,0xe5,0xda,0x89,0x30,0x80,0x58,0x22,0x1f,0x58,0xff,0xe2,0xf7,0xfc,0xf0,0x83,0xca,0x01,0x78,0xc2,0x0f,0xca,0x1f,0xfd,0x87,0xff,0xaf,0xbf,0xc1,0x90,0xff,0xe3,0xb0,0x0f,0x84,0x12,0x20,0x5f,0x18,0x07,0xf5,0x56,0x5f,0xcf,0xfe,0xff,0xbf,0x18,0x07,0x94,0x82,0x00,0x01,0x1f,0xe8,0x30,0x7f,0xbe,0xcf,0xf5,0xef,0xfd,0x38,0x83,0x70,0xa0,0xa0,0xf3,0x80,0xfe,0x38,0x56,0xf0,0x90,0xff,0xff,0x31,0x08,0x7c,0x10,0x3e,0x80,0xf1,0xa1,0x9b,0x87,0xef,0xfd,0xf9,0xc0,0x20,0xf1,0x88,0x30,0xf4,0x48,0x23,0x03,0xbf,0x79,0xe0,0x7f,0xe2,0x18,0xfc,0xf8,0x10,0x3f,0x80,0x3d,0x67,0x90,0x18,0x04,0x73,0xf8,0x10,0x1d,0x9c,0x0e,0xe1,0x05,0xe0,0x40,0x0a,0xa3,0x05,0x41,0x8c,0x00,0x04,0x2f,0x21,0xa5,0xc3,0xb2,0x10,0x4c,0x07,0xe6,0x19,0x00,0x84,0xc0,0x32,0x00,0xf1,0x80,0x78,0x3d,0xf8,0xb8,0x0d,0x80,0x1e,0x30,0x78,0x7c,0x02,0x63,0x00,0xc6,0x29,0x87,0xe0,0xb0,0x18,0x5c,0x3a,0x31,0x04,0x2e,0x08,0x08,0x78,0x38,0x0c,0x1e,0xe2,0x01,0xfe,0xf8,0x83,0xc7,0xe1,0x07,0x06,0x0c,0x1a,0x06,0x12,0x1b,0xfe,0x03,0x01,0x0f,0xf7,0x7f,0xfd,0x91,0x71,0xa0,0x83,0xc7,0xf0,0x3a,0x25,0x98,0xf0,0x21,0x69,0x01,0xe0,0x83,0xd0,0x00,0x80,0xf1,0x88,0xf6,0x3f,0x18,0x79,0x78,0x3e,0x14,0x62,0x6e,0x1b,0xc4,0x7e,0x4e,0x0f,0xaf,0x85,0xc7,0xf1,0x3f,0xa1,0x83,0x14,0x00,0x4a,0x31,0xf0,0x40,0xc1,0xe3,0x87,0x07,0xc7,0x20,0x04,0x30,0xee,0x7c,0xbe,0x06,0xb6,0x10,0x02,0x01,0x87,0xe9,0xc3,0x87,0xfe,0x23,0x77,0xc8,0x2c,0x18,0x7e,0xa0,0xf1,0xfd,0xf9,0xe3,0xf7,0x0b,0xdf,0xf0,0xf6,0x40,0xf5,0xfc,0x5c,0x27,0x93,0xc5,0x70,0xff,0xc0,}; +const uint8_t _A_Levelup1_128x64_7[] = {0x01,0x00,0xd0,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x05,0xfd,0x83,0xfb,0xbe,0x20,0xf0,0xff,0x83,0x72,0x01,0xfe,0x07,0xdf,0xf6,0x3f,0xff,0xf8,0x83,0xf3,0xcf,0x03,0xe7,0x40,0xff,0xc0,0xf9,0xfc,0x46,0x61,0x93,0x00,0xfe,0x41,0xa2,0x1c,0x0e,0xf0,0x3e,0xaf,0xb0,0x19,0x06,0x03,0xba,0x0f,0xad,0xfc,0x02,0x81,0x00,0xed,0x83,0xea,0xbe,0x0f,0x2f,0xa8,0x3e,0xa5,0xf0,0x0c,0x04,0x03,0xd4,0x0f,0xdf,0xc7,0xad,0xb5,0x51,0x70,0x78,0xc1,0xfa,0xdb,0xf0,0x84,0xc5,0xff,0xdc,0x08,0x07,0x60,0x3f,0x50,0xb8,0x0c,0x86,0x81,0xb0,0x0f,0xcf,0xef,0x17,0x7c,0x89,0x50,0x37,0x00,0xfa,0xa5,0xe0,0xa1,0x98,0x20,0x7d,0x78,0x28,0xb1,0xd8,0x2e,0x0a,0xa0,0xe3,0x10,0xfc,0x49,0x63,0xf0,0x9c,0x25,0xc2,0x17,0xfa,0x07,0xc6,0x97,0x3d,0x0a,0x82,0x5f,0xc3,0xf3,0xff,0xd2,0xff,0xa1,0x5c,0x0b,0x81,0x3e,0xb4,0x40,0xf1,0x98,0x78,0x37,0xc1,0xf9,0x07,0x94,0x23,0x81,0xbe,0xff,0x03,0xe2,0x85,0xff,0x85,0x41,0xb0,0x00,0xe1,0xfe,0x83,0x56,0x7e,0x0f,0x1b,0xef,0x36,0x03,0x9c,0x17,0xc5,0xff,0xdd,0x82,0xfd,0x4f,0xe0,0x1a,0x3e,0xf0,0xfe,0x70,0x51,0xc8,0x07,0x03,0x80,0x3e,0x9f,0xfc,0x0a,0x17,0x00,0x90,0x70,0x3f,0xbf,0x70,0x7c,0xc1,0x20,0x11,0x0a,0x01,0x34,0x7d,0xe3,0xe5,0x03,0x88,0x3c,0xa1,0x00,0xf2,0xf1,0x87,0xe6,0x03,0x06,0x90,0x03,0xc7,0xf7,0xe7,0x07,0xbc,0x03,0x0d,0x01,0x07,0x90,0x81,0x7f,0x00,0xf3,0xbc,0x10,0x04,0x1e,0x5f,0x10,0x79,0xfc,0x11,0xe2,0x0f,0x10,0x00,0xc2,0x01,0xe3,0x7f,0x50,0x27,0x82,0x7f,0xdc,0x07,0x9c,0x10,0x18,0x84,0x12,0x07,0x8f,0xf0,0x1e,0x70,0x2f,0xec,0xfd,0x22,0x5e,0x00,0x10,0xf0,0x7f,0x82,0xf4,0x80,0xef,0x63,0xe0,0xf1,0xdf,0x94,0x4a,0x0f,0xf0,0x07,0xa4,0x03,0xfb,0xc7,0xff,0xfd,0xe1,0xe2,0x22,0x8f,0xf2,0x2f,0xf0,0x10,0x79,0xfe,0xc7,0xc5,0x71,0xe0,0x28,0x0c,0x1e,0xfc,0xf0,0x58,0xe0,0x4a,0x87,0xbe,0x07,0x1c,0x03,0xeb,0xff,0xdb,0x8f,0x08,0xc4,0x7b,0xf0,0x7b,0x52,0xc1,0x83,0x0f,0xff,0xfc,0xf3,0x7f,0xfa,0x78,0x3d,0x3d,0x3f,0xfa,0x20,0x3c,0x71,0xea,0x31,0xb2,0xff,0xa6,0x60,0xf4,0xc8,0xc7,0xe8,0x7d,0x01,0xe9,0xe1,0x60,0x30,0xc0,0x7a,0x58,0x7c,0x14,0x0f,0x07,0x84,0xc8,0x50,0x5f,0xf4,0x0c,0x1e,0x98,0x18,0xfc,0x82,0x00,0x6e,0x38,0x28,0x35,0x14,0x05,0x00,0x90,0x7c,0x20,0x7f,0xe4,0x80,0xc2,0xd7,0x64,0x0f,0x58,0x87,0xc1,0x64,0x39,0xff,0xfc,0x20,0x1f,0x31,0x8b,0xf6,0x78,0xe0,0x31,0x70,0x7c,0x5a,0x26,0x1f,0x8c,0x7a,0x40,0x41,0xf3,0xf4,0xf0,0x40,0x70,0x04,0xf1,0x97,0x83,0xe3,0xf5,0xe1,0x83,0x98,0x08,}; +const uint8_t _A_Levelup1_128x64_8[] = {0x01,0x00,0xe6,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x00,0xbf,0xb0,0x7f,0x88,0x3c,0x3f,0xe1,0x0f,0x00,0x5c,0x3f,0xc0,0x1f,0xdf,0x8c,0x7c,0x1f,0x97,0xfb,0xf7,0x83,0xf8,0x21,0x10,0x04,0xe7,0xf0,0x30,0x7f,0x98,0x7e,0xed,0xf0,0x08,0x47,0xb0,0x1e,0x7c,0xf8,0x4c,0xcb,0xe6,0x0f,0x38,0xbc,0x02,0x21,0xd0,0x03,0x9e,0x3f,0x93,0x33,0x07,0xa4,0x2e,0x01,0x20,0xdc,0x07,0xcc,0x1e,0xf0,0x50,0x78,0xd1,0x80,0xe7,0x4f,0x84,0xc9,0xbf,0x20,0x62,0xff,0x40,0xa0,0x14,0x0c,0x0f,0xfb,0xde,0x0f,0x2e,0x4c,0x9c,0x1e,0xdc,0x08,0x07,0xf4,0x1e,0x5c,0xfe,0x44,0x1f,0xf0,0x7e,0x38,0x0f,0xfa,0x81,0x10,0xfe,0xf1,0xc1,0xe7,0xcf,0xfe,0x03,0xca,0xfd,0x01,0x80,0xc8,0x64,0x1f,0xa0,0xf9,0xc2,0x79,0xc0,0xf2,0xbf,0xff,0x30,0x17,0xc8,0x95,0x00,0x1e,0x60,0x06,0xdf,0x50,0x30,0x51,0x4a,0x0c,0x11,0x3d,0x3b,0xe9,0x04,0x7e,0x13,0x42,0xfe,0x0e,0x4c,0x00,0xb5,0xfd,0x04,0xce,0x15,0x04,0x83,0x24,0x07,0x9f,0x83,0xce,0x48,0x29,0xff,0x20,0x78,0xd7,0xb4,0x16,0x38,0x94,0x12,0x03,0xf4,0x07,0x8f,0xcf,0x39,0x3c,0x07,0x98,0x7c,0x6e,0x71,0x44,0x00,0xfa,0x01,0xe5,0xc9,0x07,0xb7,0xfe,0x29,0x20,0x07,0x9e,0x0f,0x92,0x2f,0x40,0x79,0xc6,0x30,0x1e,0xb0,0xfa,0x5b,0xda,0xe4,0x0f,0x38,0x3d,0x83,0xd8,0x0f,0x2f,0x18,0x3d,0x64,0x1f,0xfe,0x94,0x02,0x30,0x3f,0x30,0x78,0x9b,0xd2,0x81,0xfe,0x9d,0xc0,0x20,0x80,0xf1,0x87,0xe0,0xbe,0xf2,0x0a,0x40,0xfc,0xf0,0x11,0xc8,0x64,0x02,0x04,0x6f,0x14,0x7c,0x40,0x20,0xb0,0x88,0x01,0xfc,0x81,0xf3,0x02,0x80,0x1f,0xc7,0xf4,0x0f,0xc9,0x80,0x3f,0x30,0x10,0x02,0x00,0xff,0x41,0xf5,0x00,0xc1,0xc0,0xf0,0x1f,0xe0,0x7d,0xdf,0x20,0x14,0x00,0x41,0x43,0xc1,0x03,0x80,0x07,0xa8,0x00,0x54,0x62,0x00,0x1f,0x98,0x08,0x6f,0xe0,0xf7,0xe8,0x02,0x0a,0x1a,0x1f,0x21,0xb1,0x03,0xd3,0xb0,0x0f,0x28,0x30,0x1c,0x8a,0xc4,0x0f,0x4e,0xa0,0x3f,0x85,0xe7,0x06,0xce,0x62,0x01,0xe7,0x4f,0x07,0xc6,0x8b,0x09,0x01,0x07,0x8e,0xfe,0x5e,0x5f,0x70,0x78,0xe0,0xa0,0x61,0xf2,0x07,0xa5,0x80,0x1e,0x98,0x18,0x38,0x3c,0xa2,0xe0,0xf4,0xef,0xef,0xc3,0xee,0x0f,0x4d,0x01,0xe0,0x7f,0xc3,0xf5,0xff,0xc2,0xc1,0xed,0xfc,0x2f,0xaf,0x7e,0x0a,0x0f,0x39,0x00,0x60,0x8f,0xe9,0xf7,0xf8,0xbf,0x44,0x00,0x54,0x0f,0xd0,0x40,0x51,0xeb,0x78,0x80,0x83,0xd3,0xe8,0x1f,0x18,0x72,0xfd,0x33,0xe0,0xe3,0x07,0x8f,0x20,0x1e,0x23,0x22,0x6f,0x95,0x9c,0x1e,0xb3,0x0f,0xff,0xe3,0xf6,0x0c,0x13,0xa0,0xff,0xe3,0x34,0x00,0x7a,0x70,0x20,0x1f,0x78,0x38,0x18,0x78,0x1f,0xf8,0x0c,0x18,0x1e,0xb0,0x0f,0xff,0xa1,0x44,0x40,0x01,0xff,0x40,0x41,0xed,0x00,0xf4,0x7f,0x7b,0xe0,0xf2,0x2e,0x88,0x3e,0x3c,0x61,0xf3,}; +const uint8_t _A_Levelup1_128x64_9[] = {0x01,0x00,0xd6,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x01,0x3d,0xe0,0xff,0x06,0xe4,0x0f,0xf0,0x0f,0xab,0xf8,0x04,0x7f,0x9c,0x7c,0x18,0x7a,0xf3,0xf0,0xf9,0xc0,0x7f,0x2c,0xff,0x0e,0x07,0xb8,0x1f,0x71,0xb8,0x04,0x0f,0xda,0x09,0x3e,0x7c,0x26,0x65,0xf3,0x07,0x9c,0x16,0x01,0x0c,0xfd,0x03,0xcf,0x1f,0xc9,0x99,0x83,0xd2,0x05,0x00,0x88,0x71,0x0e,0x26,0x0f,0x59,0x7d,0xea,0x03,0x00,0x90,0x6f,0x81,0xe7,0x4f,0x84,0xc9,0xbf,0x21,0xf2,0xdf,0xc0,0x20,0x14,0x0a,0x08,0x3d,0x39,0x32,0x70,0x7b,0x60,0x30,0x1f,0xee,0x39,0x3c,0xb9,0x10,0x7f,0xc0,0x3c,0xab,0xf0,0x09,0xfd,0x03,0x21,0xfe,0x80,0x83,0xcf,0x9f,0xfc,0x2b,0x15,0x7f,0x81,0xc0,0x90,0x48,0x3f,0xa1,0xf3,0x84,0xf3,0x81,0xe5,0x7f,0x97,0xc8,0x23,0xd1,0x10,0x78,0xa8,0x66,0x5f,0x90,0xb0,0xc2,0xa4,0x3c,0x20,0x7d,0x54,0x33,0xf0,0x68,0x14,0xe8,0x1f,0x31,0x7e,0x46,0xce,0x09,0x02,0xe3,0x7f,0x87,0xc3,0x83,0xce,0x48,0x29,0xff,0x20,0x79,0x7a,0x2c,0x70,0x5c,0x14,0x07,0xfa,0x0f,0x1f,0x9e,0x72,0x78,0x0f,0x5b,0x9c,0x16,0x81,0x00,0x60,0x88,0x3c,0x79,0x20,0xf6,0xbf,0xc1,0x66,0x00,0xf3,0xc1,0xf2,0x45,0xec,0x0f,0x18,0x67,0x03,0xf6,0x1f,0x4b,0x78,0x18,0x7f,0xf0,0xbe,0x47,0xfe,0x09,0x03,0xf8,0x03,0xcf,0xc6,0x0f,0x5e,0x87,0xff,0x85,0x00,0xfc,0x5f,0x41,0xe8,0x6f,0x38,0x5e,0x42,0x1f,0x3f,0x80,0x7f,0x27,0xdf,0xe8,0x7e,0x0b,0xef,0x20,0xa4,0x0f,0xca,0x17,0x20,0x81,0x41,0x20,0x17,0xfb,0xfa,0x3e,0x21,0x7c,0x08,0x0b,0xc0,0x77,0xe0,0xe8,0x07,0x8c,0x00,0x1e,0x3e,0x0e,0xf8,0x3a,0x3e,0xe0,0xf3,0xfc,0x2f,0xa4,0x1e,0x49,0xd1,0xe7,0x40,0xd7,0xe2,0x00,0x6f,0x18,0x3c,0x70,0x1c,0x18,0x1f,0xfd,0x7e,0x21,0xf9,0x80,0x7f,0xa0,0x28,0xf2,0xff,0xc3,0xc1,0x03,0x80,0x07,0xa8,0x40,0x61,0xeb,0xf1,0xff,0xfc,0xc0,0x42,0x75,0x30,0x79,0x80,0x04,0x1e,0x50,0xd0,0xf9,0x11,0x88,0x1e,0xa2,0xf2,0x83,0x01,0x88,0x8c,0x40,0xf4,0xe0,0x7f,0x01,0xfb,0x30,0x1c,0x14,0x1b,0x39,0x88,0x07,0xc7,0x38,0x1e,0x7a,0x2c,0x24,0x04,0x1e,0xdc,0x01,0xf1,0x03,0xcb,0x05,0x03,0x07,0xb7,0xf0,0x1e,0xb8,0x18,0x38,0x3c,0xa0,0xa0,0xf2,0xfc,0x07,0xe8,0x1e,0x7e,0x0f,0xa8,0xfe,0x41,0xe7,0x00,0xfa,0x17,0xe6,0x04,0x0f,0x3f,0x60,0x3c,0xcf,0xea,0x0f,0xeb,0xfc,0x04,0x1e,0x7d,0x80,0x79,0x43,0x97,0xe8,0x0f,0x91,0x59,0x37,0xcb,0x7e,0xce,0x4d,0x40,0x3c,0x8e,0x65,0xbf,0x07,0x9d,0x00,0x1e,0xd0,0x75,0x39,0x01,0x46,0xbe,0x0f,0x4a,0x40,0x3c,0x80,0x0b,0x2f,0x80,0x48,0x01,0xe5,0x88,0x24,0x08,0x01,0xa2,0xe0,0xf4,0x84,0x13,0x08,0x00,0x80,}; +const uint8_t _A_Levelup1_128x64_10[] = {0x01,0x00,0xde,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x09,0xef,0x06,0xe4,0x0f,0xf0,0x0f,0xcb,0xff,0xf3,0x8f,0xc7,0x07,0xde,0x7e,0x1f,0x38,0x0f,0xe5,0x9f,0xe1,0xc0,0xf7,0x03,0xee,0x37,0x00,0x81,0xff,0x4a,0x27,0xcf,0x84,0xcc,0xbe,0x63,0xd2,0xff,0xc1,0x60,0x10,0xcf,0xd0,0x5c,0xf1,0xfc,0x99,0x98,0x3d,0x20,0x50,0x08,0x87,0x10,0x3e,0x60,0xf5,0x9f,0xdf,0xa0,0x30,0x09,0x06,0xf8,0x1e,0x74,0xf8,0x4c,0x9b,0xf2,0x1f,0x2d,0xfc,0x02,0x01,0x40,0xa0,0xff,0xce,0x25,0x4f,0xe4,0xc9,0xc1,0xed,0x80,0xc0,0x7f,0xb5,0x64,0xf2,0xe4,0x41,0xff,0x04,0x62,0xaf,0xc0,0x27,0xf4,0x0c,0x85,0xfa,0x22,0x62,0x10,0x78,0xf3,0xff,0x80,0xf3,0xe0,0x70,0x24,0x12,0x0f,0xe8,0x7c,0xe1,0x3c,0xe0,0x79,0xcb,0xe4,0x11,0xe8,0x88,0x3c,0x56,0x33,0x2f,0xc8,0x58,0x61,0x52,0x1e,0x12,0xc6,0x3f,0xd2,0xfa,0x86,0x7e,0x0d,0x02,0x9d,0x2b,0xa6,0x2f,0xc8,0xd9,0xc1,0x20,0x5c,0x66,0x08,0xf3,0xf0,0x79,0xc9,0x05,0x3f,0xe4,0x1f,0x18,0xbf,0xa2,0xc7,0x05,0xc1,0x40,0x4b,0xc5,0xf3,0xce,0x4f,0x01,0xeb,0x73,0x82,0xd0,0x20,0x0c,0x11,0x07,0x8f,0x24,0x1e,0xd7,0xf8,0x2c,0xc0,0x1e,0x78,0x3e,0x48,0xbc,0xab,0xff,0x40,0x79,0xc3,0x38,0x1f,0xb0,0xfa,0x5b,0xc0,0xc3,0xfe,0x85,0xf2,0x3f,0xf0,0x48,0x1f,0xc0,0x1e,0x7e,0x30,0x7a,0xf4,0x3f,0xfc,0x28,0x07,0xe0,0x9e,0x60,0xf1,0x37,0x9c,0x2f,0x21,0x0f,0x9f,0xc0,0x3f,0x9f,0xef,0xfc,0x3f,0x05,0xf7,0x90,0x52,0x09,0xe5,0x0b,0x90,0x40,0xa0,0x90,0x0b,0xfa,0x3e,0x61,0x7c,0x08,0x0b,0xc0,0x77,0xe0,0xfa,0x80,0x03,0xc7,0xc1,0xdf,0x07,0xef,0xe1,0x9d,0x00,0xf3,0x4e,0x8f,0x3a,0x06,0x4f,0x10,0x03,0x7d,0xc1,0xe3,0x80,0xe0,0xc0,0xff,0xe6,0xf1,0x0f,0xcc,0x03,0xfd,0x01,0x47,0x91,0xc0,0x41,0x03,0x80,0x07,0xa8,0x40,0x61,0xeb,0xf1,0xff,0xfc,0xc0,0x42,0x76,0x30,0x79,0x80,0x04,0x1e,0x50,0xd0,0xf9,0x11,0x88,0x1e,0xa2,0xf2,0x83,0x01,0x88,0x8c,0x40,0xf4,0xe0,0x7f,0x01,0xfb,0x30,0x1c,0x94,0x1b,0x39,0x88,0x07,0xc7,0x38,0x1e,0x7a,0x2c,0x24,0x04,0x1e,0xdc,0x0f,0xdc,0xfc,0x92,0x20,0xf1,0xc1,0x40,0xc1,0xed,0xfc,0xfd,0x87,0xd3,0x03,0x07,0x07,0x94,0x14,0x1e,0x5f,0x80,0x7a,0x87,0xd0,0x1e,0x7e,0x0f,0xaa,0x20,0x87,0xec,0x0f,0x38,0x07,0xd0,0x1e,0x65,0xf5,0x81,0x03,0xcf,0xd8,0x0f,0x33,0xfa,0x83,0xfa,0xff,0x01,0x07,0x9f,0x60,0x1e,0x50,0xe5,0xfa,0x03,0xe4,0x56,0x46,0x52,0xdf,0xb3,0x93,0x50,0x0f,0x26,0x91,0x6f,0xc1,0xe7,0x40,0x07,0xb4,0x1d,0x4e,0x40,0x51,0xaf,0x83,0xd2,0x90,0x0f,0x20,0x02,0xcb,0xe0,0x12,0x00,0x79,0x62,0x09,0x02,0x00,0x68,0xb8,0x3d,0x21,0x04,0xc2,0x00,0x20,}; +const uint8_t *_A_Levelup1_128x64[] = {_A_Levelup1_128x64_0,_A_Levelup1_128x64_1,_A_Levelup1_128x64_2,_A_Levelup1_128x64_3,_A_Levelup1_128x64_4,_A_Levelup1_128x64_5,_A_Levelup1_128x64_6,_A_Levelup1_128x64_7,_A_Levelup1_128x64_8,_A_Levelup1_128x64_9,_A_Levelup1_128x64_10}; -const uint8_t _I_card_bad2_0[] = {0x01,0x00,0x12,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xfe,0x01,0x82,0x04,0x0c,0x4a,0x01,0x70,0x8f,0x01,0x46,0x08,0x0f,0x5e,0x30,0x24,0x60,0x50,0x0c,0x44,0x88,0x1f,0x1a,0xaa,0x64,0xeb,0xaf,0x71,0x84,0x48,0xb1,0x93,0xb8,0x39,0x3d,0x72,0x55,0x2a,0x50,0x04,0x6e,0x12,0x2a,0x96,0x28,0x3e,0x20,0xf4,0xc1,0x03,0xcf,0x01,0x22,0xa1,0x03,0xf0,0x7e,0x21,0xf9,0xc6,0x52,0xea,0x57,0x22,0xf8,0xe3,0x21,0x63,0xf6,0x00,0x1d,0x01,0x3f,0xd3,0x05,0x7f,0x83,0xfc,0x1f,0xe0,0xf5,0xcf,0xfc,0xee,0x77,0xe0,0x5b,0x7e,0x28,0x10,0x18,0x25,0x02,0x7f,0xf9,0x93,0x87,0xde,0x11,0x00,0x07,0x8e,0x82,0xff,0xfc,0xc7,0x83,0xe2,0xb9,0x19,0x83,0xf4,0x01,0xf5,0x78,0xa9,0x69,0x60,0x9f,0x01,0x7d,0xd4,0xb7,0xa0,0xf1,0x27,0xd0,0x3c,0x70,0xa0,0xf1,0x37,0xd0,0xfc,0xc1,0xf6,0x00,0x30,0x7f,0xf0,0x01,0xff,0xff,0x81,0xfc,0x01,0xfb,0xf8,0xe0,0x83,0xf2,0xff,0x4c,0xc3,0x03,0xd8,0x74,0x70,0x15,0xf8,0xe1,0xa1,0x00,0xf6,0x98,0x00,0xca,0x05,0xa0,0x9f,0xc5,0xa1,0x20,0xf6,0x8c,0x00,0xca,0x09,0xd0,0xbb,0xcf,0xb3,0x17,0xb0,0x7d,0x7c,0x3e,0xf3,0xff,0xc0,0x3d,0xee,0x12,0x28,0x10,0x3c,0x7d,0xee,0x01,0xbe,0x83,0xdb,0x11,0x12,0x83,0x2f,0xec,0x1e,0x30,0xa8,0x70,0x3f,0x60,0xd1,0xe0,0xff,0x83,0xf4,0x7f,0xc5,0xf4,0x07,0xd1,0xfd,0x01,0xfe,0x0f,0x99,0xc2,0xfc,0xc1,0xf4,0x0a,0x38,0x0f,0x80,0x08,0x53,0xf0,0x7a,0x82,0x8c,0x12,0xa0,0x0f,0x00,0x78,0x03,0xc0,0x14,}; -const uint8_t *_I_card_bad2[] = {_I_card_bad2_0}; - -const uint8_t _I_card_ok1_0[] = {0x01,0x00,0x19,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xfc,0x0e,0x54,0xec,0x0e,0x00,0x08,0x35,0x48,0x20,0x3e,0x2a,0x20,0xf3,0xa8,0x03,0xeb,0xc3,0xdc,0x9c,0xc9,0x2a,0xb1,0xc8,0x19,0x3d,0xeb,0xf9,0x1c,0x94,0x90,0x1e,0x3a,0x48,0x20,0x3d,0xea,0x20,0xf5,0x83,0x83,0xf8,0xff,0x03,0xf1,0xce,0x4e,0x3b,0x15,0x41,0xfc,0xa7,0xfc,0x1f,0xe0,0xff,0x07,0xcc,0x1f,0xf8,0x0f,0xdf,0xcf,0xcc,0x1e,0x8a,0xa1,0xb8,0x47,0x80,0xa5,0x40,0xff,0xff,0xbd,0xe0,0xf6,0xc4,0x48,0x80,0xa5,0xa0,0xbf,0xff,0xfb,0xe0,0xf1,0xb0,0x4b,0xa3,0x38,0x79,0xcc,0x22,0x45,0x8c,0x9d,0xc1,0xfa,0x1b,0xff,0xfe,0xfc,0x1e,0x31,0x09,0x4e,0x96,0x89,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc0,0x1e,0x92,0x09,0x4e,0xf4,0x1e,0x38,0x09,0x15,0x08,0x1e,0x5d,0xf3,0x70,0x83,0xc6,0x81,0x29,0xc2,0x83,0xc4,0x7e,0x21,0xf3,0x07,0xa4,0xc3,0x9d,0x18,0xc3,0xd2,0x4b,0xe3,0x8c,0x85,0xc1,0xc1,0xea,0x00,0x90,0x78,0x9f,0x84,0x1f,0x7c,0x00,0x7f,0xf7,0xfe,0xe0,0xfe,0x1f,0xef,0x00,0xfe,0x80,0xa5,0x75,0x14,0x06,0x80,0x0f,0x99,0x80,0x0c,0xa0,0x4b,0xf5,0x00,0x24,0x61,0xaa,0x7d,0x06,0xfb,0x83,0xdb,0xe0,0xff,0x70,0x79,0x34,0x06,0x04,0x0f,0x28,0x3f,0xf0,0x1e,0xf8,0x88,0x94,0x18,0x1e,0x40,0x01,0x07,0xc4,0x2a,0x1c,0x0f,0xd8,0x34,0x78,0x3f,0xe0,0xfd,0x1f,0xf1,0x7d,0x41,0xf2,0x7f,0x50,0x7f,0x83,0xe2,0x70,0xbf,0x30,0x7d,0x02,0x8e,0x03,0xe0,0x02,0x14,0xfc,0x1e,0xa0,0xa3,0x04,0xa8,0x03,0xc0,0x1e,0x00,0xf0,0x05,0x00,}; -const uint8_t *_I_card_ok1[] = {_I_card_ok1_0}; - -const uint8_t _I_card_ok2_0[] = {0x01,0x00,0x1e,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xfc,0x0e,0x54,0xec,0x0e,0x00,0x08,0x35,0x48,0x20,0x3e,0x2a,0x20,0xf3,0xa8,0x03,0xeb,0xc3,0xdc,0x9c,0xc9,0x2a,0xb1,0xc8,0x19,0x3d,0xeb,0xf9,0x1c,0x94,0x90,0x1e,0x3a,0x48,0x20,0x3d,0xea,0x20,0xf5,0x83,0x83,0xf8,0xff,0x03,0xf1,0xce,0x4e,0x3b,0x15,0x41,0xfc,0xa7,0xfc,0x1f,0xe0,0xff,0x07,0xcc,0x1f,0xf8,0x0f,0xdf,0xcf,0xcc,0x1e,0x8a,0xa1,0xb8,0x47,0x80,0xa5,0x40,0xff,0xff,0xbd,0xe0,0xf6,0xc4,0x48,0x80,0xa5,0xa0,0xbf,0xff,0xfb,0xe0,0xf1,0xb0,0x4b,0xa3,0x38,0x79,0xcc,0x22,0x45,0x8c,0x9d,0xc1,0xfa,0x1b,0xff,0xfe,0xfc,0x1e,0x31,0x09,0x4e,0x96,0x89,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc0,0x1e,0x92,0x09,0x4e,0xf4,0x1e,0x38,0x09,0x15,0x08,0x1e,0x5d,0xf3,0x70,0x83,0xc6,0x81,0x29,0xc2,0x83,0xc4,0x7e,0x21,0xf3,0x07,0xa4,0xc3,0x9d,0x18,0xc3,0xd2,0x4b,0xe3,0x8c,0x85,0xc1,0xc1,0xea,0x00,0x90,0x78,0x9f,0x84,0x1f,0x7c,0x0e,0xff,0x8c,0x1f,0xd8,0x70,0x7f,0x63,0xc1,0xfb,0xbf,0xcf,0x9f,0xc8,0x14,0xae,0xa2,0x80,0xd0,0x11,0xe8,0x00,0x49,0x80,0x0c,0xa0,0x4b,0xf5,0x00,0x24,0x61,0xaa,0x7d,0x06,0xfb,0x83,0xdb,0xe0,0xff,0x70,0x79,0x34,0x06,0x04,0x0f,0x28,0x3f,0xf0,0x1e,0xf8,0x88,0x94,0x18,0x1e,0x40,0x01,0x07,0xc4,0x2a,0x1c,0x0f,0xd8,0x34,0x78,0x3f,0xe0,0xfd,0x1f,0xf1,0x7d,0x41,0xf2,0x7f,0x50,0x7f,0x83,0xe2,0x70,0xbf,0x30,0x7d,0x02,0x8e,0x03,0xe0,0x02,0x14,0xfc,0x1e,0xa0,0xa3,0x04,0xa8,0x03,0xc0,0x1e,0x00,0xf0,0x05,0x00,}; -const uint8_t *_I_card_ok2[] = {_I_card_ok2_0}; - -const uint8_t _I_card_ok3_0[] = {0x01,0x00,0x22,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xfc,0x0e,0x54,0xec,0x0e,0x00,0x08,0x35,0x48,0x20,0x3e,0x2a,0x20,0xf3,0xa8,0x03,0xeb,0xc3,0xdc,0x9c,0xc9,0x2a,0xb1,0xc8,0x19,0x3d,0xeb,0xf9,0x1c,0x94,0x90,0x1e,0x3a,0x48,0x20,0x3d,0xea,0x20,0xf5,0x83,0x83,0xf8,0xff,0x03,0xf1,0xce,0x4e,0x3b,0x15,0x41,0xfc,0xa7,0xfc,0x1f,0xe0,0xff,0x07,0xcc,0x1f,0xf8,0x0f,0xdf,0xcf,0xcc,0x1e,0x8a,0xa1,0xb8,0x47,0x80,0xa5,0x40,0xff,0xff,0xbd,0xe0,0xf6,0xc4,0x48,0x80,0xa5,0xa0,0xbf,0xff,0xfb,0xe0,0xf1,0xb0,0x4b,0xa3,0x38,0x79,0xcc,0x22,0x45,0x8c,0x9d,0xc1,0xfa,0x1b,0xff,0xfe,0xfc,0x1e,0x31,0x09,0x4e,0x96,0x89,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc0,0x1e,0x92,0x09,0x4e,0xf4,0x1e,0x38,0x09,0x15,0x08,0x1e,0x5d,0xf3,0x70,0x83,0xc6,0x81,0x29,0xc2,0x83,0xc4,0x7e,0x21,0xf3,0x07,0xa4,0xc3,0x9d,0x18,0xc3,0xd2,0x4b,0xe3,0x8c,0x85,0xc1,0xc1,0xe5,0x7d,0x3f,0xd8,0x3c,0x7e,0x77,0xc0,0x7d,0xf0,0x3b,0xf6,0x30,0x7f,0x41,0xef,0xc0,0xfd,0x87,0x93,0xc8,0x1f,0x5b,0xfc,0xf9,0xfc,0x81,0x4a,0xea,0x28,0x0d,0x01,0x1e,0x80,0x04,0x98,0x00,0xca,0x04,0xbf,0x50,0x02,0x46,0x1a,0xa7,0xd0,0x6f,0xb8,0x3d,0xbe,0x0f,0xf7,0x07,0x93,0x40,0x60,0x40,0xf2,0x83,0xff,0x01,0xef,0x88,0x89,0x41,0x81,0xe4,0x00,0x10,0x7c,0x42,0xa1,0xc0,0xfd,0x83,0x47,0x83,0xfe,0x0f,0xd1,0xff,0x17,0xd4,0x1f,0x27,0xf5,0x07,0xf8,0x3e,0x27,0x0b,0xf3,0x07,0xd0,0x28,0xe0,0x3e,0x00,0x21,0x4f,0xc1,0xea,0x0a,0x30,0x4a,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x50,}; -const uint8_t *_I_card_ok3[] = {_I_card_ok3_0}; - -const uint8_t _I_card_ok4_0[] = {0x01,0x00,0x26,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xfc,0x0e,0x54,0xec,0x0e,0x00,0x08,0x35,0x48,0x20,0x3e,0x2a,0x20,0xf3,0xa8,0x03,0xeb,0xc3,0xdc,0x9c,0xc9,0x2a,0xb1,0xc8,0x19,0x3d,0xeb,0xf9,0x1c,0x94,0x90,0x1e,0x3a,0x48,0x20,0x3d,0xea,0x20,0xf5,0x83,0x83,0xf8,0xff,0x03,0xf1,0xce,0x4e,0x3b,0x15,0x41,0xfc,0xa7,0xfc,0x1f,0xe0,0xff,0x07,0xcc,0x1f,0xf8,0x0f,0xdf,0xcf,0xcc,0x1e,0x8a,0xa1,0xb8,0x47,0x80,0xa5,0x40,0xff,0xff,0xbd,0xe0,0xf6,0xc4,0x48,0x80,0xa5,0xa0,0xbf,0xff,0xfb,0xe0,0xf1,0xb0,0x4b,0xa3,0x38,0x79,0xcc,0x22,0x45,0x8c,0x9d,0xc1,0xfa,0x1b,0xff,0xfe,0xfc,0x1e,0x31,0x09,0x4e,0x96,0x89,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc0,0x1e,0x92,0x09,0x4e,0xf4,0x1e,0x38,0x09,0x15,0x08,0x1e,0x5d,0xf3,0x70,0x83,0xc6,0x81,0x29,0xc2,0x83,0xc4,0x7e,0x21,0xf3,0x07,0x8d,0xcc,0x1e,0x33,0x0e,0x74,0x63,0x0f,0x49,0x2f,0x8e,0x32,0x17,0x07,0x07,0x95,0xc4,0xff,0x60,0xf1,0xf9,0xde,0x01,0xf7,0xc0,0xef,0xd8,0xef,0x80,0xfd,0x83,0xdf,0x81,0xfb,0x0f,0x2f,0x90,0x3e,0xb7,0xf9,0xf3,0xf9,0x02,0x95,0xd4,0x50,0x1a,0x02,0x3d,0x00,0x09,0x30,0x01,0x94,0x09,0x7e,0xa0,0x04,0x8c,0x35,0x4f,0xa0,0xdf,0x70,0x7b,0x7c,0x1f,0xee,0x0f,0x26,0x80,0xc0,0x81,0xe5,0x07,0xfe,0x03,0xdf,0x11,0x12,0x83,0x03,0xc8,0x00,0x20,0xf8,0x85,0x43,0x81,0xfb,0x06,0x8f,0x07,0xfc,0x1f,0xa3,0xfe,0x2f,0xa8,0x3e,0x4f,0xea,0x0f,0xf0,0x7c,0x4e,0x17,0xe6,0x0f,0xa0,0x51,0xc0,0x7c,0x00,0x42,0x9f,0x83,0xd4,0x14,0x60,0x95,0x00,0x78,0x03,0xc0,0x1e,0x00,0xa0,}; -const uint8_t *_I_card_ok4[] = {_I_card_ok4_0}; - -const uint8_t _I_no_databases1_0[] = {0x01,0x00,0x43,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xff,0x11,0x00,0x88,0x00,0x04,0x16,0x34,0x00,0x10,0xc1,0x01,0xf7,0x20,0x07,0xbe,0x62,0x19,0x9c,0x9d,0xdd,0xf3,0x91,0x99,0x1c,0x9a,0x3b,0x07,0x27,0xa6,0xa2,0x25,0x52,0xc9,0x65,0x2a,0x5a,0x4b,0x04,0xa7,0x4a,0x1f,0x10,0x79,0xf2,0x01,0xe7,0x92,0x9e,0x48,0x41,0xef,0x88,0x07,0x9c,0x4a,0x0b,0x22,0x07,0xc0,0xfc,0x62,0x77,0x7e,0xe6,0x62,0x43,0xc6,0x92,0x8f,0xd5,0x3f,0xe0,0xff,0x07,0xf8,0x3f,0xc1,0xf9,0x07,0x07,0xbd,0xc2,0x3c,0xaf,0x2a,0x07,0xff,0xf3,0xfc,0x07,0xb6,0x22,0x44,0x0f,0x2d,0x07,0xff,0x1d,0xfb,0x07,0xa6,0x02,0x73,0x08,0x91,0x63,0x27,0x70,0x7e,0x85,0xff,0xf7,0xf7,0x07,0xa5,0x02,0x95,0x70,0x91,0x54,0xb1,0x50,0x4f,0x86,0xff,0xfb,0xef,0x07,0xb6,0x02,0x45,0x42,0x07,0x9f,0xfc,0x1e,0xe3,0xf1,0x0f,0x9f,0x7e,0x3f,0xdf,0x1f,0xad,0x24,0xbe,0x38,0xc8,0x5c,0x1c,0x1e,0x3e,0xfe,0xf1,0xfe,0xc1,0xe3,0xff,0x07,0xe7,0x00,0x5a,0x22,0xf5,0x07,0xc6,0xfc,0x1f,0xa5,0xf7,0x07,0xc6,0xfc,0x1e,0xff,0xe6,0xd1,0x40,0x68,0x17,0xff,0xff,0x9c,0x1e,0xb8,0x08,0x08,0x10,0xa0,0x4b,0xf1,0xff,0x70,0xc1,0xeb,0xc0,0x02,0x1c,0x13,0xa0,0xdf,0x1c,0x00,0x3e,0xfe,0x0f,0xf1,0x83,0x83,0xda,0x11,0x02,0x80,0x42,0x01,0xe5,0xff,0x87,0xdf,0x81,0xeb,0x18,0x81,0xc0,0x23,0x00,0xf3,0x8f,0xdf,0x01,0xeb,0xa8,0x99,0x59,0xe7,0x00,0xf3,0x9f,0xde,0x01,0xeb,0x48,0xa5,0x64,0x6f,0x00,0xf3,0xbf,0x83,0xda,0x11,0x4a,0xf8,0x87,0xd3,0xfe,0x0f,0x88,0x88,0xfd,0x04,0x02,0x0f,0x69,0x95,0x84,0xbe,0x80,0xf7,0x3f,0xb0,0x3f,0xc1,0xf0,0xbf,0x40,0x7c,0xe0,0x01,0x24,0xdf,0x1f,0x00,0x10,0xa7,0xee,0xf5,0x07,0x98,0x25,0x40,0x1e,0x00,0xf0,0x07,0x80,0x28,}; -const uint8_t *_I_no_databases1[] = {_I_no_databases1_0}; - -const uint8_t _I_no_databases2_0[] = {0x01,0x00,0x45,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xff,0x11,0x00,0x88,0x00,0x04,0x16,0x34,0x00,0x10,0xc1,0x01,0xf7,0x20,0x07,0xbe,0x62,0x19,0x9c,0x9d,0xdd,0xf3,0x91,0x99,0x1c,0x9a,0x3b,0x07,0x27,0xa6,0xa2,0x25,0x52,0xc9,0x65,0x2a,0x5a,0x4b,0x04,0xa7,0x4a,0x1f,0x10,0x79,0xf2,0x01,0xe7,0x92,0x9e,0x48,0x41,0xef,0x88,0x07,0x9c,0x4a,0x0b,0x22,0x07,0xc0,0xfc,0x62,0x77,0x7e,0xe6,0x62,0x43,0xc6,0x92,0x8f,0xd5,0x3f,0xe0,0xff,0x07,0xf8,0x3f,0xc1,0xf9,0x1f,0xfe,0x03,0xda,0xe1,0x1e,0x57,0x95,0x03,0xff,0xe7,0xf9,0x83,0xdb,0x11,0x22,0x07,0x96,0x83,0xff,0x3b,0xf7,0x03,0xd3,0x01,0x39,0x84,0x48,0xb1,0x93,0xb8,0x3f,0x43,0xff,0xed,0xef,0x83,0xd2,0x81,0x4a,0xb8,0x48,0xaa,0x58,0xa8,0x27,0xc3,0xff,0xf6,0xdf,0x83,0xdb,0x01,0x22,0xa1,0x03,0xcf,0xfc,0x0f,0x71,0xf8,0x87,0xce,0xff,0x1f,0xbf,0x8f,0xd6,0x92,0x5f,0x1c,0x64,0x2e,0x0e,0x0f,0x1f,0x7d,0xf8,0xff,0x60,0xf1,0xff,0x83,0xf3,0x80,0x2d,0x11,0x7a,0x83,0xe0,0x9c,0x20,0xfc,0x2f,0xb8,0x3e,0x37,0xc0,0xf7,0xff,0x36,0x8a,0x02,0xbf,0x1f,0xee,0x7c,0x1e,0xb8,0x08,0x08,0x10,0xa0,0x4b,0xf1,0xfd,0xc3,0xc1,0xeb,0xc0,0x02,0x1c,0x11,0x7e,0x3e,0x78,0x1d,0xf8,0x1f,0x4a,0xf1,0x8f,0xc7,0x2f,0x80,0xf5,0x84,0x40,0xa0,0x10,0x80,0x79,0x7f,0xe7,0xf7,0x80,0x7a,0xc6,0x20,0x70,0x08,0xc0,0x3c,0xef,0xf7,0x00,0x7a,0xea,0x26,0x56,0x79,0xc0,0x3c,0xff,0xf6,0x00,0x7a,0xd2,0x29,0x59,0x1b,0xc0,0x3d,0x2c,0x23,0xf6,0xa5,0x7c,0x43,0xeb,0x63,0x07,0xbc,0x44,0x7e,0x84,0x01,0x07,0xb4,0xca,0xc2,0x5f,0x40,0x7b,0x9f,0xd8,0x1f,0xe0,0xf8,0x5f,0xa0,0x3e,0x70,0x00,0x92,0x6f,0x8f,0x80,0x08,0x53,0xf7,0x7a,0x83,0xcc,0x12,0xa0,0x0f,0x00,0x78,0x03,0xc0,0x14,}; -const uint8_t *_I_no_databases2[] = {_I_no_databases2_0}; - -const uint8_t _I_no_databases3_0[] = {0x01,0x00,0x43,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xff,0x11,0x00,0x88,0x00,0x04,0x16,0x34,0x00,0x10,0xc1,0x01,0xf7,0x20,0x07,0xbe,0x62,0x19,0x9c,0x9d,0xdd,0xf3,0x91,0x99,0x1c,0x9a,0x3b,0x07,0x27,0xa6,0xa2,0x25,0x52,0xc9,0x65,0x2a,0x5a,0x4b,0x04,0xa7,0x4a,0x1f,0x10,0x79,0xf2,0x01,0xe7,0x92,0x9e,0x48,0x41,0xef,0x88,0x07,0x9c,0x4a,0x0b,0x22,0x07,0xc0,0xfc,0x62,0x77,0x7e,0xe6,0x62,0x43,0xc6,0x92,0x8f,0xd5,0x3f,0xe0,0xff,0x07,0xf8,0x3f,0xc1,0xfe,0x0a,0x5b,0x84,0x79,0x5e,0x54,0x00,0x7c,0xe2,0x24,0x40,0xf2,0xd0,0x7f,0xe3,0xff,0xc0,0x7a,0x60,0x27,0x30,0x89,0x16,0x32,0x77,0x07,0xe8,0x7f,0xfc,0xff,0x30,0x7a,0x50,0x29,0x57,0x09,0x15,0x4b,0x15,0x04,0xf8,0x7f,0xe7,0x7e,0xe0,0x7b,0x60,0x24,0x54,0x20,0x79,0xfb,0x7b,0xe0,0xf6,0x1f,0x88,0x7d,0x22,0xdb,0xf1,0xfa,0xd2,0x4b,0xe3,0x8c,0x85,0xc1,0xc1,0xe3,0xee,0xdf,0x1f,0xef,0xe1,0x7f,0xff,0xdf,0x81,0xf7,0xc0,0xbf,0x80,0x08,0x1f,0x83,0xe1,0x07,0xea,0x78,0x43,0xfe,0x0f,0x6f,0xf2,0xe8,0xa0,0x2b,0xf1,0xff,0x1b,0xd4,0xe0,0x30,0x10,0x21,0x40,0x97,0xe2,0x0f,0x7e,0x00,0x10,0xe0,0x8b,0xf1,0xfe,0xe7,0xc1,0xf6,0x8f,0x1f,0xdc,0x3c,0x1e,0xd0,0x88,0x14,0x02,0x10,0x0f,0x2f,0x3c,0x0e,0xfc,0x0f,0x58,0xc4,0x0e,0x01,0x18,0x07,0x94,0x7e,0x39,0x7c,0x07,0xae,0xa2,0x65,0x67,0x9c,0x03,0xcb,0xff,0x3f,0xbc,0x03,0xd6,0x91,0x4a,0xc8,0xde,0x01,0xe7,0x7f,0xb8,0x0f,0xda,0x95,0xf1,0x0f,0xa7,0xfe,0xc0,0x0f,0x78,0x88,0xfc,0xc0,0x03,0x61,0x07,0xb4,0xca,0xc2,0x5f,0x30,0x00,0xd8,0xcf,0xf8,0x40,0x20,0x7f,0x83,0xd5,0x7e,0x80,0xf9,0xc0,0x02,0x49,0xbe,0x3e,0x00,0x21,0x4f,0xdd,0xea,0x0f,0x30,0x4a,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x50,}; -const uint8_t *_I_no_databases3[] = {_I_no_databases3_0}; - -const uint8_t _I_no_databases4_0[] = {0x01,0x00,0x43,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xff,0x11,0x00,0x88,0x00,0x04,0x16,0x34,0x00,0x10,0xc1,0x01,0xf7,0x20,0x07,0xbe,0x62,0x19,0x9c,0x9d,0xdd,0xf3,0x91,0x99,0x1c,0x9a,0x3b,0x07,0x27,0xa6,0xa2,0x25,0x52,0xc9,0x65,0x2a,0x5a,0x4b,0x04,0xa7,0x4a,0x1f,0x10,0x79,0xf2,0x01,0xe7,0x92,0x9e,0x48,0x41,0xef,0x88,0x07,0x9c,0x4a,0x0b,0x22,0x07,0xc0,0xfc,0x62,0x77,0x7e,0xe6,0x62,0x43,0xc6,0x92,0x8f,0xd5,0x3f,0xe0,0xff,0x07,0xf8,0x3f,0xc1,0xfe,0x0a,0x5b,0x84,0x79,0x5e,0x54,0x00,0x7c,0xe2,0x24,0x40,0xf2,0xd0,0x7f,0xe0,0xe0,0xf5,0xc0,0x4e,0x61,0x12,0x2c,0x64,0xee,0x0f,0xd0,0xff,0xfe,0x7f,0x80,0xf4,0xa0,0x52,0xae,0x12,0x2a,0x96,0x2a,0x09,0xf0,0xff,0xe3,0xbf,0x60,0xf6,0xc0,0x48,0xa8,0x40,0xf2,0xbf,0xfe,0xfe,0xe0,0xf6,0x1f,0x88,0x7c,0xf7,0xf1,0xdf,0x78,0xfd,0x69,0x25,0xf1,0xc6,0x42,0xe0,0xe0,0xf1,0xf7,0xfb,0x8f,0xf7,0xf0,0xef,0xff,0xfb,0xc0,0xfb,0xe0,0x77,0xef,0xe0,0x11,0x07,0xe6,0xfc,0x1f,0xdf,0xf0,0xff,0x83,0xdf,0xfc,0xba,0x28,0x0d,0x03,0x7f,0xff,0x37,0xa9,0xc0,0x60,0x20,0x42,0x81,0x68,0x01,0xf1,0xc0,0x02,0x1c,0x13,0xa1,0x7f,0xff,0xf9,0xc1,0xf6,0xbf,0x1f,0xf7,0x0c,0x1e,0xd0,0x88,0x14,0x02,0x10,0x0f,0x2f,0xce,0x00,0x1e,0xd1,0x88,0x1c,0x02,0x30,0x0f,0x28,0x3c,0x1c,0x1e,0xda,0x89,0x95,0x9e,0x70,0x0f,0x2f,0xfc,0x3e,0xfc,0x0f,0x5a,0x45,0x2b,0x23,0x78,0x07,0x9c,0x7e,0xf8,0x3f,0x6a,0x57,0xc4,0x3e,0x93,0xfb,0xc0,0x3d,0xe2,0x23,0xf3,0xff,0xdf,0xc1,0xef,0x32,0xb0,0x97,0xcc,0x00,0x20,0xf6,0x3f,0xb0,0x80,0x81,0xfe,0x0f,0x55,0xfa,0x03,0xe7,0x00,0x09,0x26,0xf8,0xf8,0x00,0x85,0x3f,0x77,0xa8,0x3c,0xc1,0x2a,0x00,0xf0,0x07,0x80,0x3c,0x01,0x40,}; -const uint8_t *_I_no_databases4[] = {_I_no_databases4_0}; - -const uint8_t _I_no_sd1_0[] = {0x01,0x00,0x49,0x01,0x00,0x5e,0x03,0xff,0x07,0x07,0xe5,0xc2,0x01,0x38,0x07,0xe4,0x32,0x01,0xc0,0x07,0xe4,0x0c,0x04,0x5c,0x0f,0xf8,0x00,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x00,0xf2,0x22,0xb5,0x00,0x06,0x50,0x8b,0x06,0x4a,0x49,0x49,0x83,0x03,0xd6,0x40,0x03,0x28,0x80,0x3e,0xa2,0x01,0x33,0x07,0xd4,0x20,0x1f,0xe4,0x33,0x07,0xd4,0x10,0x1e,0x65,0xfa,0x07,0x9e,0x00,0x1f,0x50,0x20,0x7f,0x81,0x0c,0x1f,0xe0,0xfa,0x80,0x80,0x86,0x1e,0x0f,0xde,0x04,0xf0,0x1f,0xb6,0x0b,0xc0,0x3f,0xc1,0xfb,0x70,0xfc,0x40,0x3a,0x00,0xfc,0xec,0x40,0x3d,0x00,0xfb,0xf8,0x7f,0x20,0x1f,0x40,0x7d,0xec,0x35,0xf0,0x0f,0xe7,0x26,0x4d,0xe7,0x0f,0xce,0xf4,0x1e,0x38,0x0d,0xdf,0x68,0x1f,0x1e,0x0a,0xe8,0x3c,0x72,0x9b,0xae,0xd8,0x3d,0xa0,0xb0,0x09,0x05,0x1c,0x1e,0x5a,0x61,0x7b,0xc0,0xd3,0xe3,0x30,0x07,0x92,0xff,0x7e,0x19,0x48,0x1f,0x44,0x1e,0xb8,0x00,0x1a,0x03,0xc7,0xf3,0x2f,0x07,0xad,0x00,0x06,0x54,0x88,0x17,0xc3,0xff,0xc0,0x8f,0x83,0xd6,0x40,0x03,0x29,0x24,0x04,0x1e,0x38,0x18,0x78,0x3d,0x62,0x00,0x32,0xc9,0x2f,0xcb,0x1f,0x00,0x07,0xac,0x20,0x06,0x54,0x95,0xf8,0xdf,0xf0,0x18,0x08,0x3f,0x80,0x22,0x70,0x40,0x10,0xc1,0x80,0x43,0xf4,0x07,0x8f,0x02,0x0f,0x10,0xec,0x04,0x08,0x1e,0x38,0x03,0x89,0x7f,0x19,0xe7,0x10,0x90,0x0b,0x08,0x1e,0x37,0x81,0x29,0x03,0xd8,0x98,0x40,0xf1,0x1a,0x98,0x3d,0x2c,0x00,0xf3,0xf2,0x78,0x16,0x24,0x0f,0x5c,0x04,0xff,0xc0,0x3a,0x18,0xc4,0x7c,0x08,0x40,0xf6,0x45,0x8c,0xf8,0xfe,0x5f,0xc0,0x7b,0xd0,0x28,0x10,0x4e,0x04,0x3e,0xc1,0x80,0xff,0x8f,0xdc,0x1e,0x4c,0x81,0x03,0x8c,0xfc,0x1f,0x1c,0x02,0x49,0x40,0x3f,0xce,0xd1,0x07,0xc2,0xc0,0xff,0xc1,0x43,0x07,0xd4,0x08,0x08,0x60,0xff,0xfc,0x03,0xca,0x07,0x80,0xb0,0x02,0x8c,0xda,0x40,0x07,0xb0,0x83,0xfb,0xfc,0x0b,0x30,0x7a,0x00,}; -const uint8_t *_I_no_sd1[] = {_I_no_sd1_0}; - -const uint8_t _I_no_sd2_0[] = {0x01,0x00,0x42,0x01,0x00,0x5e,0x03,0xff,0x07,0x07,0xe5,0xc2,0x01,0x38,0x07,0xe4,0x32,0x01,0xc0,0x07,0xe4,0x0c,0x04,0x5c,0x0f,0xf8,0x00,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x00,0xf2,0x22,0xb5,0x00,0x06,0x50,0x8b,0x06,0x4a,0x49,0x49,0x83,0x03,0xd6,0x40,0x03,0x28,0x80,0x3e,0xa2,0x01,0x33,0x07,0xd4,0x20,0x1f,0xe4,0x33,0x07,0xd4,0x10,0x1e,0x65,0xfa,0x07,0x9e,0x00,0x1f,0x50,0x20,0x7f,0x81,0x0c,0x1f,0xe0,0xfa,0x80,0x80,0x86,0x1e,0x0f,0xde,0x04,0xf0,0x1f,0xb6,0x0b,0xc0,0x3f,0xc1,0xfb,0x70,0xfc,0x40,0x3a,0x00,0xfc,0xec,0x40,0x3d,0x00,0xfb,0xf8,0x7f,0x20,0x1f,0x40,0x7d,0xec,0x35,0xf0,0x0f,0xe7,0x26,0x4d,0xe7,0x0f,0xce,0xf4,0x1e,0x38,0x0d,0xdf,0x68,0x1f,0x1e,0x0a,0xe8,0x3c,0x72,0x9b,0xae,0xd8,0x3d,0xa0,0xb0,0x09,0x05,0x1c,0x1e,0x5a,0x61,0x7b,0xc0,0xd3,0xe3,0x30,0x07,0x92,0xff,0x7e,0x19,0x48,0x1f,0x44,0x1e,0xb8,0x00,0x1a,0x03,0xc7,0xf3,0x2f,0x07,0xad,0x00,0x06,0x54,0x88,0x17,0xc3,0xff,0xc0,0x8f,0x83,0xd6,0x40,0x03,0x29,0x24,0x04,0x1e,0x38,0x18,0x78,0x3d,0x62,0x00,0x32,0xc9,0x2f,0xcb,0x1f,0x00,0x07,0xac,0x20,0x06,0x54,0x95,0xf8,0xdf,0xf0,0x18,0x00,0x7a,0xc1,0x00,0x43,0x06,0x01,0x0f,0xd0,0x1e,0x3c,0x00,0x78,0xf8,0x02,0x44,0x0f,0x1c,0x01,0xc4,0xbf,0x8c,0xf4,0x88,0x76,0x00,0x62,0x0f,0x1b,0xc0,0x94,0x81,0xed,0x20,0x1e,0x88,0x3c,0x46,0xe6,0x0f,0x72,0xe8,0xf9,0x3c,0x0b,0x12,0x07,0xb5,0x80,0x1e,0x51,0x88,0xff,0x80,0x7f,0x18,0x09,0xf8,0x2c,0x42,0x23,0xfc,0x07,0xca,0x70,0x67,0xd6,0x0c,0x07,0xfc,0x7f,0x14,0x0a,0x04,0x13,0x81,0x8f,0xff,0xcf,0xc1,0xf6,0xd9,0x1f,0xfb,0xb4,0x41,0xf1,0xc0,0x2d,0x17,0xf8,0x06,0x40,0xf8,0x05,0x14,0x09,0x6a,0x60,0xff,0xfc,0x03,0xc8,0x4e,0x20,0xf4,0x36,0x90,0x01,0xf0,0x16,0x00,0x7e,0xc0,0x2c,0x20,0xf7,}; -const uint8_t *_I_no_sd2[] = {_I_no_sd2_0}; - -const uint8_t _I_no_sd3_0[] = {0x01,0x00,0x41,0x01,0x00,0x5e,0x03,0xff,0x07,0x07,0xe5,0xc2,0x01,0x38,0x07,0xe4,0x32,0x01,0xc0,0x07,0xe4,0x0c,0x04,0x5c,0x0f,0xf8,0x00,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x00,0xf2,0x22,0xb5,0x00,0x06,0x50,0x8b,0x06,0x4a,0x49,0x49,0x83,0x03,0xd6,0x40,0x03,0x28,0x80,0x3e,0xa2,0x01,0x33,0x07,0xd4,0x20,0x1f,0xe4,0x33,0x07,0xd4,0x10,0x1e,0x65,0xfa,0x07,0x9e,0x00,0x1f,0x50,0x20,0x7f,0x81,0x0c,0x1f,0xe0,0xfa,0x80,0x83,0xfc,0x1f,0xe0,0xff,0x2e,0x8c,0xfc,0x1f,0xbe,0x0b,0xc4,0x03,0xa0,0x0f,0xbb,0x06,0xe2,0x01,0xe8,0x07,0xdf,0xc3,0xf9,0x00,0xfa,0x03,0xef,0x61,0xdf,0x80,0x7f,0x39,0x32,0x6f,0x38,0x7e,0x77,0x20,0xf1,0xc0,0x6e,0xfb,0x44,0xf9,0xac,0x83,0xc7,0x29,0xba,0xed,0x83,0xda,0x0b,0x00,0xe0,0x1b,0xc4,0x1e,0x3a,0x61,0x7b,0xc0,0xc0,0x86,0x0f,0x14,0xfd,0xe4,0x08,0x43,0x94,0x81,0xf4,0x41,0xeb,0x80,0x01,0x95,0x22,0x04,0x0f,0x1f,0xcc,0xbc,0x1e,0xb4,0x00,0x91,0x49,0x20,0x3f,0x0f,0xff,0x02,0x3e,0x0f,0x59,0x00,0x48,0xb2,0x50,0x40,0x78,0xe0,0x61,0xe0,0xf5,0x88,0x04,0x8a,0x93,0x02,0x5f,0x8e,0x3e,0x00,0x0f,0x58,0x40,0x8c,0xe1,0x3e,0x8b,0xfe,0x03,0x00,0x0f,0x58,0x20,0x08,0x60,0xd8,0x08,0x27,0xd0,0x1e,0x3c,0x00,0x7b,0xe0,0x0e,0x25,0xfc,0x67,0xc0,0x3c,0x5f,0xa2,0x0f,0x7f,0xc0,0x64,0x81,0xe3,0x1f,0x07,0xc4,0x13,0xec,0x10,0x1f,0x27,0x80,0x4e,0x60,0xf6,0x84,0x40,0xa0,0x1d,0x8f,0xf8,0x90,0x81,0xf0,0x2d,0x1f,0x07,0xc5,0x62,0x60,0xf5,0x8c,0x03,0xce,0x3f,0x70,0x07,0xc7,0x82,0x1e,0x5b,0x15,0x78,0xcf,0x01,0xf1,0x20,0x84,0x60,0x21,0xe0,0xf1,0x2f,0xcc,0x42,0x20,0xd8,0x1a,0x1f,0x02,0x1e,0x0f,0xb0,0x49,0x1b,0xe6,0x21,0xf0,0x05,0x17,0xf8,0xde,0x7f,0x80,0x79,0x40,0xc1,0xe3,0x30,0x05,0x15,0xf5,0x6c,0x8f,0xb5,0x07,0x98,0x78,0xc1,0xff,0x00,}; -const uint8_t *_I_no_sd3[] = {_I_no_sd3_0}; - -const uint8_t _I_no_sd4_0[] = {0x01,0x00,0x45,0x01,0x00,0x5e,0x03,0xff,0x07,0x07,0xe5,0xc2,0x01,0x38,0x07,0xe4,0x32,0x01,0xc0,0x07,0xe4,0x0c,0x04,0x5c,0x0f,0xf8,0x00,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x00,0xf2,0x22,0xb5,0x00,0x06,0x50,0x8b,0x06,0x4a,0x49,0x49,0x83,0x03,0xd6,0x40,0x03,0x28,0x80,0x3e,0xa2,0x01,0x33,0x07,0xd4,0x20,0x1f,0xe4,0x33,0x07,0xd4,0x10,0x1e,0x65,0xfa,0x07,0x9e,0x00,0x1f,0x50,0x20,0x7f,0x81,0x0c,0x1f,0xe0,0xfa,0x80,0x83,0xfc,0x1f,0xe0,0xff,0x2e,0x8c,0xfc,0x1f,0xbe,0x0b,0xc4,0x03,0xa0,0x0f,0xbb,0x06,0xe2,0x01,0xe8,0x07,0xdf,0xc3,0xf9,0x00,0xfa,0x03,0xef,0x61,0xdf,0x80,0x7f,0x39,0x32,0x6f,0x38,0x7e,0x77,0x20,0xf1,0xc0,0x6e,0xfb,0x44,0xf9,0xac,0x83,0xc7,0x29,0xba,0xed,0x83,0xda,0x0b,0x00,0xe0,0x1b,0xc4,0x1e,0x3a,0x61,0x7b,0xc0,0xc0,0x86,0x0f,0x14,0xfd,0xe4,0x08,0x43,0x94,0x81,0xf4,0x41,0xeb,0x80,0x01,0x95,0x22,0x04,0x0f,0x1f,0xcc,0xbc,0x1e,0xb4,0x00,0x91,0x49,0x20,0x3f,0x0f,0xff,0x02,0x3e,0x0f,0x59,0x00,0x48,0xb2,0x50,0x40,0x78,0xe0,0x61,0xe0,0xf5,0x88,0x04,0x8a,0x93,0x02,0x5f,0x8e,0x3e,0x00,0x0f,0x58,0x40,0x8c,0xe1,0x3e,0x8b,0xfe,0x03,0x00,0x0f,0x58,0x20,0x08,0x60,0xd8,0x08,0x27,0xd0,0x1e,0x3c,0x00,0x7b,0xe0,0x0e,0x25,0xfc,0x67,0xc0,0x3c,0x5f,0xa2,0x0f,0x7f,0xc0,0x64,0x81,0xe2,0x17,0x30,0x7a,0xc1,0x3e,0xc1,0x01,0xf2,0x78,0x16,0x26,0x0f,0x68,0x44,0x0a,0x01,0x18,0x8f,0xf8,0x07,0xf0,0x0f,0x11,0x68,0x9f,0xc7,0xf8,0x0f,0x88,0xc0,0x3c,0xac,0x18,0x0f,0xf8,0xfe,0x3c,0x10,0xf2,0xd8,0x83,0x85,0xfa,0x20,0xf7,0x90,0x42,0x30,0x10,0xf8,0x07,0xf8,0x04,0x20,0xf7,0x88,0x44,0x1b,0x03,0x03,0xff,0x17,0x88,0x1f,0x20,0x91,0x8f,0xa5,0x4c,0x1e,0xdf,0x00,0x51,0x1c,0x84,0x00,0x5f,0x80,0x79,0x09,0xc6,0x21,0x30,0x05,0x11,0xb4,0x80,0x0e,0x0f,0xf0,0x7c,0x80,}; -const uint8_t *_I_no_sd4[] = {_I_no_sd4_0}; - -const uint8_t _I_no_sd5_0[] = {0x01,0x00,0x3d,0x01,0x00,0x5e,0x03,0xff,0x07,0x07,0xe5,0xc2,0x01,0x38,0x07,0xe4,0x32,0x01,0xc0,0x07,0xe4,0x0c,0x04,0x5c,0x0f,0xf8,0x00,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x00,0xf2,0x22,0xb5,0x00,0x06,0x50,0x8b,0x06,0x4a,0x49,0x49,0x83,0x03,0xd6,0x40,0x03,0x28,0x80,0x3e,0xa2,0x01,0x33,0x07,0xd4,0x20,0x1f,0xe4,0x33,0x07,0xd4,0x10,0x1e,0x65,0xfa,0x07,0x9e,0x00,0x1f,0x50,0x20,0x7f,0x81,0x0c,0x1f,0xe0,0xfa,0x80,0x83,0xfc,0x1f,0xe0,0xff,0x07,0xf8,0x10,0xfa,0x00,0xfc,0xe0,0x40,0x3d,0x00,0xfc,0xf0,0x40,0x3e,0x80,0xfb,0x98,0x7c,0x20,0x1f,0xce,0x4c,0x9b,0xce,0x0f,0x8f,0x85,0xfc,0x1e,0x38,0x0d,0xdf,0x68,0x1f,0x1e,0x09,0xf8,0x3c,0x72,0x9b,0xae,0xd8,0x3d,0xa0,0xa4,0xe1,0x8f,0x83,0xcb,0x4c,0x2f,0x78,0x18,0x10,0xc1,0xe2,0x5f,0xbc,0x81,0x08,0x72,0x90,0x3e,0x88,0x3d,0x70,0x00,0x32,0xa4,0x40,0x81,0xe3,0xf9,0x97,0x83,0xd6,0x80,0x12,0x29,0x24,0x07,0xe1,0xff,0x22,0x08,0x3d,0x64,0x01,0x22,0xc9,0x41,0x01,0xe3,0x81,0x87,0x83,0xd6,0x20,0x12,0x2a,0x4c,0x09,0x7e,0x38,0xf8,0x00,0x3d,0x61,0x02,0x33,0x84,0xfa,0x2f,0xf8,0x0c,0x00,0x3d,0x60,0x80,0x21,0x83,0x60,0x20,0x9f,0x40,0x78,0xf0,0x01,0xef,0x80,0x38,0x97,0xf1,0x9f,0x00,0xf1,0xbc,0x23,0xcc,0x1e,0x9f,0x80,0xc9,0x03,0xc5,0x5a,0x20,0xf7,0x82,0x7d,0x82,0x03,0xe4,0xf0,0x09,0xcc,0x1e,0xd0,0x88,0x14,0x03,0xb1,0xff,0x12,0x10,0x3e,0x05,0xa3,0xe0,0xf8,0xac,0x4c,0x1e,0xb1,0x80,0x79,0xc7,0xee,0x00,0xf8,0xf0,0x43,0xcb,0x62,0xaf,0x19,0xe0,0x3e,0x24,0x10,0x8c,0x04,0x3c,0x1e,0x25,0xf9,0x88,0x44,0x1b,0x03,0x43,0xe0,0x43,0xc1,0xf6,0x09,0x23,0x7c,0xc4,0x3e,0x00,0xa2,0xff,0x1b,0xcf,0xf0,0x0f,0x28,0x18,0x3c,0x66,0x00,0xa2,0xbe,0xad,0x91,0xf6,0xa0,0xf3,0x0f,0x18,0x3f,0xe0,0x00,}; -const uint8_t *_I_no_sd5[] = {_I_no_sd5_0}; - -const uint8_t _I_no_sd6_0[] = {0x01,0x00,0x43,0x01,0x00,0x5e,0x03,0xff,0x07,0x07,0xe5,0xc2,0x01,0x38,0x07,0xe4,0x32,0x01,0xc0,0x07,0xe4,0x0c,0x04,0x5c,0x0f,0xf8,0x00,0x40,0xe4,0x3e,0x40,0x19,0x41,0x3c,0x00,0xf2,0x22,0xb5,0x00,0x06,0x50,0x8b,0x06,0x4a,0x49,0x49,0x83,0x03,0xd6,0x40,0x03,0x28,0x80,0x3e,0xa2,0x01,0x33,0x07,0xd4,0x20,0x1f,0xe4,0x33,0x07,0xd4,0x10,0x1e,0x65,0xfa,0x07,0x9e,0x00,0x1f,0x50,0x20,0x7f,0x81,0x0c,0x1f,0xe0,0xfa,0x80,0x80,0x86,0x1e,0x0f,0xde,0x04,0xf0,0x1f,0xb6,0x0b,0xc0,0x3f,0xc1,0xfb,0x70,0xfc,0x40,0x3a,0x00,0xfc,0xec,0x40,0x3d,0x00,0xfb,0xf8,0x7f,0x20,0x1f,0x40,0x7d,0xec,0x35,0xf0,0x0f,0xe7,0x26,0x4d,0xe7,0x0f,0xce,0xf4,0x1e,0x38,0x0d,0xdf,0x68,0x1f,0x1e,0x0a,0xe8,0x3c,0x72,0x9b,0xae,0xd8,0x3d,0xa0,0xb0,0x09,0x05,0x1c,0x1e,0x5a,0x61,0x7b,0xc0,0xd3,0xe3,0x30,0x07,0x92,0xff,0x7e,0x19,0x48,0x1f,0x44,0x1e,0xb8,0x00,0x1a,0x03,0xc7,0xf3,0x2f,0x07,0xad,0x00,0x06,0x54,0x88,0x17,0xc3,0xff,0xc0,0x8f,0x83,0xd6,0x40,0x03,0x29,0x24,0x04,0x1e,0x38,0x18,0x78,0x3d,0x62,0x00,0x32,0xc9,0x2f,0xcb,0x1f,0x00,0x07,0xac,0x20,0x06,0x54,0x95,0xf8,0xdf,0xf0,0x18,0x00,0x7a,0xc1,0x00,0x43,0x06,0x01,0x0f,0xd0,0x1e,0x3c,0x00,0x7b,0xe0,0x0e,0x25,0xfc,0x67,0xc0,0x3c,0x6f,0x00,0x52,0x07,0xaf,0xe0,0x32,0x40,0xf1,0x8f,0x83,0xe2,0x09,0xf6,0x08,0x0f,0x93,0xc0,0x27,0x30,0x7b,0x42,0x20,0x50,0x0e,0xc7,0xfc,0x48,0x40,0xf8,0x16,0x8f,0x83,0xe2,0xb1,0x30,0x7a,0xc6,0x01,0xe7,0x1f,0xb8,0x03,0xe3,0xc1,0x0f,0x2d,0x8a,0xbc,0x67,0x80,0xf8,0x90,0x42,0x30,0x10,0xf0,0x78,0x97,0xe6,0x21,0x10,0x64,0x0d,0x0f,0x80,0xfd,0x10,0x7d,0x02,0x48,0xdf,0x31,0x0f,0x80,0x28,0xbf,0xc6,0xf3,0xfc,0x03,0xca,0x06,0x0f,0x19,0x80,0x28,0xaf,0xab,0x64,0x7d,0xa8,0x3c,0xc3,0xc6,0x0f,0xf8,0x00,}; -const uint8_t *_I_no_sd6[] = {_I_no_sd6_0}; - -const uint8_t _I_tv1_0[] = {0x01,0x00,0xca,0x01,0x84,0x00,0x86,0x04,0x0b,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0x0c,0x62,0x00,0x21,0x80,0x83,0x9b,0x01,0x01,0xe0,0x03,0xf2,0x80,0x0a,0x39,0x00,0x58,0x41,0x66,0x33,0x30,0x50,0x81,0x88,0x1e,0xd0,0x50,0x19,0x0a,0x8a,0x08,0x24,0x21,0x31,0x40,0x38,0x00,0x81,0x2d,0x20,0x08,0x41,0xeb,0x38,0x07,0xc0,0xb4,0x46,0xc4,0x78,0x10,0x79,0x80,0xc8,0x64,0x20,0xf4,0x86,0x02,0xcc,0x1e,0xa6,0x21,0xe8,0x40,0x21,0xe5,0x61,0x82,0x60,0x2f,0xe0,0xf7,0xa8,0x78,0x66,0x07,0x61,0x81,0x58,0x11,0xa3,0x02,0xc0,0x43,0xce,0x47,0x48,0x8f,0x25,0x8a,0x05,0x30,0x80,0x41,0x90,0x64,0x0f,0x43,0xf9,0xc0,0x7f,0x05,0xb1,0x81,0x78,0x27,0xe0,0xf1,0xff,0xff,0xc7,0x02,0xba,0x20,0x30,0xc0,0x7e,0x10,0x3f,0x04,0x9f,0xc1,0x1f,0x22,0x8e,0x10,0x1e,0x56,0x01,0x39,0x02,0xc6,0xc1,0x26,0xf0,0x48,0xc4,0xc3,0x82,0x07,0x94,0x78,0x1e,0x5c,0x08,0x1f,0x02,0x27,0xc0,0xa0,0x8d,0x8a,0x07,0x00,0xf0,0x38,0x8a,0x08,0x55,0x12,0xf8,0xf0,0x11,0xc3,0x10,0x80,0xa3,0x44,0xec,0x41,0x71,0x30,0x8b,0x1c,0x81,0xe7,0xf0,0x9f,0xae,0x48,0x1e,0x20,0x43,0x07,0x96,0x80,0x0a,0x34,0x00,0x51,0xc4,0x16,0x46,0x0f,0xa9,0x07,0xd0,0x1e,0xbf,0x02,0x58,0x83,0xd6,0x18,0x5f,0x10,0x79,0xff,0x20,0xe0,0xf1,0x27,0x9d,0x02,0x09,0x7c,0x63,0x88,0x3c,0xbf,0xd0,0xf0,0x7a,0xe0,0x21,0x06,0xe1,0x16,0x0e,0x0f,0xff,0xfd,0xfb,0xaa,0xc7,0xfe,0xa6,0x10,0x78,0x9b,0xce,0x19,0x9c,0xff,0xa3,0x04,0x1e,0x51,0xd0,0x59,0x70,0x52,0xe2,0xa4,0x1d,0xc0,0x30,0x80,0x03,0x3f,0x0f,0x97,0xe0,0x54,0x22,0xf1,0x45,0x88,0x3d,0x39,0xe0,0xf1,0xc0,0x15,0x87,0xff,0x03,0x26,0x8f,0x81,0xf8,0x64,0x61,0x07,0x8d,0xc0,0x0a,0x3f,0xc0,0xa0,0x8f,0x10,0x00,0x3f,0x30,0x78,0xc3,0x82,0xe7,0x40,0x07,0xb7,0xd2,0x7f,0xf0,0xe0,0x83,0xd7,0xf8,0x0e,0x3b,0xff,0xdf,0xbf,0x0f,0xd3,0x18,0x8c,0x1e,0x3c,0x30,0x79,0xe7,0xfe,0xf1,0xfd,0x85,0xe6,0xfc,0xb3,0x3c,0x06,0x00,0x1e,0x7e,0xf0,0x78,0xd3,0xe9,0x39,0x26,0x38,0x83,0xc6,0x80,0x0f,0x4f,0x9f,0xdf,0x3e,0x05,0x23,0xe8,0x83,0xc4,0x40,0x24,0x63,0xfe,0x03,0xc4,0x0a,0x51,0x80,0x7a,0x07,0xcd,0x84,0x31,0xf1,0x61,0x47,0x01,0xe5,0x10,0x07,0xbc,0x08,0x18,0x31,0xe0,0x10,0xd8,0x01,0xf1,0x04,0x06,0x08,0xfc,0xae,0x0f,0x31,0xf3,0x83,0xd4,0x78,0x3c,0x06,0x99,0x6f,0x01,0xe3,0xc3,0x0b,0x0f,0xe0,0x1e,0x56,0x06,0x18,0xdf,0xc1,0xe3,0x3f,0x83,0x83,0xc7,0x5f,0x32,0xfd,0x83,0xc5,0x6a,0x8f,0x72,0x68,0x8f,0x9c,0x3e,0xae,0x64,0x80,0x4e,0x01,0xe2,0x4f,0x60,0x7a,0xc8,0x01,0xfe,0x2f,0x20,0x7f,0x00,}; -const uint8_t *_I_tv1[] = {_I_tv1_0}; - -const uint8_t _I_tv2_0[] = {0x01,0x00,0xcc,0x01,0x84,0x00,0x86,0x04,0x0b,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0x0c,0x62,0x00,0x21,0x80,0x83,0x9b,0x01,0x01,0xe0,0x03,0xf2,0x80,0x0a,0x39,0x00,0x58,0x41,0x45,0x06,0x07,0x98,0x28,0x47,0x44,0x0f,0x58,0x48,0x3c,0xc5,0x45,0x04,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0x0a,0x20,0x7b,0x0b,0x44,0x6c,0x53,0x80,0x7a,0x0b,0x04,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x08,0x9c,0xaf,0xe0,0xf9,0x10,0x88,0x28,0x6c,0x08,0xd1,0x81,0x60,0x21,0xe7,0x23,0x0d,0x88,0x44,0x41,0xe3,0x30,0x41,0x8a,0xdc,0x81,0xea,0x01,0x10,0x50,0xfe,0x00,0xa3,0x02,0xf0,0x4f,0xc1,0xe3,0xff,0x00,0x14,0x3e,0x01,0xfe,0x02,0x0c,0x07,0xe1,0x03,0xf0,0x49,0xfc,0x11,0xf1,0x50,0xc1,0x3c,0x0e,0x61,0x08,0x88,0x88,0x41,0x63,0x20,0x07,0x8c,0xfc,0x4c,0x30,0x68,0xe1,0x70,0x60,0x60,0xf2,0xe0,0x40,0xf8,0x11,0x3e,0x05,0x1c,0x1e,0x31,0xa0,0x60,0xf8,0x0f,0xa6,0x75,0x12,0xf8,0xf0,0x30,0x65,0xc1,0xf2,0x82,0xc6,0xf0,0xad,0x33,0x08,0xae,0x08,0x1e,0x50,0x50,0x30,0xc7,0x81,0xe6,0xa3,0x30,0x79,0x68,0x12,0xc4,0x50,0x14,0xd1,0x01,0xc8,0x1e,0x81,0x72,0x27,0x12,0x28,0x7e,0x80,0xf5,0xf8,0x44,0x60,0x10,0xe0,0xf9,0xc8,0x21,0x85,0xf1,0x07,0x9f,0xf3,0xcf,0xc0,0x84,0xc1,0x81,0xe5,0x40,0x82,0x5f,0x26,0x10,0x10,0x79,0x7f,0xa1,0xf3,0xf8,0x80,0x3c,0xf0,0x10,0x83,0x70,0x8b,0x07,0x3f,0xff,0xfe,0xfd,0xd6,0x24,0xa6,0x10,0x78,0x9b,0xce,0x19,0xbc,0xff,0xa3,0x04,0x1e,0x51,0xd0,0x59,0x70,0x54,0x87,0xf8,0x67,0x9f,0xfe,0x7e,0x1f,0x2f,0xc6,0x0c,0x4a,0x4d,0x41,0x07,0xa7,0x3c,0x12,0x38,0x03,0x18,0xff,0xe0,0xf8,0x05,0xca,0x00,0x07,0xe0,0x0f,0x1b,0x80,0x14,0x7f,0x90,0x10,0x79,0x07,0xd3,0xe6,0x0f,0x18,0x70,0x5c,0xe8,0x00,0xf6,0xfa,0x4f,0xfe,0x1c,0x10,0x7a,0xff,0x01,0xc7,0x7f,0xfb,0xf7,0xe1,0xfa,0x63,0x11,0x83,0xc4,0x3c,0x99,0xff,0xbc,0x7f,0x61,0x79,0xbf,0x2c,0xcf,0x01,0x87,0x07,0x9f,0xbc,0x1e,0x34,0xfa,0x4e,0x4a,0x02,0x0f,0x2e,0x06,0x04,0x9c,0x9f,0x75,0x30,0x80,0x08,0x1e,0x5e,0x03,0x08,0x80,0x0b,0xf8,0x0f,0x10,0x29,0x7e,0x01,0xe5,0x60,0xc0,0x06,0x0d,0x84,0x31,0xf1,0x61,0x7f,0x01,0xe5,0x30,0x07,0xbc,0x08,0x18,0x25,0x02,0xb0,0x03,0xe2,0x08,0x0c,0x1b,0xf8,0x08,0x6e,0x11,0x8c,0x07,0x9c,0x1e,0xb1,0x88,0x07,0x00,0x9e,0x5b,0xc0,0x78,0xf0,0xe1,0xe4,0x81,0x07,0x95,0x81,0x86,0x3f,0xf7,0x78,0xcf,0xe1,0xe0,0xf1,0xd7,0xcc,0xbf,0x60,0xf1,0x4b,0x23,0xdc,0x9c,0xc3,0xe7,0x0f,0xab,0x99,0x20,0x13,0x80,0x78,0x93,0xd8,0x1e,0xb2,0x00,0x7f,0x8b,0xc8,0x1f,0xc0,}; -const uint8_t *_I_tv2[] = {_I_tv2_0}; - -const uint8_t _I_tv3_0[] = {0x01,0x00,0xc1,0x01,0x84,0x00,0x86,0x04,0x0b,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0x0c,0x62,0x00,0x21,0x80,0x83,0x9b,0x01,0x01,0xe0,0x03,0xf2,0x80,0x0a,0x39,0x00,0x58,0x41,0x66,0x33,0x30,0x50,0x81,0x88,0x1e,0xd0,0x50,0x19,0x0a,0x8a,0x08,0x24,0x21,0x31,0x40,0x38,0x00,0x81,0x2d,0x20,0x08,0x41,0xeb,0x38,0x07,0xc0,0xb4,0x46,0xc4,0x78,0x10,0x79,0x80,0xc8,0x64,0x20,0xf4,0x86,0x02,0xcc,0x1e,0xa6,0x21,0xe8,0x40,0x21,0xe5,0x61,0x07,0xd5,0x43,0xc3,0x30,0x3b,0x09,0xbc,0xe0,0x58,0x08,0x79,0xc8,0xe9,0x11,0xe4,0xb1,0x03,0xd1,0x04,0xb4,0x83,0xf9,0xa8,0xce,0x05,0xe0,0x9f,0x83,0xc7,0xff,0xff,0xbf,0xae,0x8c,0x0c,0x20,0x01,0x81,0xf8,0x24,0xfe,0x08,0xf9,0x14,0x70,0x80,0xf2,0xb0,0x08,0xce,0x3d,0x60,0x93,0x78,0x24,0x68,0x21,0xc1,0x02,0x8c,0x1e,0x70,0x3e,0x04,0x4f,0x81,0x41,0x07,0x8c,0x0a,0x07,0x00,0xf0,0x0f,0x8c,0xaa,0x25,0xf1,0xe0,0x23,0x86,0x21,0x01,0x46,0x89,0xd8,0x80,0x03,0x30,0x09,0x98,0x3c,0xfe,0x13,0xf5,0xc9,0x40,0x3f,0x10,0x90,0x7a,0xe8,0x00,0xa3,0x40,0x07,0x9c,0x1e,0x0c,0x0f,0xc1,0xe8,0xfd,0x01,0xeb,0xf0,0x25,0x88,0x3c,0xd1,0x23,0xfc,0x2f,0x88,0x3c,0xff,0x90,0x70,0x78,0x93,0xc8,0x04,0x3e,0x0b,0xfb,0x1c,0x41,0xe5,0xfe,0x87,0x83,0xdb,0x81,0xe1,0x04,0x8f,0xc3,0x07,0xff,0xfe,0xfd,0xd5,0x44,0xa6,0x11,0x90,0xce,0x3e,0x01,0x51,0x86,0x67,0x3f,0xe2,0x71,0x07,0x94,0x74,0x1e,0x30,0x8f,0xe0,0x78,0x5a,0x43,0xb8,0x64,0x1f,0xfe,0x7e,0x1f,0x2f,0xc4,0x4e,0x01,0x0e,0x73,0x0f,0xc0,0x1e,0x9c,0xf0,0x79,0x44,0x3c,0x1c,0x08,0x19,0x34,0x7c,0x0a,0x93,0x23,0x08,0x3c,0xdf,0x42,0x0f,0x30,0xfa,0x7c,0xc1,0xe3,0x1e,0x40,0x09,0x3c,0x68,0x00,0xf6,0xfa,0x4f,0xfe,0x13,0x99,0x30,0x9c,0x81,0xe3,0xfc,0x07,0x1d,0xff,0xef,0xdf,0x87,0xfd,0xa7,0xe0,0xf4,0xe1,0x83,0xcf,0x3f,0xf7,0x8f,0xec,0x2f,0x37,0xe0,0x79,0x48,0x30,0x18,0x00,0x79,0xfb,0xc1,0xe3,0x4f,0xa4,0xe6,0x98,0xe2,0x0f,0x1a,0x00,0x3d,0x3e,0x7f,0x7c,0xf8,0x14,0x91,0xc5,0x20,0x10,0x09,0xb8,0xff,0x80,0xf1,0x02,0x94,0x60,0x1e,0x81,0xf3,0x61,0x0c,0x7c,0x58,0x51,0xc0,0x79,0x44,0x01,0xef,0x02,0x06,0x0c,0x78,0x04,0x36,0x00,0x7c,0x41,0x01,0x82,0x3f,0x2b,0x84,0x23,0x01,0xe7,0x07,0xa8,0xf0,0x78,0x0a,0x31,0x80,0x6f,0x01,0xe3,0xc3,0x0b,0x0f,0xe0,0x1e,0x56,0x05,0x68,0xdf,0xc1,0xe3,0x3f,0x83,0x83,0xc7,0x5f,0x32,0xfd,0x83,0xc5,0x6a,0x8f,0x72,0x80,0x0b,0xc4,0x3e,0xae,0x64,0x80,0x4e,0x01,0xe2,0x4f,0x60,0x7a,0xb8,0xc4,0x1f,0xe5,0xf7,0x07,0xc0,}; -const uint8_t *_I_tv3[] = {_I_tv3_0}; - -const uint8_t _I_tv4_0[] = {0x01,0x00,0xc0,0x01,0x84,0x00,0x86,0x04,0x0b,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0x0c,0x62,0x00,0x21,0x80,0x83,0x9b,0x01,0x01,0xe0,0x03,0xf2,0x80,0x0a,0x39,0x00,0x58,0x41,0x45,0x06,0x07,0x98,0x28,0x47,0x44,0x0f,0x58,0x48,0x3c,0xc5,0x45,0x04,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0x0a,0x20,0x7b,0x0b,0x44,0x6c,0x53,0x80,0x7a,0x0b,0x04,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x08,0x3f,0x44,0x22,0x0a,0x23,0x61,0x60,0x21,0xe7,0x23,0x0d,0x88,0x44,0x41,0xea,0x82,0x50,0x78,0x80,0x45,0x84,0x90,0x2f,0x04,0xfc,0x1e,0x3f,0xf0,0x01,0x43,0xe0,0x1f,0xe0,0x31,0xc0,0xfc,0x12,0x7f,0x04,0x7c,0x54,0x30,0x4f,0x03,0x98,0x42,0x22,0x00,0x28,0xf4,0x80,0x1e,0x33,0xf1,0x60,0xc1,0xa3,0x87,0x41,0x81,0x83,0xce,0x07,0xc0,0x89,0xf0,0x28,0xe0,0xf1,0x8d,0x03,0x07,0xc0,0x0e,0x33,0xa8,0x97,0xc7,0x81,0x83,0x2e,0x0f,0x94,0x14,0x37,0x80,0x79,0xcc,0x02,0x66,0x0f,0x28,0x28,0xe4,0x97,0xcc,0x0f,0x3d,0x01,0xec,0x8a,0x02,0x9e,0x43,0x68,0x83,0xcc,0x2e,0x44,0xe4,0xf2,0x2e,0x4c,0x1e,0x3f,0x08,0x8c,0x02,0x1c,0x1f,0x39,0xe5,0xf2,0x0d,0x18,0x07,0x9f,0xf3,0xcf,0xc0,0x84,0xc1,0x81,0xe5,0xc2,0x87,0xf3,0x11,0x82,0x0f,0x2f,0xf4,0x3e,0x7f,0x10,0x07,0x9c,0x04,0x42,0x22,0xf1,0xf8,0x67,0xff,0xff,0xdf,0xba,0xa8,0x83,0x23,0x80,0x08,0x8c,0x38,0x9e,0x30,0xcd,0xe7,0xfd,0x18,0x20,0xf2,0x8e,0x83,0xcc,0x8a,0x50,0x2f,0xc3,0x20,0xff,0xf3,0xf0,0xf9,0xe0,0x04,0xa5,0x01,0xf8,0x03,0xd3,0x9e,0x0f,0x31,0x38,0xc1,0xc0,0x84,0x79,0x32,0x30,0x83,0xc6,0xe1,0x01,0xfe,0x7f,0x20,0x21,0x43,0x00,0x1f,0xcc,0x1e,0x30,0xef,0xf3,0xa8,0x60,0x14,0x00,0x7b,0x7d,0x27,0xff,0x0e,0x08,0x9c,0xc1,0xe3,0xfc,0x07,0x1d,0xff,0xef,0xdf,0x87,0xe9,0x8c,0x42,0x0f,0x30,0xf2,0x67,0xfe,0xf1,0xfd,0x85,0xe6,0xfc,0x0f,0x29,0x06,0x03,0x0e,0x0f,0x3f,0x78,0x3c,0x69,0xf4,0x9c,0x92,0x80,0x41,0xe3,0xc0,0xc0,0x93,0x93,0xee,0xa6,0x10,0x01,0x03,0xcb,0xc0,0x96,0x20,0x00,0xff,0x01,0xe2,0x05,0x2f,0xc0,0x3c,0xac,0x09,0x41,0x00,0x13,0x08,0x63,0xe2,0xc2,0xfe,0x03,0xca,0x60,0x0f,0x78,0x10,0x30,0x4a,0x05,0x60,0x07,0xc4,0x10,0x18,0x37,0xf0,0x10,0xdc,0x23,0x18,0x0f,0x38,0x3d,0x63,0x10,0x0e,0x01,0x3c,0xb7,0x80,0xf1,0xe1,0xc3,0xc9,0x02,0x0f,0x2b,0x03,0x0c,0x7f,0xf0,0x38,0x04,0xfe,0x1e,0x0f,0x1d,0x7c,0xcb,0xf6,0x0f,0x14,0xb2,0x3d,0xc9,0xcc,0x3e,0x70,0xfa,0xb9,0x92,0x01,0x38,0x07,0x89,0x3d,0x81,0xeb,0x20,0x07,0xf8,0xbc,0x81,0xfc,}; -const uint8_t *_I_tv4[] = {_I_tv4_0}; - -const uint8_t _I_tv5_0[] = {0x01,0x00,0xcb,0x01,0x84,0x00,0x86,0x04,0x0b,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0x0c,0x62,0x00,0x21,0x80,0x83,0x9b,0x01,0x01,0xe0,0x03,0xf2,0x80,0x0a,0x39,0x00,0x58,0x41,0x45,0x06,0x07,0x98,0x28,0x47,0x44,0x0f,0x58,0x48,0x3c,0xc5,0x45,0x04,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0x0a,0x20,0x7b,0x0b,0x44,0x6c,0x53,0x80,0x7a,0x0b,0x04,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x08,0x9c,0xaf,0xe0,0xf9,0x10,0x88,0x28,0x6c,0x08,0xd1,0x81,0x60,0x21,0xe7,0x23,0x0d,0x88,0x44,0x41,0xe3,0x30,0x41,0x8a,0xdc,0x81,0xea,0x01,0x10,0x50,0xfe,0x00,0xa3,0x02,0xf0,0x4f,0xc1,0xe3,0xff,0x00,0x14,0x3e,0x01,0xfe,0x02,0x0c,0x07,0xe1,0x03,0xf0,0x49,0xfc,0x11,0xf1,0x50,0xc1,0x3c,0x0e,0x61,0x61,0x10,0x74,0x63,0xf6,0x09,0x37,0x82,0x46,0x26,0x18,0x34,0x71,0x64,0x90,0x2e,0x04,0x0f,0x81,0x13,0xe0,0x50,0x41,0xe3,0x1a,0x81,0x97,0x04,0xfa,0x67,0x51,0x2f,0x8f,0x00,0x32,0x31,0x0f,0x28,0x2c,0x63,0x0a,0xd3,0x30,0x8a,0xe0,0x81,0xe5,0x05,0x77,0x2c,0x20,0xca,0x25,0xd1,0x07,0x96,0x81,0x2c,0x44,0xe2,0x0b,0x88,0x1c,0x55,0x24,0x0f,0x25,0xd9,0x03,0xce,0x41,0xf4,0x1b,0x10,0x3c,0xbe,0x11,0x18,0x04,0x38,0x1e,0x90,0xc8,0x7c,0x58,0x1e,0x7f,0xcf,0x3f,0x02,0x12,0xa9,0x28,0x05,0x02,0x08,0x19,0x20,0x79,0x7f,0xa1,0xf3,0xf8,0x80,0x3c,0xf0,0x04,0xf3,0xf8,0x60,0xff,0xff,0xdf,0xba,0xc4,0x94,0xc2,0x0f,0x13,0x79,0xc3,0x33,0x9f,0xf8,0x07,0x80,0x1e,0x51,0xd0,0x59,0x70,0x52,0xe2,0xa4,0x1d,0xc3,0x3c,0xff,0xf3,0xf0,0xf9,0x7e,0x05,0x42,0xd7,0x16,0xa0,0x83,0xd3,0x9e,0x0f,0x1c,0x03,0x50,0x7f,0xf0,0x32,0x68,0xf8,0x05,0x04,0x00,0x1f,0x80,0x3c,0x6e,0x00,0x51,0xfe,0x40,0x41,0xe4,0x1f,0x4f,0x98,0x3c,0x61,0xc1,0x73,0xa0,0x03,0xdb,0xe9,0x3f,0xf8,0x70,0x41,0xeb,0xfc,0x07,0x1d,0xff,0xef,0xdf,0x87,0xe9,0x8c,0x46,0x0f,0x1e,0x18,0x3c,0xf3,0xff,0x78,0xfe,0xc2,0xf3,0x7e,0x59,0x9e,0x03,0x00,0x0f,0x3f,0x78,0x3c,0x69,0xf4,0x9c,0x93,0x10,0xa4,0x14,0x00,0x7a,0x7c,0xfe,0xf9,0xf0,0x29,0x1f,0x44,0x1e,0x22,0x01,0x23,0x1f,0xf0,0x1e,0x20,0x52,0x76,0x88,0x3c,0xc3,0xe6,0xc2,0x18,0xf8,0xb0,0xa3,0x80,0xf2,0x88,0x03,0xdd,0xc2,0x51,0xe0,0x10,0xd8,0x01,0xf1,0x04,0x06,0x08,0xfc,0xae,0x10,0x8c,0x07,0x9c,0x1e,0xa3,0xc1,0xe0,0x34,0xcb,0x78,0x0f,0x1e,0x18,0x58,0x7f,0x00,0xf2,0xb0,0x30,0xc6,0xfe,0x0f,0x19,0xfc,0x1c,0x1e,0x3a,0xf9,0x97,0xec,0x1e,0x2b,0x54,0x7b,0x93,0x98,0x7c,0xe1,0xf5,0x73,0x24,0x02,0x70,0x0f,0x12,0x7b,0x03,0xd6,0x40,0x0f,0xf1,0x79,0x03,0xf8,}; -const uint8_t *_I_tv5[] = {_I_tv5_0}; - -const uint8_t _I_tv6_0[] = {0x01,0x00,0xd1,0x01,0x84,0x00,0x86,0x04,0x0b,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0x0c,0x62,0x00,0x21,0x80,0x83,0x9b,0x01,0x01,0xe0,0x03,0xf2,0x80,0x0a,0x39,0x00,0x58,0x41,0x45,0x06,0x07,0x98,0x28,0x47,0x44,0x0f,0x58,0x48,0x3c,0xc5,0x45,0x04,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0x0a,0x20,0x7b,0x0b,0x44,0x6c,0x53,0x80,0x7a,0x0b,0x04,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x08,0x9c,0xaf,0xe0,0xf9,0x10,0x88,0x28,0x6c,0x08,0xd1,0x81,0x60,0x21,0xe7,0x23,0x0d,0x88,0x44,0x41,0xe3,0x30,0x41,0x8a,0xdc,0x81,0xea,0x01,0x10,0x50,0xfe,0x00,0xa3,0x02,0xf0,0x4f,0xc1,0xe3,0xff,0x00,0x14,0x3e,0x01,0xfe,0x02,0x0c,0x07,0xe1,0x03,0xf0,0x49,0xfc,0x11,0xf1,0x50,0xc1,0x3c,0x0e,0x61,0x08,0x88,0x88,0x41,0x63,0x20,0x07,0x8c,0xfc,0x4c,0x30,0x68,0xe1,0x70,0x60,0x60,0xf2,0xe0,0x40,0xf8,0x11,0x3e,0x05,0x1c,0x1e,0x31,0xa0,0x60,0xf8,0x0f,0xa6,0x75,0x12,0xf8,0xf0,0x30,0x65,0xc1,0xf2,0x82,0xc6,0xf0,0xad,0x33,0x08,0xae,0x08,0x1e,0x50,0x50,0x30,0xc7,0x81,0xe6,0xa3,0x30,0x79,0x68,0x12,0xc4,0x50,0x14,0xd1,0x01,0xc8,0x1e,0x81,0x72,0x27,0x12,0x28,0x7e,0x9f,0x03,0xe8,0x83,0xcb,0xe1,0x11,0x80,0x43,0x83,0xe7,0x20,0x86,0x43,0xe2,0x60,0xf3,0xfe,0x79,0xf8,0x10,0x98,0x30,0x3c,0xa8,0x02,0xf1,0x3c,0x08,0x3c,0xbf,0xd0,0xf9,0xfc,0x40,0x1e,0x78,0x06,0x39,0xfc,0x33,0xff,0xff,0xef,0xdd,0x62,0x4a,0x61,0x07,0x89,0xbc,0x41,0xe3,0x0c,0xde,0x7f,0xd1,0x82,0x0f,0x28,0xe8,0x80,0xb8,0x30,0x32,0x78,0xc0,0xbf,0x0c,0xf3,0xff,0xcf,0xc3,0xe5,0xf8,0xc1,0x89,0x49,0xa8,0x20,0xf4,0xe7,0x82,0x47,0x00,0x63,0x1f,0xfc,0x1f,0x00,0xb9,0x40,0x00,0xfc,0x01,0xe3,0x70,0x02,0x8f,0xf2,0x02,0x0f,0x20,0xfa,0x7c,0xc1,0xe3,0x0e,0x0b,0x9d,0x00,0x1e,0xdf,0x49,0xff,0xc3,0x82,0x0f,0x5f,0xe0,0x38,0xef,0xff,0x7e,0xfc,0x3f,0x4c,0x62,0x30,0x78,0x87,0x93,0x3f,0xf7,0x8f,0xec,0x2f,0x37,0xe5,0x99,0xe0,0x30,0xe0,0xf3,0xf7,0x83,0xc6,0x9f,0x49,0xc9,0x40,0x41,0xe5,0xc0,0xc0,0x93,0x93,0xee,0xa6,0x10,0x01,0x03,0xcb,0xc0,0x61,0x10,0x01,0x7f,0x01,0xe2,0x05,0x2f,0xc0,0x3c,0xac,0x18,0x00,0xc1,0xb0,0x86,0x3e,0x2c,0x2f,0xe0,0x3c,0xa6,0x00,0xf7,0x81,0x03,0x04,0xa0,0x56,0x00,0x7c,0x3f,0x06,0x01,0x7f,0x01,0x0d,0xc2,0x31,0x80,0xf3,0x83,0xd6,0x31,0x00,0xe0,0x13,0xcb,0x78,0x0f,0x1e,0x1c,0x3c,0x90,0x20,0xf2,0xb0,0x30,0xc7,0xff,0x03,0x80,0x4f,0xe1,0xe0,0xf1,0xd7,0xcc,0xbf,0x60,0xf1,0x4b,0x23,0xdc,0x9c,0xc3,0xe7,0x0f,0xab,0x99,0x20,0x13,0x80,0x78,0x93,0xd8,0x1e,0xb2,0x00,0x7f,0x8b,0xc8,0x1f,0xc0,}; -const uint8_t *_I_tv6[] = {_I_tv6_0}; - -const uint8_t _I_tv7_0[] = {0x01,0x00,0xc1,0x01,0x84,0x00,0x86,0x04,0x0b,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0x0c,0x62,0x00,0x21,0x80,0x83,0x9b,0x01,0x01,0xe0,0x03,0xf2,0x80,0x0a,0x39,0x00,0x58,0x41,0x45,0x06,0x07,0x98,0x28,0x47,0x44,0x0f,0x58,0x48,0x3c,0xc5,0x45,0x04,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0x0a,0x20,0x7b,0x0b,0x44,0x6c,0x53,0x80,0x7a,0x0b,0x04,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x08,0x3f,0x44,0x22,0x0a,0x23,0x61,0x60,0x21,0xe7,0x23,0x0d,0x88,0x44,0x41,0xea,0x82,0x50,0x78,0x80,0x45,0x84,0x90,0x2f,0x04,0xfc,0x1e,0x3f,0xf0,0x01,0x43,0xe0,0x1f,0xe0,0x31,0xc0,0xfc,0x12,0x7f,0x04,0x7c,0x54,0x30,0x4f,0x03,0x98,0x58,0x49,0x1e,0xb0,0x49,0xbc,0x12,0x31,0x60,0xc1,0xa3,0x8b,0x24,0x00,0x0c,0x0f,0x81,0x13,0xe0,0x50,0x41,0xe3,0x1a,0x81,0xc0,0x2c,0x00,0xe3,0x3a,0x89,0x7c,0x78,0x01,0x91,0x88,0x79,0x41,0x43,0x18,0x07,0x9c,0xc0,0x26,0x60,0xf2,0x82,0xbb,0x8f,0xf0,0x41,0x14,0x99,0x83,0xcb,0x40,0x7b,0x20,0x60,0xc1,0x2f,0xc8,0x34,0x07,0x98,0x5c,0x81,0xe5,0x80,0x8f,0xfd,0x01,0xeb,0xf0,0x88,0xc0,0x21,0xc2,0xc3,0xf0,0x43,0xcf,0x62,0x0f,0x3f,0xe7,0x9f,0x81,0x09,0x4f,0x0b,0x20,0x90,0xe2,0x10,0x10,0x79,0x7f,0xa1,0xf3,0xf8,0x80,0x3c,0x57,0x04,0x22,0x10,0x20,0xfc,0x30,0x7f,0xff,0xef,0xdd,0x54,0x51,0xf3,0xe0,0x9b,0xd2,0x19,0x9c,0xff,0x8e,0x04,0x1e,0x51,0xd8,0x02,0xcc,0x78,0x09,0x71,0x69,0x0e,0xe1,0x90,0x7f,0xf9,0xf8,0xe4,0x6f,0x1f,0x81,0x50,0xb5,0xc6,0x03,0xf0,0x07,0xa7,0x3c,0x1e,0x38,0x01,0x00,0xb8,0x04,0x9a,0x3e,0x06,0x4a,0x7c,0x01,0xe3,0x70,0x02,0x8f,0xf1,0xae,0x43,0xc3,0x00,0x0f,0xcc,0x1e,0x30,0xe0,0xb9,0xd0,0x01,0xed,0xf4,0x9f,0xfc,0x38,0x20,0xf5,0xfe,0x03,0x8e,0xff,0xf7,0xef,0xc3,0xf4,0xc6,0x21,0x07,0x9f,0x0c,0x1e,0x79,0xff,0xbc,0x7f,0x61,0x79,0x68,0x08,0x00,0x64,0x18,0x0c,0x00,0x3c,0xfd,0xe0,0xf1,0xa7,0xd2,0x72,0x4c,0x41,0x07,0x8d,0x00,0x1e,0x9f,0x3f,0xbe,0x7c,0x0a,0x47,0xd1,0x07,0x88,0x80,0x48,0xc7,0xfc,0x07,0x88,0x14,0xa3,0x00,0xf4,0x0f,0x9b,0x08,0x63,0xe2,0xc2,0x8e,0x03,0xca,0x20,0x0f,0x77,0x08,0xc0,0x23,0xc0,0x21,0xb0,0x03,0xe2,0x08,0x0c,0x11,0xf9,0x5c,0x21,0x18,0x0f,0x38,0x3d,0x47,0x83,0xc0,0x51,0x8c,0x03,0x78,0x0f,0x1e,0x18,0x58,0x7f,0x00,0xf2,0xb0,0x30,0xc6,0xfe,0x0f,0x19,0xfc,0x1c,0x1e,0x3a,0xf9,0x97,0xec,0x1e,0x2b,0x54,0x7b,0x93,0x44,0x7c,0xe1,0xf5,0x73,0x24,0x02,0x70,0x0f,0x12,0x7b,0x03,0xd6,0x40,0x0f,0xf1,0x79,0x03,0xf8,}; -const uint8_t *_I_tv7[] = {_I_tv7_0}; - -const uint8_t _I_tv8_0[] = {0x01,0x00,0xcd,0x01,0x84,0x00,0x86,0x04,0x0b,0x7f,0x84,0x1c,0x1f,0xb0,0xe9,0xc0,0x0c,0x62,0x00,0x21,0x80,0x83,0x9b,0x01,0x01,0xe0,0x03,0xf2,0x80,0x0a,0x39,0x00,0x58,0x41,0x45,0x06,0x07,0x98,0x28,0x47,0x44,0x0f,0x58,0x48,0x3c,0xc5,0x45,0x04,0x12,0x10,0x98,0x81,0xea,0x5a,0x20,0x10,0x83,0xd3,0x80,0x0a,0x20,0x7b,0x0b,0x44,0x6c,0x53,0x80,0x7a,0x0b,0x04,0x64,0x40,0xf4,0x83,0x83,0xe4,0xc4,0x20,0x31,0x3b,0x08,0x3f,0x44,0x22,0x0a,0x23,0x61,0x60,0x21,0xe7,0x23,0x0d,0x88,0x44,0x41,0xea,0x82,0x50,0x78,0x80,0x45,0x84,0x7f,0x08,0x1f,0x82,0x7e,0x0f,0x1f,0xf8,0x00,0xa1,0xf0,0x0f,0xf0,0x14,0xe1,0xde,0x09,0x3f,0x82,0x3e,0x2a,0x18,0x27,0x81,0xcc,0x21,0x11,0x27,0x14,0xc2,0x40,0x0f,0x19,0xf8,0xb0,0x60,0xd1,0xc3,0xa0,0xc0,0xc1,0xe5,0x74,0xe0,0x70,0x22,0x7c,0x0a,0x38,0x3c,0x63,0x40,0xc1,0xf0,0x13,0x8f,0xf9,0x01,0x2f,0x8f,0x03,0x06,0x5c,0x1f,0x28,0x28,0x6f,0x00,0xf3,0xfc,0x0d,0x85,0x12,0x20,0xf2,0x82,0x81,0x86,0x3c,0x0c,0x17,0xc8,0x92,0xc8,0x1e,0x7a,0x03,0xd9,0x06,0x46,0x09,0x7e,0x22,0x0d,0xfc,0x1e,0xaa,0xb2,0x20,0x8c,0x13,0x00,0x1d,0x1c,0x38,0x18,0x41,0xe5,0xf0,0x88,0xc0,0x21,0xc1,0xf1,0x0a,0x0f,0x83,0x1f,0x01,0x09,0x08,0x3c,0xbf,0x9e,0x7e,0x04,0x26,0x0c,0xc8,0x3f,0xc7,0xfd,0x3a,0x20,0xf2,0xff,0x43,0xe7,0xf1,0x00,0x78,0xae,0x09,0xc6,0x7f,0x0c,0xff,0xff,0xfb,0xf7,0x55,0x94,0x7d,0xe4,0x20,0xf4,0x86,0x6f,0x3f,0xe3,0x81,0x07,0x94,0x74,0xc4,0x53,0x07,0x11,0x8d,0x04,0x00,0x73,0xf2,0x48,0xde,0x3f,0x1c,0x31,0x28,0xc0,0x20,0x3f,0x00,0x7a,0x73,0xc1,0x23,0x80,0x83,0xe0,0x3f,0xe0,0x21,0x5c,0xa9,0x18,0x41,0xe3,0x70,0x02,0x8f,0xf9,0x80,0x23,0xc4,0x00,0x0f,0xcc,0x1e,0x30,0xe0,0xb9,0xd0,0x01,0xed,0xf4,0x9f,0xfc,0x38,0x20,0xf5,0xfe,0x03,0x8e,0xff,0xf7,0xef,0xc3,0xf4,0xc6,0x21,0x07,0x98,0x79,0x33,0xff,0x78,0xfe,0xc2,0xf2,0xd0,0x10,0x00,0xc8,0x30,0x18,0x70,0x79,0xfb,0xc1,0xe3,0x4f,0xa4,0xe4,0x9e,0x22,0x0f,0x1e,0x06,0x04,0x9c,0x9f,0x75,0x30,0x80,0x08,0x1e,0x5e,0x03,0x08,0x80,0x0b,0xf8,0x0f,0x10,0x29,0x7e,0x01,0xe5,0x60,0x42,0x08,0x00,0x98,0x43,0x1f,0x16,0x17,0xf0,0x1e,0x53,0x00,0x7b,0xc0,0x81,0x82,0x50,0x2b,0x00,0x3e,0x20,0x80,0xc1,0xbf,0x80,0x86,0xe1,0x18,0xc0,0x79,0xc1,0xeb,0x18,0x80,0x70,0x09,0xe5,0xbc,0x07,0x8f,0x0e,0x1e,0x48,0x10,0x79,0x58,0x18,0x63,0xff,0x81,0xc0,0x27,0xf0,0xf0,0x78,0xeb,0xe6,0x5f,0xb0,0x78,0xa5,0x91,0xee,0x4e,0x61,0xf3,0x87,0xd5,0xcc,0x90,0x09,0xc0,0x3c,0x49,0xec,0x0f,0x59,0x00,0x3f,0xc5,0xe4,0x0f,0xe0,}; -const uint8_t *_I_tv8[] = {_I_tv8_0}; - -const uint8_t _I_url1_0[] = {0x01,0x00,0x33,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x08,0x20,0x3f,0x32,0x80,0xff,0x07,0xee,0x02,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0x0f,0xf0,0x7f,0x83,0xd6,0x0e,0x0f,0x29,0xf0,0x20,0x60,0x30,0x1d,0x40,0x10,0x8e,0x63,0xff,0xfc,0xff,0x01,0xe3,0x47,0x07,0x9c,0x90,0x1e,0x7a,0x0f,0xfe,0x3b,0xf7,0x7f,0xc0,0x6b,0xa9,0x1c,0x7d,0xcc,0xcf,0x49,0xce,0xe0,0xe6,0x60,0x9d,0x0b,0xff,0xef,0xee,0x0f,0x1d,0xe5,0x22,0x53,0x25,0xa4,0xeb,0x2a,0x52,0x2d,0x2c,0x13,0xe1,0xbf,0xfe,0xfb,0xc1,0xe3,0x8f,0x07,0x95,0xe7,0x48,0x0f,0x1d,0xe8,0x3c,0xbf,0xe0,0xf2,0xcf,0x03,0xca,0x12,0x0f,0x2c,0x28,0x3c,0x7b,0xf1,0xfe,0xf8,0x3c,0x7b,0xd7,0x0e,0x3c,0xe6,0x63,0xa5,0xe7,0x72,0x63,0x30,0x30,0x78,0xfb,0xfb,0xc5,0xf1,0x00,0x89,0x64,0x40,0x03,0x42,0x01,0x90,0x3c,0x7f,0xe0,0xf2,0x3f,0x88,0x3d,0xf8,0x02,0xd1,0x00,0x8a,0x7e,0x81,0xe3,0xbf,0x07,0xe9,0x7c,0xc1,0xf9,0xbf,0x07,0xc7,0xe1,0xb4,0x30,0x1a,0x05,0xff,0xff,0xe7,0x07,0xbc,0x18,0x04,0x30,0x25,0xf8,0xff,0xb8,0x60,0xf7,0x81,0x80,0x85,0x7e,0x2d,0xf1,0xc0,0x03,0xef,0xe0,0xff,0x18,0x38,0x3d,0xf8,0x78,0x98,0x40,0x3c,0xbf,0xf0,0xfb,0xf0,0x3d,0xa4,0x74,0xa8,0xc0,0x3c,0xe3,0xf7,0xc0,0x7b,0xca,0xa7,0x00,0xf3,0x9f,0xde,0x01,0xef,0x1a,0xbc,0x03,0xce,0xfe,0x0f,0x80,0xfa,0xff,0xc1,0xf0,0x3f,0x51,0x00,0x97,0xf4,0x1f,0x07,0xf5,0x07,0xf8,0x3e,0x60,0xeb,0xf2,0x07,0xdf,0xf9,0xbe,0x5e,0x00,0x79,0x4f,0xc1,0xed,0xfc,0x05,0x08,0x25,0x80,0x1e,0x00,0xf0,0x07,0x80,0x24,}; -const uint8_t *_I_url1[] = {_I_url1_0}; - -const uint8_t _I_url2_0[] = {0x01,0x00,0x33,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x08,0x20,0x3f,0x32,0x80,0xff,0x07,0xee,0x02,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0x0f,0xf0,0x7f,0x83,0xd6,0x3f,0xfc,0x07,0x8c,0xf8,0x10,0x30,0x18,0x0e,0xa0,0x08,0x47,0x31,0xff,0xf9,0xfe,0x60,0xf1,0xa3,0x83,0xce,0x48,0x0f,0x3d,0x07,0xfe,0x77,0xee,0xbf,0xe0,0x35,0xd4,0x8e,0x3e,0xe6,0x67,0xa4,0xe7,0x70,0x73,0x30,0x4e,0x87,0xff,0xdb,0xdf,0x07,0x8e,0xf2,0x91,0x29,0x92,0xd2,0x75,0x95,0x29,0x16,0x96,0x09,0xf0,0xff,0xfd,0xb7,0xe0,0xf1,0xc7,0x83,0xca,0xf3,0xa4,0x07,0x8e,0xf4,0x1e,0x5f,0xe0,0x79,0x67,0x81,0xe5,0x09,0x07,0x96,0x14,0x1e,0x37,0xf8,0xfd,0xfc,0x1e,0x3d,0xeb,0x87,0x1e,0x73,0x31,0xd2,0xf3,0xb9,0x31,0x98,0x18,0x3c,0x7d,0xf7,0xe2,0xf8,0x80,0x44,0xb2,0x20,0x01,0xa1,0x00,0xc8,0x1e,0x3f,0xf0,0x79,0x1f,0xc4,0x1e,0xfc,0x01,0x68,0x80,0x05,0x3f,0x40,0xf1,0x27,0x08,0x3f,0x0b,0xe6,0x0f,0xcd,0xf0,0x3e,0x3f,0x0d,0xa1,0x80,0xaf,0xc7,0xfb,0x9f,0x07,0xbc,0x18,0x04,0x30,0x25,0xf8,0xfe,0xe1,0xe0,0xf7,0x81,0x80,0x85,0x7e,0x5e,0x78,0x1d,0xf8,0x1f,0x4a,0xf1,0x8f,0xc7,0x2f,0x80,0xf6,0xe1,0xe2,0x61,0x00,0xf2,0xff,0xcf,0xef,0x00,0xf6,0x91,0xd2,0xa3,0x00,0xf3,0xbf,0xdc,0x01,0xef,0x2a,0x9c,0x03,0xcf,0xff,0x60,0x07,0xbc,0x6a,0xf0,0x0f,0x4b,0x08,0x7f,0xac,0x63,0xfd,0x20,0x09,0x7f,0x41,0xf0,0x7f,0x50,0x7f,0x83,0xe6,0x0e,0xbf,0x20,0x7d,0xff,0x9b,0xe5,0xe0,0x07,0x94,0xfc,0x1e,0xdf,0xc0,0x50,0x82,0x58,0x01,0xe0,0x0f,0x00,0x78,0x02,0x40,}; -const uint8_t *_I_url2[] = {_I_url2_0}; - -const uint8_t _I_url3_0[] = {0x01,0x00,0x2e,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x08,0x20,0x3f,0x32,0x80,0xff,0x07,0xee,0x02,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0x0f,0xf0,0x7f,0x83,0xe6,0x7c,0x08,0x18,0x0c,0x07,0x50,0x04,0x23,0x98,0x83,0xd2,0x8e,0x0f,0x39,0x20,0x3c,0xf4,0x1f,0xf8,0xff,0xf2,0xff,0x80,0xd7,0x52,0x38,0xfb,0x99,0x9e,0x93,0x9d,0xc1,0xcc,0xc1,0x3a,0x1f,0xff,0x3f,0xcc,0x1e,0x3b,0xca,0x44,0xa6,0x4b,0x49,0xd6,0x54,0xa4,0x5a,0x58,0x27,0xc3,0xff,0x3b,0xf7,0x03,0xc7,0x1e,0x0f,0x2b,0xce,0x90,0x1e,0x3b,0xd0,0x79,0x7b,0x7b,0xe0,0xf1,0xcf,0x03,0xca,0x12,0x0f,0x2c,0x28,0x3c,0xa2,0xdb,0xf0,0x78,0xf7,0xae,0x1c,0x79,0xcc,0xc7,0x4b,0xce,0xe4,0xc6,0x60,0x60,0xf1,0xf7,0x6f,0x8b,0xe2,0x01,0x12,0xc8,0x80,0x06,0x84,0x03,0x2f,0x85,0xff,0xff,0x7e,0x3f,0x98,0x3d,0xf8,0x17,0xf0,0x01,0x27,0xe8,0x1e,0x23,0xe1,0x07,0xea,0x78,0x43,0xfe,0x0f,0x7f,0xc2,0xe8,0x60,0x2b,0xf1,0xff,0x04,0x04,0x1e,0xd0,0x60,0x10,0xc0,0x97,0xe2,0x0f,0x98,0x18,0x08,0x57,0xe5,0xfd,0xcf,0x83,0xed,0x1e,0x3f,0xb8,0x78,0x3d,0xf8,0x78,0x98,0x40,0x3c,0xbc,0xf0,0x3b,0xf0,0x3d,0xa4,0x74,0xa8,0xc0,0x3c,0xa3,0xf1,0xcb,0xe0,0x3d,0xe5,0x53,0x80,0x79,0x7f,0xe7,0xf7,0x80,0x7b,0xc6,0xaf,0x00,0xf3,0xbf,0xdc,0x03,0xfb,0xff,0xb0,0x0f,0xf0,0x00,0x36,0x12,0xfe,0x00,0x06,0xc6,0x7f,0xc2,0x01,0x03,0xfc,0x1e,0xd0,0x75,0xf9,0x03,0xef,0xfc,0xdf,0x2f,0x00,0x3c,0xa7,0xe0,0xf6,0xfe,0x02,0x84,0x12,0xc0,0x0f,0x00,0x78,0x03,0xc0,0x12,}; -const uint8_t *_I_url3[] = {_I_url3_0}; - -const uint8_t _I_url4_0[] = {0x01,0x00,0x31,0x01,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf8,0x07,0xfc,0x00,0x33,0xf0,0x75,0x60,0x01,0xe5,0x7f,0x07,0xde,0x4e,0x49,0x49,0xb9,0x03,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x08,0x20,0x3f,0x32,0x80,0xff,0x07,0xee,0x02,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0x0f,0xf0,0x7f,0x83,0xe6,0x7c,0x08,0x18,0x0c,0x07,0x50,0x04,0x23,0x98,0x83,0xd2,0x8e,0x0f,0x39,0x20,0x3c,0xf4,0x1f,0xf8,0x38,0x3c,0x70,0x1a,0xea,0x47,0x1f,0x73,0x33,0xd2,0x73,0xb8,0x39,0x98,0x27,0x43,0xff,0xf9,0xfe,0x03,0xc7,0x79,0x48,0x94,0xc9,0x69,0x3a,0xca,0x94,0x8b,0x4b,0x04,0xf8,0x7f,0xf1,0xdf,0xb0,0x78,0xe3,0xc1,0xe5,0x79,0xd2,0x03,0xc7,0x7a,0x0f,0x1b,0xff,0xef,0xee,0x0f,0x1c,0xf0,0x3c,0xa1,0x20,0xf2,0xc2,0x83,0xc7,0x7f,0x1d,0xf7,0x83,0xc7,0xbd,0x70,0xe3,0xce,0x66,0x3a,0x5e,0x77,0x26,0x33,0x03,0x07,0x8f,0xbf,0xdc,0x5f,0x10,0x08,0x96,0x44,0x00,0x34,0x20,0x19,0x7c,0x3b,0xff,0xfe,0xf1,0xfc,0xc1,0xef,0xc0,0xef,0xdf,0xc0,0x22,0x9f,0xa0,0x78,0xef,0xc1,0xfd,0xff,0x0f,0xf8,0x3e,0x3f,0x0b,0xa1,0x80,0xd0,0x37,0xff,0xf3,0x78,0x83,0xda,0x0c,0x02,0x18,0x16,0x80,0x1f,0x50,0x30,0x10,0xaf,0xc6,0xff,0xff,0xf3,0x83,0xed,0x7e,0x3f,0xee,0x18,0x3d,0xf8,0x78,0x98,0x40,0x3c,0xbf,0x38,0x00,0x7b,0xc8,0xe9,0x51,0x80,0x79,0x41,0xe0,0xe0,0xf8,0x95,0x4e,0x01,0xe5,0xff,0x87,0xdf,0x81,0xef,0x1a,0xbc,0x03,0xce,0x3f,0x7c,0x0f,0xec,0xfe,0xf0,0x3f,0xcf,0xfd,0xfc,0x1e,0xe5,0xf5,0x00,0x08,0x3d,0xcf,0xea,0x20,0x20,0x7f,0x83,0xda,0x0e,0xbf,0x20,0x7d,0xff,0x9b,0xe5,0xe0,0x07,0x94,0xfc,0x1e,0xdf,0xc0,0x50,0x82,0x58,0x01,0xe0,0x0f,0x00,0x78,0x02,0x40,}; -const uint8_t *_I_url4[] = {_I_url4_0}; +const uint8_t _A_Levelup2_128x64_0[] = {0x01,0x00,0x34,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0x38,0x1f,0xe0,0x1d,0x97,0xff,0xe7,0x1c,0x1f,0x99,0xf8,0x1c,0xfc,0x1f,0x96,0x7f,0x87,0x03,0xf8,0x0f,0xb8,0xdc,0x22,0x01,0xfb,0x07,0xdc,0x16,0x09,0x00,0xfa,0x03,0xee,0x1d,0x02,0x80,0x7a,0x0b,0xd7,0x31,0x07,0x8f,0x40,0x1f,0x5b,0xfa,0x04,0x06,0x01,0xa0,0x07,0xd5,0x7f,0x00,0x0f,0xe8,0x26,0x06,0x7f,0x40,0x07,0xd4,0xbe,0x05,0x42,0xa0,0x03,0xf2,0x03,0x24,0xcf,0xe0,0x3f,0xc5,0xe9,0x88,0x50,0x72,0x92,0x0c,0x08,0x3e,0x73,0xf1,0xf9,0x0d,0x22,0xf9,0x82,0x07,0xcd,0xbe,0x61,0x10,0x94,0x79,0xa0,0x5f,0xd0,0x7c,0x45,0xe8,0x11,0x09,0x27,0x8c,0x1f,0x50,0xb3,0xf0,0xc5,0x3c,0xe0,0xfb,0x80,0x40,0xb2,0x9f,0xf0,0x7d,0x7a,0xe0,0x10,0xc0,0x7e,0x46,0xe0,0x77,0x00,0x7e,0x42,0xe1,0x98,0x0d,0x2d,0xfc,0x1f,0x71,0x08,0x05,0x3a,0x7f,0x01,0x37,0xd4,0x81,0xfa,0x39,0xf8,0x01,0xfe,0xe0,0x12,0x0a,0x40,0x3e,0xa5,0xef,0xe2,0x98,0x03,0xee,0x01,0x06,0x80,0x10,0x84,0x1f,0x35,0xf8,0x04,0x62,0x00,0x00,0x10,0x7c,0xef,0xe0,0x1e,0x00,0x7e,0x5f,0xc7,0xc3,0x0f,0x07,0xda,0x6c,0x43,0xc4,0x0f,0xb8,0x28,0x3f,0xa1,0xa0,0xfe,0x8a,0x8b,0xfc,0x1f,0xe0,0xfe,0x2f,0xa7,0xe8,0xff,0x30,0x30,0x7f,0x83,0xcf,0xe8,0xaf,0x91,0x7a,0x03,0xff,0xd0,0xdf,0x90,0x7a,0x74,0x1f,0xf2,0xcf,0x10,0x01,0x68,0x01,0xf1,0x17,0x07,0xa5,0x00,0x1f,0x10,0x90,0x7a,0x60,0x3f,0x80,0xd5,0xc7,0xdf,0xe0,0xc0,0xf4,0x80,0x7c,0xc1,0xeb,0x77,0xc0,0x40,0x41,0xe9,0x01,0xe6,0x03,0xd7,0x17,0x7f,0x05,0x08,0x3d,0x26,0x18,0x00,0x7a,0x42,0xc1,0x44,0x0f,0x4e,0x05,0xfc,0x1f,0xa5,0x11,0xff,0x03,0xcc,}; +const uint8_t _A_Levelup2_128x64_1[] = {0x01,0x00,0x17,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x2f,0xf8,0x17,0x59,0xfe,0xf8,0x6b,0x37,0xf9,0xf0,0x32,0x7e,0xc1,0xac,0x02,0x19,0xff,0xfe,0x03,0xfc,0x11,0x5c,0xfe,0x7f,0xfe,0xf1,0x8c,0x2e,0x3d,0xce,0x80,0xe7,0xbe,0xff,0x90,0x7c,0xc3,0xe6,0x18,0x0b,0x0f,0xfb,0xf0,0x61,0x8c,0x7c,0x3e,0x19,0x40,0xc0,0x43,0x6f,0xc1,0xe8,0xbf,0xe3,0xa1,0x52,0x08,0x04,0x0a,0xfe,0x83,0x7f,0xdf,0xf6,0x09,0x05,0x88,0x40,0x30,0x89,0x28,0xfb,0xfb,0xf0,0x10,0x40,0x78,0xca,0x0f,0xee,0x00,0x18,0xfd,0x02,0x05,0x08,0x80,0x44,0x3f,0xc6,0x08,0xbf,0xd2,0x3f,0xc0,0xf2,0xfe,0x7f,0x41,0xef,0xf7,0x90,0x40,0xe1,0xf0,0x09,0x06,0xf1,0x3d,0x3a,0x88,0x04,0x63,0xf1,0xa3,0xfc,0x03,0xe6,0xa1,0x10,0x90,0x41,0x28,0x80,0xf1,0xf3,0xbe,0x5a,0xff,0xb2,0x88,0x50,0x3f,0x54,0x80,0x78,0xb0,0xda,0xfb,0xff,0xd8,0x42,0x30,0x50,0x5a,0x8e,0xe2,0x1f,0xfc,0xf7,0x84,0x17,0xf9,0x68,0x84,0x40,0xbc,0x79,0x2f,0xe7,0xdc,0xdf,0x17,0x88,0x46,0x07,0xc5,0xa3,0xfe,0x3c,0x9e,0xff,0x38,0xfc,0x41,0xf0,0x3e,0x5d,0x2f,0xe0,0x1e,0xf2,0x78,0x04,0xe2,0x19,0x80,0xfe,0xe9,0x78,0x1f,0x00,0x7b,0x61,0xf4,0x31,0xc7,0xf8,0xff,0x64,0xb0,0x9f,0xe7,0xff,0xbe,0x10,0x58,0x1b,0xf8,0x81,0xe3,0x01,0xff,0x6f,0xf7,0xe0,0xf5,0xd1,0xc1,0x30,0x18,0x1f,0xec,0x4e,0x13,0x8f,0xfb,0x83,0xda,0x1f,0xe4,0x80,0x65,0xbf,0x71,0x2c,0x0f,0x9f,0xe7,0xdf,0x39,0x1d,0xee,0xfd,0x9f,0x8a,0x40,0xfc,0x17,0xf8,0x4f,0x27,0xff,0xfb,0xf7,0xb8,0x8e,0x7f,0xfc,0x9f,0x43,0x21,0x90,0x0f,0x82,0x08,0x59,0xaf,0xff,0xcf,0xc3,0xa2,0x10,0x0c,0x04,0x1a,0x53,0xe0,0x07,0xa9,0x10,0x60,0x10,0xa9,0x04,0x02,0x01,0x01,0x80,0x83,0xda,0xff,0x1f,0xd0,0x42,0xa8,0x00,0xf1,0x80,0x6a,0x51,0xe3,0xf3,0x08,0x26,0x7a,0x03,0x12,0xc0,0x40,0x44,0x04,0x8f,0x1f,0x39,0xfd,0xa2,0x50,0x08,0x30,0x7c,0xbf,0xdf,0xfe,0x79,0xfd,0xa4,0x50,0x0b,0xc0,0x7c,0x81,0xee,0x96,0x1a,0x10,0xf8,0x83,0xe2,0x2f,0x1f,0x7f,0xec,0x1e,0x7c,0xf8,0x5e,0x08,0x1e,0x70,0x11,0xf0,0xa3,0xd0,0xfc,0x3a,0x38,0x11,0x38,0x83,0xe3,0xf7,0xf1,0xab,0x8d,0x4a,0x2d,0xf1,0x81,0x40,0x81,0xe5,0xc1,0xff,0xfc,0x45,0xc8,0x04,0x1d,0x38,0x38,0xe0,0x1c,0x99,0xff,0xe0,0xbc,0xbf,0x38,0x7c,0x0c,0x1e,0x74,0x28,0x79,0x80,0x49,0xc9,0xc3,0x97,0x83,0xd2,0x15,0x06,0x0f,0x2c,0xde,0x0f,0x87,0x17,0xa4,0x12,0x04,0x1f,0x1f,0x78,0x3c,0xa9,0x70,0xed,0x00,0x3d,0x34,0x92,0x0c,0xf6,0xfc,0xc0,0x78,0xb8,0xe5,0x00,0x1e,0x90,0x88,0x05,0x9f,0x3e,0x2f,0x38,0x5e,0x0e,0x44,0x0f,0x49,0x84,0xab,0x33,0xce,0x07,0xa4,0x72,0x30,0x0f,0x4e,0x04,0x03,0x0c,0x60,0x48,0xbf,0x82,0x0e,0x0f,0x48,0x07,0xff,0x02,0x0f,0x50,0x48,0x83,0xd6,0x01,0x80,0x07,0x89,0x40,0xa5,0xe0,0xf6,0x61,0x8d,0x01,0x22,0x80,0xfa,0xb3,0x03,0xce,0x82,0x0f,0x89,0x07,0x00,0xfe,0x78,0x10,0x7c,0xf8,0x3f,0x22,0x02,0x81,0x82,0x04,0x1e,0xd9,0x0a,0x17,0xf0,0x3e,0x40,}; +const uint8_t _A_Levelup2_128x64_2[] = {0x01,0x00,0xed,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x3f,0xe4,0x1f,0xdf,0x40,0x43,0xf3,0xc0,0xa9,0x7f,0xfb,0x03,0xdf,0x66,0x05,0x4d,0xff,0xbc,0x1e,0xf3,0xbf,0xf0,0x14,0xe3,0xf7,0x8f,0xf7,0xc4,0x1e,0xb1,0x3f,0xe0,0x14,0xe1,0xf9,0x02,0x0b,0xc5,0xc1,0xeb,0xcc,0xff,0x03,0xda,0x1e,0x0f,0x48,0x3f,0xbf,0xfd,0xf8,0x07,0xad,0xfc,0x1e,0x57,0xff,0xf4,0x0f,0xe7,0xff,0x07,0xaf,0x8e,0xff,0xf8,0xed,0xc7,0xee,0x1f,0xc8,0x18,0x34,0x41,0xeb,0xc3,0x9f,0xfc,0x3f,0x70,0xfe,0x07,0xfe,0x01,0x9c,0x0b,0x88,0x88,0x41,0xe7,0x1f,0xc8,0x5f,0xe0,0x7c,0x08,0x7c,0x03,0xf9,0x7f,0x9e,0x07,0xd3,0x8f,0x17,0x80,0x5e,0xde,0xe5,0x0a,0xff,0x4f,0xe3,0xc0,0xf4,0xc7,0xcf,0xe0,0x11,0x32,0x68,0x84,0x07,0xf7,0x3f,0x4b,0xa7,0xe2,0x7f,0x7f,0x82,0x70,0x20,0xb9,0xdd,0x54,0x08,0x3e,0x21,0xe4,0xfc,0x4d,0xff,0x10,0xe9,0x86,0x22,0xc0,0x1f,0x1b,0xf8,0xb8,0x58,0x47,0xfe,0x99,0xda,0x31,0xd0,0xcc,0x46,0x03,0x53,0x82,0xbd,0xe7,0x83,0xe9,0x3f,0x99,0xf0,0x20,0x90,0x28,0x24,0x06,0x05,0x80,0xbf,0xe3,0x2f,0xeb,0xe5,0x07,0x8c,0x04,0x02,0x3a,0x4e,0x07,0xbf,0x00,0xa6,0x25,0xf1,0xe0,0x30,0x10,0x00,0x78,0xc2,0x30,0x13,0xc0,0x79,0x00,0x0e,0xfd,0x80,0xa0,0x03,0xcb,0x21,0x0a,0x08,0x88,0x39,0x19,0x83,0x00,0x07,0x8c,0x0a,0x05,0x10,0x30,0x0f,0x03,0x7e,0x0f,0x3c,0xe7,0xbe,0x03,0x20,0x07,0x96,0x82,0x05,0x00,0x90,0x23,0xd2,0x33,0xff,0x07,0xa0,0x0c,0x41,0xe7,0xc7,0x07,0x8c,0x6b,0x9d,0x01,0x15,0x88,0x3c,0x68,0x1a,0x88,0x54,0x00,0x18,0x38,0xb0,0x10,0x9e,0x04,0x1e,0xa1,0xf1,0xc7,0x7f,0xfc,0x7f,0xd0,0x78,0xc1,0xe0,0x18,0x00,0xc8,0xa0,0x07,0x01,0xaa,0x85,0x36,0x47,0xce,0x3f,0x28,0x69,0x20,0x71,0x10,0x70,0x78,0xe3,0xc2,0xc3,0xff,0x07,0x18,0x00,0x60,0x38,0x0a,0x54,0x23,0xff,0x87,0xc8,0x68,0xa1,0x5f,0x80,0x7a,0x8c,0x06,0x49,0x90,0x80,0xd3,0x24,0x01,0x61,0xfc,0xfe,0xc1,0xeb,0x8a,0x92,0x54,0x20,0x15,0x09,0x06,0xa7,0xc0,0xeb,0x20,0x71,0x5f,0xe1,0xf0,0x0a,0xa4,0xc2,0x41,0x60,0xa8,0x40,0x7e,0x1e,0xff,0xe8,0x3c,0xa1,0xff,0xf8,0xf4,0xa3,0xa9,0x30,0x91,0x58,0xab,0x1a,0x9f,0x87,0x1e,0xff,0xde,0xc7,0x8b,0x47,0xd2,0x1f,0x1e,0xa4,0x42,0x45,0x42,0xac,0x07,0xc7,0x8f,0x3f,0xff,0x61,0xff,0xff,0x7e,0xfc,0x1f,0x40,0x0f,0x41,0xf8,0xf9,0xdf,0xa3,0xe3,0x7f,0x98,0x7c,0x62,0x2e,0x21,0xae,0x40,0x78,0x00,0xc2,0x4f,0x91,0x40,0x43,0xe3,0x1f,0x75,0x8d,0x7f,0x53,0x80,0xf1,0xbb,0xd0,0x00,0x30,0x0d,0x26,0x7f,0xff,0xcf,0x97,0xc0,0x60,0x1f,0x00,0x50,0x82,0x07,0xff,0xf3,0xfe,0xe0,0x64,0x94,0xf8,0x07,0x42,0x4f,0xa9,0x81,0x7f,0x3e,0xe0,0xf2,0xfe,0x78,0x3d,0xf0,0x1a,0x24,0xc2,0x01,0x60,0x88,0x07,0xc7,0xfc,0x0f,0x10,0xe8,0xa4,0xca,0x01,0x84,0x1f,0x94,0x3f,0x52,0xdf,0x10,0xf0,0xf9,0xfe,0x3f,0xfe,0x3c,0xf2,0x01,0x04,0x88,0x17,0xc5,0xe4,0x30,0x02,0x20,0xf7,0xfc,0xff,0x9f,0xfc,0x0a,0x31,0xa0,0x82,0x48,0x20,0x00,0x11,0xd4,0xe0,0xb3,0xfc,0x7f,0x3f,0xcf,0xf9,0xff,0x90,0xc0,0x03,0xe2,0x0f,0x36,0xf8,0xc3,0xf8,0x3e,0x7b,0xc0,0xf4,0x6f,0xf0,0x00,0xfa,0xe0,0x61,0x50,0x7f,0x05,0xde,0x38,0x7e,0x38,0x04,0x18,0x7a,0x24,0x11,0x81,0x81,0xc7,0xc1,0x13,0xc0,0x03,0x87,0x9f,0x80,0xd5,0x03,0xd3,0x07,0x0a,0x85,0x7c,0x20,0x3e,0x00,0x78,0xed,0xc2,0xe3,0x05,0xe0,0x40,0x23,0x00,0x41,0x41,0x8f,0x81,0x44,0x2b,0x21,0xa5,0x6a,0x31,0x50,0x4c,0x07,0xe6,0x19,0x00,0xc4,0xea,0xb2,0x41,0x91,0xfc,0x07,0xc7,0x15,0x01,0xb0,0x03,0xc6,0x0e,0xe4,0x19,0x8c,0x03,0x18,0x0f,0x1d,0xc7,0xef,0xff,0x08,0x87,0x46,0x20,0x86,0xc1,0x01,0x0f,0x07,0x01,0x83,0x81,0x4a,0xb9,0x06,0xe1,0x84,0x7c,0x20,0xe0,0xc1,0x83,0x17,0x46,0x03,0x7f,0xc0,0x18,0x48,0x5e,0x25,0x91,0x47,0x88,0xdc,0x40,0x82,0x00,0x1a,0x06,0x88,0xc2,0x20,0xf6,0x00,0x21,0xd4,0x4b,0xe2,0x0f,0x15,0x79,0x83,0xd7,0x41,0xaa,0x85,0x2f,0x87,0xfe,0xa9,0x10,0x7b,0x82,0x4b,0xfc,0xbf,0x11,0x29,0x00,0x1b,0x21,0xaa,0x95,0x03,0x87,0xfd,0x94,0x07,0xc4,0x20,0x3e,0x5f,0xff,0xc4,0x2e,0x02,0x0d,0x50,0x30,0xe9,0x07,0xe3,0xf6,0xff,0xfe,0x61,0x70,0x61,0xfa,0x83,0xc5,0xc2,0x4a,0xf2,0x81,0x9e,0xc4,0x1e,0xbf,0x8d,0x46,0xab,0x14,0x0f,0x20,}; +const uint8_t _A_Levelup2_128x64_3[] = {0x01,0x00,0x2d,0x03,0x8f,0xc0,0xb8,0x1f,0xfb,0xfd,0xe2,0x7f,0xf8,0x02,0x0f,0xff,0xff,0x03,0xff,0x00,0xc6,0xff,0x36,0xe0,0x47,0xfd,0xff,0x08,0xff,0xf3,0xff,0x3f,0x05,0x8f,0xf0,0x1e,0x5f,0xf8,0xfe,0x02,0xfb,0xff,0xf8,0x43,0xff,0x99,0xfd,0xf8,0x44,0x81,0xe7,0x17,0x88,0x7d,0x37,0xe0,0xf2,0x87,0xe7,0xff,0xe0,0x11,0xfe,0x83,0xca,0x1f,0x20,0xf8,0x0f,0x46,0x0f,0xfe,0x83,0xf6,0xff,0xfc,0xf0,0xfa,0x47,0xec,0x1e,0x08,0xf8,0x3c,0xa0,0x7c,0x3f,0xff,0x9c,0x1e,0x93,0xf8,0x06,0x02,0x1f,0xf8,0x2c,0x8c,0x07,0xc1,0xff,0xfd,0x83,0xdb,0xc1,0x07,0xfc,0x40,0x6f,0xda,0x0d,0x47,0xff,0xf2,0x0f,0x4b,0xf8,0x7c,0x60,0xda,0x88,0x0c,0x72,0x01,0xb0,0xff,0xe0,0x01,0xe9,0xff,0x80,0x68,0x21,0xff,0xa9,0x06,0x02,0x01,0xf2,0xbf,0x40,0x12,0x44,0x1f,0x2b,0x82,0xa1,0x7d,0x11,0xf8,0x05,0xf8,0x1e,0x74,0x7f,0x80,0xc0,0x75,0x50,0xa8,0x04,0x83,0xf0,0x0f,0x1b,0xe1,0x48,0x6f,0xfb,0x78,0x38,0x3c,0x40,0x09,0xfc,0x81,0x83,0xcb,0xfb,0xbf,0xbf,0xcb,0xbe,0x1a,0x8d,0x56,0xaa,0x55,0x80,0x85,0x18,0xc4,0x5e,0xb3,0xce,0x00,0x7d,0x7b,0x80,0x21,0xdf,0xcf,0xef,0xee,0x72,0x2f,0x8e,0xaa,0x01,0xa8,0xd1,0x62,0xa7,0xfa,0x0c,0x06,0x7d,0x82,0x33,0x8f,0x3d,0xfe,0x04,0x18,0x15,0x68,0xc0,0x1e,0xa2,0x02,0x1f,0x0f,0xff,0xbf,0x3f,0xe3,0xcf,0xc7,0x63,0xca,0xd7,0xe7,0xf5,0x58,0xa8,0x3e,0xa3,0x80,0x8e,0x29,0xfe,0x3c,0x2e,0x30,0x0b,0x87,0x76,0xea,0x73,0x11,0x10,0xd8,0x01,0xe5,0xcf,0x9f,0xcf,0xf5,0x50,0x2d,0x61,0x80,0x75,0x38,0xa2,0x28,0xda,0x09,0x63,0x9f,0x1f,0x0c,0xf8,0x3e,0x35,0x6a,0xad,0x54,0x3a,0x20,0x01,0xba,0x7f,0xf7,0xf9,0xff,0xbc,0xfe,0x7c,0x9c,0x1d,0x5e,0xbb,0x57,0xa6,0x85,0x68,0xb5,0x5b,0x8d,0xff,0x7f,0xde,0x0f,0x18,0x60,0xe8,0x43,0xc3,0x55,0x86,0x87,0xcb,0x31,0xfd,0xff,0xf9,0xfc,0xe4,0xe1,0xd4,0x72,0xb5,0x41,0xf1,0xcd,0x42,0x88,0x63,0xe4,0xff,0xfe,0x7c,0xff,0x18,0x38,0x5c,0x68,0x15,0x5a,0xbd,0x5e,0x2a,0x1f,0x2f,0x87,0xcf,0xf3,0x27,0xfc,0x41,0xe5,0x4b,0xe2,0x00,0x16,0x29,0x86,0x3f,0x0f,0x8e,0xe2,0x07,0xfc,0x87,0x85,0xc6,0xc0,0x1f,0x29,0xa8,0x7c,0xbc,0x13,0x9f,0x74,0x0f,0xd1,0x0f,0x0d,0x0e,0xc8,0x3c,0x56,0xa2,0xf0,0xc0,0xbf,0x19,0x8f,0xfc,0x07,0xf9,0x06,0x0b,0x8d,0x40,0x3e,0x55,0x50,0xf9,0x7e,0x38,0x5f,0xf8,0x00,0x04,0x47,0xc6,0x80,0x10,0x21,0x42,0xaf,0x1d,0x09,0xfe,0x00,0x1e,0x20,0x01,0xec,0x07,0x46,0xab,0xdf,0x03,0x94,0xf3,0x85,0x0f,0x07,0x90,0x7c,0x7d,0x5a,0xaf,0xfe,0xbf,0x74,0x1f,0x19,0x54,0xf3,0xd0,0xb5,0x1e,0x1a,0xdc,0xfa,0xb5,0x5a,0xed,0xd6,0x02,0x1f,0x2f,0x00,0x0c,0x78,0xf0,0x1d,0x03,0x78,0x7f,0x5a,0xa0,0x08,0xea,0x47,0xe3,0x38,0xa0,0x40,0x25,0x1e,0x34,0xf9,0x55,0x2e,0xa0,0x01,0xaa,0x87,0xc8,0x00,0x7f,0xa8,0x06,0x8e,0x15,0xfc,0x1e,0x0f,0xab,0xf4,0x1f,0x20,0x71,0x42,0xbf,0x1e,0x70,0xc0,0xf5,0x2a,0xb7,0x7a,0xbd,0x74,0x3e,0xdf,0x8f,0xfe,0x0e,0x54,0x1f,0x59,0x54,0xaa,0x01,0x08,0xc0,0x28,0xc7,0xfe,0x63,0x10,0xf8,0x80,0x04,0x3f,0x08,0x81,0xd5,0x7f,0x37,0xe1,0xf1,0xff,0xea,0x70,0x41,0xf1,0x90,0x6a,0x20,0x5f,0xeb,0xf8,0x4c,0x7e,0x9d,0xff,0xff,0x7e,0xfe,0x1f,0x6d,0xf5,0xff,0x51,0x2a,0xd6,0x7b,0xcf,0xe3,0xaf,0xd4,0xe0,0x03,0xe2,0xa3,0x18,0x17,0xf2,0xf6,0x7f,0x3a,0xa9,0xfe,0x09,0xe3,0xa8,0x85,0x6b,0x07,0xe5,0xaf,0x80,0xe0,0x35,0x40,0x11,0x0f,0x97,0xfc,0x30,0x35,0x42,0xf9,0x07,0xde,0xfd,0x0f,0x0f,0x93,0xf0,0xb5,0x58,0x10,0xe9,0x07,0xca,0x7d,0x1f,0x1f,0xec,0xf2,0x7c,0x57,0x10,0xfa,0x6a,0x71,0x40,0x53,0x80,0x4e,0x03,0xe5,0x56,0x1f,0x9a,0x98,0x40,0x0c,0xb7,0x1d,0x77,0xab,0x54,0xc1,0x1d,0x5e,0x88,0x40,0x48,0x21,0xf0,0x4c,0x02,0x23,0x55,0xea,0xaf,0x86,0xab,0x05,0x80,0x58,0x03,0xa7,0xf4,0xb4,0x6a,0xb1,0x5a,0xed,0x57,0xec,0x04,0x38,0xbd,0x16,0xc8,0x3e,0x30,0xa8,0x07,0xf3,0xb1,0x01,0xb0,0x07,0xc6,0xaf,0x5f,0xaa,0xcd,0x60,0x1d,0xc4,0xfa,0x6a,0x21,0xdb,0x80,0xe0,0xea,0xc0,0x43,0xeb,0xc0,0x6a,0xc3,0xe3,0xa0,0x85,0x7f,0xab,0x3f,0x5a,0xb9,0x70,0x6a,0xe0,0x32,0xbf,0xf5,0x43,0xe7,0xff,0xdb,0x85,0x44,0x38,0x3f,0xa3,0xd9,0xda,0xa1,0x50,0xa2,0x00,0xcf,0x6a,0x67,0xc3,0x00,0x28,0x7c,0xf8,0x1a,0xf0,0xf9,0x80,0x12,0x55,0x28,0x94,0x2f,0xc7,0xc7,0x6b,0x0f,0x41,0x84,0x40,0x03,0x80,0xf0,0xf7,0xc3,0x8a,0x00,0x2c,0xd0,0x84,0x75,0x5c,0x2f,0x8e,0x7c,0x3f,0x10,0xd1,0xf1,0xfc,0x20,0x27,0x62,0x00,0x18,0x18,0x74,0xca,0x91,0x1f,0x8f,0xe1,0xba,0xae,0x18,0xfe,0x28,0x44,0xbe,0xba,0xbf,0xd6,0xa3,0x55,0xa2,0x0f,0x8f,0xf0,}; +const uint8_t _A_Levelup2_128x64_4[] = {0x01,0x00,0x90,0x02,0xff,0x80,0x3c,0x01,0xf1,0xff,0xe0,0x3f,0x7d,0xff,0xd1,0x0f,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x2d,0xff,0xee,0x0f,0xef,0x47,0xff,0xfc,0x06,0x2d,0xf8,0x3d,0xe0,0x3e,0x49,0x3f,0xc0,0xfc,0x7f,0x8f,0xfc,0xed,0x02,0x37,0xff,0xc5,0xbe,0x01,0xf0,0xaf,0xe0,0xc1,0xe7,0xe0,0xff,0xc0,0xc2,0xe3,0x1f,0xf8,0x4f,0xe0,0x17,0x0b,0xf5,0x81,0x34,0x40,0xf1,0xb8,0xc1,0x38,0x1f,0xd8,0x3f,0xe2,0x73,0x00,0xf7,0xc7,0xe4,0x02,0xb1,0xff,0xcf,0xf0,0x02,0x81,0xc0,0x77,0xe0,0x37,0xf8,0x47,0x82,0xff,0x0e,0x6e,0x1c,0x1d,0xc4,0x3e,0x08,0x0c,0x0b,0x80,0x2e,0x1f,0x00,0x08,0x60,0x06,0x02,0xc3,0xc0,0x41,0xe4,0x09,0x12,0x70,0xd8,0x23,0xf8,0x08,0x78,0x3c,0x7e,0xf0,0x78,0x1c,0x03,0x81,0x07,0xff,0x40,0xc0,0xa5,0x19,0x10,0x8a,0x00,0xc6,0x05,0xc4,0xd7,0xc7,0xc0,0x82,0x00,0x13,0xf1,0xa4,0xc6,0x9e,0x08,0x3b,0xf8,0x3c,0xcb,0xa4,0x02,0x13,0x90,0xc1,0xa0,0x1a,0xcd,0x56,0xa8,0x84,0x50,0x0f,0x67,0xff,0xe7,0xf1,0xf9,0xfb,0x3f,0x30,0xfa,0x80,0xd8,0xa0,0x71,0x40,0x78,0xff,0x39,0xfe,0x7b,0xff,0x9f,0x89,0xff,0x85,0xc0,0x35,0x7a,0xed,0x58,0x90,0x45,0xe5,0x87,0x1f,0x94,0x02,0x9f,0x08,0xca,0x01,0x8a,0x9f,0x15,0x07,0x8d,0xe3,0x80,0x0f,0x30,0xc8,0xf0,0x35,0x41,0xf1,0x8d,0x14,0x13,0x9f,0xfb,0x07,0x8c,0x02,0x21,0xd0,0x0b,0x15,0x7e,0x2a,0x51,0x1b,0x07,0xfb,0xcd,0xff,0xe1,0x9f,0x8b,0x40,0x5e,0x1d,0x54,0xa8,0x3c,0x53,0xc9,0xce,0x43,0xff,0x01,0x44,0x93,0xc4,0x5a,0xc5,0x55,0xa8,0x40,0x77,0xd1,0xe8,0x07,0xdd,0xa4,0x20,0xf1,0xd8,0x07,0xca,0xd4,0x1f,0x28,0xf3,0x80,0x6f,0xf3,0x05,0x78,0xc1,0x14,0xe7,0x7f,0xaa,0xd5,0x60,0x30,0x48,0x06,0x02,0x3f,0xfe,0xfe,0x90,0x07,0x51,0xaa,0x40,0x0e,0xa8,0xbe,0x66,0x91,0xe3,0x86,0x45,0x3c,0x3f,0x96,0x39,0xd5,0x2a,0xa1,0x04,0xf7,0xfe,0xc4,0xa3,0xe8,0xd5,0x7f,0xf5,0xfb,0xa0,0xfa,0x16,0x87,0xc7,0x6f,0x80,0x55,0x3f,0xa1,0xf3,0x1f,0x8b,0xc9,0x38,0x70,0x30,0x20,0xeb,0x3f,0x5a,0xa0,0x08,0xb8,0x0c,0x1e,0x58,0x10,0x18,0xd0,0x03,0xef,0x54,0x09,0xab,0x9c,0x77,0x5a,0xaf,0x57,0xe8,0x16,0xd1,0xfb,0x85,0xc2,0x00,0x1f,0x50,0x80,0xd5,0x22,0x20,0xf1,0xff,0x7e,0x3f,0x01,0xfb,0xec,0x7f,0xef,0x12,0x00,0x78,0x87,0xce,0x2b,0x04,0x82,0xc5,0x03,0xc4,0x08,0x1f,0x1c,0x07,0xf9,0xbf,0x0f,0x8b,0x60,0x43,0xe9,0x5b,0x4f,0x90,0x7d,0x6a,0x35,0x58,0x28,0x04,0x59,0xe3,0xbe,0xbf,0x83,0xc7,0x59,0xef,0x3f,0x8e,0xbc,0x3e,0xbf,0xf8,0xf8,0x04,0x43,0xeb,0x55,0xa2,0xd0,0x6a,0xb1,0x58,0x07,0xee,0x13,0x97,0x07,0x8e,0xb0,0x7e,0x41,0xf5,0xe0,0x7f,0xe1,0xb1,0xf8,0x7a,0xfd,0xc3,0xe3,0x05,0xb0,0x43,0xf8,0x17,0xf6,0xf8,0xeb,0x35,0x40,0x02,0x0f,0xa4,0xc2,0x09,0xe0,0x8c,0x40,0x2a,0xa1,0xf8,0x09,0x95,0xc8,0x2a,0x41,0xf9,0x00,0x0c,0x40,0x04,0x35,0x14,0xa1,0x00,0x06,0xa7,0x55,0xaa,0x17,0x84,0x00,0x36,0x00,0x19,0x6b,0xbd,0x5a,0xa6,0x08,0xc0,0xc3,0xeb,0xf8,0x98,0x40,0x22,0xa1,0xe3,0xff,0xd5,0xea,0xb6,0x53,0xf9,0x03,0xc6,0xd1,0x00,0xc0,0x6b,0xb5,0x5f,0xb0,0x10,0xc2,0xe0,0x1b,0x00,0xf9,0xfb,0xbf,0x35,0x1f,0x28,0x7d,0x27,0xf5,0x5f,0xe1,0x00,0x4c,0x23,0xfe,0xd5,0xc3,0xb7,0x01,0xc1,0xd5,0x80,0x87,0xd7,0x80,0xd5,0x87,0x8b,0x01,0xff,0xfd,0x87,0x50,0x00,0x95,0x44,0x18,0xf8,0x29,0xfb,0x33,0xd0,0x87,0x07,0xf4,0x81,0x3b,0x50,0xfc,0xe1,0x1f,0x70,0xf4,0x5f,0xea,0xb5,0x03,0x01,0x69,0xc3,0xe6,0x00,0x49,0x52,0x01,0x3d,0xe1,0xf8,0x30,0x8c,0x16,0x82,0xdc,0x1e,0x68,0x71,0x40,0x05,0x1a,0x0f,0xa1,0x84,0x40,0x0f,0x4f,0x2f,0x0a,0xac,0x42,0x03,0xab,0x0e,0xa8,0x18,0x60,0xcc,0x15,0x6e,0xa3,0x85,0x6a,0xb4,0x16,0x09,0x97,0xd7,0x57,0xfa,0x0f,0x28,}; +const uint8_t _A_Levelup2_128x64_5[] = {0x01,0x00,0x9c,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1f,0xff,0xfb,0xcf,0xff,0xf0,0x3f,0xc0,0x18,0x7e,0x1e,0x30,0x83,0xdf,0xef,0xd0,0x0e,0x27,0xf6,0xf7,0xfc,0xe7,0x83,0x9b,0x7f,0xff,0x8f,0xff,0xa4,0x63,0x1c,0xe3,0xea,0xf3,0xd1,0xc0,0x20,0xe7,0xc6,0x84,0x2f,0x5b,0x97,0xfe,0xef,0xca,0xf8,0xf1,0xe0,0x20,0xd6,0xff,0x4c,0x7d,0x9a,0xad,0xd5,0x87,0xe1,0x4f,0xc0,0x7f,0xff,0xc3,0xe4,0xbe,0x40,0x2e,0xd5,0x5b,0xae,0x0f,0xe7,0x0f,0xf0,0x7f,0xfc,0x22,0x04,0x9b,0xc0,0x35,0x7a,0xad,0x56,0x1b,0xff,0x00,0xf8,0x7f,0x78,0xe0,0xf4,0x9f,0xe0,0xaa,0xa0,0x01,0xd6,0xcf,0xe0,0x04,0xe1,0x38,0x98,0xf8,0x67,0xfc,0x70,0xf0,0xea,0xa3,0x50,0xf0,0x79,0x13,0x93,0xa1,0xff,0xa3,0xd5,0xc3,0xe3,0x17,0x80,0x40,0x3f,0x80,0xf5,0x0b,0x0e,0xbf,0x56,0x02,0x19,0x70,0x3c,0x67,0x07,0xf6,0xc7,0xd9,0xee,0xa5,0xf1,0x9a,0xc0,0x20,0x90,0x03,0x00,0xef,0xfd,0xe0,0xf2,0x87,0xec,0x37,0x5a,0xaf,0x55,0xa8,0x3e,0x23,0x12,0xfe,0xf7,0xdb,0xa3,0x9f,0x86,0x74,0x2b,0xb5,0x5e,0xa8,0x08,0x60,0x20,0xf1,0xf8,0x10,0x12,0x11,0xa8,0xd7,0x17,0xc7,0x56,0x0d,0x18,0xe0,0xc0,0x8f,0xa5,0xff,0x89,0xf6,0x0b,0xe5,0xdf,0xaa,0x40,0x6f,0xe0,0xf1,0xfd,0xb7,0x0e,0x07,0xe8,0xd5,0x7f,0xb5,0x7b,0xa8,0x06,0x02,0x1f,0x8c,0xf1,0xb0,0x47,0xc7,0xef,0x07,0x8f,0xd7,0xaf,0x57,0xaf,0xdf,0xea,0xb8,0x58,0x7e,0xff,0xce,0x1d,0x12,0x10,0xfc,0xe0,0x7e,0xcf,0xd6,0xab,0xf5,0xba,0x27,0x0c,0x0d,0xbc,0x26,0xe2,0xbf,0xcb,0xe0,0x15,0x5b,0xed,0x5f,0xef,0x55,0xa0,0x84,0x04,0x1e,0x30,0xf7,0x89,0x41,0x8e,0xc2,0x7f,0x2f,0xd1,0xb8,0xaf,0xf7,0xfb,0xf2,0xcc,0x7e,0x70,0xe8,0x07,0x52,0xab,0x57,0xab,0xd7,0x68,0xb0,0x58,0x00,0x6c,0x6f,0x8b,0x21,0xb1,0xa5,0x88,0x3e,0xc6,0xe4,0x17,0x0d,0x53,0xaa,0x1f,0x51,0x00,0x8f,0x4b,0xff,0x0c,0x0f,0x96,0xfc,0x3e,0x3f,0xf0,0xf9,0x40,0x3f,0xa0,0xf2,0xc4,0xc0,0xe8,0x1f,0x5e,0xef,0xff,0xbf,0x7d,0xa2,0xb0,0x0b,0xf1,0x7f,0x10,0x8f,0x82,0x0f,0x00,0xd7,0x7f,0xf5,0x7f,0xed,0x7c,0x0c,0x3c,0x38,0x0f,0xfc,0xe7,0xfd,0x8d,0xff,0xc7,0xcf,0xe2,0xff,0x2a,0xa8,0x7c,0x68,0x38,0x0e,0xf9,0x88,0x70,0xe3,0x11,0x80,0xeb,0xf7,0xfa,0xbf,0x76,0xbc,0x4c,0x20,0x01,0x83,0x08,0x45,0xc0,0x50,0x76,0xe8,0x80,0x11,0x42,0x58,0x06,0x88,0xff,0xe7,0xd0,0x5d,0x5b,0xf8,0x40,0x02,0x77,0x10,0x01,0x70,0x3e,0x2b,0xf1,0xbc,0x4e,0x2b,0xb7,0x5a,0xbd,0xdd,0x06,0x31,0x5a,0x00,0x7c,0x7c,0x1f,0xcf,0xbf,0xff,0xd3,0x78,0xdd,0x87,0x8b,0xd4,0x1f,0x48,0x04,0xc1,0xc0,0x57,0x81,0xd0,0xa7,0xc6,0xab,0x05,0xa0,0x18,0x44,0x20,0x58,0xcc,0x1c,0x7f,0xe1,0xab,0xf5,0x6b,0x84,0x42,0x1f,0x51,0x09,0x43,0xa8,0x17,0x51,0xe0,0x90,0x86,0x0b,0x50,0xb2,0x90,0x86,0x01,0xf0,0x81,0xda,0x0c,0x82,0x5f,0x1f,0xfe,0xbf,0x54,0xf6,0x1d,0x80,0x74,0x96,0x23,0xd8,0x80,0x85,0xc7,0xab,0x57,0xaf,0xd5,0x66,0xb5,0x4e,0xe5,0x51,0xc2,0x7a,0x88,0x76,0xe0,0x78,0x3a,0xbd,0x77,0xab,0xdc,0x26,0x16,0x09,0xdf,0xab,0x7f,0x52,0xd8,0x97,0xce,0xab,0x7f,0xea,0xd1,0x20,0x14,0x0f,0x84,0xff,0x6e,0x7b,0x11,0xf8,0xfe,0x80,0x83,0xae,0xd5,0x5a,0x87,0xe5,0xe0,0x9f,0xd5,0xdb,0x43,0x5d,0x5e,0x11,0x88,0x40,0xe2,0x3e,0x18,0x07,0x9e,0xff,0xad,0x5e,0x18,0x00,0x83,0xe3,0x2a,0x07,0x0f,0xf3,0x9f,0xff,0xb7,0x85,0xc4,0xb8,0x21,0xf2,0x13,0x8c,0xd6,0xaa,0x4e,0x1e,0x3e,0x73,0x9d,0xba,0x10,0x37,0xaa,0x34,0x5e,0x1e,0xff,0xff,0xf3,0xb0,0x1e,0x88,0x7d,0x7a,0xb4,0xda,0x84,0x01,0x9a,0x3e,0x38,0x02,0x68,0x40,0x0d,0x07,0x1f,0x8d,0xff,0xec,0x0f,0x1a,0xb0,0x7d,0xaa,0xb0,0x33,0x00,0xc7,0x04,0x02,0xb2,0x10,0xf3,0x7e,0x9b,0xa7,0x3b,0xff,0x00,}; +const uint8_t _A_Levelup2_128x64_6[] = {0x01,0x00,0x54,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0x5f,0x78,0x37,0x20,0x3f,0xc0,0x7e,0x4f,0xff,0xde,0x3e,0x38,0xae,0xf9,0xf0,0x1c,0xe0,0x7e,0xf8,0xf3,0x3f,0xfd,0x9f,0xdc,0x1f,0xbe,0x6c,0x03,0x31,0xfd,0x1f,0xdc,0xca,0x01,0x60,0xfd,0x03,0xaa,0xff,0x09,0x80,0x60,0x3e,0x80,0xfa,0xdf,0xc1,0x20,0x10,0x0f,0x48,0x3e,0xab,0xf0,0x20,0x78,0xf4,0x81,0xd3,0xf7,0x07,0xfc,0xbf,0x03,0xff,0x87,0xe9,0x36,0xe0,0xf8,0xf1,0xcb,0xec,0x30,0x09,0x86,0x93,0x7f,0xf7,0x0f,0xc6,0x5e,0x21,0x00,0xa0,0x52,0x23,0xe0,0xe7,0xfe,0x83,0xc6,0x10,0x6f,0x1a,0x46,0xfc,0x5f,0x1f,0xcc,0x59,0xbc,0xb1,0x3b,0xe4,0x6c,0x03,0xc6,0x0e,0x0f,0x1c,0x7e,0xfb,0x07,0xdf,0x59,0xad,0xfe,0xf9,0x4b,0x84,0x7f,0xb0,0x79,0x0f,0x76,0x1c,0x7e,0xff,0x8d,0x2e,0x5e,0x07,0x4e,0x97,0xfd,0x7f,0xc0,0xf6,0xfd,0xfe,0xec,0xb5,0x88,0x17,0x4a,0x60,0x2c,0x4f,0x79,0xbd,0x2a,0xb3,0x88,0x17,0x8a,0xa0,0x0f,0x2f,0x88,0x85,0xaa,0xb3,0x08,0x15,0x8a,0xa1,0xbd,0x03,0x8f,0xc0,0x7a,0x65,0x02,0xea,0xc4,0x20,0x54,0x2a,0xc0,0x20,0x6f,0x9f,0x0f,0x98,0x30,0x7f,0xd8,0x7f,0x1f,0xf8,0x1e,0xb7,0x78,0xf7,0xe3,0xf6,0x20,0x2c,0x3f,0x0f,0xdf,0xd5,0x88,0x83,0xc6,0xb8,0x1f,0x18,0x7f,0xf0,0xc4,0x90,0x7c,0x1d,0x56,0x3f,0x02,0xe1,0x55,0xc7,0xe3,0x07,0x07,0x13,0x50,0xa7,0xf0,0x2d,0x2e,0x63,0xff,0xcf,0x94,0x07,0xc7,0xc7,0xff,0x8f,0x84,0x4a,0xfb,0x7e,0xb1,0x49,0xab,0xf0,0x1e,0xa4,0x9f,0x97,0x3d,0xf0,0x16,0x44,0x04,0x21,0xe1,0xfe,0x5d,0xa8,0xb3,0x08,0x0d,0x92,0x21,0xf5,0x8f,0xfe,0x2f,0x7f,0xcf,0x08,0x3c,0xa0,0x17,0x8c,0x2c,0x7e,0x03,0xc4,0x87,0xfd,0x61,0xff,0xeb,0xef,0xf0,0x64,0x3f,0xf8,0xec,0x02,0xe1,0x05,0x88,0x40,0x68,0x90,0x0f,0xaa,0xac,0xbf,0x9f,0xfd,0xff,0x7e,0x30,0x0f,0x18,0x4c,0x82,0x05,0x22,0xc0,0x7d,0x01,0x83,0xfd,0xf6,0x7f,0xaf,0x7f,0xe9,0xc4,0x1a,0x84,0x0f,0x48,0x27,0xe3,0x85,0x6f,0x09,0x0f,0xff,0xf3,0x10,0x87,0xc1,0x22,0x20,0xf2,0xa0,0x03,0xc6,0x86,0x6e,0x1f,0xbf,0xf7,0xe7,0x00,0x83,0xc6,0x22,0x34,0x08,0x14,0x48,0x1e,0x37,0xef,0x3c,0x0f,0xfc,0x43,0x1f,0x9f,0x02,0x07,0xf0,0x90,0x83,0x04,0x44,0x30,0x49,0xe4,0x06,0x01,0x1c,0xfe,0x04,0x07,0x67,0x03,0xb8,0x48,0x78,0x10,0x48,0xc8,0x3c,0x60,0x16,0x08,0x00,0x08,0x5e,0x43,0x4b,0x87,0x64,0x24,0x38,0x0f,0xec,0x36,0x41,0x0c,0x80,0x64,0x01,0xe3,0x00,0xf0,0x7b,0xf1,0x70,0x1b,0x04,0x47,0x01,0x07,0x87,0xd0,0x26,0x90,0x0c,0x64,0xc2,0x01,0xf0,0x58,0x0c,0x2e,0x1c,0x4f,0x18,0x04,0x06,0x09,0x40,0xe2,0x60,0x30,0x7b,0x88,0x07,0xfb,0xe2,0x0f,0x1f,0x84,0x1c,0x1e,0x30,0x68,0x19,0x48,0x6f,0xf8,0x0c,0x04,0x3f,0xdd,0xff,0xf6,0x45,0xe4,0x10,0x08,0x4c,0x03,0xf1,0x00,0x47,0x8c,0x82,0x81,0xc0,0x85,0xa4,0x07,0x82,0x0f,0x40,0x00,0x83,0xd2,0x23,0xd8,0xfc,0x61,0xe5,0xe0,0xf1,0x85,0x03,0xd4,0x10,0x26,0xe1,0xbc,0x47,0xe4,0xe0,0xf6,0x81,0x03,0xcb,0xe1,0x71,0xfc,0x4f,0xe8,0x71,0x00,0x7b,0x50,0x01,0x03,0xe0,0x81,0x83,0xc7,0x0f,0x08,0x07,0xb6,0x03,0x90,0x05,0x18,0x77,0x3e,0x5f,0x03,0x83,0x83,0xda,0x01,0xf7,0xe1,0xc3,0xff,0x11,0xbb,0xe4,0x16,0x0c,0x0f,0x7f,0xdf,0x9e,0x3f,0x70,0xbd,0xff,0x0f,0x64,0x0f,0x5f,0xc5,0xc2,0x79,0x3c,0x57,0x0f,0xfc,}; +const uint8_t _A_Levelup2_128x64_7[] = {0x01,0x00,0xf7,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x05,0xfd,0x83,0xfb,0xbe,0x20,0xf0,0xff,0x83,0x72,0x01,0xfe,0x07,0xdf,0xf6,0x3f,0xff,0xf8,0x83,0xf3,0xcf,0xf8,0xe7,0xc0,0xff,0xc0,0xf9,0xfc,0x46,0x60,0xd3,0x00,0xfe,0x41,0xa0,0x3c,0x0e,0xf0,0x3e,0xaf,0xb8,0x18,0x06,0x03,0xba,0x0f,0xad,0xfd,0x06,0x01,0x00,0xed,0x9e,0xee,0x80,0x0f,0x1f,0xa8,0x3e,0xb5,0xf2,0x00,0x78,0xfa,0x81,0xfb,0xf8,0xf5,0xb6,0xab,0x2e,0x0f,0x18,0x3f,0x5b,0x7e,0x10,0x9c,0xbf,0xfb,0x01,0x00,0xec,0x07,0xeb,0x17,0x01,0xa0,0xc0,0x76,0x01,0xf9,0x07,0x8d,0xf2,0x45,0x02,0x07,0xdd,0x2f,0x05,0x14,0x82,0x68,0x01,0xf3,0xe0,0xa2,0xe0,0xe1,0xb0,0x4b,0x03,0x8c,0x43,0xf1,0x25,0xa1,0xc2,0x61,0x16,0x08,0x5f,0xe8,0x1f,0x1a,0x59,0xe4,0x2b,0x11,0x6f,0x0f,0xcf,0xff,0x4b,0x24,0x85,0x5a,0x2e,0x04,0xfa,0xd1,0x03,0xc6,0x31,0xa0,0xdf,0x07,0xe7,0x44,0x2f,0x18,0x67,0x03,0x7d,0xfe,0x07,0xc5,0x0a,0x87,0x0a,0x89,0x60,0x01,0xc3,0xfd,0x06,0xac,0xff,0xff,0x46,0xc1,0xf3,0x64,0xf9,0xc1,0x7c,0x5f,0xfd,0xd8,0x6f,0x14,0xfe,0x51,0xa3,0xef,0x0f,0xe7,0x15,0x1c,0x80,0x7a,0x38,0x03,0xe9,0xff,0xc2,0xa1,0x70,0x09,0x47,0x03,0xfb,0xf7,0x07,0xc4,0x4a,0x09,0x00,0x8c,0x50,0x09,0xa3,0xef,0x1f,0x28,0x1c,0x41,0xe5,0x08,0x07,0x97,0x8c,0x3f,0x30,0x18,0x34,0x80,0x1e,0x3f,0xbf,0x38,0x3d,0xe0,0x18,0x68,0x08,0x3c,0x84,0x0b,0xf8,0x18,0x89,0x38,0x6f,0x10,0x08,0x80,0x3c,0xbe,0x20,0xf3,0xf8,0x4f,0xf7,0xf0,0x68,0x00,0x00,0x61,0x00,0xf1,0xbf,0xa8,0x13,0xc1,0x3f,0xce,0x40,0x81,0xe5,0x04,0x06,0x21,0x04,0x81,0xe3,0xbc,0x2f,0x08,0x00,0x60,0x5f,0x99,0xfa,0x44,0xbc,0x00,0x21,0xe0,0xff,0x37,0xf1,0x80,0x79,0x40,0x76,0xf1,0xf0,0x78,0xef,0xca,0x25,0x07,0xf8,0x6f,0xec,0x00,0xf2,0x80,0x7a,0x78,0xff,0xff,0xbc,0x3c,0x44,0x51,0xfe,0x46,0xff,0x81,0x01,0x07,0x98,0xf8,0xae,0x3c,0x05,0x01,0xef,0xe8,0x05,0x03,0x07,0x8f,0x3c,0x16,0x38,0x12,0xa1,0xef,0x81,0xed,0xb7,0x1e,0x11,0x88,0xc3,0xeb,0xed,0xff,0xd2,0xc1,0x83,0x0f,0xff,0xfc,0xf3,0x7f,0xfa,0x7c,0x84,0x7e,0x60,0xf1,0xa2,0x03,0xc7,0x1e,0xa3,0x1b,0x2f,0xfa,0x66,0x0f,0x4c,0xac,0x7e,0x87,0xd0,0x1e,0x9e,0x16,0x03,0x0c,0xd0,0x9b,0xce,0xc7,0xe0,0xa0,0x78,0x3c,0x3f,0xb0,0x78,0xc1,0x7f,0xd0,0x3c,0x88,0x3c,0xf0,0x71,0xf9,0x04,0x00,0xdc,0x70,0x58,0x44,0x02,0xa2,0x0f,0x38,0x1c,0x22,0x41,0xf0,0x81,0xff,0x92,0x03,0x0b,0x07,0x8d,0x28,0x1e,0x70,0x18,0x44,0x43,0xe0,0xb2,0x1c,0xff,0xfe,0x10,0x0f,0x19,0x50,0x3d,0x22,0x11,0x08,0xc5,0xfb,0x3c,0x70,0x18,0xbb,0x74,0x64,0xc0,0xf5,0xb4,0x4c,0x3f,0x18,0xf4,0x80,0x83,0xca,0x2c,0x0f,0x49,0x07,0xd3,0xc1,0x01,0xc0,0x13,0xc6,0x5e,0x9c,0x10,0x7a,0xd0,0x3f,0x5e,0x18,0x39,0x80,0x80,}; +const uint8_t _A_Levelup2_128x64_8[] = {0x01,0x00,0x02,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x00,0xbf,0xb0,0x7f,0x88,0x3c,0x3f,0xe1,0x0f,0x00,0x5c,0x3f,0xc0,0x1f,0xdf,0x8c,0x7c,0x1f,0x97,0xf8,0x77,0xf3,0xf8,0x21,0x10,0x04,0xe7,0xe0,0x30,0x2f,0x98,0x7e,0xed,0xf0,0x18,0x0f,0xb0,0x1e,0x7c,0xf8,0x4c,0xcb,0xe6,0x0f,0x38,0xb8,0x3c,0x7a,0x00,0x73,0xc7,0xf2,0x66,0x60,0xf4,0x85,0xe0,0x60,0x1a,0x00,0xf9,0x83,0xde,0x0b,0x82,0x80,0x50,0x00,0xe7,0x4f,0x84,0xc9,0xbf,0x20,0x62,0xff,0x40,0xa8,0x50,0x0f,0xc7,0xfb,0xde,0x0f,0x2e,0x4c,0x9c,0x1e,0xf0,0x6f,0xe8,0x3c,0xb9,0xfc,0x88,0x3f,0xe0,0xfc,0x70,0x1f,0xf4,0x02,0x03,0xfd,0xe3,0x83,0xcf,0x9f,0xfc,0x07,0x95,0xf8,0xbc,0x25,0x01,0xfd,0x07,0xce,0x13,0xce,0x07,0x95,0xff,0xf9,0x80,0xbe,0x0c,0x04,0x1e,0x60,0x06,0xdf,0x50,0x30,0x52,0x48,0x04,0x11,0x3d,0x3b,0xe9,0x06,0x0e,0x53,0x00,0x60,0x88,0x3e,0x2b,0xfa,0x0a,0x14,0x68,0xc0,0x29,0x01,0xe7,0xe0,0xf3,0x92,0x0a,0x7f,0xc8,0x1e,0x35,0xed,0x04,0xf0,0x1e,0x30,0x1f,0xa0,0x3c,0x7e,0x79,0xc9,0xe0,0x3c,0xc3,0xe3,0x24,0x85,0x70,0x20,0x1e,0x80,0x79,0x72,0x41,0xf1,0x30,0x80,0x83,0xcb,0x07,0xc9,0x17,0xa7,0x7c,0x5e,0x30,0xaf,0xc6,0x0b,0xd6,0x1f,0x4b,0x7b,0x5c,0x81,0xe3,0xc2,0x85,0x43,0xac,0xbe,0xc0,0x79,0x78,0xc1,0xeb,0x20,0x81,0xe2,0xe0,0x31,0xa1,0xf9,0x83,0xc4,0xde,0x94,0x1f,0x15,0xed,0x1e,0x20,0xf1,0x87,0xe0,0xbe,0xf2,0x0a,0x41,0x3c,0xf0,0x31,0xc8,0x64,0x02,0x04,0x6f,0x14,0x7c,0x40,0xa0,0xb0,0x83,0xf9,0x83,0xe2,0x09,0x02,0x80,0x1f,0xc7,0xf4,0x0f,0x98,0x40,0x3c,0x66,0x00,0xfb,0x88,0x60,0x20,0x04,0x01,0xfe,0x83,0xe6,0x41,0x00,0xc1,0xc0,0xf0,0x1f,0xe0,0x7d,0xdf,0x20,0x14,0x00,0x41,0x43,0xe0,0x10,0x0c,0x00,0x18,0xad,0xe0,0xf1,0x00,0x0e,0x80,0x10,0x5f,0x30,0x10,0xdf,0xc0,0xc5,0x97,0x8c,0x03,0xcb,0xa0,0x08,0x28,0x68,0x7c,0x86,0xc5,0x17,0x83,0x83,0xcb,0x30,0x0f,0x28,0x30,0x1c,0x8a,0xc5,0x17,0x37,0x08,0x00,0x6e,0x80,0xfa,0x82,0x01,0xcb,0x20,0x28,0x28,0x36,0x73,0x10,0x0f,0x45,0x68,0x83,0xdb,0x45,0x84,0x80,0x83,0xc7,0x7f,0x17,0x4e,0x09,0x7c,0x81,0xe9,0x82,0x81,0x87,0xcd,0x78,0x20,0xf7,0xc0,0xc1,0xc1,0xe7,0x40,0x80,0x83,0xcb,0xbd,0xbf,0x0f,0xc5,0x00,0xc0,0x41,0xf2,0xff,0x0f,0xd7,0xff,0x1b,0x07,0xb7,0xf0,0xbe,0xbd,0xf9,0x28,0x3c,0xfc,0x01,0x82,0x3f,0xa7,0xdf,0xe3,0x22,0x07,0x9f,0x03,0xf4,0x10,0x14,0x7a,0xde,0x24,0x20,0xf4,0xfa,0x07,0xc6,0x1c,0xbf,0x4c,0xfc,0x82,0x40,0x5f,0x2e,0x07,0x20,0x1e,0x23,0x22,0x6f,0x95,0x9c,0x1e,0xb3,0x0f,0xff,0xe3,0xf6,0x0c,0x13,0xa0,0xff,0xe3,0x20,0xf5,0x4a,0x0f,0xdd,0xce,0x5c,0x0f,0xfc,0x06,0x0d,0x40,0xc8,0x11,0xca,0x81,0x00,0xff,0xfa,0x1c,0x44,0x00,0x1f,0xf4,0x24,0x1e,0xd0,0x4f,0x47,0xf7,0xbe,0x0f,0x28,0x0c,0x22,0x81,0x50,0x07,0xa4,0x0b,0xd1,0xe3,0x0f,0x98,}; +const uint8_t _A_Levelup2_128x64_9[] = {0x01,0x00,0xfb,0x01,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x01,0x3d,0xe0,0xff,0x06,0xe4,0x07,0xe0,0x0f,0xab,0xff,0xfe,0x7f,0xfe,0xe7,0xe0,0xc3,0xd7,0xdf,0x80,0xce,0x03,0xf9,0x67,0x80,0x71,0xbd,0xc0,0xfb,0xad,0xc0,0x20,0x3e,0xd0,0x49,0xf3,0xe1,0x33,0x2f,0x98,0x3c,0xe8,0xb8,0x08,0x07,0xe8,0x1e,0x78,0xfe,0x4c,0xcc,0x1e,0x98,0x2a,0x04,0x03,0x88,0x71,0x30,0x7a,0xcb,0xef,0x58,0x10,0x78,0xee,0x01,0xe7,0x4f,0x84,0xc9,0xbf,0x21,0xf2,0xdf,0xe0,0x24,0x10,0x0a,0x30,0x3d,0x39,0x32,0x70,0x7a,0x40,0x24,0x30,0x0c,0x0f,0xfb,0x8e,0x4f,0x2e,0x44,0x1f,0xf0,0x0f,0x2a,0xfc,0x02,0x7f,0x80,0xc0,0x7f,0xa0,0x20,0xf3,0xe7,0xff,0x0a,0xc5,0x5f,0xe0,0x00,0x06,0x01,0xfd,0x0f,0x9c,0x27,0x9c,0x0f,0x2b,0xfc,0xbe,0x41,0x1e,0x90,0xc0,0x7f,0xaa,0x19,0x97,0xe4,0x2c,0x31,0x28,0x17,0x08,0x1f,0x5d,0x0e,0x04,0x3a,0x05,0x3a,0x07,0xcc,0x5e,0x91,0xa1,0x86,0x41,0x38,0xdf,0xe1,0xf0,0xe0,0xf3,0x92,0x0a,0x7f,0xc8,0x1e,0x52,0x88,0xf4,0x17,0x08,0x40,0x10,0x78,0xfc,0xf3,0x93,0xc0,0x7a,0xc4,0xa0,0xb4,0x86,0x09,0x03,0xc7,0x92,0x0f,0x8f,0xc0,0x3c,0xf0,0x7c,0x91,0x7c,0x43,0x38,0x3f,0xb0,0xfa,0x5b,0xc0,0xc3,0xff,0x9d,0x93,0xc6,0x09,0x7f,0xf9,0x03,0xcf,0xc6,0x0f,0x4a,0x5f,0x43,0xe1,0xc2,0xc0,0x7f,0x2f,0xa0,0xf4,0x37,0x9e,0x2f,0x21,0x0d,0x9f,0xc0,0x3f,0xf3,0xef,0xf4,0x3f,0x05,0xf7,0x90,0x52,0x07,0xe5,0x0b,0x90,0xc0,0xa0,0x90,0x0b,0xfd,0xfd,0x1f,0x10,0xbe,0x14,0x06,0x01,0x80,0xdf,0x83,0xa0,0x1e,0x30,0x40,0x78,0xf8,0x3b,0xe0,0xe8,0xfb,0xc2,0xe1,0x00,0xf1,0xfc,0x2f,0xa4,0x1e,0x54,0x08,0x07,0x3a,0x06,0xbf,0x10,0x03,0x78,0xc1,0xe3,0x80,0xe0,0xc0,0xff,0xeb,0xf1,0x0f,0xbc,0x34,0xba,0x3f,0xe8,0x0f,0xc1,0x10,0x50,0xf8,0x01,0x5c,0x41,0xe5,0x12,0x81,0x01,0xc4,0xf8,0x2b,0xf1,0xff,0xfc,0xc0,0x42,0x75,0x39,0x11,0x38,0x40,0x04,0x0f,0x28,0x68,0x7c,0x88,0xc5,0xc2,0x07,0x1c,0x00,0x5e,0x50,0x60,0x31,0x11,0x8a,0x05,0x03,0x03,0x97,0x03,0xf8,0x0f,0x98,0x60,0x1c,0xa6,0x03,0x82,0x83,0x67,0x31,0x00,0xf4,0x98,0x03,0xcb,0x9c,0x0f,0x3d,0x16,0x12,0x02,0x0f,0x3e,0x00,0xb8,0x87,0xc4,0x0f,0x2c,0x14,0x0c,0x1e,0x70,0x02,0x00,0xff,0x01,0xeb,0x81,0x83,0x83,0xd2,0x1c,0xbf,0x10,0xfe,0x44,0x9b,0xe3,0xf5,0x1f,0xd0,0x3c,0xa0,0x1f,0x42,0xfc,0xce,0xa0,0x10,0x90,0x78,0xfb,0x01,0xe6,0x7f,0x5a,0x30,0x3f,0x6f,0xf8,0x18,0x04,0x14,0x0e,0x3d,0x80,0x79,0x15,0x85,0x7e,0x77,0xf8,0x0e,0x05,0xe0,0x20,0xf4,0x15,0x93,0x7c,0xb7,0xf0,0x0c,0x13,0xc0,0xb5,0x00,0xf2,0x39,0x96,0xfc,0x1e,0x74,0x40,0x7b,0x41,0xd4,0xe4,0x05,0x1a,0xf8,0x3c,0x60,0x20,0x81,0xa4,0x03,0xc8,0x00,0xb2,0xf8,0x04,0xa0,0x1e,0x58,0x82,0x40,0x80,0x1a,0x2e,0x2b,0x13,0x39,0x42,0x09,0x84,0x00,0x40,}; +const uint8_t _A_Levelup2_128x64_10[] = {0x01,0x00,0x06,0x02,0xff,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x1e,0x00,0xf0,0x07,0x80,0x3c,0x01,0xe0,0x0f,0x00,0x78,0x03,0xc0,0x09,0xef,0x06,0xe4,0x07,0xe0,0x0f,0xc9,0xff,0xfb,0x9f,0xc7,0x07,0xdf,0x7e,0x03,0x38,0x0f,0xe5,0x9e,0x01,0xc6,0xf7,0x03,0xee,0xb7,0x00,0x80,0xff,0x4a,0x27,0xcf,0x84,0xcc,0xbe,0x60,0x51,0xbf,0xff,0xe8,0xb8,0x08,0x07,0xe8,0x2e,0x78,0xfe,0x4c,0xcc,0x1e,0x98,0x2a,0x04,0x03,0x88,0x1f,0x30,0x7a,0xcf,0xef,0xd8,0x10,0x78,0xee,0x01,0xe7,0x4f,0x84,0xc9,0xbf,0x21,0xf2,0xdf,0xe0,0x24,0x10,0x0a,0x37,0xfc,0xe2,0x54,0xfe,0x4c,0x9c,0x1e,0x90,0x09,0x0c,0x03,0x03,0xfe,0xd5,0x93,0xcb,0x91,0x07,0xfc,0x11,0x8a,0xbf,0x00,0x9f,0xe0,0x30,0x17,0xe8,0x89,0x88,0x41,0xe3,0xcf,0xfe,0x03,0xcf,0x80,0x00,0x18,0x07,0xf4,0x3e,0x70,0x9e,0x70,0x3c,0xe5,0xf2,0x08,0xf4,0x85,0x00,0x2b,0x19,0x97,0xe4,0x2c,0x31,0x28,0x17,0x09,0x63,0x1f,0xe9,0x7f,0x43,0x81,0x0e,0x81,0x4e,0x95,0xd3,0x17,0xa4,0x68,0x61,0x90,0x46,0x09,0x73,0xf0,0x79,0xc9,0x05,0x3f,0xe4,0x1f,0x18,0xbc,0xa2,0x3d,0x05,0xc2,0x30,0x4b,0x9f,0xf3,0xce,0x4f,0x01,0xeb,0x12,0x82,0xd2,0x18,0x24,0x0f,0x1e,0x48,0x3e,0x3f,0x00,0xf3,0xc1,0xf2,0x45,0xe5,0x5f,0xfa,0x0b,0xce,0x19,0xc1,0xfd,0x87,0xd2,0xde,0x06,0x1f,0xf4,0xec,0x9e,0x30,0x4b,0xff,0xc8,0x1e,0x7e,0x30,0x7a,0x52,0xfa,0x1f,0x0e,0x16,0x03,0xf8,0x4f,0x30,0x78,0x9b,0xcf,0x17,0x90,0x86,0xcf,0xe0,0x01,0x61,0xff,0xc3,0xf0,0x5f,0x79,0x05,0x20,0x9e,0x50,0xb9,0x0c,0x0a,0x09,0x00,0xbf,0xa3,0xe6,0x17,0xc2,0x80,0xc0,0x30,0x1b,0xf0,0x7d,0x41,0x01,0xe3,0xe0,0xef,0x83,0xea,0x10,0x0f,0x1f,0xc3,0x3a,0x01,0xe7,0x40,0x80,0x73,0xa0,0x64,0xf1,0x00,0x37,0xdc,0x1e,0x38,0x0e,0x0c,0x0f,0xfe,0x6f,0x10,0x03,0xc3,0x4b,0xa3,0xfe,0x80,0xfc,0x11,0x02,0x70,0x18,0x01,0x5c,0x41,0xe5,0x12,0x81,0x01,0xc7,0xfd,0x0f,0x5f,0x8f,0xff,0xe6,0x02,0x13,0xb1,0xc8,0x89,0xc2,0x00,0x20,0x79,0x43,0x43,0xe4,0x46,0x2e,0x10,0x38,0xe0,0x02,0xf2,0x83,0x01,0x88,0x8c,0x50,0x28,0x18,0x1c,0xb8,0x1f,0xc0,0x7c,0xc3,0x00,0xe5,0x30,0x1c,0x94,0x1b,0x39,0x88,0x07,0xa4,0xc0,0x1e,0x5c,0xe0,0x79,0xe8,0xb0,0x90,0x10,0x79,0xf0,0x05,0xc5,0xfb,0x9f,0x92,0x44,0x1e,0x38,0x28,0x18,0x3c,0xe0,0x04,0x01,0xfe,0x7e,0xc3,0xe9,0x81,0x83,0x83,0xd2,0x1c,0xbf,0x10,0x7a,0x87,0xda,0x24,0xdf,0x1f,0xaa,0x20,0x87,0xee,0x0f,0x28,0x07,0xd0,0x1e,0x65,0xf5,0x9d,0x40,0x21,0x20,0xf1,0xf6,0x03,0xcc,0xfe,0xb4,0x60,0x7e,0xdf,0xf0,0x30,0x08,0x28,0x1c,0x7b,0x00,0xf2,0x2b,0x0a,0xfc,0xef,0xf0,0x1c,0x0b,0xc0,0x41,0xe8,0x2b,0x23,0x29,0x6f,0xe0,0x18,0x27,0x81,0x6a,0x01,0xe4,0xd2,0x2d,0xf8,0x3c,0xe8,0x80,0xf6,0x83,0xa9,0xc8,0x0a,0x35,0xf0,0x78,0xc0,0x41,0x03,0x48,0x07,0x90,0x01,0x65,0xf0,0x09,0x40,0x3c,0xb1,0x04,0x81,0x00,0x34,0x5c,0x56,0x26,0x72,0x84,0x13,0x08,0x00,0x80,}; +const uint8_t *_A_Levelup2_128x64[] = {_A_Levelup2_128x64_0,_A_Levelup2_128x64_1,_A_Levelup2_128x64_2,_A_Levelup2_128x64_3,_A_Levelup2_128x64_4,_A_Levelup2_128x64_5,_A_Levelup2_128x64_6,_A_Levelup2_128x64_7,_A_Levelup2_128x64_8,_A_Levelup2_128x64_9,_A_Levelup2_128x64_10}; const uint8_t _I_125_10px_0[] = {0x00,0xE0,0x00,0x00,0x01,0x0E,0x02,0x31,0x02,0x45,0x02,0x91,0x00,0xAA,0x00,0x92,0x00,0x44,0x00,0x38,0x00,}; const uint8_t *_I_125_10px[] = {_I_125_10px_0}; @@ -245,6 +187,9 @@ const uint8_t *_I_ArrowUpEmpty_14x15[] = {_I_ArrowUpEmpty_14x15_0}; const uint8_t _I_ArrowUpFilled_14x15_0[] = {0x00,0xC0,0x00,0x20,0x01,0xD0,0x02,0xE8,0x05,0xF4,0x0B,0xFA,0x17,0x61,0x21,0xAF,0x3D,0x68,0x05,0xA8,0x05,0x68,0x05,0xA8,0x05,0xE8,0x05,0x08,0x04,0xF8,0x07,}; const uint8_t *_I_ArrowUpFilled_14x15[] = {_I_ArrowUpFilled_14x15_0}; +const uint8_t _I_Back3_45x8_0[] = {0x00,0x04,0x00,0x10,0x00,0x40,0x00,0x06,0x00,0x18,0x00,0x60,0x00,0x7F,0x00,0xFC,0x01,0xF0,0x07,0x86,0x20,0x18,0x82,0x60,0x08,0x04,0x71,0x10,0xC4,0x41,0x10,0x00,0x21,0x00,0x84,0x00,0x10,0x80,0x00,0x00,0x02,0x00,0x08,0x7E,0x00,0xF8,0x01,0xE0,0x07,}; +const uint8_t *_I_Back3_45x8[] = {_I_Back3_45x8_0}; + const uint8_t _I_DoorLeft_70x55_0[] = {0x01,0x00,0x19,0x01,0x00,0x2c,0x32,0x01,0x03,0x04,0x2c,0x18,0x10,0xf0,0x40,0x47,0x82,0x06,0x81,0x03,0xff,0x80,0x08,0x1a,0x20,0x82,0x15,0x28,0x21,0x87,0x82,0x08,0x6f,0xc0,0xb1,0xe6,0x10,0x10,0x8b,0x46,0x20,0x43,0x55,0x8f,0x82,0x10,0x32,0x73,0x0a,0x09,0x89,0x6c,0x1e,0x09,0x00,0x18,0x60,0xf0,0x0c,0x84,0x93,0x82,0x03,0x18,0x0c,0x02,0x1d,0x00,0x90,0x52,0x70,0x50,0x1e,0x00,0x58,0x63,0x90,0x0a,0x06,0x4a,0x09,0x03,0xb0,0x02,0x06,0x70,0x62,0x49,0xf8,0x0c,0x66,0x3f,0xf0,0x41,0x63,0x04,0x43,0x00,0x99,0x60,0x00,0x85,0xc8,0x06,0x14,0xd0,0x80,0x3f,0xc8,0x0d,0xb8,0x10,0x70,0xf8,0x34,0x13,0x03,0x39,0x04,0x1c,0x42,0x19,0xf8,0xa0,0xc2,0x01,0x07,0xef,0x02,0x8c,0x80,0x10,0x9d,0x00,0x43,0xec,0x00,0xa3,0x10,0x04,0x25,0xce,0x19,0xfc,0x88,0x82,0x12,0x0c,0x35,0x10,0x42,0x4c,0xa1,0x90,0x3f,0xc0,0x21,0x22,0x39,0x82,0xc8,0x88,0xd2,0x11,0xf0,0x01,0x88,0xd5,0x18,0xe2,0x08,0x68,0x10,0x0c,0xa8,0x00,0x83,0x81,0xcc,0xd5,0xc3,0x80,0x84,0x82,0x0e,0xcc,0xc0,0x15,0x79,0x02,0x0b,0x98,0xf8,0x11,0x88,0x82,0x0f,0x31,0x19,0x02,0x08,0x2c,0x9f,0x6a,0x1d,0x20,0x41,0x31,0x4c,0x10,0x8d,0x73,0x04,0x23,0xa4,0xc4,0x6c,0xde,0x20,0x42,0xcc,0x01,0x07,0x07,0xff,0x80,0x06,0x3e,0x08,0x38,0x70,0x20,0xa1,0xe0,0x83,0x8e,0x01,0x0c,0xf0,0x73,0x80,0x43,0x70,0x05,0x08,0x00,0x2c,0x04,0xc4,0x46,0x53,0x09,0x98,0x24,0x80,0x65,0x80,0xb0,0xd9,0x84,0x65,0x32,0x06,0x17,0x0f,0x98,0x23,0x63,0xe1,0x88,0xc4,0x08,0x5f,0xc1,0x30,0x9d,0x84,0x4e,0x66,0x94,0x11,0x98,0x75,0x26,0x00,}; const uint8_t *_I_DoorLeft_70x55[] = {_I_DoorLeft_70x55_0}; @@ -263,6 +208,9 @@ const uint8_t *_I_PassportBottom_128x17[] = {_I_PassportBottom_128x17_0}; const uint8_t _I_PassportLeft_6x47_0[] = {0x01,0x00,0x1c,0x00,0x9e,0x40,0xa3,0x32,0x59,0x2c,0x66,0x03,0x01,0x82,0xc2,0x62,0x32,0x50,0x16,0xc8,0x60,0x30,0x28,0x24,0x32,0x39,0x3c,0x9e,0x4d,0x25,0x80,0x1a,}; const uint8_t *_I_PassportLeft_6x47[] = {_I_PassportLeft_6x47_0}; +const uint8_t _I_WarningDolphin_45x42_0[] = {0x01,0x00,0xc6,0x00,0x00,0x1c,0x22,0x04,0x05,0x7f,0xfc,0x1e,0x20,0x05,0x1e,0x04,0x02,0x30,0x05,0x29,0x84,0x02,0xc1,0x20,0x02,0x8c,0x22,0x01,0x80,0x02,0x94,0x10,0x32,0x30,0x10,0x10,0x87,0xca,0x84,0x03,0x10,0x42,0x81,0x48,0x28,0x38,0x08,0x04,0x3e,0x01,0x84,0x83,0xe0,0x30,0x11,0x08,0x05,0xa2,0x11,0x40,0xa0,0x4b,0xc6,0xc5,0x40,0xd0,0x56,0xe0,0x10,0x60,0x29,0x54,0xf0,0x10,0x18,0xf0,0x14,0x6b,0xf6,0x0c,0x04,0x3e,0x40,0x05,0x12,0x80,0xc1,0xe4,0x01,0xd2,0xf8,0x40,0xe4,0x18,0x09,0xf4,0x03,0xf1,0x01,0x90,0x40,0x28,0x30,0x0f,0xe4,0x00,0x16,0x24,0x11,0xbf,0x01,0x44,0xee,0x53,0xf0,0x29,0xf0,0x3e,0x02,0x91,0x3b,0x8c,0xc3,0x81,0x13,0x90,0x48,0x20,0x3f,0xf9,0xfc,0x42,0x60,0x05,0x10,0x98,0x81,0x56,0x11,0x38,0x02,0x9c,0x1a,0x31,0x1e,0x02,0x8f,0x02,0x03,0x1c,0x90,0xc0,0x7c,0x02,0xf1,0xce,0x02,0x07,0x01,0x1f,0x80,0x63,0xa8,0x08,0x71,0x3c,0x8e,0x39,0x24,0x40,0x51,0xc7,0x81,0x53,0x0f,0x3c,0x02,0x9d,0x1e,0x38,0x29,0x10,0x29,0x17,0xc8,0x0a,0x32,0x3a,0x00,0x14,0x4b,0xa2,0x05,0x58,0x98,0x15,0x22,0x20,0x54,0x84,0x81,0x50,}; +const uint8_t *_I_WarningDolphin_45x42[] = {_I_WarningDolphin_45x42_0}; + const uint8_t _I_Back_15x10_0[] = {0x00,0x04,0x00,0x06,0x00,0xFF,0x0F,0x06,0x10,0x04,0x20,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x10,0xFE,0x0F,}; const uint8_t *_I_Back_15x10[] = {_I_Back_15x10_0}; @@ -574,6 +522,9 @@ const uint8_t *_I_SDQuestion_35x43[] = {_I_SDQuestion_35x43_0}; const uint8_t _I_Cry_dolph_55x52_0[] = {0x01,0x00,0xe8,0x00,0x00,0x0f,0xe3,0xff,0x01,0x03,0x1f,0xfb,0xff,0x0f,0x02,0x96,0x02,0x0f,0x00,0x9f,0x01,0x8b,0xc0,0x12,0x1f,0x80,0x18,0xae,0x00,0x21,0xe0,0x07,0x0a,0x30,0x0a,0x28,0x18,0x08,0x61,0x80,0x62,0x83,0x00,0x90,0x14,0x61,0x02,0x0c,0x16,0x00,0x76,0x60,0x66,0x98,0x0b,0x04,0x90,0x60,0x66,0xb0,0x00,0x48,0x0d,0x21,0x21,0x03,0x30,0x74,0x40,0xd3,0x80,0x03,0x34,0x04,0xc0,0x52,0x00,0x32,0xc7,0xa0,0x18,0x80,0x31,0x80,0x07,0xe1,0x01,0x37,0x18,0x50,0x80,0xc2,0x92,0x10,0x31,0xe8,0x23,0xe9,0x63,0x86,0x54,0x3f,0xe0,0xe1,0x0d,0x96,0x83,0xfc,0x06,0x40,0x69,0x6c,0x3c,0x60,0xd2,0xfc,0xc0,0x60,0x58,0x48,0x0c,0x1b,0x81,0x08,0x14,0x9c,0x1a,0x81,0x04,0x03,0x46,0x80,0x0c,0x50,0x26,0x21,0xc1,0x94,0x26,0x14,0x27,0x8a,0x40,0xc0,0xc2,0xe7,0x26,0x40,0x81,0x86,0xc0,0x6b,0x28,0x64,0x0f,0x01,0x10,0x4e,0x14,0x60,0x0c,0x29,0x02,0x48,0x8b,0x5c,0x45,0x22,0x01,0x10,0x31,0x3a,0x4c,0x0c,0x34,0x06,0xf1,0xd8,0x00,0xc5,0x1a,0x64,0x94,0x0c,0xc0,0x37,0x52,0x20,0x81,0x84,0x26,0x3e,0x88,0x0c,0x38,0x28,0x54,0x0e,0xac,0x1f,0xe1,0x3f,0x06,0x96,0x82,0x7e,0x29,0x4a,0xaf,0xfd,0x76,0x30,0x3a,0x41,0x14,0x7f,0xd0,0xf8,0x78,0x18,0xaa,0x9f,0xd4,0xe0,0x83,0x4f,0xf5,0xf7,0x38,0x0b,0x9c,0x6a,0x1f,0x5b,0x5c,0x00,}; const uint8_t *_I_Cry_dolph_55x52[] = {_I_Cry_dolph_55x52_0}; +const uint8_t _I_Attention_5x8_0[] = {0x00,0x0E,0x0A,0x0A,0x0A,0x0E,0x04,0x00,0x0E,}; +const uint8_t *_I_Attention_5x8[] = {_I_Attention_5x8_0}; + const uint8_t _I_BT_Pair_9x8_0[] = {0x00,0x11,0x01,0x35,0x00,0x58,0x01,0x31,0x00,0x30,0x01,0x59,0x00,0x34,0x01,0x11,0x01,}; const uint8_t *_I_BT_Pair_9x8[] = {_I_BT_Pair_9x8_0}; @@ -669,34 +620,8 @@ const uint8_t *_I_iButtonKey_49x44[] = {_I_iButtonKey_49x44_0}; const Icon I_Certification1_103x23 = {.width=103,.height=23,.frame_count=1,.frame_rate=0,.frames=_I_Certification1_103x23}; const Icon I_Certification2_119x30 = {.width=119,.height=30,.frame_count=1,.frame_rate=0,.frames=_I_Certification2_119x30}; -const Icon I_card_bad1 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_card_bad1}; -const Icon I_card_bad2 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_card_bad2}; -const Icon I_card_ok1 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_card_ok1}; -const Icon I_card_ok2 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_card_ok2}; -const Icon I_card_ok3 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_card_ok3}; -const Icon I_card_ok4 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_card_ok4}; -const Icon I_no_databases1 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_no_databases1}; -const Icon I_no_databases2 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_no_databases2}; -const Icon I_no_databases3 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_no_databases3}; -const Icon I_no_databases4 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_no_databases4}; -const Icon I_no_sd1 = {.width=128,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_no_sd1}; -const Icon I_no_sd2 = {.width=128,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_no_sd2}; -const Icon I_no_sd3 = {.width=128,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_no_sd3}; -const Icon I_no_sd4 = {.width=128,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_no_sd4}; -const Icon I_no_sd5 = {.width=128,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_no_sd5}; -const Icon I_no_sd6 = {.width=128,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_no_sd6}; -const Icon I_tv1 = {.width=128,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_tv1}; -const Icon I_tv2 = {.width=128,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_tv2}; -const Icon I_tv3 = {.width=128,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_tv3}; -const Icon I_tv4 = {.width=128,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_tv4}; -const Icon I_tv5 = {.width=128,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_tv5}; -const Icon I_tv6 = {.width=128,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_tv6}; -const Icon I_tv7 = {.width=128,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_tv7}; -const Icon I_tv8 = {.width=128,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_tv8}; -const Icon I_url1 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_url1}; -const Icon I_url2 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_url2}; -const Icon I_url3 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_url3}; -const Icon I_url4 = {.width=128,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_url4}; +const Icon A_Levelup1_128x64 = {.width=128,.height=64,.frame_count=11,.frame_rate=2,.frames=_A_Levelup1_128x64}; +const Icon A_Levelup2_128x64 = {.width=128,.height=64,.frame_count=11,.frame_rate=2,.frames=_A_Levelup2_128x64}; const Icon I_125_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_125_10px}; const Icon I_Nfc_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Nfc_10px}; const Icon I_ble_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ble_10px}; @@ -748,12 +673,14 @@ const Icon I_ArrowDownEmpty_14x15 = {.width=14,.height=15,.frame_count=1,.frame_ const Icon I_ArrowDownFilled_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowDownFilled_14x15}; const Icon I_ArrowUpEmpty_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowUpEmpty_14x15}; const Icon I_ArrowUpFilled_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowUpFilled_14x15}; +const Icon I_Back3_45x8 = {.width=45,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Back3_45x8}; const Icon I_DoorLeft_70x55 = {.width=70,.height=55,.frame_count=1,.frame_rate=0,.frames=_I_DoorLeft_70x55}; const Icon I_DoorLocked_10x56 = {.width=10,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLocked_10x56}; const Icon I_DoorRight_70x55 = {.width=70,.height=55,.frame_count=1,.frame_rate=0,.frames=_I_DoorRight_70x55}; const Icon I_LockPopup_100x49 = {.width=100,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_LockPopup_100x49}; const Icon I_PassportBottom_128x17 = {.width=128,.height=17,.frame_count=1,.frame_rate=0,.frames=_I_PassportBottom_128x17}; const Icon I_PassportLeft_6x47 = {.width=6,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_PassportLeft_6x47}; +const Icon I_WarningDolphin_45x42 = {.width=45,.height=42,.frame_count=1,.frame_rate=0,.frames=_I_WarningDolphin_45x42}; const Icon I_Back_15x10 = {.width=15,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Back_15x10}; const Icon I_DolphinReadingSuccess_59x63 = {.width=59,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinReadingSuccess_59x63}; const Icon I_Down_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Down_25x27}; @@ -825,6 +752,7 @@ const Icon I_RFIDDolphinSuccess_108x57 = {.width=108,.height=57,.frame_count=1,. const Icon I_SDError_43x35 = {.width=43,.height=35,.frame_count=1,.frame_rate=0,.frames=_I_SDError_43x35}; const Icon I_SDQuestion_35x43 = {.width=35,.height=43,.frame_count=1,.frame_rate=0,.frames=_I_SDQuestion_35x43}; const Icon I_Cry_dolph_55x52 = {.width=55,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Cry_dolph_55x52}; +const Icon I_Attention_5x8 = {.width=5,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Attention_5x8}; const Icon I_BT_Pair_9x8 = {.width=9,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_BT_Pair_9x8}; const Icon I_Background_128x11 = {.width=128,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_Background_128x11}; const Icon I_BadUsb_9x8 = {.width=9,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_BadUsb_9x8}; diff --git a/assets/compiled/assets_icons.h b/assets/compiled/assets_icons.h index 3dac8eb1..3b756c1b 100644 --- a/assets/compiled/assets_icons.h +++ b/assets/compiled/assets_icons.h @@ -3,34 +3,8 @@ extern const Icon I_Certification1_103x23; extern const Icon I_Certification2_119x30; -extern const Icon I_card_bad1; -extern const Icon I_card_bad2; -extern const Icon I_card_ok1; -extern const Icon I_card_ok2; -extern const Icon I_card_ok3; -extern const Icon I_card_ok4; -extern const Icon I_no_databases1; -extern const Icon I_no_databases2; -extern const Icon I_no_databases3; -extern const Icon I_no_databases4; -extern const Icon I_no_sd1; -extern const Icon I_no_sd2; -extern const Icon I_no_sd3; -extern const Icon I_no_sd4; -extern const Icon I_no_sd5; -extern const Icon I_no_sd6; -extern const Icon I_tv1; -extern const Icon I_tv2; -extern const Icon I_tv3; -extern const Icon I_tv4; -extern const Icon I_tv5; -extern const Icon I_tv6; -extern const Icon I_tv7; -extern const Icon I_tv8; -extern const Icon I_url1; -extern const Icon I_url2; -extern const Icon I_url3; -extern const Icon I_url4; +extern const Icon A_Levelup1_128x64; +extern const Icon A_Levelup2_128x64; extern const Icon I_125_10px; extern const Icon I_Nfc_10px; extern const Icon I_ble_10px; @@ -82,12 +56,14 @@ extern const Icon I_ArrowDownEmpty_14x15; extern const Icon I_ArrowDownFilled_14x15; extern const Icon I_ArrowUpEmpty_14x15; extern const Icon I_ArrowUpFilled_14x15; +extern const Icon I_Back3_45x8; extern const Icon I_DoorLeft_70x55; extern const Icon I_DoorLocked_10x56; extern const Icon I_DoorRight_70x55; extern const Icon I_LockPopup_100x49; extern const Icon I_PassportBottom_128x17; extern const Icon I_PassportLeft_6x47; +extern const Icon I_WarningDolphin_45x42; extern const Icon I_Back_15x10; extern const Icon I_DolphinReadingSuccess_59x63; extern const Icon I_Down_25x27; @@ -159,6 +135,7 @@ extern const Icon I_RFIDDolphinSuccess_108x57; extern const Icon I_SDError_43x35; extern const Icon I_SDQuestion_35x43; extern const Icon I_Cry_dolph_55x52; +extern const Icon I_Attention_5x8; extern const Icon I_BT_Pair_9x8; extern const Icon I_Background_128x11; extern const Icon I_BadUsb_9x8; diff --git a/assets/dolphin/ReadMe.md b/assets/dolphin/ReadMe.md new file mode 100644 index 00000000..f6959255 --- /dev/null +++ b/assets/dolphin/ReadMe.md @@ -0,0 +1,81 @@ +# Dolphin assets + +Dolphin assets are split into 3 parts: + +- essential - Essential animations that are used for blocking system notifications. They are packed to `assets_dolphin_essential.[h,c]`. +- internal - Internal animations that are used for idle dolphin animation. Converted to `assets_dolphin_internal.[h,c]`. +- external - External animations that are used for idle dolphin animation. Packed to resource folder and placed on SD card. + +# Files + +- `manifest.txt` - contains animations enumeration that is used for random animation selection. Starting point for Dolphin. +- `meta.txt` - contains data that describes how animation is drawn. +- `frame_X.bm` - Flipper Compressed Bitmap. + +## File manifest.txt + +Flipper Format File with ordered keys. + +Header: + +``` +Filetype: Flipper Animation Manifest +Version: 1 +``` + +- `Name` - name of animation. Must be exact animation directory name. +- `Min butthurt`, `Max butthurt` - range of dolphin's butthurt for this animation. +- `Min level`, `Max level` - range of dolphin's level for this animation. If 0, this animation doesn't participate in random idle animation selection and can only be selected by exact name. +- `Weight` - chance of this animation to be choosen at random animation selection. + +Some animations can be excluded from participation in random animation selection, such as `L1_NoSd_128x49`. + +## File meta.txt + +Flipper Format File with ordered keys. + +Header: + +``` +Filetype: Flipper Animation +Version: 1 +``` + +- `Width` - animation width in px (<= 128) +- `Height` - animation height in px (<= 64) +- `Passive frames` - number of bitmap frames for passive animation state +- `Active frames` - number of bitmap frames for active animation state (can be 0) +- `Frames order` - order of bitmap frames where first N frames are passive and following M are active. Each X number in order refers to bitmap frame, with name frame\_X.bm. This file must exist. Any X number can be repeated to refer same frame in animation. +- `Active cycles` - cycles to repeat of N active frames for full active period. E.g. if frames for active cycles are 6 and 7, and active cycles is 3, so full active period plays 6 7 6 7 6 7. Full period of passive + active period are called *total period*. +- `Frame rate` - number of frames to play for 1 second. +- `Duration` - total amount of seconds to play 1 animation. +- `Active cooldown` - amount of seconds (after passive mode) to pass before entering next active mode. + +- `Bubble slots` - amount of bubble sequences. +- Any bubble sequence plays whole sequence during active mode. There can be many bubble sequences and bubbles inside it. Bubbles in 1 bubble sequence have to reside in 1 slot. Bubbles order in 1 bubble sequence is determined by occurance in file. As soon as frame index goes out of EndFrame index of bubble - next animation bubble is choosen. There can also be free of bubbles frames between 2 bubbles. + +- `Slot` - number to unite bubbles for same sequence. +- `X`, `Y` - are coordinates of left top corner of bubble. +- `Text` - text in bubble. New line is `\n` +- `AlignH` - horizontal place of bubble corner (Left, Center, Right) +- `AlignV` - vertical place of bubble corner (Top, Center, Bottom) +- `StartFrame`, `EndFrame` - frame index range inside whole period to show bubble. + +### Understanding of frame indexes + +For example we have + +``` +Passive frames: 6 +Active frames: 2 +Frames order: 0 1 2 3 4 5 6 7 +Active cycles: 4 +``` + +Then we have indexes + +``` + passive(6) active (2 * 4) +Real frames order: 0 1 2 3 4 5 6 7 6 7 6 7 6 7 +Frames indexes: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 +``` diff --git a/assets/dolphin/animations/recording/frame_0.png b/assets/dolphin/animations/recording/frame_0.png deleted file mode 100644 index 8a91feb6..00000000 Binary files a/assets/dolphin/animations/recording/frame_0.png and /dev/null differ diff --git a/assets/dolphin/animations/recording/frame_10.png b/assets/dolphin/animations/recording/frame_10.png deleted file mode 100644 index ab1f58b8..00000000 Binary files a/assets/dolphin/animations/recording/frame_10.png and /dev/null differ diff --git a/assets/dolphin/animations/recording/frame_11.png b/assets/dolphin/animations/recording/frame_11.png deleted file mode 100644 index aa900eba..00000000 Binary files a/assets/dolphin/animations/recording/frame_11.png and /dev/null differ diff --git a/assets/dolphin/animations/recording/frame_3.png b/assets/dolphin/animations/recording/frame_3.png deleted file mode 100644 index 282188f7..00000000 Binary files a/assets/dolphin/animations/recording/frame_3.png and /dev/null differ diff --git a/assets/dolphin/animations/recording/frame_4.png b/assets/dolphin/animations/recording/frame_4.png deleted file mode 100644 index 2c4ab7c9..00000000 Binary files a/assets/dolphin/animations/recording/frame_4.png and /dev/null differ diff --git a/assets/dolphin/animations/recording/frame_5.png b/assets/dolphin/animations/recording/frame_5.png deleted file mode 100644 index d7934598..00000000 Binary files a/assets/dolphin/animations/recording/frame_5.png and /dev/null differ diff --git a/assets/dolphin/animations/recording/frame_9.png b/assets/dolphin/animations/recording/frame_9.png deleted file mode 100644 index becd0fd4..00000000 Binary files a/assets/dolphin/animations/recording/frame_9.png and /dev/null differ diff --git a/assets/dolphin/blocking/L0_NewMail_128x51/frame_0.png b/assets/dolphin/blocking/L0_NewMail_128x51/frame_0.png new file mode 100644 index 00000000..5f7f5fa4 Binary files /dev/null and b/assets/dolphin/blocking/L0_NewMail_128x51/frame_0.png differ diff --git a/assets/dolphin/blocking/L0_NewMail_128x51/frame_1.png b/assets/dolphin/blocking/L0_NewMail_128x51/frame_1.png new file mode 100644 index 00000000..db9bf227 Binary files /dev/null and b/assets/dolphin/blocking/L0_NewMail_128x51/frame_1.png differ diff --git a/assets/dolphin/blocking/L0_NewMail_128x51/frame_2.png b/assets/dolphin/blocking/L0_NewMail_128x51/frame_2.png new file mode 100644 index 00000000..5394851f Binary files /dev/null and b/assets/dolphin/blocking/L0_NewMail_128x51/frame_2.png differ diff --git a/assets/dolphin/blocking/L0_NewMail_128x51/frame_3.png b/assets/dolphin/blocking/L0_NewMail_128x51/frame_3.png new file mode 100644 index 00000000..d16966fb Binary files /dev/null and b/assets/dolphin/blocking/L0_NewMail_128x51/frame_3.png differ diff --git a/assets/dolphin/blocking/L0_NewMail_128x51/meta.txt b/assets/dolphin/blocking/L0_NewMail_128x51/meta.txt new file mode 100644 index 00000000..82c9abe1 --- /dev/null +++ b/assets/dolphin/blocking/L0_NewMail_128x51/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 51 +Passive frames: 6 +Active frames: 0 +Frames order: 0 1 2 3 2 1 +Active cycles: 0 +Frame rate: 2 +Duration: 0 +Active cooldown: 0 + +Bubble slots: 0 \ No newline at end of file diff --git a/assets/icons/Animations/no_databases1.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_0.png similarity index 100% rename from assets/icons/Animations/no_databases1.png rename to assets/dolphin/blocking/L0_NoDb_128x51/frame_0.png diff --git a/assets/icons/Animations/no_databases2.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_1.png similarity index 100% rename from assets/icons/Animations/no_databases2.png rename to assets/dolphin/blocking/L0_NoDb_128x51/frame_1.png diff --git a/assets/icons/Animations/no_databases3.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_2.png similarity index 100% rename from assets/icons/Animations/no_databases3.png rename to assets/dolphin/blocking/L0_NoDb_128x51/frame_2.png diff --git a/assets/icons/Animations/no_databases4.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_3.png similarity index 100% rename from assets/icons/Animations/no_databases4.png rename to assets/dolphin/blocking/L0_NoDb_128x51/frame_3.png diff --git a/assets/dolphin/blocking/L0_NoDb_128x51/meta.txt b/assets/dolphin/blocking/L0_NoDb_128x51/meta.txt new file mode 100644 index 00000000..2c8d9871 --- /dev/null +++ b/assets/dolphin/blocking/L0_NoDb_128x51/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 51 +Passive frames: 4 +Active frames: 0 +Frames order: 0 1 2 3 +Active cycles: 0 +Frame rate: 2 +Duration: 0 +Active cooldown: 0 + +Bubble slots: 0 diff --git a/assets/icons/Animations/card_bad1.png b/assets/dolphin/blocking/L0_SdBad_128x51/frame_0.png similarity index 100% rename from assets/icons/Animations/card_bad1.png rename to assets/dolphin/blocking/L0_SdBad_128x51/frame_0.png diff --git a/assets/icons/Animations/card_bad2.png b/assets/dolphin/blocking/L0_SdBad_128x51/frame_1.png similarity index 100% rename from assets/icons/Animations/card_bad2.png rename to assets/dolphin/blocking/L0_SdBad_128x51/frame_1.png diff --git a/assets/dolphin/blocking/L0_SdBad_128x51/meta.txt b/assets/dolphin/blocking/L0_SdBad_128x51/meta.txt new file mode 100644 index 00000000..3248d17a --- /dev/null +++ b/assets/dolphin/blocking/L0_SdBad_128x51/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 51 +Passive frames: 2 +Active frames: 0 +Frames order: 0 1 +Active cycles: 0 +Frame rate: 2 +Duration: 0 +Active cooldown: 0 + +Bubble slots: 0 diff --git a/assets/icons/Animations/card_ok1.png b/assets/dolphin/blocking/L0_SdOk_128x51/frame_0.png similarity index 100% rename from assets/icons/Animations/card_ok1.png rename to assets/dolphin/blocking/L0_SdOk_128x51/frame_0.png diff --git a/assets/icons/Animations/card_ok2.png b/assets/dolphin/blocking/L0_SdOk_128x51/frame_1.png similarity index 100% rename from assets/icons/Animations/card_ok2.png rename to assets/dolphin/blocking/L0_SdOk_128x51/frame_1.png diff --git a/assets/icons/Animations/card_ok3.png b/assets/dolphin/blocking/L0_SdOk_128x51/frame_2.png similarity index 100% rename from assets/icons/Animations/card_ok3.png rename to assets/dolphin/blocking/L0_SdOk_128x51/frame_2.png diff --git a/assets/icons/Animations/card_ok4.png b/assets/dolphin/blocking/L0_SdOk_128x51/frame_3.png similarity index 100% rename from assets/icons/Animations/card_ok4.png rename to assets/dolphin/blocking/L0_SdOk_128x51/frame_3.png diff --git a/assets/dolphin/blocking/L0_SdOk_128x51/meta.txt b/assets/dolphin/blocking/L0_SdOk_128x51/meta.txt new file mode 100644 index 00000000..2c8d9871 --- /dev/null +++ b/assets/dolphin/blocking/L0_SdOk_128x51/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 51 +Passive frames: 4 +Active frames: 0 +Frames order: 0 1 2 3 +Active cycles: 0 +Frame rate: 2 +Duration: 0 +Active cooldown: 0 + +Bubble slots: 0 diff --git a/assets/icons/Animations/url1.png b/assets/dolphin/blocking/L0_Url_128x51/frame_0.png similarity index 100% rename from assets/icons/Animations/url1.png rename to assets/dolphin/blocking/L0_Url_128x51/frame_0.png diff --git a/assets/icons/Animations/url2.png b/assets/dolphin/blocking/L0_Url_128x51/frame_1.png similarity index 100% rename from assets/icons/Animations/url2.png rename to assets/dolphin/blocking/L0_Url_128x51/frame_1.png diff --git a/assets/icons/Animations/url3.png b/assets/dolphin/blocking/L0_Url_128x51/frame_2.png similarity index 100% rename from assets/icons/Animations/url3.png rename to assets/dolphin/blocking/L0_Url_128x51/frame_2.png diff --git a/assets/icons/Animations/url4.png b/assets/dolphin/blocking/L0_Url_128x51/frame_3.png similarity index 100% rename from assets/icons/Animations/url4.png rename to assets/dolphin/blocking/L0_Url_128x51/frame_3.png diff --git a/assets/dolphin/blocking/L0_Url_128x51/meta.txt b/assets/dolphin/blocking/L0_Url_128x51/meta.txt new file mode 100644 index 00000000..2c8d9871 --- /dev/null +++ b/assets/dolphin/blocking/L0_Url_128x51/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 51 +Passive frames: 4 +Active frames: 0 +Frames order: 0 1 2 3 +Active cycles: 0 +Frame rate: 2 +Duration: 0 +Active cooldown: 0 + +Bubble slots: 0 diff --git a/assets/dolphin/blocking/manifest.txt b/assets/dolphin/blocking/manifest.txt new file mode 100644 index 00000000..b646b9ec --- /dev/null +++ b/assets/dolphin/blocking/manifest.txt @@ -0,0 +1,42 @@ +Filetype: Flipper Animation Manifest +Version: 1 + +# Animation 1 +Name: L0_NoDb_128x51 +Min butthurt: 0 +Max butthurt: 0 +Min level: 0 +Max level: 0 +Weight: 0 + +# Animation 2 +Name: L0_SdBad_128x51 +Min butthurt: 0 +Max butthurt: 0 +Min level: 0 +Max level: 0 +Weight: 0 + +# Animation 3 +Name: L0_SdOk_128x51 +Min butthurt: 0 +Max butthurt: 0 +Min level: 0 +Max level: 0 +Weight: 0 + +# Animation 4 +Name: L0_Url_128x51 +Min butthurt: 0 +Max butthurt: 0 +Min level: 0 +Max level: 0 +Weight: 0 + +# Animation 5 +Name: L0_NewMail_128x51 +Min butthurt: 0 +Max butthurt: 0 +Min level: 0 +Max level: 0 +Weight: 0 diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_0.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_0.png new file mode 100644 index 00000000..396ec251 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_1.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_1.png new file mode 100644 index 00000000..2a497f85 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_10.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_10.png new file mode 100644 index 00000000..d33f1e41 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_11.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_11.png new file mode 100644 index 00000000..e5ee82f7 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_12.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_12.png new file mode 100644 index 00000000..f3059dde Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_13.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_13.png new file mode 100644 index 00000000..5d1ff45b Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_14.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_14.png new file mode 100644 index 00000000..d46f62e8 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_15.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_15.png new file mode 100644 index 00000000..ec11dbd0 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_16.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_16.png new file mode 100644 index 00000000..720e95f9 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_17.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_17.png new file mode 100644 index 00000000..7debe764 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_18.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_18.png new file mode 100644 index 00000000..d3674a02 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_2.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_2.png new file mode 100644 index 00000000..ba443515 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_3.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_3.png new file mode 100644 index 00000000..c0ee4162 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_4.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_4.png new file mode 100644 index 00000000..ecda8127 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_5.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_5.png new file mode 100644 index 00000000..e8662b2e Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_6.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_6.png new file mode 100644 index 00000000..29cadd14 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_7.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_7.png new file mode 100644 index 00000000..18e793b5 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_8.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_8.png new file mode 100644 index 00000000..34b2e400 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_9.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_9.png new file mode 100644 index 00000000..d192f2e3 Binary files /dev/null and b/assets/dolphin/external/L1_Furippa1_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/meta.txt b/assets/dolphin/external/L1_Furippa1_128x64/meta.txt new file mode 100644 index 00000000..c21027e4 --- /dev/null +++ b/assets/dolphin/external/L1_Furippa1_128x64/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 64 +Passive frames: 8 +Active frames: 11 +Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 +Active cycles: 1 +Frame rate: 2 +Duration: 3600 +Active cooldown: 7 + +Bubble slots: 0 diff --git a/assets/dolphin/animations/laptop/frame_0.png b/assets/dolphin/external/L1_Laptop_128x51/frame_0.png similarity index 100% rename from assets/dolphin/animations/laptop/frame_0.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_0.png diff --git a/assets/dolphin/animations/laptop/frame_1.png b/assets/dolphin/external/L1_Laptop_128x51/frame_1.png similarity index 100% rename from assets/dolphin/animations/laptop/frame_1.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_1.png diff --git a/assets/dolphin/animations/laptop/frame_2.png b/assets/dolphin/external/L1_Laptop_128x51/frame_2.png similarity index 100% rename from assets/dolphin/animations/laptop/frame_2.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_2.png diff --git a/assets/dolphin/animations/laptop/frame_3.png b/assets/dolphin/external/L1_Laptop_128x51/frame_3.png similarity index 100% rename from assets/dolphin/animations/laptop/frame_3.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_3.png diff --git a/assets/dolphin/animations/laptop/frame_4.png b/assets/dolphin/external/L1_Laptop_128x51/frame_4.png similarity index 100% rename from assets/dolphin/animations/laptop/frame_4.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_4.png diff --git a/assets/dolphin/animations/laptop/frame_5.png b/assets/dolphin/external/L1_Laptop_128x51/frame_5.png similarity index 100% rename from assets/dolphin/animations/laptop/frame_5.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_5.png diff --git a/assets/dolphin/animations/laptop/frame_6.png b/assets/dolphin/external/L1_Laptop_128x51/frame_6.png similarity index 100% rename from assets/dolphin/animations/laptop/frame_6.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_6.png diff --git a/assets/dolphin/animations/laptop/frame_7.png b/assets/dolphin/external/L1_Laptop_128x51/frame_7.png similarity index 100% rename from assets/dolphin/animations/laptop/frame_7.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_7.png diff --git a/assets/resources/dolphin/animations/laptop/meta.txt b/assets/dolphin/external/L1_Laptop_128x51/meta.txt similarity index 80% rename from assets/resources/dolphin/animations/laptop/meta.txt rename to assets/dolphin/external/L1_Laptop_128x51/meta.txt index 56d1e5b9..90cdc5ce 100644 --- a/assets/resources/dolphin/animations/laptop/meta.txt +++ b/assets/dolphin/external/L1_Laptop_128x51/meta.txt @@ -6,10 +6,10 @@ Height: 51 Passive frames: 6 Active frames: 2 Frames order: 0 1 2 3 4 5 6 7 -Active cycles: 3 +Active cycles: 4 Frame rate: 2 Duration: 3600 -Active cooldown: 5 +Active cooldown: 7 Bubble slots: 1 @@ -20,7 +20,7 @@ Text: I have to rest AlignH: Left AlignV: Bottom StartFrame: 7 -EndFrame: 9 +EndFrame: 10 Slot: 0 X: 60 @@ -28,5 +28,5 @@ Y: 23 Text: but not today AlignH: Left AlignV: Bottom -StartFrame: 10 -EndFrame: 12 \ No newline at end of file +StartFrame: 11 +EndFrame: 13 diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_0.png b/assets/dolphin/external/L1_Recording_128x51/frame_0.png new file mode 100644 index 00000000..ed0f030b Binary files /dev/null and b/assets/dolphin/external/L1_Recording_128x51/frame_0.png differ diff --git a/assets/dolphin/animations/recording/frame_1.png b/assets/dolphin/external/L1_Recording_128x51/frame_1.png similarity index 72% rename from assets/dolphin/animations/recording/frame_1.png rename to assets/dolphin/external/L1_Recording_128x51/frame_1.png index c4bac194..f3b3f8a9 100644 Binary files a/assets/dolphin/animations/recording/frame_1.png and b/assets/dolphin/external/L1_Recording_128x51/frame_1.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_10.png b/assets/dolphin/external/L1_Recording_128x51/frame_10.png new file mode 100644 index 00000000..a474c214 Binary files /dev/null and b/assets/dolphin/external/L1_Recording_128x51/frame_10.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_11.png b/assets/dolphin/external/L1_Recording_128x51/frame_11.png new file mode 100644 index 00000000..cf654afb Binary files /dev/null and b/assets/dolphin/external/L1_Recording_128x51/frame_11.png differ diff --git a/assets/dolphin/animations/recording/frame_2.png b/assets/dolphin/external/L1_Recording_128x51/frame_2.png similarity index 84% rename from assets/dolphin/animations/recording/frame_2.png rename to assets/dolphin/external/L1_Recording_128x51/frame_2.png index f14fc60c..f61e59ef 100644 Binary files a/assets/dolphin/animations/recording/frame_2.png and b/assets/dolphin/external/L1_Recording_128x51/frame_2.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_3.png b/assets/dolphin/external/L1_Recording_128x51/frame_3.png new file mode 100644 index 00000000..87e297b2 Binary files /dev/null and b/assets/dolphin/external/L1_Recording_128x51/frame_3.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_4.png b/assets/dolphin/external/L1_Recording_128x51/frame_4.png new file mode 100644 index 00000000..62428a40 Binary files /dev/null and b/assets/dolphin/external/L1_Recording_128x51/frame_4.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_5.png b/assets/dolphin/external/L1_Recording_128x51/frame_5.png new file mode 100644 index 00000000..93953024 Binary files /dev/null and b/assets/dolphin/external/L1_Recording_128x51/frame_5.png differ diff --git a/assets/dolphin/animations/recording/frame_6.png b/assets/dolphin/external/L1_Recording_128x51/frame_6.png similarity index 85% rename from assets/dolphin/animations/recording/frame_6.png rename to assets/dolphin/external/L1_Recording_128x51/frame_6.png index ea73c361..942f082b 100644 Binary files a/assets/dolphin/animations/recording/frame_6.png and b/assets/dolphin/external/L1_Recording_128x51/frame_6.png differ diff --git a/assets/dolphin/animations/recording/frame_7.png b/assets/dolphin/external/L1_Recording_128x51/frame_7.png similarity index 84% rename from assets/dolphin/animations/recording/frame_7.png rename to assets/dolphin/external/L1_Recording_128x51/frame_7.png index 23c31d54..84ce00d2 100644 Binary files a/assets/dolphin/animations/recording/frame_7.png and b/assets/dolphin/external/L1_Recording_128x51/frame_7.png differ diff --git a/assets/dolphin/animations/recording/frame_8.png b/assets/dolphin/external/L1_Recording_128x51/frame_8.png similarity index 85% rename from assets/dolphin/animations/recording/frame_8.png rename to assets/dolphin/external/L1_Recording_128x51/frame_8.png index 63e29fb6..f6f45552 100644 Binary files a/assets/dolphin/animations/recording/frame_8.png and b/assets/dolphin/external/L1_Recording_128x51/frame_8.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_9.png b/assets/dolphin/external/L1_Recording_128x51/frame_9.png new file mode 100644 index 00000000..dcd3aa0b Binary files /dev/null and b/assets/dolphin/external/L1_Recording_128x51/frame_9.png differ diff --git a/assets/resources/dolphin/animations/recording/meta.txt b/assets/dolphin/external/L1_Recording_128x51/meta.txt similarity index 84% rename from assets/resources/dolphin/animations/recording/meta.txt rename to assets/dolphin/external/L1_Recording_128x51/meta.txt index bb9a0ca4..de37d5b2 100644 --- a/assets/resources/dolphin/animations/recording/meta.txt +++ b/assets/dolphin/external/L1_Recording_128x51/meta.txt @@ -6,9 +6,9 @@ Height: 51 Passive frames: 6 Active frames: 6 Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 -Active cycles: 2 +Active cycles: 1 Frame rate: 2 Duration: 3600 Active cooldown: 5 -Bubble slots: 0 \ No newline at end of file +Bubble slots: 0 diff --git a/assets/dolphin/animations/sleep/frame_0.png b/assets/dolphin/external/L1_Sleep_128x64/frame_0.png similarity index 100% rename from assets/dolphin/animations/sleep/frame_0.png rename to assets/dolphin/external/L1_Sleep_128x64/frame_0.png diff --git a/assets/dolphin/animations/sleep/frame_1.png b/assets/dolphin/external/L1_Sleep_128x64/frame_1.png similarity index 100% rename from assets/dolphin/animations/sleep/frame_1.png rename to assets/dolphin/external/L1_Sleep_128x64/frame_1.png diff --git a/assets/dolphin/animations/sleep/frame_2.png b/assets/dolphin/external/L1_Sleep_128x64/frame_2.png similarity index 100% rename from assets/dolphin/animations/sleep/frame_2.png rename to assets/dolphin/external/L1_Sleep_128x64/frame_2.png diff --git a/assets/dolphin/animations/sleep/frame_3.png b/assets/dolphin/external/L1_Sleep_128x64/frame_3.png similarity index 100% rename from assets/dolphin/animations/sleep/frame_3.png rename to assets/dolphin/external/L1_Sleep_128x64/frame_3.png diff --git a/assets/dolphin/animations/sleep/meta.txt b/assets/dolphin/external/L1_Sleep_128x64/meta.txt similarity index 100% rename from assets/dolphin/animations/sleep/meta.txt rename to assets/dolphin/external/L1_Sleep_128x64/meta.txt diff --git a/assets/dolphin/animations/waves/frame_0.png b/assets/dolphin/external/L1_Waves_128x50/frame_0.png similarity index 100% rename from assets/dolphin/animations/waves/frame_0.png rename to assets/dolphin/external/L1_Waves_128x50/frame_0.png diff --git a/assets/dolphin/animations/waves/frame_1.png b/assets/dolphin/external/L1_Waves_128x50/frame_1.png similarity index 100% rename from assets/dolphin/animations/waves/frame_1.png rename to assets/dolphin/external/L1_Waves_128x50/frame_1.png diff --git a/assets/dolphin/animations/waves/frame_2.png b/assets/dolphin/external/L1_Waves_128x50/frame_2.png similarity index 100% rename from assets/dolphin/animations/waves/frame_2.png rename to assets/dolphin/external/L1_Waves_128x50/frame_2.png diff --git a/assets/dolphin/animations/waves/frame_3.png b/assets/dolphin/external/L1_Waves_128x50/frame_3.png similarity index 100% rename from assets/dolphin/animations/waves/frame_3.png rename to assets/dolphin/external/L1_Waves_128x50/frame_3.png diff --git a/assets/dolphin/animations/waves/meta.txt b/assets/dolphin/external/L1_Waves_128x50/meta.txt similarity index 100% rename from assets/dolphin/animations/waves/meta.txt rename to assets/dolphin/external/L1_Waves_128x50/meta.txt diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_0.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_0.png new file mode 100644 index 00000000..43b26283 Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_1.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_1.png new file mode 100644 index 00000000..fecba5ad Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_10.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_10.png new file mode 100644 index 00000000..3c15e7cc Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_11.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_11.png new file mode 100644 index 00000000..0f293281 Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_12.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_12.png new file mode 100644 index 00000000..733962d3 Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_13.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_13.png new file mode 100644 index 00000000..4b7ed184 Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_14.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_14.png new file mode 100644 index 00000000..1efff0f2 Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_15.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_15.png new file mode 100644 index 00000000..f2d76409 Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_16.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_16.png new file mode 100644 index 00000000..125fb98f Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_17.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_17.png new file mode 100644 index 00000000..3a4a5f5a Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_18.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_18.png new file mode 100644 index 00000000..13dd3485 Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_2.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_2.png new file mode 100644 index 00000000..ef3150fd Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_3.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_3.png new file mode 100644 index 00000000..537ab523 Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_4.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_4.png new file mode 100644 index 00000000..87357012 Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_5.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_5.png new file mode 100644 index 00000000..dbbeb1fe Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_6.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_6.png new file mode 100644 index 00000000..d1808502 Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_7.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_7.png new file mode 100644 index 00000000..24f9333f Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_8.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_8.png new file mode 100644 index 00000000..30b97cdf Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_9.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_9.png new file mode 100644 index 00000000..7ceead05 Binary files /dev/null and b/assets/dolphin/external/L2_Furippa2_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/meta.txt b/assets/dolphin/external/L2_Furippa2_128x64/meta.txt new file mode 100644 index 00000000..c21027e4 --- /dev/null +++ b/assets/dolphin/external/L2_Furippa2_128x64/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 64 +Passive frames: 8 +Active frames: 11 +Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 +Active cycles: 1 +Frame rate: 2 +Duration: 3600 +Active cooldown: 7 + +Bubble slots: 0 diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_0.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_0.png new file mode 100644 index 00000000..3b82285e Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_1.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_1.png new file mode 100644 index 00000000..7af08829 Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_10.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_10.png new file mode 100644 index 00000000..0ef6d471 Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_11.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_11.png new file mode 100644 index 00000000..e6f397eb Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_12.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_12.png new file mode 100644 index 00000000..9221fb15 Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_13.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_13.png new file mode 100644 index 00000000..e43b1edb Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_14.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_14.png new file mode 100644 index 00000000..64da8d8f Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_15.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_15.png new file mode 100644 index 00000000..96b19669 Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_16.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_16.png new file mode 100644 index 00000000..620dbca2 Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_17.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_17.png new file mode 100644 index 00000000..49aa979d Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_18.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_18.png new file mode 100644 index 00000000..7739e294 Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_2.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_2.png new file mode 100644 index 00000000..c36e54b2 Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_3.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_3.png new file mode 100644 index 00000000..dce96b74 Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_4.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_4.png new file mode 100644 index 00000000..2c096689 Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_5.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_5.png new file mode 100644 index 00000000..79271997 Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_6.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_6.png new file mode 100644 index 00000000..689e7dd7 Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_7.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_7.png new file mode 100644 index 00000000..7b468ab8 Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_8.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_8.png new file mode 100644 index 00000000..e9246c0b Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_9.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_9.png new file mode 100644 index 00000000..c2e164c5 Binary files /dev/null and b/assets/dolphin/external/L3_Furippa3_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/meta.txt b/assets/dolphin/external/L3_Furippa3_128x64/meta.txt new file mode 100644 index 00000000..c21027e4 --- /dev/null +++ b/assets/dolphin/external/L3_Furippa3_128x64/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 64 +Passive frames: 8 +Active frames: 11 +Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 +Active cycles: 1 +Frame rate: 2 +Duration: 3600 +Active cooldown: 7 + +Bubble slots: 0 diff --git a/assets/dolphin/external/manifest.txt b/assets/dolphin/external/manifest.txt new file mode 100644 index 00000000..d5a8e2a1 --- /dev/null +++ b/assets/dolphin/external/manifest.txt @@ -0,0 +1,58 @@ +Filetype: Flipper Animation Manifest +Version: 1 + +# Animation 1 +Name: L1_Waves_128x50 +Min butthurt: 0 +Max butthurt: 5 +Min level: 1 +Max level: 3 +Weight: 3 + +# Animation 2 +Name: L1_Laptop_128x51 +Min butthurt: 0 +Max butthurt: 9 +Min level: 1 +Max level: 3 +Weight: 3 + +# Animation 3 +Name: L1_Sleep_128x64 +Min butthurt: 0 +Max butthurt: 10 +Min level: 1 +Max level: 3 +Weight: 3 + +# Animation 4 +Name: L1_Recording_128x51 +Min butthurt: 0 +Max butthurt: 8 +Min level: 1 +Max level: 1 +Weight: 3 + +# Animation 5 +Name: L1_Furippa1_128x64 +Min butthurt: 0 +Max butthurt: 6 +Min level: 1 +Max level: 1 +Weight: 3 + +# Animation 6 +Name: L2_Furippa2_128x64 +Min butthurt: 0 +Max butthurt: 6 +Min level: 2 +Max level: 2 +Weight: 3 + +# Animation 7 +Name: L3_Furippa3_128x64 +Min butthurt: 0 +Max butthurt: 6 +Min level: 3 +Max level: 3 +Weight: 3 diff --git a/assets/dolphin/internal/L1_BadBattery_128x47/frame_0.png b/assets/dolphin/internal/L1_BadBattery_128x47/frame_0.png new file mode 100644 index 00000000..7d3f3dcd Binary files /dev/null and b/assets/dolphin/internal/L1_BadBattery_128x47/frame_0.png differ diff --git a/assets/dolphin/internal/L1_BadBattery_128x47/frame_1.png b/assets/dolphin/internal/L1_BadBattery_128x47/frame_1.png new file mode 100644 index 00000000..98c2979c Binary files /dev/null and b/assets/dolphin/internal/L1_BadBattery_128x47/frame_1.png differ diff --git a/assets/dolphin/internal/L1_BadBattery_128x47/meta.txt b/assets/dolphin/internal/L1_BadBattery_128x47/meta.txt new file mode 100644 index 00000000..ab19e10d --- /dev/null +++ b/assets/dolphin/internal/L1_BadBattery_128x47/meta.txt @@ -0,0 +1,23 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 47 +Passive frames: 2 +Active frames: 0 +Frames order: 0 1 +Active cycles: 0 +Frame rate: 2 +Duration: 3600 +Active cooldown: 0 + +Bubble slots: 1 + +Slot: 0 +X: 4 +Y: 21 +Text: I feel so sick!\nI'm dying... +AlignH: Right +AlignV: Center +StartFrame: 0 +EndFrame: 1 diff --git a/assets/icons/Animations/no_sd1.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_0.png similarity index 100% rename from assets/icons/Animations/no_sd1.png rename to assets/dolphin/internal/L1_NoSd_128x49/frame_0.png diff --git a/assets/icons/Animations/no_sd2.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_1.png similarity index 100% rename from assets/icons/Animations/no_sd2.png rename to assets/dolphin/internal/L1_NoSd_128x49/frame_1.png diff --git a/assets/icons/Animations/no_sd3.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_2.png similarity index 100% rename from assets/icons/Animations/no_sd3.png rename to assets/dolphin/internal/L1_NoSd_128x49/frame_2.png diff --git a/assets/icons/Animations/no_sd4.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_3.png similarity index 100% rename from assets/icons/Animations/no_sd4.png rename to assets/dolphin/internal/L1_NoSd_128x49/frame_3.png diff --git a/assets/icons/Animations/no_sd5.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_4.png similarity index 100% rename from assets/icons/Animations/no_sd5.png rename to assets/dolphin/internal/L1_NoSd_128x49/frame_4.png diff --git a/assets/icons/Animations/no_sd6.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_5.png similarity index 100% rename from assets/icons/Animations/no_sd6.png rename to assets/dolphin/internal/L1_NoSd_128x49/frame_5.png diff --git a/assets/dolphin/internal/L1_NoSd_128x49/meta.txt b/assets/dolphin/internal/L1_NoSd_128x49/meta.txt new file mode 100644 index 00000000..08b1f9d9 --- /dev/null +++ b/assets/dolphin/internal/L1_NoSd_128x49/meta.txt @@ -0,0 +1,23 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 49 +Passive frames: 10 +Active frames: 0 +Frames order: 0 1 0 1 0 2 3 4 3 5 +Active cycles: 0 +Frame rate: 2 +Duration: 3600 +Active cooldown: 0 + +Bubble slots: 1 + +Slot: 0 +X: 40 +Y: 18 +Text: Need an\nSD card +AlignH: Right +AlignV: Bottom +StartFrame: 0 +EndFrame: 9 diff --git a/assets/icons/Animations/tv1.png b/assets/dolphin/internal/L1_Tv_128x47/frame_0.png similarity index 100% rename from assets/icons/Animations/tv1.png rename to assets/dolphin/internal/L1_Tv_128x47/frame_0.png diff --git a/assets/icons/Animations/tv2.png b/assets/dolphin/internal/L1_Tv_128x47/frame_1.png similarity index 100% rename from assets/icons/Animations/tv2.png rename to assets/dolphin/internal/L1_Tv_128x47/frame_1.png diff --git a/assets/icons/Animations/tv3.png b/assets/dolphin/internal/L1_Tv_128x47/frame_2.png similarity index 100% rename from assets/icons/Animations/tv3.png rename to assets/dolphin/internal/L1_Tv_128x47/frame_2.png diff --git a/assets/icons/Animations/tv4.png b/assets/dolphin/internal/L1_Tv_128x47/frame_3.png similarity index 100% rename from assets/icons/Animations/tv4.png rename to assets/dolphin/internal/L1_Tv_128x47/frame_3.png diff --git a/assets/icons/Animations/tv5.png b/assets/dolphin/internal/L1_Tv_128x47/frame_4.png similarity index 100% rename from assets/icons/Animations/tv5.png rename to assets/dolphin/internal/L1_Tv_128x47/frame_4.png diff --git a/assets/icons/Animations/tv6.png b/assets/dolphin/internal/L1_Tv_128x47/frame_5.png similarity index 100% rename from assets/icons/Animations/tv6.png rename to assets/dolphin/internal/L1_Tv_128x47/frame_5.png diff --git a/assets/icons/Animations/tv7.png b/assets/dolphin/internal/L1_Tv_128x47/frame_6.png similarity index 100% rename from assets/icons/Animations/tv7.png rename to assets/dolphin/internal/L1_Tv_128x47/frame_6.png diff --git a/assets/icons/Animations/tv8.png b/assets/dolphin/internal/L1_Tv_128x47/frame_7.png similarity index 100% rename from assets/icons/Animations/tv8.png rename to assets/dolphin/internal/L1_Tv_128x47/frame_7.png diff --git a/assets/dolphin/internal/L1_Tv_128x47/meta.txt b/assets/dolphin/internal/L1_Tv_128x47/meta.txt new file mode 100644 index 00000000..93f598e8 --- /dev/null +++ b/assets/dolphin/internal/L1_Tv_128x47/meta.txt @@ -0,0 +1,32 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 47 +Passive frames: 6 +Active frames: 2 +Frames order: 0 1 2 3 4 5 6 7 +Active cycles: 2 +Frame rate: 2 +Duration: 3600 +Active cooldown: 5 + +Bubble slots: 2 + +Slot: 0 +X: 1 +Y: 23 +Text: Take the red pill +AlignH: Right +AlignV: Bottom +StartFrame: 7 +EndFrame: 9 + +Slot: 1 +X: 1 +Y: 23 +Text: I can joke better +AlignH: Right +AlignV: Bottom +StartFrame: 7 +EndFrame: 9 diff --git a/assets/dolphin/animations/manifest.txt b/assets/dolphin/internal/manifest.txt similarity index 55% rename from assets/dolphin/animations/manifest.txt rename to assets/dolphin/internal/manifest.txt index 85d5b45d..8ae579de 100644 --- a/assets/dolphin/animations/manifest.txt +++ b/assets/dolphin/internal/manifest.txt @@ -2,33 +2,26 @@ Filetype: Flipper Animation Manifest Version: 1 # Animation 1 -Name: waves +Name: L1_Tv_128x47 Min butthurt: 0 -Max butthurt: 5 +Max butthurt: 14 Min level: 1 Max level: 3 Weight: 3 # Animation 2 -Name: laptop +Name: L1_BadBattery_128x47 Min butthurt: 0 -Max butthurt: 9 +Max butthurt: 14 Min level: 1 Max level: 3 Weight: 3 # Animation 3 -Name: sleep +Name: L1_NoSd_128x49 Min butthurt: 0 -Max butthurt: 10 +Max butthurt: 14 Min level: 1 Max level: 3 -Weight: 3 +Weight: 6 -# Animation 4 -Name: recording -Min butthurt: 0 -Max butthurt: 8 -Min level: 1 -Max level: 1 -Weight: 3 \ No newline at end of file diff --git a/assets/icons/Animations/Levelup1_128x64/frame_00.png b/assets/icons/Animations/Levelup1_128x64/frame_00.png new file mode 100644 index 00000000..bf97f8d6 Binary files /dev/null and b/assets/icons/Animations/Levelup1_128x64/frame_00.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_01.png b/assets/icons/Animations/Levelup1_128x64/frame_01.png new file mode 100644 index 00000000..39c910d3 Binary files /dev/null and b/assets/icons/Animations/Levelup1_128x64/frame_01.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_02.png b/assets/icons/Animations/Levelup1_128x64/frame_02.png new file mode 100644 index 00000000..4975adf8 Binary files /dev/null and b/assets/icons/Animations/Levelup1_128x64/frame_02.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_03.png b/assets/icons/Animations/Levelup1_128x64/frame_03.png new file mode 100644 index 00000000..5a05529c Binary files /dev/null and b/assets/icons/Animations/Levelup1_128x64/frame_03.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_04.png b/assets/icons/Animations/Levelup1_128x64/frame_04.png new file mode 100644 index 00000000..e6c88df9 Binary files /dev/null and b/assets/icons/Animations/Levelup1_128x64/frame_04.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_05.png b/assets/icons/Animations/Levelup1_128x64/frame_05.png new file mode 100644 index 00000000..e7bae4d6 Binary files /dev/null and b/assets/icons/Animations/Levelup1_128x64/frame_05.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_06.png b/assets/icons/Animations/Levelup1_128x64/frame_06.png new file mode 100644 index 00000000..489bce36 Binary files /dev/null and b/assets/icons/Animations/Levelup1_128x64/frame_06.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_07.png b/assets/icons/Animations/Levelup1_128x64/frame_07.png new file mode 100644 index 00000000..32e864e9 Binary files /dev/null and b/assets/icons/Animations/Levelup1_128x64/frame_07.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_08.png b/assets/icons/Animations/Levelup1_128x64/frame_08.png new file mode 100644 index 00000000..c692f489 Binary files /dev/null and b/assets/icons/Animations/Levelup1_128x64/frame_08.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_09.png b/assets/icons/Animations/Levelup1_128x64/frame_09.png new file mode 100644 index 00000000..fb1c8bb9 Binary files /dev/null and b/assets/icons/Animations/Levelup1_128x64/frame_09.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_10.png b/assets/icons/Animations/Levelup1_128x64/frame_10.png new file mode 100644 index 00000000..3b0205a4 Binary files /dev/null and b/assets/icons/Animations/Levelup1_128x64/frame_10.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_rate b/assets/icons/Animations/Levelup1_128x64/frame_rate new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/assets/icons/Animations/Levelup1_128x64/frame_rate @@ -0,0 +1 @@ +2 diff --git a/assets/icons/Animations/Levelup2_128x64/frame_00.png b/assets/icons/Animations/Levelup2_128x64/frame_00.png new file mode 100644 index 00000000..77b53107 Binary files /dev/null and b/assets/icons/Animations/Levelup2_128x64/frame_00.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_01.png b/assets/icons/Animations/Levelup2_128x64/frame_01.png new file mode 100644 index 00000000..b5343726 Binary files /dev/null and b/assets/icons/Animations/Levelup2_128x64/frame_01.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_02.png b/assets/icons/Animations/Levelup2_128x64/frame_02.png new file mode 100644 index 00000000..9623af7d Binary files /dev/null and b/assets/icons/Animations/Levelup2_128x64/frame_02.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_03.png b/assets/icons/Animations/Levelup2_128x64/frame_03.png new file mode 100644 index 00000000..f1826901 Binary files /dev/null and b/assets/icons/Animations/Levelup2_128x64/frame_03.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_04.png b/assets/icons/Animations/Levelup2_128x64/frame_04.png new file mode 100644 index 00000000..677a3367 Binary files /dev/null and b/assets/icons/Animations/Levelup2_128x64/frame_04.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_05.png b/assets/icons/Animations/Levelup2_128x64/frame_05.png new file mode 100644 index 00000000..fb58fed1 Binary files /dev/null and b/assets/icons/Animations/Levelup2_128x64/frame_05.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_06.png b/assets/icons/Animations/Levelup2_128x64/frame_06.png new file mode 100644 index 00000000..b2cbd699 Binary files /dev/null and b/assets/icons/Animations/Levelup2_128x64/frame_06.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_07.png b/assets/icons/Animations/Levelup2_128x64/frame_07.png new file mode 100644 index 00000000..4f3dfc8c Binary files /dev/null and b/assets/icons/Animations/Levelup2_128x64/frame_07.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_08.png b/assets/icons/Animations/Levelup2_128x64/frame_08.png new file mode 100644 index 00000000..3a5a2880 Binary files /dev/null and b/assets/icons/Animations/Levelup2_128x64/frame_08.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_09.png b/assets/icons/Animations/Levelup2_128x64/frame_09.png new file mode 100644 index 00000000..76267a2a Binary files /dev/null and b/assets/icons/Animations/Levelup2_128x64/frame_09.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_10.png b/assets/icons/Animations/Levelup2_128x64/frame_10.png new file mode 100644 index 00000000..bda1bf44 Binary files /dev/null and b/assets/icons/Animations/Levelup2_128x64/frame_10.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_rate b/assets/icons/Animations/Levelup2_128x64/frame_rate new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/assets/icons/Animations/Levelup2_128x64/frame_rate @@ -0,0 +1 @@ +2 diff --git a/assets/icons/Interface/Back3_45x8.png b/assets/icons/Interface/Back3_45x8.png new file mode 100644 index 00000000..6cb945f6 Binary files /dev/null and b/assets/icons/Interface/Back3_45x8.png differ diff --git a/assets/icons/Interface/WarningDolphin_45x42.png b/assets/icons/Interface/WarningDolphin_45x42.png new file mode 100644 index 00000000..d766ffbb Binary files /dev/null and b/assets/icons/Interface/WarningDolphin_45x42.png differ diff --git a/assets/icons/StatusBar/Attention_5x8.png b/assets/icons/StatusBar/Attention_5x8.png new file mode 100644 index 00000000..137d4c4d Binary files /dev/null and b/assets/icons/StatusBar/Attention_5x8.png differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_0.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_0.bm new file mode 100644 index 00000000..8558f0f5 Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_0.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_1.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_1.bm new file mode 100644 index 00000000..ac7a126e Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_1.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_10.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_10.bm new file mode 100644 index 00000000..c5312e5e Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_10.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_11.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_11.bm new file mode 100644 index 00000000..c91ed2fd Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_11.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_12.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_12.bm new file mode 100644 index 00000000..392905a5 Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_12.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_13.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_13.bm new file mode 100644 index 00000000..aa5353e9 Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_13.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_14.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_14.bm new file mode 100644 index 00000000..837c6c71 Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_14.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_15.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_15.bm new file mode 100644 index 00000000..4cb6e533 Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_15.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_16.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_16.bm new file mode 100644 index 00000000..ce3ccdec Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_16.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_17.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_17.bm new file mode 100644 index 00000000..02af0bcf Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_17.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_18.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_18.bm new file mode 100644 index 00000000..72620a7c Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_18.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_2.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_2.bm new file mode 100644 index 00000000..94357802 Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_2.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_3.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_3.bm new file mode 100644 index 00000000..b0d0e691 Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_3.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_4.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_4.bm new file mode 100644 index 00000000..3413e507 Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_4.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_5.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_5.bm new file mode 100644 index 00000000..fd83dd1c Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_5.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_6.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_6.bm new file mode 100644 index 00000000..8c946d18 Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_6.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_7.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_7.bm new file mode 100644 index 00000000..8558f0f5 Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_7.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_8.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_8.bm new file mode 100644 index 00000000..a57e4bac Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_8.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/frame_9.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_9.bm new file mode 100644 index 00000000..114b2639 Binary files /dev/null and b/assets/resources/dolphin/L1_Furippa1_128x64/frame_9.bm differ diff --git a/assets/resources/dolphin/L1_Furippa1_128x64/meta.txt b/assets/resources/dolphin/L1_Furippa1_128x64/meta.txt new file mode 100644 index 00000000..c21027e4 --- /dev/null +++ b/assets/resources/dolphin/L1_Furippa1_128x64/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 64 +Passive frames: 8 +Active frames: 11 +Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 +Active cycles: 1 +Frame rate: 2 +Duration: 3600 +Active cooldown: 7 + +Bubble slots: 0 diff --git a/assets/resources/dolphin/animations/laptop/frame_0.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_0.bm similarity index 100% rename from assets/resources/dolphin/animations/laptop/frame_0.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_0.bm diff --git a/assets/resources/dolphin/animations/laptop/frame_1.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_1.bm similarity index 100% rename from assets/resources/dolphin/animations/laptop/frame_1.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_1.bm diff --git a/assets/resources/dolphin/animations/laptop/frame_2.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_2.bm similarity index 100% rename from assets/resources/dolphin/animations/laptop/frame_2.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_2.bm diff --git a/assets/resources/dolphin/animations/laptop/frame_3.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_3.bm similarity index 100% rename from assets/resources/dolphin/animations/laptop/frame_3.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_3.bm diff --git a/assets/resources/dolphin/animations/laptop/frame_4.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_4.bm similarity index 100% rename from assets/resources/dolphin/animations/laptop/frame_4.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_4.bm diff --git a/assets/resources/dolphin/animations/laptop/frame_5.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_5.bm similarity index 100% rename from assets/resources/dolphin/animations/laptop/frame_5.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_5.bm diff --git a/assets/resources/dolphin/animations/laptop/frame_6.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_6.bm similarity index 100% rename from assets/resources/dolphin/animations/laptop/frame_6.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_6.bm diff --git a/assets/resources/dolphin/animations/laptop/frame_7.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_7.bm similarity index 100% rename from assets/resources/dolphin/animations/laptop/frame_7.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_7.bm diff --git a/assets/dolphin/animations/laptop/meta.txt b/assets/resources/dolphin/L1_Laptop_128x51/meta.txt similarity index 80% rename from assets/dolphin/animations/laptop/meta.txt rename to assets/resources/dolphin/L1_Laptop_128x51/meta.txt index 56d1e5b9..90cdc5ce 100644 --- a/assets/dolphin/animations/laptop/meta.txt +++ b/assets/resources/dolphin/L1_Laptop_128x51/meta.txt @@ -6,10 +6,10 @@ Height: 51 Passive frames: 6 Active frames: 2 Frames order: 0 1 2 3 4 5 6 7 -Active cycles: 3 +Active cycles: 4 Frame rate: 2 Duration: 3600 -Active cooldown: 5 +Active cooldown: 7 Bubble slots: 1 @@ -20,7 +20,7 @@ Text: I have to rest AlignH: Left AlignV: Bottom StartFrame: 7 -EndFrame: 9 +EndFrame: 10 Slot: 0 X: 60 @@ -28,5 +28,5 @@ Y: 23 Text: but not today AlignH: Left AlignV: Bottom -StartFrame: 10 -EndFrame: 12 \ No newline at end of file +StartFrame: 11 +EndFrame: 13 diff --git a/assets/resources/dolphin/animations/recording/frame_0.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_0.bm similarity index 100% rename from assets/resources/dolphin/animations/recording/frame_0.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_0.bm diff --git a/assets/resources/dolphin/animations/recording/frame_1.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_1.bm similarity index 100% rename from assets/resources/dolphin/animations/recording/frame_1.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_1.bm diff --git a/assets/resources/dolphin/animations/recording/frame_10.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_10.bm similarity index 50% rename from assets/resources/dolphin/animations/recording/frame_10.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_10.bm index 356eeb1c..7684384f 100644 Binary files a/assets/resources/dolphin/animations/recording/frame_10.bm and b/assets/resources/dolphin/L1_Recording_128x51/frame_10.bm differ diff --git a/assets/resources/dolphin/animations/recording/frame_11.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_11.bm similarity index 58% rename from assets/resources/dolphin/animations/recording/frame_11.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_11.bm index 804dca32..478c1e8b 100644 Binary files a/assets/resources/dolphin/animations/recording/frame_11.bm and b/assets/resources/dolphin/L1_Recording_128x51/frame_11.bm differ diff --git a/assets/resources/dolphin/animations/recording/frame_2.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_2.bm similarity index 100% rename from assets/resources/dolphin/animations/recording/frame_2.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_2.bm diff --git a/assets/resources/dolphin/animations/recording/frame_3.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_3.bm similarity index 58% rename from assets/resources/dolphin/animations/recording/frame_3.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_3.bm index 4ecea338..eb4b3644 100644 Binary files a/assets/resources/dolphin/animations/recording/frame_3.bm and b/assets/resources/dolphin/L1_Recording_128x51/frame_3.bm differ diff --git a/assets/resources/dolphin/animations/recording/frame_4.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_4.bm similarity index 58% rename from assets/resources/dolphin/animations/recording/frame_4.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_4.bm index 241cf66b..e0db66ff 100644 Binary files a/assets/resources/dolphin/animations/recording/frame_4.bm and b/assets/resources/dolphin/L1_Recording_128x51/frame_4.bm differ diff --git a/assets/resources/dolphin/animations/recording/frame_5.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_5.bm similarity index 59% rename from assets/resources/dolphin/animations/recording/frame_5.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_5.bm index 876d6e37..9265ef6d 100644 Binary files a/assets/resources/dolphin/animations/recording/frame_5.bm and b/assets/resources/dolphin/L1_Recording_128x51/frame_5.bm differ diff --git a/assets/resources/dolphin/animations/recording/frame_6.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_6.bm similarity index 100% rename from assets/resources/dolphin/animations/recording/frame_6.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_6.bm diff --git a/assets/resources/dolphin/animations/recording/frame_7.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_7.bm similarity index 100% rename from assets/resources/dolphin/animations/recording/frame_7.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_7.bm diff --git a/assets/resources/dolphin/animations/recording/frame_8.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_8.bm similarity index 100% rename from assets/resources/dolphin/animations/recording/frame_8.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_8.bm diff --git a/assets/resources/dolphin/L1_Recording_128x51/frame_9.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_9.bm new file mode 100644 index 00000000..65b72320 Binary files /dev/null and b/assets/resources/dolphin/L1_Recording_128x51/frame_9.bm differ diff --git a/assets/dolphin/animations/recording/meta.txt b/assets/resources/dolphin/L1_Recording_128x51/meta.txt similarity index 84% rename from assets/dolphin/animations/recording/meta.txt rename to assets/resources/dolphin/L1_Recording_128x51/meta.txt index bb9a0ca4..de37d5b2 100644 --- a/assets/dolphin/animations/recording/meta.txt +++ b/assets/resources/dolphin/L1_Recording_128x51/meta.txt @@ -6,9 +6,9 @@ Height: 51 Passive frames: 6 Active frames: 6 Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 -Active cycles: 2 +Active cycles: 1 Frame rate: 2 Duration: 3600 Active cooldown: 5 -Bubble slots: 0 \ No newline at end of file +Bubble slots: 0 diff --git a/assets/resources/dolphin/animations/sleep/frame_0.bm b/assets/resources/dolphin/L1_Sleep_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/animations/sleep/frame_0.bm rename to assets/resources/dolphin/L1_Sleep_128x64/frame_0.bm diff --git a/assets/resources/dolphin/animations/sleep/frame_1.bm b/assets/resources/dolphin/L1_Sleep_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/animations/sleep/frame_1.bm rename to assets/resources/dolphin/L1_Sleep_128x64/frame_1.bm diff --git a/assets/resources/dolphin/animations/sleep/frame_2.bm b/assets/resources/dolphin/L1_Sleep_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/animations/sleep/frame_2.bm rename to assets/resources/dolphin/L1_Sleep_128x64/frame_2.bm diff --git a/assets/resources/dolphin/animations/sleep/frame_3.bm b/assets/resources/dolphin/L1_Sleep_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/animations/sleep/frame_3.bm rename to assets/resources/dolphin/L1_Sleep_128x64/frame_3.bm diff --git a/assets/resources/dolphin/animations/sleep/meta.txt b/assets/resources/dolphin/L1_Sleep_128x64/meta.txt similarity index 97% rename from assets/resources/dolphin/animations/sleep/meta.txt rename to assets/resources/dolphin/L1_Sleep_128x64/meta.txt index 7960b065..ffd845e8 100644 --- a/assets/resources/dolphin/animations/sleep/meta.txt +++ b/assets/resources/dolphin/L1_Sleep_128x64/meta.txt @@ -38,4 +38,4 @@ Text: Just a dream... AlignH: Left AlignV: Bottom StartFrame: 6 -EndFrame: 9 \ No newline at end of file +EndFrame: 9 diff --git a/assets/resources/dolphin/animations/waves/frame_0.bm b/assets/resources/dolphin/L1_Waves_128x50/frame_0.bm similarity index 100% rename from assets/resources/dolphin/animations/waves/frame_0.bm rename to assets/resources/dolphin/L1_Waves_128x50/frame_0.bm diff --git a/assets/resources/dolphin/animations/waves/frame_1.bm b/assets/resources/dolphin/L1_Waves_128x50/frame_1.bm similarity index 100% rename from assets/resources/dolphin/animations/waves/frame_1.bm rename to assets/resources/dolphin/L1_Waves_128x50/frame_1.bm diff --git a/assets/resources/dolphin/animations/waves/frame_2.bm b/assets/resources/dolphin/L1_Waves_128x50/frame_2.bm similarity index 100% rename from assets/resources/dolphin/animations/waves/frame_2.bm rename to assets/resources/dolphin/L1_Waves_128x50/frame_2.bm diff --git a/assets/resources/dolphin/animations/waves/frame_3.bm b/assets/resources/dolphin/L1_Waves_128x50/frame_3.bm similarity index 100% rename from assets/resources/dolphin/animations/waves/frame_3.bm rename to assets/resources/dolphin/L1_Waves_128x50/frame_3.bm diff --git a/assets/resources/dolphin/animations/waves/meta.txt b/assets/resources/dolphin/L1_Waves_128x50/meta.txt similarity index 98% rename from assets/resources/dolphin/animations/waves/meta.txt rename to assets/resources/dolphin/L1_Waves_128x50/meta.txt index c2f63b4c..376447af 100644 --- a/assets/resources/dolphin/animations/waves/meta.txt +++ b/assets/resources/dolphin/L1_Waves_128x50/meta.txt @@ -47,4 +47,4 @@ Text: swim all day AlignH: Right AlignV: Bottom StartFrame: 6 -EndFrame: 9 \ No newline at end of file +EndFrame: 9 diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_0.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_0.bm new file mode 100644 index 00000000..7e83e14a Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_0.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_1.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_1.bm new file mode 100644 index 00000000..f149f01e Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_1.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_10.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_10.bm new file mode 100644 index 00000000..c5312e5e Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_10.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_11.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_11.bm new file mode 100644 index 00000000..c91ed2fd Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_11.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_12.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_12.bm new file mode 100644 index 00000000..392905a5 Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_12.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_13.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_13.bm new file mode 100644 index 00000000..aa5353e9 Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_13.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_14.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_14.bm new file mode 100644 index 00000000..837c6c71 Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_14.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_15.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_15.bm new file mode 100644 index 00000000..0000a886 Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_15.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_16.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_16.bm new file mode 100644 index 00000000..46a96ff4 Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_16.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_17.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_17.bm new file mode 100644 index 00000000..edccc739 Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_17.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_18.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_18.bm new file mode 100644 index 00000000..84f60c81 Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_18.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_2.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_2.bm new file mode 100644 index 00000000..ade67d10 Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_2.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_3.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_3.bm new file mode 100644 index 00000000..d05e8ae2 Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_3.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_4.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_4.bm new file mode 100644 index 00000000..5aef1276 Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_4.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_5.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_5.bm new file mode 100644 index 00000000..3be1790d Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_5.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_6.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_6.bm new file mode 100644 index 00000000..c457e787 Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_6.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_7.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_7.bm new file mode 100644 index 00000000..7e83e14a Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_7.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_8.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_8.bm new file mode 100644 index 00000000..b7b871d1 Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_8.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/frame_9.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_9.bm new file mode 100644 index 00000000..269e5b1d Binary files /dev/null and b/assets/resources/dolphin/L2_Furippa2_128x64/frame_9.bm differ diff --git a/assets/resources/dolphin/L2_Furippa2_128x64/meta.txt b/assets/resources/dolphin/L2_Furippa2_128x64/meta.txt new file mode 100644 index 00000000..c21027e4 --- /dev/null +++ b/assets/resources/dolphin/L2_Furippa2_128x64/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 64 +Passive frames: 8 +Active frames: 11 +Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 +Active cycles: 1 +Frame rate: 2 +Duration: 3600 +Active cooldown: 7 + +Bubble slots: 0 diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_0.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_0.bm new file mode 100644 index 00000000..07a63d64 Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_0.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_1.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_1.bm new file mode 100644 index 00000000..6d118f28 Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_1.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_10.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_10.bm new file mode 100644 index 00000000..8010501d Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_10.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_11.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_11.bm new file mode 100644 index 00000000..4d650bff Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_11.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_12.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_12.bm new file mode 100644 index 00000000..392905a5 Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_12.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_13.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_13.bm new file mode 100644 index 00000000..aa5353e9 Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_13.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_14.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_14.bm new file mode 100644 index 00000000..837c6c71 Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_14.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_15.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_15.bm new file mode 100644 index 00000000..9ff56a5b Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_15.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_16.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_16.bm new file mode 100644 index 00000000..34cc0b51 Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_16.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_17.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_17.bm new file mode 100644 index 00000000..80cb06fd Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_17.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_18.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_18.bm new file mode 100644 index 00000000..719a80f0 Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_18.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_2.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_2.bm new file mode 100644 index 00000000..c0148585 Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_2.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_3.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_3.bm new file mode 100644 index 00000000..f70c33ca Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_3.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_4.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_4.bm new file mode 100644 index 00000000..3fee74b7 Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_4.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_5.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_5.bm new file mode 100644 index 00000000..e363bf7d Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_5.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_6.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_6.bm new file mode 100644 index 00000000..f46aabad Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_6.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_7.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_7.bm new file mode 100644 index 00000000..07a63d64 Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_7.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_8.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_8.bm new file mode 100644 index 00000000..f8bae3a6 Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_8.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/frame_9.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_9.bm new file mode 100644 index 00000000..6b5810dc Binary files /dev/null and b/assets/resources/dolphin/L3_Furippa3_128x64/frame_9.bm differ diff --git a/assets/resources/dolphin/L3_Furippa3_128x64/meta.txt b/assets/resources/dolphin/L3_Furippa3_128x64/meta.txt new file mode 100644 index 00000000..c21027e4 --- /dev/null +++ b/assets/resources/dolphin/L3_Furippa3_128x64/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 64 +Passive frames: 8 +Active frames: 11 +Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 +Active cycles: 1 +Frame rate: 2 +Duration: 3600 +Active cooldown: 7 + +Bubble slots: 0 diff --git a/assets/resources/dolphin/animations/manifest.txt b/assets/resources/dolphin/animations/manifest.txt deleted file mode 100644 index 85d5b45d..00000000 --- a/assets/resources/dolphin/animations/manifest.txt +++ /dev/null @@ -1,34 +0,0 @@ -Filetype: Flipper Animation Manifest -Version: 1 - -# Animation 1 -Name: waves -Min butthurt: 0 -Max butthurt: 5 -Min level: 1 -Max level: 3 -Weight: 3 - -# Animation 2 -Name: laptop -Min butthurt: 0 -Max butthurt: 9 -Min level: 1 -Max level: 3 -Weight: 3 - -# Animation 3 -Name: sleep -Min butthurt: 0 -Max butthurt: 10 -Min level: 1 -Max level: 3 -Weight: 3 - -# Animation 4 -Name: recording -Min butthurt: 0 -Max butthurt: 8 -Min level: 1 -Max level: 1 -Weight: 3 \ No newline at end of file diff --git a/assets/resources/dolphin/animations/recording/frame_9.bm b/assets/resources/dolphin/animations/recording/frame_9.bm deleted file mode 100644 index 315d585f..00000000 Binary files a/assets/resources/dolphin/animations/recording/frame_9.bm and /dev/null differ diff --git a/assets/resources/dolphin/manifest.txt b/assets/resources/dolphin/manifest.txt new file mode 100644 index 00000000..8be65c11 --- /dev/null +++ b/assets/resources/dolphin/manifest.txt @@ -0,0 +1,51 @@ +Filetype: Flipper Animation Manifest +Version: 1 + +Name: L1_Waves_128x50 +Min butthurt: 0 +Max butthurt: 5 +Min level: 1 +Max level: 3 +Weight: 3 + +Name: L1_Laptop_128x51 +Min butthurt: 0 +Max butthurt: 9 +Min level: 1 +Max level: 3 +Weight: 3 + +Name: L1_Sleep_128x64 +Min butthurt: 0 +Max butthurt: 10 +Min level: 1 +Max level: 3 +Weight: 3 + +Name: L1_Recording_128x51 +Min butthurt: 0 +Max butthurt: 8 +Min level: 1 +Max level: 1 +Weight: 3 + +Name: L1_Furippa1_128x64 +Min butthurt: 0 +Max butthurt: 6 +Min level: 1 +Max level: 1 +Weight: 3 + +Name: L2_Furippa2_128x64 +Min butthurt: 0 +Max butthurt: 6 +Min level: 2 +Max level: 2 +Weight: 3 + +Name: L3_Furippa3_128x64 +Min butthurt: 0 +Max butthurt: 6 +Min level: 3 +Max level: 3 +Weight: 3 diff --git a/assets/resources/subghz/keeloq_mfcodes b/assets/resources/subghz/keeloq_mfcodes index a18dd590..c969b592 100644 --- a/assets/resources/subghz/keeloq_mfcodes +++ b/assets/resources/subghz/keeloq_mfcodes @@ -1,38 +1,40 @@ Filetype: Flipper SubGhz Keystore File Version: 0 Encryption: 1 -IV: 7A 44 FE 5D C3 B3 65 13 73 A6 F4 2D 1E B6 7D F0 -89153B35033574AAA06D7E792CB92A486B37A2CCDF0B0152BF1A563E321518C8 -F6583A3E4148439E8A8D7ED6A095ACC0C3E22A48F1637E78DF023CAC9272934E -AA0439E6B76CD43F3FCC27CF69C5F3B6508E8103B164E4ECDDF8B2FB222D46FF -A9826C663033D25AE21CB8790406997ADCE84360B258F2B989D967009659859C -3474E7BBFA0173928F414CFD5EE19B27A558D9C171D96FE7B7840A01323A7E7446FAE3E98EA9A8C69B4A6B781BD7906A -2873939A8E0EAC16D748967E987BB0F1079C106E4235B7D35B4BF37F54B21F8E -EF6F1DC0201FCB8CEBC5642A5194A1FDCFBE1FA772A79CEAD54D2F0DA3AC4F6C -3F595EAA0E81E96C5D6DB41799D314E3E81E7F4197E19A3341C55592B1B6C4B0 -7B2D75FE11B27E99CA7610E47D712C8CFB619EC69EBC976A70CFD9574C9F4FF8 -39735CF1D009D132A33B9C546D95FA6D3E69BF3A57EF219392E57C9560E7B037 -D56FDDFB0C4E808143D3ED5F15D6FF47F6EDEBD01192FC7ACF3ACCE9FD5162FC297D0089D65ED2CBE3CE05DDA7B96446 -2750D4F0650061C3AF72C88FD080BE241F2BDD8D8C1B0EFE781120EBEFFE2C72D0EECC42CDDED50CFE4AC51C48AE68C6 -F8CE64921CB73015F2672A9EF0A8359269CAE0E515D6DBB3130CFC9E5E1A98AD -ACF6ADB9E02D67B44EB6C6F126BF64BDAB37926B8BE39E27F323E8F5A0F8FC38 -FBB1302D697F94ECED681CE047819001EDE6E013850258F61E97091DD37D24F2 -D8CD53AB5A94898EB53D4FF46546ADBAA24691181A396052A58AAC657D6817AB -43200E08C21747CABC59538888A259238E782545732A1A6EEE00A6929EC9DD97A8BA9812372374046AC66652CC561D60 -C38CBE29F22D0E83E58A52E94AA2485DA8E702FBDB89D27249473CB8A19AEF61 -9F0EB580F7474985E8460E1682451E213778B77A9CAB4734B75C5386851050BF -2364EBB8237363B21226565675B9F47819C5BBC7E917C761BA3652D0A6ED7D3273EB8F3B7FBA68DE4143FB15BBEC35FB -CCDE559A2901A8290D6B2E8EDF66612E4C90E2E7C63643C8C5F244E30874B41039E078089E2253DA73B3A6DD821A84CD -33B239455FBE7AB8CE833C3B9C063EFEAE1FC7AC876AF3294C67D5B08BF7E9EC -F0FBBCEFE99D25104022CD3621B21B5F84FFBC9A5E21B0AED2B1560B39524A5B -E15B0614D9ECA17784E994652755559B7A3DA4B53CE6E63108BCFCD8024761DD -9E244C80E72937274DD6B2787F1A75F278A2DF7CB3B89F7C2BF7CC8DBBF2A3F0 -689DCA188A40DFDD3575A9BD9D7AF2427D0CE707F591029463AEC6B8679969AC -25D9B04D10AF541925901F55D8D7FA9C87523995F53183FB04F00C6023D5930A -D11F70508485C019AFC5FDBE5FD7223710033483C803FC7C2C69BAAD6ACB7CA7 -C081A0ACEA8210AB117028EDFF15641EE287CB1CFF8332A9D208B7324523129E -4C5B7C959C00A30F39A431B20EA1FEBDFB1C71C01CCC45DD883CD511360479BE -ECC0A8237E19D3883A06C5A700647860B3D9E570976D3606A11A4005424FD935 -8F5D7B39696F6F5C2100FFDF71D1C8ECAD98BD1D4CEE7BA8C793815747CE6FD5 -52ED6DE1583093E8D8AB8D16C912F7E89F78A24CE36ED53D3E06D3F81BF62ED1 -416015A128EA3A008573DE760C6AE05BD958BFCB46351F614B617CEE55C5E294 +IV: 2A 44 FE 5A A3 63 F5 11 83 A6 FE DA 1E B7 3D F1 +BF22677F79DF533C83FFE485B5F9CFABA24352FDEBED14B6FFA16EE9F00D6AC4 +B9343EDBB8B8C6EEFDA7AE9934445E27B04950DBB4F31ECCD1735CCB8C1600DE +54CC71AF6794D47FFC49823DA6C4CCAD94EC5540515FD6F537A078BFD736105C +4A3A12125D4F1186369B3B0ECB86B28A6EE4A0AF49DD4C42743A5C2C9BD1F5FC +190D7746CDC7782157E95532070BCFE8637CF9A7BE03F9382A435ACAAA7A5F5E6BEB8E34A320BDB6E492D793E470CAB4 +59ABF9B68B31BF9CCF2CCCC0A6B3182FA2772691A400B2BFB5E2490DA2BCD2A4 +304DF68472EC9C78341218C10242DC3D62887A5281B52061BC0C9D117CDE1185 +D146050F90D30FA166615706FBC8D5B3573BDCB081E2445930CE1B71F5BDB7AE +9386C94D044CCCBEE7972319191933328A06B20138C432B86C76EB909BB06019 +CFC23206853E9D01C3986FD849908686A2442287277C06574928A362F988CE1B +534B351BE03A98B56ED622D37B9BBCD871CA76EB6EF250B1615105FA496E991C8F195293F83EE38AE5831D95F45238E3 +AFF90EC99CF4278D79DA9B1163FF07C83203AD34F9C4228423B4B58FF3F6978C605CC282FB1E37C0946D86C51809222C +44C9EF18971905D2207F62D3365CB4A31D449FA215F950CEB67368D13181959C +0CF10950D8A3EDEEEEA9AA4E41354373584FBFE6BB2E8A52C3149757C133445C +4FBE939E87B8438AFC86773DADA39FE3856A3518A5159C9BF6B2EFA752F5B3F5 +CBFD648024823A33481B8A7381CD28930765265A1CA9BBDE1879F0827273A860 +8D3C70EF2E4ED2EF23752046538BF30F6DA8266F2B10A4BAD8549B3D20298F08EF9E6C21F78DDA9CA6EBB1E3CDF82C78 +D31EBB7C994C397776777D4904661C6F8DF5CDA9F828CA19378CAA397555F8C0 +FDA58BA7B0CD5C9090FE891029A3773EA16DB77EB5FA06A4C443C01B537B2615 +5CEE7A27D0D1B1AB5BAAC93D78121BC6D5FCD589C093A22C71E81C390045C85FDE98C202340FDD2046FF906A035E31E9 +C3121624E5B91EDCF651B8A89C2EEF4379876D0E0D918596F3E5CED9F3C92AB689D609AA1FB5362F57738A0AF62E3C92 +25F715B4CEA880E4879C6C03DC61875A43FB314AB4F21AE1CF7C933172B4A29D +574166A278E2FA4AB8A09078152929E631E4E182E20CCF803250A0A2D4BB62F3 +B0D1C7AA1752135BA7627D8F65EC9651B810EC29BA01C8D9BC5B3EB20B1A0939 +E3E9D30E4F7003E63917DF3B5FC4E03863E37AFD6C5987CCFEC8129C692474EF +67A35F2E3C400953EC1CD1874A35A4734D3E9F116F7E334276BF898E48C21AFE +BC8D612FA363AB364BB9D2701273C4FA587B2F8D8CD039DEFB72BAD00360149F +9A88BBDA111C9185EE5BBA610574D46A4D53EC79B63D5FB57BAB5A6609F2160F +9512A1F77A4C46BD7F79D792B1578AC1FA41F15F6D7C72BC952BD89262C85327 +182685E3E0A23055025F7218AB16F7AE3A7F9DD71761AAE3B5E4AB85E2EFBF929D640258AEBC9F0BB167985A1E4B132D +1DD9156B6BF97424DC639708ACEE21DD1D64FC5BC0DD5252DDDDE7832C2B7B6F +109BB4D660897DB00676093B585535D267426310CDE81F05793ACB46B9F6176E +D7A2D468DF76A8E5C495D5280524B2996254B94458485B11CCAB36CD1EE3918F +9F445C93FF382433015BEAE6D78F70AE2C02E0C961E1B9576D66E64978D984D0 +195CB755E6AC710B5AF10761AC2B13F8CA57355443B593BC59AAF3A819070568028BBAE75C0DA4BA6B90D63E679098B7 +C6ECD39EC47DFFD1ABC55F47AC8E2C26A8DB5EB8184153746F7D9AD5F0015E85 diff --git a/assets/resources/subghz/keeloq_mfcodes_user b/assets/resources/subghz/keeloq_mfcodes_user index 910157d6..f013afa2 100644 --- a/assets/resources/subghz/keeloq_mfcodes_user +++ b/assets/resources/subghz/keeloq_mfcodes_user @@ -1,7 +1,7 @@ # for adding manufacture keys # AABBCCDDEEFFAABB:X:NAME\r\n # AABBCCDDEEFFAABB - man 64 bit -# X - encryption method 1 - Simple Learning, 2 - Normal_Learning, 3 - Secure_Learning +# X - encryption method 1 - Simple Learning, 2 - Normal_Learning, 3 - Secure_Learning, 4 - Magic_xor_type1 Learning # 0 - iterates over both previous and man in direct and reverse byte sequence # NAME - name (string without spaces) max 64 characters long Filetype: Flipper SubGhz Keystore File diff --git a/bootloader/targets/f6/furi_hal/furi_hal_i2c.c b/bootloader/targets/f6/furi_hal/furi_hal_i2c.c index c918264a..210f96d6 100644 --- a/bootloader/targets/f6/furi_hal/furi_hal_i2c.c +++ b/bootloader/targets/f6/furi_hal/furi_hal_i2c.c @@ -134,3 +134,72 @@ bool furi_hal_i2c_trx( return false; } } + +bool furi_hal_i2c_read_reg_8( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint8_t* data, + uint32_t timeout) { + assert(handle); + + return furi_hal_i2c_trx(handle, i2c_addr, ®_addr, 1, data, 1, timeout); +} + +bool furi_hal_i2c_read_reg_16( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint16_t* data, + uint32_t timeout) { + assert(handle); + + uint8_t reg_data[2]; + bool ret = furi_hal_i2c_trx(handle, i2c_addr, ®_addr, 1, reg_data, 2, timeout); + *data = (reg_data[0] << 8) | (reg_data[1]); + + return ret; +} + +bool furi_hal_i2c_read_mem( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t mem_addr, + uint8_t* data, + uint8_t len, + uint32_t timeout) { + assert(handle); + + return furi_hal_i2c_trx(handle, i2c_addr, &mem_addr, 1, data, len, timeout); +} + +bool furi_hal_i2c_write_reg_8( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint8_t data, + uint32_t timeout) { + assert(handle); + + uint8_t tx_data[2]; + tx_data[0] = reg_addr; + tx_data[1] = data; + + return furi_hal_i2c_tx(handle, i2c_addr, (const uint8_t*)&tx_data, 2, timeout); +} + +bool furi_hal_i2c_write_reg_16( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint16_t data, + uint32_t timeout) { + assert(handle); + + uint8_t tx_data[3]; + tx_data[0] = reg_addr; + tx_data[1] = (data >> 8) & 0xFF; + tx_data[2] = data & 0xFF; + + return furi_hal_i2c_tx(handle, i2c_addr, (const uint8_t*)&tx_data, 3, timeout); +} diff --git a/bootloader/targets/f6/furi_hal/furi_hal_i2c.h b/bootloader/targets/f6/furi_hal/furi_hal_i2c.h index 35269ec5..c2ad1728 100644 --- a/bootloader/targets/f6/furi_hal/furi_hal_i2c.h +++ b/bootloader/targets/f6/furi_hal/furi_hal_i2c.h @@ -84,6 +84,112 @@ bool furi_hal_i2c_trx( const uint8_t rx_size, uint32_t timeout); +/** Perform I2C device register read (8-bit) + * + * @param handle pointer to FuriHalI2cBusHandle instance + * @param i2c_addr I2C slave address + * @param reg_addr register address + * @param data pointer to register value + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ +bool furi_hal_i2c_read_reg_8( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint8_t* data, + uint32_t timeout); + +/** Perform I2C device register read (16-bit) + * + * @param handle pointer to FuriHalI2cBusHandle instance + * @param i2c_addr I2C slave address + * @param reg_addr register address + * @param data pointer to register value + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ +bool furi_hal_i2c_read_reg_16( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint16_t* data, + uint32_t timeout); + +/** Perform I2C device memory read + * + * @param handle pointer to FuriHalI2cBusHandle instance + * @param i2c_addr I2C slave address + * @param mem_addr memory start address + * @param data pointer to data buffer + * @param len size of data buffer + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ +bool furi_hal_i2c_read_mem( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t mem_addr, + uint8_t* data, + uint8_t len, + uint32_t timeout); + +/** Perform I2C device register write (8-bit) + * + * @param handle pointer to FuriHalI2cBusHandle instance + * @param i2c_addr I2C slave address + * @param reg_addr register address + * @param data register value + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ +bool furi_hal_i2c_write_reg_8( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint8_t data, + uint32_t timeout); + +/** Perform I2C device register write (16-bit) + * + * @param handle pointer to FuriHalI2cBusHandle instance + * @param i2c_addr I2C slave address + * @param reg_addr register address + * @param data register value + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ +bool furi_hal_i2c_write_reg_16( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint16_t data, + uint32_t timeout); + +/** Perform I2C device memory + * + * @param handle pointer to FuriHalI2cBusHandle instance + * @param i2c_addr I2C slave address + * @param mem_addr memory start address + * @param data pointer to data buffer + * @param len size of data buffer + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ +bool furi_hal_i2c_write_mem( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t mem_addr, + uint8_t* data, + uint8_t len, + uint32_t timeout); + #ifdef __cplusplus } #endif diff --git a/bootloader/targets/f7/furi_hal/furi_hal_i2c.c b/bootloader/targets/f7/furi_hal/furi_hal_i2c.c index c918264a..210f96d6 100644 --- a/bootloader/targets/f7/furi_hal/furi_hal_i2c.c +++ b/bootloader/targets/f7/furi_hal/furi_hal_i2c.c @@ -134,3 +134,72 @@ bool furi_hal_i2c_trx( return false; } } + +bool furi_hal_i2c_read_reg_8( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint8_t* data, + uint32_t timeout) { + assert(handle); + + return furi_hal_i2c_trx(handle, i2c_addr, ®_addr, 1, data, 1, timeout); +} + +bool furi_hal_i2c_read_reg_16( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint16_t* data, + uint32_t timeout) { + assert(handle); + + uint8_t reg_data[2]; + bool ret = furi_hal_i2c_trx(handle, i2c_addr, ®_addr, 1, reg_data, 2, timeout); + *data = (reg_data[0] << 8) | (reg_data[1]); + + return ret; +} + +bool furi_hal_i2c_read_mem( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t mem_addr, + uint8_t* data, + uint8_t len, + uint32_t timeout) { + assert(handle); + + return furi_hal_i2c_trx(handle, i2c_addr, &mem_addr, 1, data, len, timeout); +} + +bool furi_hal_i2c_write_reg_8( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint8_t data, + uint32_t timeout) { + assert(handle); + + uint8_t tx_data[2]; + tx_data[0] = reg_addr; + tx_data[1] = data; + + return furi_hal_i2c_tx(handle, i2c_addr, (const uint8_t*)&tx_data, 2, timeout); +} + +bool furi_hal_i2c_write_reg_16( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint16_t data, + uint32_t timeout) { + assert(handle); + + uint8_t tx_data[3]; + tx_data[0] = reg_addr; + tx_data[1] = (data >> 8) & 0xFF; + tx_data[2] = data & 0xFF; + + return furi_hal_i2c_tx(handle, i2c_addr, (const uint8_t*)&tx_data, 3, timeout); +} diff --git a/bootloader/targets/f7/furi_hal/furi_hal_i2c.h b/bootloader/targets/f7/furi_hal/furi_hal_i2c.h index 35269ec5..c2ad1728 100644 --- a/bootloader/targets/f7/furi_hal/furi_hal_i2c.h +++ b/bootloader/targets/f7/furi_hal/furi_hal_i2c.h @@ -84,6 +84,112 @@ bool furi_hal_i2c_trx( const uint8_t rx_size, uint32_t timeout); +/** Perform I2C device register read (8-bit) + * + * @param handle pointer to FuriHalI2cBusHandle instance + * @param i2c_addr I2C slave address + * @param reg_addr register address + * @param data pointer to register value + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ +bool furi_hal_i2c_read_reg_8( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint8_t* data, + uint32_t timeout); + +/** Perform I2C device register read (16-bit) + * + * @param handle pointer to FuriHalI2cBusHandle instance + * @param i2c_addr I2C slave address + * @param reg_addr register address + * @param data pointer to register value + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ +bool furi_hal_i2c_read_reg_16( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint16_t* data, + uint32_t timeout); + +/** Perform I2C device memory read + * + * @param handle pointer to FuriHalI2cBusHandle instance + * @param i2c_addr I2C slave address + * @param mem_addr memory start address + * @param data pointer to data buffer + * @param len size of data buffer + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ +bool furi_hal_i2c_read_mem( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t mem_addr, + uint8_t* data, + uint8_t len, + uint32_t timeout); + +/** Perform I2C device register write (8-bit) + * + * @param handle pointer to FuriHalI2cBusHandle instance + * @param i2c_addr I2C slave address + * @param reg_addr register address + * @param data register value + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ +bool furi_hal_i2c_write_reg_8( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint8_t data, + uint32_t timeout); + +/** Perform I2C device register write (16-bit) + * + * @param handle pointer to FuriHalI2cBusHandle instance + * @param i2c_addr I2C slave address + * @param reg_addr register address + * @param data register value + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ +bool furi_hal_i2c_write_reg_16( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t reg_addr, + uint16_t data, + uint32_t timeout); + +/** Perform I2C device memory + * + * @param handle pointer to FuriHalI2cBusHandle instance + * @param i2c_addr I2C slave address + * @param mem_addr memory start address + * @param data pointer to data buffer + * @param len size of data buffer + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ +bool furi_hal_i2c_write_mem( + FuriHalI2cBusHandle* handle, + uint8_t i2c_addr, + uint8_t mem_addr, + uint8_t* data, + uint8_t len, + uint32_t timeout); + #ifdef __cplusplus } #endif diff --git a/core/furi/dangerous_defines.h b/core/furi/dangerous_defines.h index 7f302d14..b477710a 100644 --- a/core/furi/dangerous_defines.h +++ b/core/furi/dangerous_defines.h @@ -20,6 +20,12 @@ *tmp_x = y; \ *tmp_x; \ }) +#define FURI_CONST_ASSIGN_PTR(x, y) \ + ({ \ + void** tmp_x = (void**)&x; \ + *tmp_x = y; \ + *tmp_x; \ + }) #define FURI_CONST_ASSIGN(x, y) \ _Generic((x), signed char \ : FURI_CONST_ASSIGN_(signed char, x, y), unsigned char \ diff --git a/documentation/KeyCombo.md b/documentation/KeyCombo.md new file mode 100644 index 00000000..359fd5b9 --- /dev/null +++ b/documentation/KeyCombo.md @@ -0,0 +1,134 @@ +# Key Combos + +There are times when your flipper feels blue and don't respond to your commands. +In that case you may find this guide useful. + + +## Basic Combos + + +### Hardware Reset + +- Press `LEFT` and `BACK` and hold for couple seconds +- Release `LEFT` and `BACK` + +This combo performs hardware reset by pulling MCU reset line down. +Main components involved: Keys -> DD8(NC7SZ32M5X, OR-gate) -> DD1(STM32WB55, MCU) + +There is 1 case when it's not working: + +- MCU debug block is active and holding reset line from inside. + + +### Hardware Power Reset + +- Disconnect USB and any external power supplies +- Disconnect USB once again +- Make sure that you've disconnected USB and any external power supplies +- Press `BACK` and hold for 30 seconds (Only will work with USB Disconnected) +- If you have not disconnected USB, then disconnect USB and repeat previous step +- Release `BACK` key + +This combo performs reset by switching SYS power line off and then on. +Main components involved: Keys -> DD6(bq25896, charger) + +There is 1 case when it's not working: + +- Power supply is connected to USB or 5V_ext + + +### Software DFU + +- Press `LEFT` on boot to enter DFU with flipper boot-loader + +There is 1 case when it's not working: + +- Flipper Boot-loader is damaged or absent + + +### Hardware DFU + +- Press `OK` on boot to enter DFU with ST boot-loader + +There is 1 case when it's not working: + +- Option Bytes are damaged or set to ignore `OK` key + + +## DFU Combos + + +### Hardware Reset + Software DFU + +- Press `LEFT` and `BACK` and hold for couple seconds +- Release `BACK` +- Device will enter DFU with indication (Blue LED + DFU Screen) +- Release `LEFT` + +This combo performs hardware reset by pulling MCU reset line down. +Then `LEFT` key indicates to boot-loader that DFU mode requested. + +There are 2 cases when it's not working: + +- MCU debug block is active and holding reset line from inside +- Flipper Boot-loader is damaged or absent + + +### Hardware Reset + Hardware DFU + +- Press `LEFT` and `BACK` and `OK` and hold for couple seconds +- Release `BACK` and `LEFT` +- Device will enter DFU without indication + +This combo performs hardware reset by pulling MCU reset line down. +Then `OK` key forces MCU to load internal boot-loader. + +There are 2 cases when it's not working: + +- MCU debug block is active and holding reset line from inside +- Option Bytes are damaged or set to ignore `OK` key + + +### Hardware Power Reset + Software DFU + +- Disconnect USB and any external power supplies +- Press `BACK` and `LEFT` for 30 seconds +- Release `BACK` +- Device will enter DFU with indication (Blue LED + DFU Screen) +- Release `LEFT` +- Plug USB + +This combo performs reset by switching SYS power line off and then on. +Then `LEFT` key indicates to boot-loader that DFU mode requested. + +There are 2 cases when it's not working: + +- Power supply is connected to USB or 5V_ext +- Flipper Boot-loader is damaged or absent + + +### Hardware Power Reset + Hardware DFU + +- Disconnect USB and any external power supplies +- Press `BACK` and `OK` and hold for 30 seconds +- Release `BACK` and `OK` +- Device will enter DFU without indication +- Plug USB + +This combo performs reset by switching SYS power line off and then on. +Then `OK` key forces MCU to load internal boot-loader. + +There are 2 cases when it's not working: + +- Power supply is connected to USB or 5V_ext +- Option Bytes are damaged or set to ignore `OK` key + +# Alternative ways to recover your device + +If none of the described methods were useful: + +- Ensure battery charged +- Disconnect battery and connect again (Requires disassembly) +- Try to Flash device with ST-Link or other programmer that support SWD + +If you still here and your device is not working: it's not software issue. diff --git a/firmware/targets/f6/ble_glue/gap.c b/firmware/targets/f6/ble_glue/gap.c old mode 100644 new mode 100755 index dfcd174e..d9a2096f --- a/firmware/targets/f6/ble_glue/gap.c +++ b/firmware/targets/f6/ble_glue/gap.c @@ -94,9 +94,17 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { case EVT_LE_META_EVENT: meta_evt = (evt_le_meta_event*)event_pckt->data; switch(meta_evt->subevent) { - case EVT_LE_CONN_UPDATE_COMPLETE: - FURI_LOG_D(TAG, "Connection update event"); + case EVT_LE_CONN_UPDATE_COMPLETE: { + hci_le_connection_update_complete_event_rp0* event = + (hci_le_connection_update_complete_event_rp0*)meta_evt->data; + FURI_LOG_I( + TAG, + "Connection interval: %d, latency: %d, supervision timeout: %d", + event->Conn_Interval, + event->Conn_Latency, + event->Supervision_Timeout); break; + } case EVT_LE_PHY_UPDATE_COMPLETE: evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data; @@ -129,6 +137,15 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { // Update connection status and handle gap->state = GapStateConnected; gap->service.connection_handle = connection_complete_event->Connection_Handle; + GapConnectionParams* params = &gap->config->conn_param; + if(aci_l2cap_connection_parameter_update_req( + gap->service.connection_handle, + params->conn_int_min, + params->conn_int_max, + params->slave_latency, + params->supervisor_timeout)) { + FURI_LOG_W(TAG, "Failed to request connection parameters update"); + } // Start pairing by sending security request aci_gap_slave_security_req(connection_complete_event->Connection_Handle); @@ -184,28 +201,28 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { } break; case EVT_BLUE_GAP_AUTHORIZATION_REQUEST: - FURI_LOG_I(TAG, "Authorization request event"); + FURI_LOG_D(TAG, "Authorization request event"); break; case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED: - FURI_LOG_I(TAG, "Slave security initiated"); + FURI_LOG_D(TAG, "Slave security initiated"); break; case EVT_BLUE_GAP_BOND_LOST: - FURI_LOG_I(TAG, "Bond lost event. Start rebonding"); + FURI_LOG_D(TAG, "Bond lost event. Start rebonding"); aci_gap_allow_rebond(gap->service.connection_handle); break; case EVT_BLUE_GAP_DEVICE_FOUND: - FURI_LOG_I(TAG, "Device found event"); + FURI_LOG_D(TAG, "Device found event"); break; case EVT_BLUE_GAP_ADDR_NOT_RESOLVED: - FURI_LOG_I(TAG, "Address not resolved event"); + FURI_LOG_D(TAG, "Address not resolved event"); break; case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION: - FURI_LOG_I(TAG, "Key press notification event"); + FURI_LOG_D(TAG, "Key press notification event"); break; case EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE: { @@ -234,8 +251,19 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { break; case EVT_BLUE_GAP_PROCEDURE_COMPLETE: - FURI_LOG_I(TAG, "Procedure complete event"); + FURI_LOG_D(TAG, "Procedure complete event"); break; + + case EVT_BLUE_L2CAP_CONNECTION_UPDATE_RESP: { + uint16_t result = + ((aci_l2cap_connection_update_resp_event_rp0*)(blue_evt->data))->Result; + if(result == 0) { + FURI_LOG_D(TAG, "Connection parameters accepted"); + } else if(result == 1) { + FURI_LOG_D(TAG, "Connection parameters denied"); + } + break; + } } default: break; diff --git a/firmware/targets/f6/ble_glue/gap.h b/firmware/targets/f6/ble_glue/gap.h index 635a4c3c..1a2e7962 100644 --- a/firmware/targets/f6/ble_glue/gap.h +++ b/firmware/targets/f6/ble_glue/gap.h @@ -55,6 +55,13 @@ typedef enum { GapPairingPinCodeVerifyYesNo, } GapPairing; +typedef struct { + uint16_t conn_int_min; + uint16_t conn_int_max; + uint16_t slave_latency; + uint16_t supervisor_timeout; +} GapConnectionParams; + typedef struct { uint16_t adv_service_uuid; uint16_t appearance_char; @@ -62,6 +69,7 @@ typedef struct { GapPairing pairing_method; uint8_t mac_address[GAP_MAC_ADDR_SIZE]; char adv_name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH]; + GapConnectionParams conn_param; } GapConfig; bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context); diff --git a/firmware/targets/f6/furi_hal/furi_hal_bt.c b/firmware/targets/f6/furi_hal/furi_hal_bt.c old mode 100644 new mode 100755 index 7147c7f0..4465f15e --- a/firmware/targets/f6/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f6/furi_hal/furi_hal_bt.c @@ -42,6 +42,13 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = { .bonding_mode = true, .pairing_method = GapPairingPinCodeShow, .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, + .conn_param = + { + .conn_int_min = 0x08, + .conn_int_max = 0x18, + .slave_latency = 0, + .supervisor_timeout = 50, + }, }, }, [FuriHalBtProfileHidKeyboard] = @@ -55,6 +62,14 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = { .bonding_mode = true, .pairing_method = GapPairingPinCodeVerifyYesNo, .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, + // TODO optimize + .conn_param = + { + .conn_int_min = 0x12, + .conn_int_max = 0x1e, + .slave_latency = 6, + .supervisor_timeout = 700, + }, }, }, }; @@ -277,6 +292,16 @@ void furi_hal_bt_nvm_sram_sem_release() { HAL_HSEM_Release(CFG_HW_BLE_NVM_SRAM_SEMID, 0); } +bool furi_hal_bt_clear_white_list() { + furi_hal_bt_nvm_sram_sem_acquire(); + tBleStatus status = aci_gap_clear_security_db(); + if(status) { + FURI_LOG_E(TAG, "Clear while list failed with status %d", status); + } + furi_hal_bt_nvm_sram_sem_release(); + return status != BLE_STATUS_SUCCESS; +} + void furi_hal_bt_dump_state(string_t buffer) { if(furi_hal_bt_is_alive()) { uint8_t HCI_Version; diff --git a/firmware/targets/f6/furi_hal/furi_hal_light.c b/firmware/targets/f6/furi_hal/furi_hal_light.c index 6aba7efb..1bd1adad 100644 --- a/firmware/targets/f6/furi_hal/furi_hal_light.c +++ b/firmware/targets/f6/furi_hal/furi_hal_light.c @@ -28,6 +28,7 @@ void furi_hal_light_init() { } void furi_hal_light_set(Light light, uint8_t value) { + uint8_t prev = 0; furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); switch(light) { case LightRed: @@ -40,10 +41,12 @@ void furi_hal_light_set(Light light, uint8_t value) { lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); break; case LightBacklight: - lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value); + prev = lp5562_get_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite); + lp5562_execute_ramp( + &furi_hal_i2c_handle_power, LP5562Engine1, LP5562ChannelWhite, prev, value, 100); break; default: break; } furi_hal_i2c_release(&furi_hal_i2c_handle_power); -} \ No newline at end of file +} diff --git a/firmware/targets/f6/furi_hal/furi_hal_power.c b/firmware/targets/f6/furi_hal/furi_hal_power.c index a574ebcc..1dbdb3dd 100644 --- a/firmware/targets/f6/furi_hal/furi_hal_power.c +++ b/firmware/targets/f6/furi_hal/furi_hal_power.c @@ -216,6 +216,13 @@ bool furi_hal_power_is_otg_enabled() { return ret; } +void furi_hal_power_check_otg_status() { + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + if(bq25896_check_otg_fault(&furi_hal_i2c_handle_power)) + bq25896_disable_otg(&furi_hal_i2c_handle_power); + furi_hal_i2c_release(&furi_hal_i2c_handle_power); +} + uint32_t furi_hal_power_get_battery_remaining_capacity() { furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); uint32_t ret = bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power); @@ -297,6 +304,7 @@ void furi_hal_power_dump_state() { BQ27220_ERROR) { printf("Failed to get bq27220 status. Communication error.\r\n"); } else { + // Operation status register printf( "bq27220: CALMD: %d, SEC0: %d, SEC1: %d, EDV2: %d, VDQ: %d, INITCOMP: %d, SMTH: %d, BTPINT: %d, CFGUPDATE: %d\r\n", operation_status.CALMD, diff --git a/firmware/targets/f6/furi_hal/furi_hal_usb.c b/firmware/targets/f6/furi_hal/furi_hal_usb.c index 59b37bbf..881081b6 100644 --- a/firmware/targets/f6/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f6/furi_hal/furi_hal_usb.c @@ -9,15 +9,19 @@ #define USB_RECONNECT_DELAY 500 -static UsbInterface* usb_if_cur; -static UsbInterface* usb_if_next; +static FuriHalUsbInterface* usb_if_cur; +static FuriHalUsbInterface* usb_if_next; static const struct usb_string_descriptor dev_lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US); static uint32_t ubuf[0x20]; usbd_device udev; +static FuriHalUsbStateCallback callback; +static void* cb_ctx; + static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_t* length); +static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep); static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep); static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep); @@ -25,6 +29,7 @@ struct UsbCfg { osTimerId_t reconnect_tmr; bool enabled; bool connected; + bool mode_changing; } usb_config; static void furi_hal_usb_tmr_cb(void* context); @@ -48,6 +53,7 @@ void furi_hal_usb_init(void) { usbd_reg_descr(&udev, usb_descriptor_get); usbd_reg_event(&udev, usbd_evt_susp, susp_evt); usbd_reg_event(&udev, usbd_evt_wkup, wkup_evt); + // Reset callback will be enabled after first mode change to avoid getting false reset events usb_config.enabled = false; usb_config.reconnect_tmr = NULL; @@ -57,28 +63,49 @@ void furi_hal_usb_init(void) { FURI_LOG_I(TAG, "Init OK"); } -void furi_hal_usb_set_config(UsbInterface* new_if) { - if(new_if != usb_if_cur) { - if(usb_config.enabled) { - usb_if_next = new_if; - if(usb_config.reconnect_tmr == NULL) - usb_config.reconnect_tmr = - osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); - furi_hal_usb_disable(); - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); - } else { - if(usb_if_cur != NULL) usb_if_cur->deinit(&udev); - if(new_if != NULL) { - new_if->init(&udev, new_if); - FURI_LOG_I(TAG, "USB mode change"); - usb_config.enabled = true; - usb_if_cur = new_if; - } +void furi_hal_usb_set_config(FuriHalUsbInterface* new_if) { + if((new_if != usb_if_cur) && (usb_config.enabled)) { // Interface mode change - first stage + usb_config.mode_changing = true; + usb_if_next = new_if; + if(usb_config.reconnect_tmr == NULL) + usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); + furi_hal_usb_disable(); + usb_config.mode_changing = true; + osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); + } else if( + (usb_config.mode_changing) && + (usb_if_next != new_if)) { // Last interface mode change wasn't completed + osTimerStop(usb_config.reconnect_tmr); + usb_if_next = new_if; + osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); + } else { // Interface mode change - second stage + if(usb_if_cur != NULL) usb_if_cur->deinit(&udev); + if(new_if != NULL) { + new_if->init(&udev, new_if); + usbd_reg_event(&udev, usbd_evt_reset, reset_evt); + FURI_LOG_I(TAG, "USB Mode change done"); + usb_config.enabled = true; + usb_if_cur = new_if; + usb_config.mode_changing = false; } } } -UsbInterface* furi_hal_usb_get_config() { +void furi_hal_usb_reinit() { + // Temporary disable callback to avoid getting false reset events + usbd_reg_event(&udev, usbd_evt_reset, NULL); + FURI_LOG_I(TAG, "USB Reinit"); + furi_hal_usb_disable(); + usbd_enable(&udev, false); + usbd_enable(&udev, true); + if(usb_config.reconnect_tmr == NULL) + usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); + usb_config.mode_changing = true; + usb_if_next = usb_if_cur; + osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); +} + +FuriHalUsbInterface* furi_hal_usb_get_config() { return usb_if_cur; } @@ -113,6 +140,9 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ switch(dtype) { case USB_DTYPE_DEVICE: + if(callback != NULL) { + callback(FuriHalUsbStateEventDescriptorRequest, cb_ctx); + } desc = usb_if_cur->dev_descr; break; case USB_DTYPE_CONFIGURATION: @@ -122,11 +152,11 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ case USB_DTYPE_STRING: if(dnumber == UsbDevLang) { desc = &dev_lang_desc; - } else if(dnumber == UsbDevManuf) { + } else if((dnumber == UsbDevManuf) && (usb_if_cur->str_manuf_descr != NULL)) { desc = usb_if_cur->str_manuf_descr; - } else if(dnumber == UsbDevProduct) { + } else if((dnumber == UsbDevProduct) && (usb_if_cur->str_prod_descr != NULL)) { desc = usb_if_cur->str_prod_descr; - } else if(dnumber == UsbDevSerial) { + } else if((dnumber == UsbDevSerial) && (usb_if_cur->str_serial_descr != NULL)) { desc = usb_if_cur->str_serial_descr; } else return usbd_fail; @@ -144,11 +174,25 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ return usbd_ack; } +void furi_hal_usb_set_state_callback(FuriHalUsbStateCallback cb, void* ctx) { + callback = cb; + cb_ctx = ctx; +} + +static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep) { + if(callback != NULL) { + callback(FuriHalUsbStateEventReset, cb_ctx); + } +} + static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep) { if((usb_if_cur != NULL) && (usb_config.connected == true)) { usb_config.connected = false; usb_if_cur->suspend(&udev); } + if(callback != NULL) { + callback(FuriHalUsbStateEventSuspend, cb_ctx); + } } static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep) { @@ -156,4 +200,7 @@ static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep) { usb_config.connected = true; usb_if_cur->wakeup(&udev); } + if(callback != NULL) { + callback(FuriHalUsbStateEventWakeup, cb_ctx); + } } diff --git a/firmware/targets/f6/furi_hal/furi_hal_usb_cdc.c b/firmware/targets/f6/furi_hal/furi_hal_usb_cdc.c index 26fd40c3..d7fcbc58 100644 --- a/firmware/targets/f6/furi_hal/furi_hal_usb_cdc.c +++ b/firmware/targets/f6/furi_hal/furi_hal_usb_cdc.c @@ -385,7 +385,7 @@ static const struct CdcConfigDescriptorDual static struct usb_cdc_line_coding cdc_config[IF_NUM_MAX] = {}; static uint8_t cdc_ctrl_line_state[IF_NUM_MAX]; -static void cdc_init(usbd_device* dev, UsbInterface* intf); +static void cdc_init(usbd_device* dev, FuriHalUsbInterface* intf); static void cdc_deinit(usbd_device* dev); static void cdc_on_wakeup(usbd_device* dev); static void cdc_on_suspend(usbd_device* dev); @@ -393,12 +393,12 @@ static void cdc_on_suspend(usbd_device* dev); static usbd_respond cdc_ep_config(usbd_device* dev, uint8_t cfg); static usbd_respond cdc_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback); static usbd_device* usb_dev; -static UsbInterface* cdc_if_cur = NULL; +static FuriHalUsbInterface* cdc_if_cur = NULL; static bool connected = false; static CdcCallbacks* callbacks[IF_NUM_MAX] = {NULL}; static void* cb_ctx[IF_NUM_MAX]; -UsbInterface usb_cdc_single = { +FuriHalUsbInterface usb_cdc_single = { .init = cdc_init, .deinit = cdc_deinit, .wakeup = cdc_on_wakeup, @@ -413,7 +413,7 @@ UsbInterface usb_cdc_single = { .cfg_descr = (void*)&cdc_cfg_desc_single, }; -UsbInterface usb_cdc_dual = { +FuriHalUsbInterface usb_cdc_dual = { .init = cdc_init, .deinit = cdc_deinit, .wakeup = cdc_on_wakeup, @@ -428,7 +428,7 @@ UsbInterface usb_cdc_dual = { .cfg_descr = (void*)&cdc_cfg_desc_dual, }; -static void cdc_init(usbd_device* dev, UsbInterface* intf) { +static void cdc_init(usbd_device* dev, FuriHalUsbInterface* intf) { usb_dev = dev; cdc_if_cur = intf; diff --git a/firmware/targets/f6/furi_hal/furi_hal_usb_hid.c b/firmware/targets/f6/furi_hal/furi_hal_usb_hid.c index 098acc73..6f94fb33 100644 --- a/firmware/targets/f6/furi_hal/furi_hal_usb_hid.c +++ b/firmware/targets/f6/furi_hal/furi_hal_usb_hid.c @@ -236,7 +236,7 @@ static struct HidReport { struct HidReportConsumer consumer; } __attribute__((packed)) hid_report; -static void hid_init(usbd_device* dev, UsbInterface* intf); +static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf); static void hid_deinit(usbd_device* dev); static void hid_on_wakeup(usbd_device* dev); static void hid_on_suspend(usbd_device* dev); @@ -348,7 +348,7 @@ bool furi_hal_hid_consumer_key_release(uint16_t button) { return hid_send_report(ReportIdConsumer); } -UsbInterface usb_hid = { +FuriHalUsbInterface usb_hid = { .init = hid_init, .deinit = hid_deinit, .wakeup = hid_on_wakeup, @@ -363,7 +363,7 @@ UsbInterface usb_hid = { .cfg_descr = (void*)&hid_cfg_desc, }; -static void hid_init(usbd_device* dev, UsbInterface* intf) { +static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf) { if(hid_semaphore == NULL) hid_semaphore = osSemaphoreNew(1, 1, NULL); usb_dev = dev; hid_report.keyboard.report_id = ReportIdKeyboard; diff --git a/firmware/targets/f6/furi_hal/furi_hal_usb_u2f.c b/firmware/targets/f6/furi_hal/furi_hal_usb_u2f.c index a3bb145e..4ee3d712 100644 --- a/firmware/targets/f6/furi_hal/furi_hal_usb_u2f.c +++ b/firmware/targets/f6/furi_hal/furi_hal_usb_u2f.c @@ -48,8 +48,7 @@ static const uint8_t hid_u2f_report_desc[] = { }; static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Flipper Devices Inc."); -static const struct usb_string_descriptor dev_prod_desc = USB_STRING_DESC("U2F Token test"); -static const struct usb_string_descriptor dev_serial_desc = USB_STRING_DESC("TODO: serial"); +static const struct usb_string_descriptor dev_prod_desc = USB_STRING_DESC("U2F Token"); /* Device descriptor */ static const struct usb_device_descriptor hid_u2f_device_desc = { @@ -65,7 +64,7 @@ static const struct usb_device_descriptor hid_u2f_device_desc = { .bcdDevice = VERSION_BCD(1, 0, 0), .iManufacturer = UsbDevManuf, .iProduct = UsbDevProduct, - .iSerialNumber = UsbDevSerial, + .iSerialNumber = 0, .bNumConfigurations = 1, }; @@ -138,7 +137,7 @@ static const struct HidConfigDescriptor hid_u2f_cfg_desc = { }, }; -static void hid_u2f_init(usbd_device* dev, UsbInterface* intf); +static void hid_u2f_init(usbd_device* dev, FuriHalUsbInterface* intf); static void hid_u2f_deinit(usbd_device* dev); static void hid_u2f_on_wakeup(usbd_device* dev); static void hid_u2f_on_suspend(usbd_device* dev); @@ -171,7 +170,7 @@ void furi_hal_hid_u2f_set_callback(HidU2fCallback cb, void* ctx) { } } -UsbInterface usb_hid_u2f = { +FuriHalUsbInterface usb_hid_u2f = { .init = hid_u2f_init, .deinit = hid_u2f_deinit, .wakeup = hid_u2f_on_wakeup, @@ -181,12 +180,12 @@ UsbInterface usb_hid_u2f = { .str_manuf_descr = (void*)&dev_manuf_desc, .str_prod_descr = (void*)&dev_prod_desc, - .str_serial_descr = (void*)&dev_serial_desc, + .str_serial_descr = NULL, .cfg_descr = (void*)&hid_u2f_cfg_desc, }; -static void hid_u2f_init(usbd_device* dev, UsbInterface* intf) { +static void hid_u2f_init(usbd_device* dev, FuriHalUsbInterface* intf) { if(hid_u2f_semaphore == NULL) hid_u2f_semaphore = osSemaphoreNew(1, 1, NULL); usb_dev = dev; diff --git a/firmware/targets/f6/target.mk b/firmware/targets/f6/target.mk index 029c8f40..0c9bd182 100644 --- a/firmware/targets/f6/target.mk +++ b/firmware/targets/f6/target.mk @@ -112,6 +112,7 @@ C_SOURCES += \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gatt_aci.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hal_aci.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_l2cap_aci.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl_if.c \ diff --git a/firmware/targets/f7/ble_glue/gap.c b/firmware/targets/f7/ble_glue/gap.c old mode 100644 new mode 100755 index dfcd174e..d9a2096f --- a/firmware/targets/f7/ble_glue/gap.c +++ b/firmware/targets/f7/ble_glue/gap.c @@ -94,9 +94,17 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { case EVT_LE_META_EVENT: meta_evt = (evt_le_meta_event*)event_pckt->data; switch(meta_evt->subevent) { - case EVT_LE_CONN_UPDATE_COMPLETE: - FURI_LOG_D(TAG, "Connection update event"); + case EVT_LE_CONN_UPDATE_COMPLETE: { + hci_le_connection_update_complete_event_rp0* event = + (hci_le_connection_update_complete_event_rp0*)meta_evt->data; + FURI_LOG_I( + TAG, + "Connection interval: %d, latency: %d, supervision timeout: %d", + event->Conn_Interval, + event->Conn_Latency, + event->Supervision_Timeout); break; + } case EVT_LE_PHY_UPDATE_COMPLETE: evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data; @@ -129,6 +137,15 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { // Update connection status and handle gap->state = GapStateConnected; gap->service.connection_handle = connection_complete_event->Connection_Handle; + GapConnectionParams* params = &gap->config->conn_param; + if(aci_l2cap_connection_parameter_update_req( + gap->service.connection_handle, + params->conn_int_min, + params->conn_int_max, + params->slave_latency, + params->supervisor_timeout)) { + FURI_LOG_W(TAG, "Failed to request connection parameters update"); + } // Start pairing by sending security request aci_gap_slave_security_req(connection_complete_event->Connection_Handle); @@ -184,28 +201,28 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { } break; case EVT_BLUE_GAP_AUTHORIZATION_REQUEST: - FURI_LOG_I(TAG, "Authorization request event"); + FURI_LOG_D(TAG, "Authorization request event"); break; case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED: - FURI_LOG_I(TAG, "Slave security initiated"); + FURI_LOG_D(TAG, "Slave security initiated"); break; case EVT_BLUE_GAP_BOND_LOST: - FURI_LOG_I(TAG, "Bond lost event. Start rebonding"); + FURI_LOG_D(TAG, "Bond lost event. Start rebonding"); aci_gap_allow_rebond(gap->service.connection_handle); break; case EVT_BLUE_GAP_DEVICE_FOUND: - FURI_LOG_I(TAG, "Device found event"); + FURI_LOG_D(TAG, "Device found event"); break; case EVT_BLUE_GAP_ADDR_NOT_RESOLVED: - FURI_LOG_I(TAG, "Address not resolved event"); + FURI_LOG_D(TAG, "Address not resolved event"); break; case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION: - FURI_LOG_I(TAG, "Key press notification event"); + FURI_LOG_D(TAG, "Key press notification event"); break; case EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE: { @@ -234,8 +251,19 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { break; case EVT_BLUE_GAP_PROCEDURE_COMPLETE: - FURI_LOG_I(TAG, "Procedure complete event"); + FURI_LOG_D(TAG, "Procedure complete event"); break; + + case EVT_BLUE_L2CAP_CONNECTION_UPDATE_RESP: { + uint16_t result = + ((aci_l2cap_connection_update_resp_event_rp0*)(blue_evt->data))->Result; + if(result == 0) { + FURI_LOG_D(TAG, "Connection parameters accepted"); + } else if(result == 1) { + FURI_LOG_D(TAG, "Connection parameters denied"); + } + break; + } } default: break; diff --git a/firmware/targets/f7/ble_glue/gap.h b/firmware/targets/f7/ble_glue/gap.h index 635a4c3c..1a2e7962 100644 --- a/firmware/targets/f7/ble_glue/gap.h +++ b/firmware/targets/f7/ble_glue/gap.h @@ -55,6 +55,13 @@ typedef enum { GapPairingPinCodeVerifyYesNo, } GapPairing; +typedef struct { + uint16_t conn_int_min; + uint16_t conn_int_max; + uint16_t slave_latency; + uint16_t supervisor_timeout; +} GapConnectionParams; + typedef struct { uint16_t adv_service_uuid; uint16_t appearance_char; @@ -62,6 +69,7 @@ typedef struct { GapPairing pairing_method; uint8_t mac_address[GAP_MAC_ADDR_SIZE]; char adv_name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH]; + GapConnectionParams conn_param; } GapConfig; bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context); diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c old mode 100644 new mode 100755 index 7147c7f0..4465f15e --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -42,6 +42,13 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = { .bonding_mode = true, .pairing_method = GapPairingPinCodeShow, .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, + .conn_param = + { + .conn_int_min = 0x08, + .conn_int_max = 0x18, + .slave_latency = 0, + .supervisor_timeout = 50, + }, }, }, [FuriHalBtProfileHidKeyboard] = @@ -55,6 +62,14 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = { .bonding_mode = true, .pairing_method = GapPairingPinCodeVerifyYesNo, .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, + // TODO optimize + .conn_param = + { + .conn_int_min = 0x12, + .conn_int_max = 0x1e, + .slave_latency = 6, + .supervisor_timeout = 700, + }, }, }, }; @@ -277,6 +292,16 @@ void furi_hal_bt_nvm_sram_sem_release() { HAL_HSEM_Release(CFG_HW_BLE_NVM_SRAM_SEMID, 0); } +bool furi_hal_bt_clear_white_list() { + furi_hal_bt_nvm_sram_sem_acquire(); + tBleStatus status = aci_gap_clear_security_db(); + if(status) { + FURI_LOG_E(TAG, "Clear while list failed with status %d", status); + } + furi_hal_bt_nvm_sram_sem_release(); + return status != BLE_STATUS_SUCCESS; +} + void furi_hal_bt_dump_state(string_t buffer) { if(furi_hal_bt_is_alive()) { uint8_t HCI_Version; diff --git a/firmware/targets/f7/furi_hal/furi_hal_light.c b/firmware/targets/f7/furi_hal/furi_hal_light.c index 6aba7efb..1bd1adad 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_light.c +++ b/firmware/targets/f7/furi_hal/furi_hal_light.c @@ -28,6 +28,7 @@ void furi_hal_light_init() { } void furi_hal_light_set(Light light, uint8_t value) { + uint8_t prev = 0; furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); switch(light) { case LightRed: @@ -40,10 +41,12 @@ void furi_hal_light_set(Light light, uint8_t value) { lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); break; case LightBacklight: - lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value); + prev = lp5562_get_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite); + lp5562_execute_ramp( + &furi_hal_i2c_handle_power, LP5562Engine1, LP5562ChannelWhite, prev, value, 100); break; default: break; } furi_hal_i2c_release(&furi_hal_i2c_handle_power); -} \ No newline at end of file +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c index a574ebcc..1dbdb3dd 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_power.c +++ b/firmware/targets/f7/furi_hal/furi_hal_power.c @@ -216,6 +216,13 @@ bool furi_hal_power_is_otg_enabled() { return ret; } +void furi_hal_power_check_otg_status() { + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + if(bq25896_check_otg_fault(&furi_hal_i2c_handle_power)) + bq25896_disable_otg(&furi_hal_i2c_handle_power); + furi_hal_i2c_release(&furi_hal_i2c_handle_power); +} + uint32_t furi_hal_power_get_battery_remaining_capacity() { furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); uint32_t ret = bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power); @@ -297,6 +304,7 @@ void furi_hal_power_dump_state() { BQ27220_ERROR) { printf("Failed to get bq27220 status. Communication error.\r\n"); } else { + // Operation status register printf( "bq27220: CALMD: %d, SEC0: %d, SEC1: %d, EDV2: %d, VDQ: %d, INITCOMP: %d, SMTH: %d, BTPINT: %d, CFGUPDATE: %d\r\n", operation_status.CALMD, diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/firmware/targets/f7/furi_hal/furi_hal_usb.c index 59b37bbf..881081b6 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb.c @@ -9,15 +9,19 @@ #define USB_RECONNECT_DELAY 500 -static UsbInterface* usb_if_cur; -static UsbInterface* usb_if_next; +static FuriHalUsbInterface* usb_if_cur; +static FuriHalUsbInterface* usb_if_next; static const struct usb_string_descriptor dev_lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US); static uint32_t ubuf[0x20]; usbd_device udev; +static FuriHalUsbStateCallback callback; +static void* cb_ctx; + static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_t* length); +static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep); static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep); static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep); @@ -25,6 +29,7 @@ struct UsbCfg { osTimerId_t reconnect_tmr; bool enabled; bool connected; + bool mode_changing; } usb_config; static void furi_hal_usb_tmr_cb(void* context); @@ -48,6 +53,7 @@ void furi_hal_usb_init(void) { usbd_reg_descr(&udev, usb_descriptor_get); usbd_reg_event(&udev, usbd_evt_susp, susp_evt); usbd_reg_event(&udev, usbd_evt_wkup, wkup_evt); + // Reset callback will be enabled after first mode change to avoid getting false reset events usb_config.enabled = false; usb_config.reconnect_tmr = NULL; @@ -57,28 +63,49 @@ void furi_hal_usb_init(void) { FURI_LOG_I(TAG, "Init OK"); } -void furi_hal_usb_set_config(UsbInterface* new_if) { - if(new_if != usb_if_cur) { - if(usb_config.enabled) { - usb_if_next = new_if; - if(usb_config.reconnect_tmr == NULL) - usb_config.reconnect_tmr = - osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); - furi_hal_usb_disable(); - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); - } else { - if(usb_if_cur != NULL) usb_if_cur->deinit(&udev); - if(new_if != NULL) { - new_if->init(&udev, new_if); - FURI_LOG_I(TAG, "USB mode change"); - usb_config.enabled = true; - usb_if_cur = new_if; - } +void furi_hal_usb_set_config(FuriHalUsbInterface* new_if) { + if((new_if != usb_if_cur) && (usb_config.enabled)) { // Interface mode change - first stage + usb_config.mode_changing = true; + usb_if_next = new_if; + if(usb_config.reconnect_tmr == NULL) + usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); + furi_hal_usb_disable(); + usb_config.mode_changing = true; + osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); + } else if( + (usb_config.mode_changing) && + (usb_if_next != new_if)) { // Last interface mode change wasn't completed + osTimerStop(usb_config.reconnect_tmr); + usb_if_next = new_if; + osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); + } else { // Interface mode change - second stage + if(usb_if_cur != NULL) usb_if_cur->deinit(&udev); + if(new_if != NULL) { + new_if->init(&udev, new_if); + usbd_reg_event(&udev, usbd_evt_reset, reset_evt); + FURI_LOG_I(TAG, "USB Mode change done"); + usb_config.enabled = true; + usb_if_cur = new_if; + usb_config.mode_changing = false; } } } -UsbInterface* furi_hal_usb_get_config() { +void furi_hal_usb_reinit() { + // Temporary disable callback to avoid getting false reset events + usbd_reg_event(&udev, usbd_evt_reset, NULL); + FURI_LOG_I(TAG, "USB Reinit"); + furi_hal_usb_disable(); + usbd_enable(&udev, false); + usbd_enable(&udev, true); + if(usb_config.reconnect_tmr == NULL) + usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); + usb_config.mode_changing = true; + usb_if_next = usb_if_cur; + osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); +} + +FuriHalUsbInterface* furi_hal_usb_get_config() { return usb_if_cur; } @@ -113,6 +140,9 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ switch(dtype) { case USB_DTYPE_DEVICE: + if(callback != NULL) { + callback(FuriHalUsbStateEventDescriptorRequest, cb_ctx); + } desc = usb_if_cur->dev_descr; break; case USB_DTYPE_CONFIGURATION: @@ -122,11 +152,11 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ case USB_DTYPE_STRING: if(dnumber == UsbDevLang) { desc = &dev_lang_desc; - } else if(dnumber == UsbDevManuf) { + } else if((dnumber == UsbDevManuf) && (usb_if_cur->str_manuf_descr != NULL)) { desc = usb_if_cur->str_manuf_descr; - } else if(dnumber == UsbDevProduct) { + } else if((dnumber == UsbDevProduct) && (usb_if_cur->str_prod_descr != NULL)) { desc = usb_if_cur->str_prod_descr; - } else if(dnumber == UsbDevSerial) { + } else if((dnumber == UsbDevSerial) && (usb_if_cur->str_serial_descr != NULL)) { desc = usb_if_cur->str_serial_descr; } else return usbd_fail; @@ -144,11 +174,25 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ return usbd_ack; } +void furi_hal_usb_set_state_callback(FuriHalUsbStateCallback cb, void* ctx) { + callback = cb; + cb_ctx = ctx; +} + +static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep) { + if(callback != NULL) { + callback(FuriHalUsbStateEventReset, cb_ctx); + } +} + static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep) { if((usb_if_cur != NULL) && (usb_config.connected == true)) { usb_config.connected = false; usb_if_cur->suspend(&udev); } + if(callback != NULL) { + callback(FuriHalUsbStateEventSuspend, cb_ctx); + } } static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep) { @@ -156,4 +200,7 @@ static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep) { usb_config.connected = true; usb_if_cur->wakeup(&udev); } + if(callback != NULL) { + callback(FuriHalUsbStateEventWakeup, cb_ctx); + } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c b/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c index 26fd40c3..d7fcbc58 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c @@ -385,7 +385,7 @@ static const struct CdcConfigDescriptorDual static struct usb_cdc_line_coding cdc_config[IF_NUM_MAX] = {}; static uint8_t cdc_ctrl_line_state[IF_NUM_MAX]; -static void cdc_init(usbd_device* dev, UsbInterface* intf); +static void cdc_init(usbd_device* dev, FuriHalUsbInterface* intf); static void cdc_deinit(usbd_device* dev); static void cdc_on_wakeup(usbd_device* dev); static void cdc_on_suspend(usbd_device* dev); @@ -393,12 +393,12 @@ static void cdc_on_suspend(usbd_device* dev); static usbd_respond cdc_ep_config(usbd_device* dev, uint8_t cfg); static usbd_respond cdc_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback); static usbd_device* usb_dev; -static UsbInterface* cdc_if_cur = NULL; +static FuriHalUsbInterface* cdc_if_cur = NULL; static bool connected = false; static CdcCallbacks* callbacks[IF_NUM_MAX] = {NULL}; static void* cb_ctx[IF_NUM_MAX]; -UsbInterface usb_cdc_single = { +FuriHalUsbInterface usb_cdc_single = { .init = cdc_init, .deinit = cdc_deinit, .wakeup = cdc_on_wakeup, @@ -413,7 +413,7 @@ UsbInterface usb_cdc_single = { .cfg_descr = (void*)&cdc_cfg_desc_single, }; -UsbInterface usb_cdc_dual = { +FuriHalUsbInterface usb_cdc_dual = { .init = cdc_init, .deinit = cdc_deinit, .wakeup = cdc_on_wakeup, @@ -428,7 +428,7 @@ UsbInterface usb_cdc_dual = { .cfg_descr = (void*)&cdc_cfg_desc_dual, }; -static void cdc_init(usbd_device* dev, UsbInterface* intf) { +static void cdc_init(usbd_device* dev, FuriHalUsbInterface* intf) { usb_dev = dev; cdc_if_cur = intf; diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c index 098acc73..6f94fb33 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c @@ -236,7 +236,7 @@ static struct HidReport { struct HidReportConsumer consumer; } __attribute__((packed)) hid_report; -static void hid_init(usbd_device* dev, UsbInterface* intf); +static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf); static void hid_deinit(usbd_device* dev); static void hid_on_wakeup(usbd_device* dev); static void hid_on_suspend(usbd_device* dev); @@ -348,7 +348,7 @@ bool furi_hal_hid_consumer_key_release(uint16_t button) { return hid_send_report(ReportIdConsumer); } -UsbInterface usb_hid = { +FuriHalUsbInterface usb_hid = { .init = hid_init, .deinit = hid_deinit, .wakeup = hid_on_wakeup, @@ -363,7 +363,7 @@ UsbInterface usb_hid = { .cfg_descr = (void*)&hid_cfg_desc, }; -static void hid_init(usbd_device* dev, UsbInterface* intf) { +static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf) { if(hid_semaphore == NULL) hid_semaphore = osSemaphoreNew(1, 1, NULL); usb_dev = dev; hid_report.keyboard.report_id = ReportIdKeyboard; diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_u2f.c b/firmware/targets/f7/furi_hal/furi_hal_usb_u2f.c index a3bb145e..4ee3d712 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_u2f.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_u2f.c @@ -48,8 +48,7 @@ static const uint8_t hid_u2f_report_desc[] = { }; static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Flipper Devices Inc."); -static const struct usb_string_descriptor dev_prod_desc = USB_STRING_DESC("U2F Token test"); -static const struct usb_string_descriptor dev_serial_desc = USB_STRING_DESC("TODO: serial"); +static const struct usb_string_descriptor dev_prod_desc = USB_STRING_DESC("U2F Token"); /* Device descriptor */ static const struct usb_device_descriptor hid_u2f_device_desc = { @@ -65,7 +64,7 @@ static const struct usb_device_descriptor hid_u2f_device_desc = { .bcdDevice = VERSION_BCD(1, 0, 0), .iManufacturer = UsbDevManuf, .iProduct = UsbDevProduct, - .iSerialNumber = UsbDevSerial, + .iSerialNumber = 0, .bNumConfigurations = 1, }; @@ -138,7 +137,7 @@ static const struct HidConfigDescriptor hid_u2f_cfg_desc = { }, }; -static void hid_u2f_init(usbd_device* dev, UsbInterface* intf); +static void hid_u2f_init(usbd_device* dev, FuriHalUsbInterface* intf); static void hid_u2f_deinit(usbd_device* dev); static void hid_u2f_on_wakeup(usbd_device* dev); static void hid_u2f_on_suspend(usbd_device* dev); @@ -171,7 +170,7 @@ void furi_hal_hid_u2f_set_callback(HidU2fCallback cb, void* ctx) { } } -UsbInterface usb_hid_u2f = { +FuriHalUsbInterface usb_hid_u2f = { .init = hid_u2f_init, .deinit = hid_u2f_deinit, .wakeup = hid_u2f_on_wakeup, @@ -181,12 +180,12 @@ UsbInterface usb_hid_u2f = { .str_manuf_descr = (void*)&dev_manuf_desc, .str_prod_descr = (void*)&dev_prod_desc, - .str_serial_descr = (void*)&dev_serial_desc, + .str_serial_descr = NULL, .cfg_descr = (void*)&hid_u2f_cfg_desc, }; -static void hid_u2f_init(usbd_device* dev, UsbInterface* intf) { +static void hid_u2f_init(usbd_device* dev, FuriHalUsbInterface* intf) { if(hid_u2f_semaphore == NULL) hid_u2f_semaphore = osSemaphoreNew(1, 1, NULL); usb_dev = dev; diff --git a/firmware/targets/f7/target.mk b/firmware/targets/f7/target.mk index 029c8f40..0c9bd182 100644 --- a/firmware/targets/f7/target.mk +++ b/firmware/targets/f7/target.mk @@ -112,6 +112,7 @@ C_SOURCES += \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gatt_aci.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hal_aci.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_l2cap_aci.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl_if.c \ diff --git a/firmware/targets/furi_hal_include/furi_hal_bt.h b/firmware/targets/furi_hal_include/furi_hal_bt.h index cacf33a3..e10901b0 100644 --- a/firmware/targets/furi_hal_include/furi_hal_bt.h +++ b/firmware/targets/furi_hal_include/furi_hal_bt.h @@ -121,6 +121,12 @@ void furi_hal_bt_nvm_sram_sem_acquire(); */ void furi_hal_bt_nvm_sram_sem_release(); +/** Clear key storage + * + * @return true on success +*/ +bool furi_hal_bt_clear_white_list(); + /** Set key storage change callback * * @param callback BleGlueKeyStorageChangedCallback instance diff --git a/firmware/targets/furi_hal_include/furi_hal_power.h b/firmware/targets/furi_hal_include/furi_hal_power.h index 62387059..3f5a0020 100644 --- a/firmware/targets/furi_hal_include/furi_hal_power.h +++ b/firmware/targets/furi_hal_include/furi_hal_power.h @@ -91,6 +91,10 @@ void furi_hal_power_enable_otg(); */ void furi_hal_power_disable_otg(); +/** Check OTG status and disable it if falt happened + */ +void furi_hal_power_check_otg_status(); + /** Get OTG status * * @return true if enabled diff --git a/firmware/targets/furi_hal_include/furi_hal_usb.h b/firmware/targets/furi_hal_include/furi_hal_usb.h index b4f001e8..9ab9b642 100644 --- a/firmware/targets/furi_hal_include/furi_hal_usb.h +++ b/firmware/targets/furi_hal_include/furi_hal_usb.h @@ -2,10 +2,10 @@ #include "usb.h" -typedef struct UsbInterface UsbInterface; +typedef struct FuriHalUsbInterface FuriHalUsbInterface; -struct UsbInterface { - void (*init)(usbd_device* dev, UsbInterface* intf); +struct FuriHalUsbInterface { + void (*init)(usbd_device* dev, FuriHalUsbInterface* intf); void (*deinit)(usbd_device* dev); void (*wakeup)(usbd_device* dev); void (*suspend)(usbd_device* dev); @@ -20,10 +20,19 @@ struct UsbInterface { }; /** USB device interface modes */ -extern UsbInterface usb_cdc_single; -extern UsbInterface usb_cdc_dual; -extern UsbInterface usb_hid; -extern UsbInterface usb_hid_u2f; +extern FuriHalUsbInterface usb_cdc_single; +extern FuriHalUsbInterface usb_cdc_dual; +extern FuriHalUsbInterface usb_hid; +extern FuriHalUsbInterface usb_hid_u2f; + +typedef enum { + FuriHalUsbStateEventReset, + FuriHalUsbStateEventWakeup, + FuriHalUsbStateEventSuspend, + FuriHalUsbStateEventDescriptorRequest, +} FuriHalUsbStateEvent; + +typedef void (*FuriHalUsbStateCallback)(FuriHalUsbStateEvent state, void* context); /** USB device low-level initialization */ @@ -33,13 +42,13 @@ void furi_hal_usb_init(); * * @param mode new USB device mode */ -void furi_hal_usb_set_config(UsbInterface* new_if); +void furi_hal_usb_set_config(FuriHalUsbInterface* new_if); /** Get USB device configuration * * @return current USB device mode */ -UsbInterface* furi_hal_usb_get_config(); +FuriHalUsbInterface* furi_hal_usb_get_config(); /** Disable USB device */ @@ -48,3 +57,11 @@ void furi_hal_usb_disable(); /** Enable USB device */ void furi_hal_usb_enable(); + +/** Set USB state callback + */ +void furi_hal_usb_set_state_callback(FuriHalUsbStateCallback cb, void* ctx); + +/** Restart USB device + */ +void furi_hal_usb_reinit(); diff --git a/lib/app-scened-template/view_modules/submenu_vm.cpp b/lib/app-scened-template/view_modules/submenu_vm.cpp index ee6b4441..939bb6b1 100644 --- a/lib/app-scened-template/view_modules/submenu_vm.cpp +++ b/lib/app-scened-template/view_modules/submenu_vm.cpp @@ -13,7 +13,7 @@ View* SubmenuVM::get_view() { } void SubmenuVM::clean() { - submenu_clean(submenu); + submenu_reset(submenu); } void SubmenuVM::add_item( diff --git a/lib/app-scened-template/view_modules/text_input_vm.cpp b/lib/app-scened-template/view_modules/text_input_vm.cpp index 6777fb29..05e5ed1d 100644 --- a/lib/app-scened-template/view_modules/text_input_vm.cpp +++ b/lib/app-scened-template/view_modules/text_input_vm.cpp @@ -13,7 +13,7 @@ View* TextInputVM::get_view() { } void TextInputVM::clean() { - text_input_clean(text_input); + text_input_reset(text_input); } void TextInputVM::set_result_callback( @@ -29,3 +29,11 @@ void TextInputVM::set_result_callback( void TextInputVM::set_header_text(const char* text) { text_input_set_header_text(text_input, text); } + +void TextInputVM::set_validator(TextInputValidatorCallback callback, void* callback_context) { + text_input_set_validator(text_input, callback, callback_context); +} + +void* TextInputVM::get_validator_callback_context() { + return text_input_get_validator_callback_context(text_input); +} diff --git a/lib/app-scened-template/view_modules/text_input_vm.h b/lib/app-scened-template/view_modules/text_input_vm.h index 3aedc9be..8fafe861 100644 --- a/lib/app-scened-template/view_modules/text_input_vm.h +++ b/lib/app-scened-template/view_modules/text_input_vm.h @@ -32,6 +32,10 @@ public: */ void set_header_text(const char* text); + void set_validator(TextInputValidatorCallback callback, void* callback_context); + + void* get_validator_callback_context(); + private: TextInput* text_input; }; \ No newline at end of file diff --git a/lib/drivers/bq25896.c b/lib/drivers/bq25896.c index 3f923b97..73135d93 100644 --- a/lib/drivers/bq25896.c +++ b/lib/drivers/bq25896.c @@ -10,19 +10,6 @@ uint8_t bit_reverse(uint8_t b) { return b; } -bool bq25896_read(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data, size_t size) { - return furi_hal_i2c_trx(handle, BQ25896_ADDRESS, &address, 1, data, size, BQ25896_I2C_TIMEOUT); -} - -bool bq25896_read_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) { - return bq25896_read(handle, address, data, 1); -} - -bool bq25896_write_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) { - uint8_t buffer[2] = {address, *data}; - return furi_hal_i2c_tx(handle, BQ25896_ADDRESS, buffer, 2, BQ25896_I2C_TIMEOUT); -} - typedef struct { REG00 r00; REG01 r01; @@ -51,60 +38,101 @@ static bq25896_regs_t bq25896_regs; void bq25896_init(FuriHalI2cBusHandle* handle) { bq25896_regs.r14.REG_RST = 1; - bq25896_write_reg(handle, 0x14, (uint8_t*)&bq25896_regs.r14); + furi_hal_i2c_write_reg_8( + handle, BQ25896_ADDRESS, 0x14, *(uint8_t*)&bq25896_regs.r14, BQ25896_I2C_TIMEOUT); // Readout all registers - bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs)); + furi_hal_i2c_read_mem( + handle, + BQ25896_ADDRESS, + 0x00, + (uint8_t*)&bq25896_regs, + sizeof(bq25896_regs), + BQ25896_I2C_TIMEOUT); // Poll ADC forever bq25896_regs.r02.CONV_START = 1; bq25896_regs.r02.CONV_RATE = 1; - bq25896_write_reg(handle, 0x02, (uint8_t*)&bq25896_regs.r02); + furi_hal_i2c_write_reg_8( + handle, BQ25896_ADDRESS, 0x02, *(uint8_t*)&bq25896_regs.r02, BQ25896_I2C_TIMEOUT); bq25896_regs.r07.WATCHDOG = WatchdogDisable; - bq25896_write_reg(handle, 0x07, (uint8_t*)&bq25896_regs.r07); + furi_hal_i2c_write_reg_8( + handle, BQ25896_ADDRESS, 0x07, *(uint8_t*)&bq25896_regs.r07, BQ25896_I2C_TIMEOUT); - bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs)); + // OTG power configuration + bq25896_regs.r0A.BOOSTV = 0x8; // BOOST Voltage: 5.062V + bq25896_regs.r0A.BOOST_LIM = BOOST_LIM_1400; // BOOST Current limit: 1.4A + furi_hal_i2c_write_reg_8( + handle, BQ25896_ADDRESS, 0x0A, *(uint8_t*)&bq25896_regs.r0A, BQ25896_I2C_TIMEOUT); + + furi_hal_i2c_read_mem( + handle, + BQ25896_ADDRESS, + 0x00, + (uint8_t*)&bq25896_regs, + sizeof(bq25896_regs), + BQ25896_I2C_TIMEOUT); } void bq25896_poweroff(FuriHalI2cBusHandle* handle) { bq25896_regs.r09.BATFET_DIS = 1; - bq25896_write_reg(handle, 0x09, (uint8_t*)&bq25896_regs.r09); + furi_hal_i2c_write_reg_8( + handle, BQ25896_ADDRESS, 0x09, *(uint8_t*)&bq25896_regs.r09, BQ25896_I2C_TIMEOUT); } bool bq25896_is_charging(FuriHalI2cBusHandle* handle) { - bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs)); - bq25896_read_reg(handle, 0x0B, (uint8_t*)&bq25896_regs.r0B); + furi_hal_i2c_read_mem( + handle, + BQ25896_ADDRESS, + 0x00, + (uint8_t*)&bq25896_regs, + sizeof(bq25896_regs), + BQ25896_I2C_TIMEOUT); + furi_hal_i2c_read_reg_8( + handle, BQ25896_ADDRESS, 0x0B, (uint8_t*)&bq25896_regs.r0B, BQ25896_I2C_TIMEOUT); return bq25896_regs.r0B.CHRG_STAT != ChrgStatNo; } void bq25896_enable_charging(FuriHalI2cBusHandle* handle) { bq25896_regs.r03.CHG_CONFIG = 1; - bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03); + furi_hal_i2c_write_reg_8( + handle, BQ25896_ADDRESS, 0x03, *(uint8_t*)&bq25896_regs.r03, BQ25896_I2C_TIMEOUT); } void bq25896_disable_charging(FuriHalI2cBusHandle* handle) { bq25896_regs.r03.CHG_CONFIG = 0; - bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03); + furi_hal_i2c_write_reg_8( + handle, BQ25896_ADDRESS, 0x03, *(uint8_t*)&bq25896_regs.r03, BQ25896_I2C_TIMEOUT); } void bq25896_enable_otg(FuriHalI2cBusHandle* handle) { bq25896_regs.r03.OTG_CONFIG = 1; - bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03); + furi_hal_i2c_write_reg_8( + handle, BQ25896_ADDRESS, 0x03, *(uint8_t*)&bq25896_regs.r03, BQ25896_I2C_TIMEOUT); } void bq25896_disable_otg(FuriHalI2cBusHandle* handle) { bq25896_regs.r03.OTG_CONFIG = 0; - bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03); + furi_hal_i2c_write_reg_8( + handle, BQ25896_ADDRESS, 0x03, *(uint8_t*)&bq25896_regs.r03, BQ25896_I2C_TIMEOUT); } bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle) { - bq25896_read_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03); + furi_hal_i2c_read_reg_8( + handle, BQ25896_ADDRESS, 0x03, (uint8_t*)&bq25896_regs.r03, BQ25896_I2C_TIMEOUT); return bq25896_regs.r03.OTG_CONFIG; } +bool bq25896_check_otg_fault(FuriHalI2cBusHandle* handle) { + furi_hal_i2c_read_reg_8( + handle, BQ25896_ADDRESS, 0x0C, (uint8_t*)&bq25896_regs.r0C, BQ25896_I2C_TIMEOUT); + return bq25896_regs.r0C.BOOST_FAULT; +} + uint16_t bq25896_get_vbus_voltage(FuriHalI2cBusHandle* handle) { - bq25896_read_reg(handle, 0x11, (uint8_t*)&bq25896_regs.r11); + furi_hal_i2c_read_reg_8( + handle, BQ25896_ADDRESS, 0x11, (uint8_t*)&bq25896_regs.r11, BQ25896_I2C_TIMEOUT); if(bq25896_regs.r11.VBUS_GD) { return (uint16_t)bq25896_regs.r11.VBUSV * 100 + 2600; } else { @@ -113,21 +141,25 @@ uint16_t bq25896_get_vbus_voltage(FuriHalI2cBusHandle* handle) { } uint16_t bq25896_get_vsys_voltage(FuriHalI2cBusHandle* handle) { - bq25896_read_reg(handle, 0x0F, (uint8_t*)&bq25896_regs.r0F); + furi_hal_i2c_read_reg_8( + handle, BQ25896_ADDRESS, 0x0F, (uint8_t*)&bq25896_regs.r0F, BQ25896_I2C_TIMEOUT); return (uint16_t)bq25896_regs.r0F.SYSV * 20 + 2304; } uint16_t bq25896_get_vbat_voltage(FuriHalI2cBusHandle* handle) { - bq25896_read_reg(handle, 0x0E, (uint8_t*)&bq25896_regs.r0E); + furi_hal_i2c_read_reg_8( + handle, BQ25896_ADDRESS, 0x0E, (uint8_t*)&bq25896_regs.r0E, BQ25896_I2C_TIMEOUT); return (uint16_t)bq25896_regs.r0E.BATV * 20 + 2304; } uint16_t bq25896_get_vbat_current(FuriHalI2cBusHandle* handle) { - bq25896_read_reg(handle, 0x12, (uint8_t*)&bq25896_regs.r12); + furi_hal_i2c_read_reg_8( + handle, BQ25896_ADDRESS, 0x12, (uint8_t*)&bq25896_regs.r12, BQ25896_I2C_TIMEOUT); return (uint16_t)bq25896_regs.r12.ICHGR * 50; } uint32_t bq25896_get_ntc_mpct(FuriHalI2cBusHandle* handle) { - bq25896_read_reg(handle, 0x10, (uint8_t*)&bq25896_regs.r10); + furi_hal_i2c_read_reg_8( + handle, BQ25896_ADDRESS, 0x10, (uint8_t*)&bq25896_regs.r10, BQ25896_I2C_TIMEOUT); return (uint32_t)bq25896_regs.r10.TSPCT * 465 + 21000; } diff --git a/lib/drivers/bq25896.h b/lib/drivers/bq25896.h index 5019a816..39d343c3 100644 --- a/lib/drivers/bq25896.h +++ b/lib/drivers/bq25896.h @@ -28,6 +28,9 @@ void bq25896_disable_otg(FuriHalI2cBusHandle* handle); /** Is otg enabled */ bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle); +/** Check OTG BOOST Fault status */ +bool bq25896_check_otg_fault(FuriHalI2cBusHandle* handle); + /** Get VBUS Voltage in mV */ uint16_t bq25896_get_vbus_voltage(FuriHalI2cBusHandle* handle); diff --git a/lib/drivers/bq27220.c b/lib/drivers/bq27220.c index 0dcae180..bcdf4535 100644 --- a/lib/drivers/bq27220.c +++ b/lib/drivers/bq27220.c @@ -8,24 +8,17 @@ #define TAG "Gauge" uint16_t bq27220_read_word(FuriHalI2cBusHandle* handle, uint8_t address) { - uint8_t buffer[2] = {address}; - uint16_t ret = 0; + uint16_t buf = 0; - if(furi_hal_i2c_trx(handle, BQ27220_ADDRESS, buffer, 1, buffer, 2, BQ27220_I2C_TIMEOUT)) { - ret = *(uint16_t*)buffer; - } + furi_hal_i2c_read_mem( + handle, BQ27220_ADDRESS, address, (uint8_t*)&buf, 2, BQ27220_I2C_TIMEOUT); - return ret; + return buf; } bool bq27220_control(FuriHalI2cBusHandle* handle, uint16_t control) { - bool ret = false; - uint8_t buffer[3]; - - buffer[0] = CommandControl; - buffer[1] = control & 0xFF; - buffer[2] = (control >> 8) & 0xFF; - ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT); + bool ret = furi_hal_i2c_write_mem( + handle, BQ27220_ADDRESS, CommandControl, (uint8_t*)&control, 2, BQ27220_I2C_TIMEOUT); return ret; } @@ -40,22 +33,22 @@ uint8_t bq27220_get_checksum(uint8_t* data, uint16_t len) { bool bq27220_set_parameter_u16(FuriHalI2cBusHandle* handle, uint16_t address, uint16_t value) { bool ret; - uint8_t buffer[5]; + uint8_t buffer[4]; - buffer[0] = CommandSelectSubclass; - buffer[1] = address & 0xFF; - buffer[2] = (address >> 8) & 0xFF; - buffer[3] = (value >> 8) & 0xFF; - buffer[4] = value & 0xFF; - ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 5, BQ27220_I2C_TIMEOUT); + buffer[0] = address & 0xFF; + buffer[1] = (address >> 8) & 0xFF; + buffer[2] = (value >> 8) & 0xFF; + buffer[3] = value & 0xFF; + ret = furi_hal_i2c_write_mem( + handle, BQ27220_ADDRESS, CommandSelectSubclass, buffer, 4, BQ27220_I2C_TIMEOUT); delay_us(10000); uint8_t checksum = bq27220_get_checksum(&buffer[1], 4); - buffer[0] = CommandMACDataSum; - buffer[1] = checksum; - buffer[2] = 6; - ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT); + buffer[0] = checksum; + buffer[1] = 6; + ret = furi_hal_i2c_write_mem( + handle, BQ27220_ADDRESS, CommandMACDataSum, buffer, 2, BQ27220_I2C_TIMEOUT); delay_us(10000); return ret; diff --git a/lib/drivers/lp5562.c b/lib/drivers/lp5562.c index 8535f3ac..82554365 100644 --- a/lib/drivers/lp5562.c +++ b/lib/drivers/lp5562.c @@ -1,21 +1,17 @@ #include "lp5562.h" #include "lp5562_reg.h" +#include #include -static bool lp5562_write_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) { - uint8_t buffer[2] = {address, *data}; - return furi_hal_i2c_tx(handle, LP5562_ADDRESS, buffer, 2, LP5562_I2C_TIMEOUT); -} - void lp5562_reset(FuriHalI2cBusHandle* handle) { Reg0D_Reset reg = {.value = 0xFF}; - lp5562_write_reg(handle, 0x0D, (uint8_t*)®); + furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x0D, *(uint8_t*)®, LP5562_I2C_TIMEOUT); } void lp5562_configure(FuriHalI2cBusHandle* handle) { Reg08_Config config = {.INT_CLK_EN = true, .PS_EN = true, .PWM_HF = true}; - lp5562_write_reg(handle, 0x08, (uint8_t*)&config); + furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x08, *(uint8_t*)&config, LP5562_I2C_TIMEOUT); Reg70_LedMap map = { .red = EngSelectI2C, @@ -23,42 +19,178 @@ void lp5562_configure(FuriHalI2cBusHandle* handle) { .blue = EngSelectI2C, .white = EngSelectI2C, }; - lp5562_write_reg(handle, 0x70, (uint8_t*)&map); + furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x70, *(uint8_t*)&map, LP5562_I2C_TIMEOUT); } void lp5562_enable(FuriHalI2cBusHandle* handle) { Reg00_Enable reg = {.CHIP_EN = true, .LOG_EN = true}; - lp5562_write_reg(handle, 0x00, (uint8_t*)®); + furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x00, *(uint8_t*)®, LP5562_I2C_TIMEOUT); + //>488μs delay is required after writing to 0x00 register, otherwise program engine will not work + delay_us(500); } void lp5562_set_channel_current(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value) { uint8_t reg_no; if(channel == LP5562ChannelRed) { - reg_no = 0x07; + reg_no = LP5562_CHANNEL_RED_CURRENT_REGISTER; } else if(channel == LP5562ChannelGreen) { - reg_no = 0x06; + reg_no = LP5562_CHANNEL_GREEN_CURRENT_REGISTER; } else if(channel == LP5562ChannelBlue) { - reg_no = 0x05; + reg_no = LP5562_CHANNEL_BLUE_CURRENT_REGISTER; } else if(channel == LP5562ChannelWhite) { - reg_no = 0x0F; + reg_no = LP5562_CHANNEL_WHITE_CURRENT_REGISTER; } else { return; } - lp5562_write_reg(handle, reg_no, &value); + furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, reg_no, value, LP5562_I2C_TIMEOUT); } void lp5562_set_channel_value(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value) { uint8_t reg_no; if(channel == LP5562ChannelRed) { - reg_no = 0x04; + reg_no = LP5562_CHANNEL_RED_VALUE_REGISTER; } else if(channel == LP5562ChannelGreen) { - reg_no = 0x03; + reg_no = LP5562_CHANNEL_GREEN_VALUE_REGISTER; } else if(channel == LP5562ChannelBlue) { - reg_no = 0x02; + reg_no = LP5562_CHANNEL_BLUE_VALUE_REGISTER; } else if(channel == LP5562ChannelWhite) { - reg_no = 0x0E; + reg_no = LP5562_CHANNEL_WHITE_VALUE_REGISTER; } else { return; } - lp5562_write_reg(handle, reg_no, &value); + furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, reg_no, value, LP5562_I2C_TIMEOUT); +} + +uint8_t lp5562_get_channel_value(FuriHalI2cBusHandle* handle, LP5562Channel channel) { + uint8_t reg_no; + uint8_t value; + if(channel == LP5562ChannelRed) { + reg_no = LP5562_CHANNEL_RED_VALUE_REGISTER; + } else if(channel == LP5562ChannelGreen) { + reg_no = LP5562_CHANNEL_GREEN_VALUE_REGISTER; + } else if(channel == LP5562ChannelBlue) { + reg_no = LP5562_CHANNEL_BLUE_VALUE_REGISTER; + } else if(channel == LP5562ChannelWhite) { + reg_no = LP5562_CHANNEL_WHITE_VALUE_REGISTER; + } else { + return 0; + } + furi_hal_i2c_read_reg_8(handle, LP5562_ADDRESS, reg_no, &value, LP5562_I2C_TIMEOUT); + return value; +} + +static void + lp5562_set_channel_src(FuriHalI2cBusHandle* handle, LP5562Channel channel, LP5562Engine src) { + uint8_t reg_val = 0; + uint8_t bit_offset = 0; + + if(channel == LP5562ChannelRed) { + bit_offset = 4; + } else if(channel == LP5562ChannelGreen) { + bit_offset = 2; + } else if(channel == LP5562ChannelBlue) { + bit_offset = 0; + } else if(channel == LP5562ChannelWhite) { + bit_offset = 6; + } else { + return; + } + + furi_hal_i2c_read_reg_8(handle, LP5562_ADDRESS, 0x70, ®_val, LP5562_I2C_TIMEOUT); + reg_val &= ~(0x3 << bit_offset); + reg_val |= ((src & 0x03) << bit_offset); + furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x70, reg_val, LP5562_I2C_TIMEOUT); +} + +void lp5562_execute_program( + FuriHalI2cBusHandle* handle, + LP5562Engine eng, + LP5562Channel ch, + uint16_t* program) { + if((eng < LP5562Engine1) || (eng > LP5562Engine3)) return; + uint8_t reg_val = 0; + uint8_t bit_offset = 0; + uint8_t enable_reg = 0; + + // Read old value of enable register + furi_hal_i2c_read_reg_8(handle, LP5562_ADDRESS, 0x00, &enable_reg, LP5562_I2C_TIMEOUT); + + // Engine configuration + bit_offset = (3 - eng) * 2; + furi_hal_i2c_read_reg_8(handle, LP5562_ADDRESS, 0x01, ®_val, LP5562_I2C_TIMEOUT); + reg_val &= ~(0x3 << bit_offset); + reg_val |= (0x01 << bit_offset); // load + furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x01, reg_val, LP5562_I2C_TIMEOUT); + delay_us(100); + + // Program load + for(uint8_t i = 0; i < 16; i++) { + // Program words are big-endian, so reverse byte order before loading + program[i] = __REV16(program[i]); + } + furi_hal_i2c_write_mem( + handle, + LP5562_ADDRESS, + 0x10 + (0x20 * (eng - 1)), + (uint8_t*)program, + 16 * 2, + LP5562_I2C_TIMEOUT); + + // Program start + bit_offset = (3 - eng) * 2; + furi_hal_i2c_read_reg_8(handle, LP5562_ADDRESS, 0x01, ®_val, LP5562_I2C_TIMEOUT); + reg_val &= ~(0x3 << bit_offset); + reg_val |= (0x02 << bit_offset); // run + furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x01, reg_val, LP5562_I2C_TIMEOUT); + + // Switch output to Execution Engine + lp5562_set_channel_src(handle, ch, eng); + + enable_reg &= ~(0x3 << bit_offset); + enable_reg |= (0x02 << bit_offset); // run + furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x00, enable_reg, LP5562_I2C_TIMEOUT); +} + +void lp5562_execute_ramp( + FuriHalI2cBusHandle* handle, + LP5562Engine eng, + LP5562Channel ch, + uint8_t val_start, + uint8_t val_end, + uint16_t time) { + if(val_start == val_end) return; + + // Temporary switch to constant value from register + lp5562_set_channel_src(handle, ch, LP5562Direct); + + // Prepare command sequence + uint16_t program[16]; + uint8_t diff = (val_end > val_start) ? (val_end - val_start) : (val_start - val_end); + uint16_t time_step = time * 2 / diff; + uint8_t prescaller = 0; + if(time_step > 0x3F) { + time_step /= 32; + prescaller = 1; + } + + if(time_step == 0) { + time_step = 1; + } else if(time_step > 0x3F) + time_step = 0x3F; + + program[0] = 0x4000 | val_start; // Set PWM + if(val_end > val_start) { + program[1] = (prescaller << 14) | (time_step << 8) | ((diff / 2) & 0x7F); // Ramp Up + } else { + program[1] = (prescaller << 14) | (time_step << 8) | 0x80 | + ((diff / 2) & 0x7F); // Ramp Down + } + program[2] = 0xA001 | ((2 - 1) << 7); // Loop to step 1, repeat twice to get full 8-bit scale + program[3] = 0xC000; // End + + // Execute program + lp5562_execute_program(handle, eng, LP5562ChannelWhite, program); + + // Write end value to register + lp5562_set_channel_value(handle, ch, val_end); } diff --git a/lib/drivers/lp5562.h b/lib/drivers/lp5562.h index 536ef899..33790d00 100644 --- a/lib/drivers/lp5562.h +++ b/lib/drivers/lp5562.h @@ -12,6 +12,13 @@ typedef enum { LP5562ChannelWhite, } LP5562Channel; +typedef enum { + LP5562Direct = 0, + LP5562Engine1 = 1, + LP5562Engine2 = 2, + LP5562Engine3 = 3, +} LP5562Engine; + /** Initialize Driver */ void lp5562_reset(FuriHalI2cBusHandle* handle); @@ -24,5 +31,24 @@ void lp5562_enable(FuriHalI2cBusHandle* handle); /** Set channel current */ void lp5562_set_channel_current(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value); -/** Set channel current */ +/** Set channel PWM value */ void lp5562_set_channel_value(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value); + +/** Get channel PWM value */ +uint8_t lp5562_get_channel_value(FuriHalI2cBusHandle* handle, LP5562Channel channel); + +/** Execute program sequence */ +void lp5562_execute_program( + FuriHalI2cBusHandle* handle, + LP5562Engine eng, + LP5562Channel ch, + uint16_t* program); + +/** Execute ramp program sequence */ +void lp5562_execute_ramp( + FuriHalI2cBusHandle* handle, + LP5562Engine eng, + LP5562Channel ch, + uint8_t val_start, + uint8_t val_end, + uint16_t time); diff --git a/lib/drivers/lp5562_reg.h b/lib/drivers/lp5562_reg.h index 2f2c1a52..e65cc2af 100644 --- a/lib/drivers/lp5562_reg.h +++ b/lib/drivers/lp5562_reg.h @@ -7,6 +7,16 @@ #define LP5562_ADDRESS 0x60 #define LP5562_I2C_TIMEOUT 50 +#define LP5562_CHANNEL_RED_CURRENT_REGISTER 0x07 +#define LP5562_CHANNEL_GREEN_CURRENT_REGISTER 0x06 +#define LP5562_CHANNEL_BLUE_CURRENT_REGISTER 0x05 +#define LP5562_CHANNEL_WHITE_CURRENT_REGISTER 0x0F + +#define LP5562_CHANNEL_RED_VALUE_REGISTER 0x04 +#define LP5562_CHANNEL_GREEN_VALUE_REGISTER 0x03 +#define LP5562_CHANNEL_BLUE_VALUE_REGISTER 0x02 +#define LP5562_CHANNEL_WHITE_VALUE_REGISTER 0x0E + typedef enum { EngExecHold = 0b00, EngExecStep = 0b01, diff --git a/lib/subghz/protocols/subghz_protocol_keeloq.c b/lib/subghz/protocols/subghz_protocol_keeloq.c index 1db8da4d..bdecb4ee 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq.c +++ b/lib/subghz/protocols/subghz_protocol_keeloq.c @@ -115,6 +115,15 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector( return 1; } break; + case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1: + man_learning = subghz_protocol_keeloq_common_magic_xor_type1_learning( + fix, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + return 1; + } + break; case KEELOQ_LEARNING_UNKNOWN: // Simple Learning decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); @@ -144,6 +153,8 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector( instance->manufacture_name = string_get_cstr(manufacture_code->name); return 1; } + + // Check for mirrored man man_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev); decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { @@ -161,13 +172,30 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector( } // Check for mirrored man - man_learning = subghz_protocol_keeloq_common_secure_learning(fix, seed, man_rev); decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { instance->manufacture_name = string_get_cstr(manufacture_code->name); return 1; } + + // Magic xor type1 learning + man_learning = subghz_protocol_keeloq_common_magic_xor_type1_learning( + fix, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + return 1; + } + + // Check for mirrored man + man_learning = + subghz_protocol_keeloq_common_magic_xor_type1_learning(fix, man_rev); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + return 1; + } break; } } @@ -198,6 +226,7 @@ void subghz_protocol_keeloq_check_remote_controller(SubGhzProtocolKeeloq* instan } else { subghz_protocol_keeloq_check_remote_controller_selector(instance, key_fix, key_hop); } + instance->common.serial = key_fix & 0x0FFFFFFF; instance->common.btn = key_fix >> 28; } diff --git a/lib/subghz/protocols/subghz_protocol_keeloq_common.c b/lib/subghz/protocols/subghz_protocol_keeloq_common.c index 0726a604..9f9d105b 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq_common.c +++ b/lib/subghz/protocols/subghz_protocol_keeloq_common.c @@ -53,7 +53,7 @@ inline uint64_t subghz_protocol_keeloq_common_normal_learning(uint32_t data, con /** Secure Learning * @param data - serial number (28bit) - * @param seed - serial number (32bit) + * @param seed - seed number (32bit) * @param key - manufacture (64bit) * @return manufacture for this serial number (64bit) */ @@ -69,4 +69,16 @@ inline uint64_t subghz_protocol_keeloq_common_secure_learning( k2 = subghz_protocol_keeloq_common_decrypt(seed, key); return ((uint64_t)k1 << 32) | k2; +} + +/** Magic_xor_type1 Learning + * @param data - serial number (28bit) + * @param xor - magic xor (64bit) + * @return manufacture for this serial number (64bit) + */ + +inline uint64_t + subghz_protocol_keeloq_common_magic_xor_type1_learning(uint32_t data, uint64_t xor) { + data &= 0x0FFFFFFF; + return (((uint64_t)data << 32) | data) ^ xor; } \ No newline at end of file diff --git a/lib/subghz/protocols/subghz_protocol_keeloq_common.h b/lib/subghz/protocols/subghz_protocol_keeloq_common.h index 906aad1f..110ce9f9 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq_common.h +++ b/lib/subghz/protocols/subghz_protocol_keeloq_common.h @@ -24,6 +24,7 @@ #define KEELOQ_LEARNING_SIMPLE 1u #define KEELOQ_LEARNING_NORMAL 2u #define KEELOQ_LEARNING_SECURE 3u +#define KEELOQ_LEARNING_MAGIC_XOR_TYPE_1 4u /** Simple Learning Encrypt * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter @@ -48,10 +49,18 @@ uint64_t subghz_protocol_keeloq_common_normal_learning(uint32_t data, const uint /** Secure Learning * @param data - serial number (28bit) - * @param seed - serial number (32bit) + * @param seed - seed number (32bit) * @param key - manufacture (64bit) * @return manufacture for this serial number (64bit) */ uint64_t - subghz_protocol_keeloq_common_secure_learning(uint32_t data, uint32_t seed, const uint64_t key); \ No newline at end of file + subghz_protocol_keeloq_common_secure_learning(uint32_t data, uint32_t seed, const uint64_t key); + +/** Magic_xor_type1 Learning + * @param data - serial number (28bit) + * @param xor - magic xor (64bit) + * @return manufacture for this serial number (64bit) + */ + +uint64_t subghz_protocol_keeloq_common_magic_xor_type1_learning(uint32_t data, uint64_t xor); diff --git a/lib/subghz/protocols/subghz_protocol_somfy_keytis.c b/lib/subghz/protocols/subghz_protocol_somfy_keytis.c new file mode 100644 index 00000000..f8e023d9 --- /dev/null +++ b/lib/subghz/protocols/subghz_protocol_somfy_keytis.c @@ -0,0 +1,345 @@ +#include "subghz_protocol_somfy_keytis.h" +#include "subghz_protocol_common.h" +#include + +#define TAG "SubGhzSomfyKeytis" + +struct SubGhzProtocolSomfyKeytis { + SubGhzProtocolCommon common; + ManchesterState manchester_saved_state; + uint32_t press_duration_counter; +}; + +typedef enum { + SomfyKeytisDecoderStepReset = 0, + SomfyKeytisDecoderStepCheckPreambula, + SomfyKeytisDecoderStepFoundPreambula, + SomfyKeytisDecoderStepStartDecode, + SomfyKeytisDecoderStepDecoderData, +} SomfyKeytisDecoderStep; + +SubGhzProtocolSomfyKeytis* subghz_protocol_somfy_keytis_alloc() { + SubGhzProtocolSomfyKeytis* instance = furi_alloc(sizeof(SubGhzProtocolSomfyKeytis)); + + instance->common.name = "Somfy Keytis"; + instance->common.code_min_count_bit_for_found = 80; + instance->common.te_short = 640; + instance->common.te_long = 1280; + instance->common.te_delta = 250; + instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic; + instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_somfy_keytis_to_str; + instance->common.to_load_protocol = + (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_somfy_keytis_to_load_protocol; + + return instance; +} + +void subghz_protocol_somfy_keytis_free(SubGhzProtocolSomfyKeytis* instance) { + furi_assert(instance); + free(instance); +} + +/** Analysis of received data + * + * @param instance SubGhzProtocolSomfyKeytis instance + */ +void subghz_protocol_somfy_keytis_remote_controller(SubGhzProtocolSomfyKeytis* instance) { + //https://pushstack.wordpress.com/somfy-rts-protocol/ + /* + * 604 us + * / + * | 2416us | 2416us | 2416us | 2416us | 4550 us | | + * + * +--------+ +--------+ +---...---+ + * + +--------+ +--------+ +--+XXXX...XXX+ + * + * | hw. sync. | soft. | | + * | | sync. | data | + * + * + * encrypt | decrypt + * + * package 80 bit pdc key btn crc cnt serial + * + * 0xA453537C4B9855 C40019 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 C80026 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 CC0033 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 D00049 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 D4005C => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 D80063 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 DC0076 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 E00086 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 E40093 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 E800AC => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 EC00B9 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 F000C3 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 F400D6 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 F800E9 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 FC00FC => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 FC0102 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 FC0113 => 0xA 4 F 7 002F 37D3CD + * 0xA453537C4B9855 FC0120 => 0xA 4 F 7 002F 37D3CD + * .......... + * 0xA453537C4B9855 FC048F => 0xA 4 F 7 002F 37D3CD + * + * Pdc: "Press Duration Counter" the total delay of the button is sent 72 parcels, + * pdc cnt4b cnt8b pdc_crc + * C40019 => 11 0001 00 0000 00000001 1001 + * C80026 => 11 0010 00 0000 00000010 0110 + * CC0033 => 11 0011 00 0000 00000011 0011 + * D00049 => 11 0100 00 0000 00000100 1001 + * D4005C => 11 0101 00 0000 00000101 1100 + * D80063 => 11 0110 00 0000 00000110 0011 + * DC0076 => 11 0111 00 0000 00000111 0110 + * E00086 => 11 1000 00 0000 00001000 0110 + * E40093 => 11 1001 00 0000 00001001 0011 + * E800AC => 11 1010 00 0000 00001010 1100 + * EC00B9 => 11 1011 00 0000 00001011 1001 + * F000C3 => 11 1100 00 0000 00001100 0011 + * F400D6 => 11 1101 00 0000 00001101 0110 + * F800E9 => 11 1110 00 0000 00001110 1001 + * FC00FC => 11 1111 00 0000 00001111 1100 + * FC0102 => 11 1111 00 0000 00010000 0010 + * FC0113 => 11 1111 00 0000 00010001 0011 + * FC0120 => 11 1111 00 0000 00010010 0000 + * + * Cnt4b: 4-bit counter changes from 1 to 15 then always equals 15 + * Cnt8b: 8-bit counter changes from 1 to 72 (0x48) + * Ppdc_crc: + * uint8_t crc=0; + * for(i=4; i<24; i+=4){ + * crc ^=(pdc>>i); + * } + * return crc; + * example: crc = 1^0^0^4^C = 9 + * 11, 00, 0000: const + * + * Key: “Encryption Key”, Most significant 4-bit are always 0xA, Least Significant bits is + * a linear counter. In the Smoove Origin this counter is increased together with the + * rolling code. But leaving this on a constant value also works. Gerardwr notes that + * for some other types of remotes the MSB is not constant. + * Btn: 4-bit Control codes, this indicates the button that is pressed + * CRC: 4-bit Checksum. + * Ctn: 16-bit rolling code (big-endian) increased with every button press. + * Serial: 24-bit identifier of sending device (little-endian) + * + * + * Decrypt + * + * uint8_t frame[7]; + * for (i=1; i < 7; i++) { + * frame[i] = frame[i] ^ frame[i-1]; + * } + * or + * uint64 Decrypt = frame ^ (frame>>8); + * + * CRC + * + * uint8_t frame[7]; + * for (i=0; i < 7; i++) { + * crc = crc ^ frame[i] ^ (frame[i] >> 4); + * } + * crc = crc & 0xf; + * + */ + + uint64_t data = instance->common.code_last_found ^ (instance->common.code_last_found >> 8); + instance->common.btn = (data >> 48) & 0xF; + instance->common.cnt = (data >> 24) & 0xFFFF; + instance->common.serial = data & 0xFFFFFF; +} + +uint8_t subghz_protocol_somfy_keytis_crc(uint64_t data) { + uint8_t crc = 0; + data &= 0xFFF0FFFFFFFFFF; + for(uint8_t i = 0; i < 56; i += 8) { + crc = crc ^ data >> i ^ (data >> (i + 4)); + } + return crc & 0xf; +} +const char* subghz_protocol_somfy_keytis_get_name_button(uint8_t btn) { + const char* name_btn[0x10] = { + "Unknown", + "0x01", + "0x02", + "Prog", + "Key_1", + "0x05", + "0x06", + "0x07", + "0x08", + "0x09", + "0x0A", + "0x0B", + "0x0C", + "0x0D", + "0x0E", + "0x0F"}; + return btn <= 0xf ? name_btn[btn] : name_btn[0]; +} + +uint32_t subghz_protocol_somfy_keytis_get_press_duration(void* context) { + SubGhzProtocolSomfyKeytis* instance = context; + return instance->press_duration_counter; +} + +void subghz_protocol_somfy_keytis_reset(SubGhzProtocolSomfyKeytis* instance) { + instance->common.parser_step = SomfyKeytisDecoderStepReset; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); +} + +void subghz_protocol_somfy_keytis_parse( + SubGhzProtocolSomfyKeytis* instance, + bool level, + uint32_t duration) { + ManchesterEvent event = ManchesterEventReset; + switch(instance->common.parser_step) { + case SomfyKeytisDecoderStepReset: + if((level) && DURATION_DIFF(duration, instance->common.te_short * 4) < + instance->common.te_delta * 4) { + instance->common.parser_step = SomfyKeytisDecoderStepFoundPreambula; + instance->common.header_count++; + } + break; + case SomfyKeytisDecoderStepFoundPreambula: + if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 4) < + instance->common.te_delta * 4)) { + instance->common.parser_step = SomfyKeytisDecoderStepCheckPreambula; + } else { + instance->common.header_count = 0; + instance->common.parser_step = SomfyKeytisDecoderStepReset; + } + break; + case SomfyKeytisDecoderStepCheckPreambula: + if(level) { + if(DURATION_DIFF(duration, instance->common.te_short * 4) < + instance->common.te_delta * 4) { + instance->common.parser_step = SomfyKeytisDecoderStepFoundPreambula; + instance->common.header_count++; + } else if( + (instance->common.header_count > 1) && + (DURATION_DIFF(duration, instance->common.te_short * 7) < + instance->common.te_delta * 4)) { + instance->common.parser_step = SomfyKeytisDecoderStepDecoderData; + instance->common.code_found = 0; + instance->common.code_count_bit = 0; + instance->press_duration_counter = 0; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); + manchester_advance( + instance->manchester_saved_state, + ManchesterEventLongHigh, + &instance->manchester_saved_state, + NULL); + } + } + + break; + + case SomfyKeytisDecoderStepDecoderData: + if(!level) { + if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) { + event = ManchesterEventShortLow; + } else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) { + event = ManchesterEventLongLow; + } else if(duration >= (instance->common.te_long + instance->common.te_delta)) { + if(instance->common.code_count_bit == + instance->common.code_min_count_bit_for_found) { + instance->common.code_last_found = instance->common.code_found; + instance->common.code_last_count_bit = instance->common.code_count_bit; + + //check crc + uint64_t data_tmp = instance->common.code_last_found ^ + (instance->common.code_last_found >> 8); + if(((data_tmp >> 40) & 0xF) == subghz_protocol_somfy_keytis_crc(data_tmp)) { + if(instance->common.callback) + instance->common.callback( + (SubGhzProtocolCommon*)instance, instance->common.context); + } + } + instance->common.code_found = 0; + instance->common.code_count_bit = 0; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); + manchester_advance( + instance->manchester_saved_state, + ManchesterEventLongHigh, + &instance->manchester_saved_state, + NULL); + instance->common.parser_step = SomfyKeytisDecoderStepReset; + } else { + instance->common.parser_step = SomfyKeytisDecoderStepReset; + } + } else { + if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) { + event = ManchesterEventShortHigh; + } else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) { + event = ManchesterEventLongHigh; + } else { + instance->common.parser_step = SomfyKeytisDecoderStepReset; + } + } + if(event != ManchesterEventReset) { + bool data; + bool data_ok = manchester_advance( + instance->manchester_saved_state, event, &instance->manchester_saved_state, &data); + + if(data_ok) { + if(instance->common.code_count_bit < 56) { + instance->common.code_found = (instance->common.code_found << 1) | data; + } else { + instance->press_duration_counter = (instance->press_duration_counter << 1) | + data; + } + + instance->common.code_count_bit++; + } + } + break; + } +} + +void subghz_protocol_somfy_keytis_to_str(SubGhzProtocolSomfyKeytis* instance, string_t output) { + subghz_protocol_somfy_keytis_remote_controller(instance); + uint32_t code_found_hi = instance->common.code_last_found >> 32; + uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff; + + string_cat_printf( + output, + "%s %db\r\n" + "%lX%08lX%06lX\r\n" + "Sn:0x%06lX \r\n" + "Cnt:0x%04X\r\n" + "Btn:%s\r\n", + + instance->common.name, + instance->common.code_last_count_bit, + code_found_hi, + code_found_lo, + instance->press_duration_counter, + instance->common.serial, + instance->common.cnt, + subghz_protocol_somfy_keytis_get_name_button(instance->common.btn)); +} + +void subghz_decoder_somfy_keytis_to_load_protocol( + SubGhzProtocolSomfyKeytis* instance, + void* context) { + furi_assert(context); + furi_assert(instance); + SubGhzProtocolCommonLoad* data = context; + instance->common.code_last_found = data->code_found; + instance->common.code_last_count_bit = data->code_count_bit; + instance->press_duration_counter = data->param1; + subghz_protocol_somfy_keytis_remote_controller(instance); +} diff --git a/lib/subghz/protocols/subghz_protocol_somfy_keytis.h b/lib/subghz/protocols/subghz_protocol_somfy_keytis.h new file mode 100644 index 00000000..c5aa4244 --- /dev/null +++ b/lib/subghz/protocols/subghz_protocol_somfy_keytis.h @@ -0,0 +1,50 @@ +#pragma once + +#include "subghz_protocol_common.h" + +typedef struct SubGhzProtocolSomfyKeytis SubGhzProtocolSomfyKeytis; + +/** Allocate SubGhzProtocolSomfyKeytis + * + * @return SubGhzProtocolSomfyKeytis* + */ +SubGhzProtocolSomfyKeytis* subghz_protocol_somfy_keytis_alloc(); + +/** Free SubGhzProtocolSomfyKeytis + * + * @param instance + */ +void subghz_protocol_somfy_keytis_free(SubGhzProtocolSomfyKeytis* instance); + +uint32_t subghz_protocol_somfy_keytis_get_press_duration(void* context); + +/** Reset internal state + * @param instance - SubGhzProtocolSomfyKeytis instance + */ +void subghz_protocol_somfy_keytis_reset(SubGhzProtocolSomfyKeytis* instance); + +/** Parse accepted duration + * + * @param instance - SubGhzProtocolSomfyKeytis instance + * @param data - LevelDuration level_duration + */ +void subghz_protocol_somfy_keytis_parse( + SubGhzProtocolSomfyKeytis* instance, + bool level, + uint32_t duration); + +/** Outputting information from the parser + * + * @param instance - SubGhzProtocolSomfyKeytis* instance + * @param output - output string + */ +void subghz_protocol_somfy_keytis_to_str(SubGhzProtocolSomfyKeytis* instance, string_t output); + +/** Loading protocol from bin data + * + * @param instance - SubGhzProtocolSomfyKeytis instance + * @param context - SubGhzProtocolCommonLoad context + */ +void subghz_decoder_somfy_keytis_to_load_protocol( + SubGhzProtocolSomfyKeytis* instance, + void* context); \ No newline at end of file diff --git a/lib/subghz/protocols/subghz_protocol_somfy_telis.c b/lib/subghz/protocols/subghz_protocol_somfy_telis.c new file mode 100644 index 00000000..02d3c47b --- /dev/null +++ b/lib/subghz/protocols/subghz_protocol_somfy_telis.c @@ -0,0 +1,293 @@ +#include "subghz_protocol_somfy_telis.h" +#include "subghz_protocol_common.h" +#include + +#define TAG "SubGhzSomfyTelis" + +struct SubGhzProtocolSomfyTelis { + SubGhzProtocolCommon common; + ManchesterState manchester_saved_state; +}; + +typedef enum { + SomfyTelisDecoderStepReset = 0, + SomfyTelisDecoderStepCheckPreambula, + SomfyTelisDecoderStepFoundPreambula, + SomfyTelisDecoderStepStartDecode, + SomfyTelisDecoderStepDecoderData, +} SomfyTelisDecoderStep; + +SubGhzProtocolSomfyTelis* subghz_protocol_somfy_telis_alloc() { + SubGhzProtocolSomfyTelis* instance = furi_alloc(sizeof(SubGhzProtocolSomfyTelis)); + + instance->common.name = "Somfy Telis"; + instance->common.code_min_count_bit_for_found = 56; + instance->common.te_short = 640; + instance->common.te_long = 1280; + instance->common.te_delta = 250; + instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic; + instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_somfy_telis_to_str; + instance->common.to_load_protocol = + (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_somfy_telis_to_load_protocol; + + return instance; +} + +void subghz_protocol_somfy_telis_free(SubGhzProtocolSomfyTelis* instance) { + furi_assert(instance); + free(instance); +} + +/** Analysis of received data + * + * @param instance SubGhzProtocolSomfyTelis instance + */ +void subghz_protocol_somfy_telis_remote_controller(SubGhzProtocolSomfyTelis* instance) { + //https://pushstack.wordpress.com/somfy-rts-protocol/ + /* + * 604 us + * / + * | 2416us | 2416us | 2416us | 2416us | 4550 us | | 67648 us | 30415 us | + * + * +--------+ +--------+ +---...---+ + * + +--------+ +--------+ +--+XXXX...XXX+-----...----- + * + * | hw. sync. | soft. | | Inter-frame + * | | sync. | data | gap + * + * + * encrypt | decrypt + * + * package 56 bit cnt key btn|crc cnt serial + * 0xA7232323312222 - 0 => A7 8 0 | 00 00 | 12 13 00 + * 0xA7222223312222 - 1 => A7 8 5 | 00 01 | 12 13 00 + * 0xA7212123312222 - 2 => A7 8 6 | 00 02 | 12 13 00 + * + * Key: “Encryption Key”, Most significant 4-bit are always 0xA, Least Significant bits is + * a linear counter. In the Smoove Origin this counter is increased together with the + * rolling code. But leaving this on a constant value also works. Gerardwr notes that + * for some other types of remotes the MSB is not constant. + * Btn: 4-bit Control codes, this indicates the button that is pressed + * CRC: 4-bit Checksum. + * Ctn: 16-bit rolling code (big-endian) increased with every button press. + * Serial: 24-bit identifier of sending device (little-endian) + * + * + * Decrypt + * + * uint8_t frame[7]; + * for (i=1; i < 7; i++) { + * frame[i] = frame[i] ^ frame[i-1]; + * } + * or + * uint64 Decrypt = frame ^ (frame>>8); + * + * Btn + * + * Value Button(s) Description + * 0x1 My Stop or move to favourite position + * 0x2 Up Move up + * 0x3 My + Up Set upper motor limit in initial programming mode + * 0x4 Down Move down + * 0x5 My + Down Set lower motor limit in initial programming mode + * 0x6 Up + Down Change motor limit and initial programming mode + * 0x8 Prog Used for (de-)registering remotes, see below + * 0x9 Sun + Flag Enable sun and wind detector (SUN and FLAG symbol on the Telis Soliris RC) + * 0xA Flag Disable sun detector (FLAG symbol on the Telis Soliris RC) + * + * CRC + * + * uint8_t frame[7]; + * for (i=0; i < 7; i++) { + * cksum = cksum ^ frame[i] ^ (frame[i] >> 4); + * } + * cksum = cksum & 0xf; + * + */ + + uint64_t data = instance->common.code_last_found ^ (instance->common.code_last_found >> 8); + instance->common.btn = (data >> 44) & 0xF; + instance->common.cnt = (data >> 24) & 0xFFFF; + instance->common.serial = data & 0xFFFFFF; +} + +uint8_t subghz_protocol_somfy_telis_crc(uint64_t data) { + uint8_t crc = 0; + data &= 0xFFF0FFFFFFFFFF; + for(uint8_t i = 0; i < 56; i += 8) { + crc = crc ^ data >> i ^ (data >> (i + 4)); + } + return crc & 0xf; +} + +const char* subghz_protocol_somfy_telis_get_name_button(uint8_t btn) { + const char* name_btn[0x10] = { + "Unknown", + "My", + "Up", + "My+Up", + "Down", + "My+Down", + "Up+Down", + "0x07", + "Prog", + "Sun+Flag", + "Flag", + "0x0B", + "0x0C", + "0x0D", + "0x0E", + "0x0F"}; + return btn <= 0xf ? name_btn[btn] : name_btn[0]; +} + +void subghz_protocol_somfy_telis_reset(SubGhzProtocolSomfyTelis* instance) { + instance->common.parser_step = SomfyTelisDecoderStepReset; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); +} + +void subghz_protocol_somfy_telis_parse( + SubGhzProtocolSomfyTelis* instance, + bool level, + uint32_t duration) { + ManchesterEvent event = ManchesterEventReset; + switch(instance->common.parser_step) { + case SomfyTelisDecoderStepReset: + if((level) && DURATION_DIFF(duration, instance->common.te_short * 4) < + instance->common.te_delta * 4) { + instance->common.parser_step = SomfyTelisDecoderStepFoundPreambula; + instance->common.header_count++; + } + break; + case SomfyTelisDecoderStepFoundPreambula: + if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 4) < + instance->common.te_delta * 4)) { + instance->common.parser_step = SomfyTelisDecoderStepCheckPreambula; + } else { + instance->common.header_count = 0; + instance->common.parser_step = SomfyTelisDecoderStepReset; + } + break; + case SomfyTelisDecoderStepCheckPreambula: + if(level) { + if(DURATION_DIFF(duration, instance->common.te_short * 4) < + instance->common.te_delta * 4) { + instance->common.parser_step = SomfyTelisDecoderStepFoundPreambula; + instance->common.header_count++; + } else if( + (instance->common.header_count > 1) && + (DURATION_DIFF(duration, instance->common.te_short * 7) < + instance->common.te_delta * 4)) { + instance->common.parser_step = SomfyTelisDecoderStepDecoderData; + instance->common.code_found = 0; + instance->common.code_count_bit = 0; + instance->common.header_count = 0; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); + manchester_advance( + instance->manchester_saved_state, + ManchesterEventLongHigh, + &instance->manchester_saved_state, + NULL); + } + } + + break; + + case SomfyTelisDecoderStepDecoderData: + if(!level) { + if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) { + event = ManchesterEventShortLow; + } else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) { + event = ManchesterEventLongLow; + } else if(duration >= (instance->common.te_long + instance->common.te_delta)) { + if(instance->common.code_count_bit == + instance->common.code_min_count_bit_for_found) { + instance->common.code_last_found = instance->common.code_found; + instance->common.code_last_count_bit = instance->common.code_count_bit; + + //check crc + uint64_t data_tmp = instance->common.code_last_found ^ + (instance->common.code_last_found >> 8); + if(((data_tmp >> 40) & 0xF) == subghz_protocol_somfy_telis_crc(data_tmp)) { + if(instance->common.callback) + instance->common.callback( + (SubGhzProtocolCommon*)instance, instance->common.context); + } + } + instance->common.code_found = 0; + instance->common.code_count_bit = 0; + manchester_advance( + instance->manchester_saved_state, + ManchesterEventReset, + &instance->manchester_saved_state, + NULL); + manchester_advance( + instance->manchester_saved_state, + ManchesterEventLongHigh, + &instance->manchester_saved_state, + NULL); + instance->common.parser_step = SomfyTelisDecoderStepReset; + } else { + instance->common.parser_step = SomfyTelisDecoderStepReset; + } + } else { + if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) { + event = ManchesterEventShortHigh; + } else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) { + event = ManchesterEventLongHigh; + } else { + instance->common.parser_step = SomfyTelisDecoderStepReset; + } + } + if(event != ManchesterEventReset) { + bool data; + bool data_ok = manchester_advance( + instance->manchester_saved_state, event, &instance->manchester_saved_state, &data); + + if(data_ok) { + instance->common.code_found = (instance->common.code_found << 1) | data; + instance->common.code_count_bit++; + } + } + break; + } +} + +void subghz_protocol_somfy_telis_to_str(SubGhzProtocolSomfyTelis* instance, string_t output) { + subghz_protocol_somfy_telis_remote_controller(instance); + uint32_t code_found_hi = instance->common.code_last_found >> 32; + uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff; + + string_cat_printf( + output, + "%s %db\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%06lX \r\n" + "Cnt:0x%04X\r\n" + "Btn:%s\r\n", + + instance->common.name, + instance->common.code_last_count_bit, + code_found_hi, + code_found_lo, + instance->common.serial, + instance->common.cnt, + subghz_protocol_somfy_telis_get_name_button(instance->common.btn)); +} + +void subghz_decoder_somfy_telis_to_load_protocol(SubGhzProtocolSomfyTelis* instance, void* context) { + furi_assert(context); + furi_assert(instance); + SubGhzProtocolCommonLoad* data = context; + instance->common.code_last_found = data->code_found; + instance->common.code_last_count_bit = data->code_count_bit; + subghz_protocol_somfy_telis_remote_controller(instance); +} diff --git a/lib/subghz/protocols/subghz_protocol_somfy_telis.h b/lib/subghz/protocols/subghz_protocol_somfy_telis.h new file mode 100644 index 00000000..007ae829 --- /dev/null +++ b/lib/subghz/protocols/subghz_protocol_somfy_telis.h @@ -0,0 +1,46 @@ +#pragma once + +#include "subghz_protocol_common.h" + +typedef struct SubGhzProtocolSomfyTelis SubGhzProtocolSomfyTelis; + +/** Allocate SubGhzProtocolSomfyTelis + * + * @return SubGhzProtocolSomfyTelis* + */ +SubGhzProtocolSomfyTelis* subghz_protocol_somfy_telis_alloc(); + +/** Free SubGhzProtocolSomfyTelis + * + * @param instance + */ +void subghz_protocol_somfy_telis_free(SubGhzProtocolSomfyTelis* instance); + +/** Reset internal state + * @param instance - SubGhzProtocolSomfyTelis instance + */ +void subghz_protocol_somfy_telis_reset(SubGhzProtocolSomfyTelis* instance); + +/** Parse accepted duration + * + * @param instance - SubGhzProtocolSomfyTelis instance + * @param data - LevelDuration level_duration + */ +void subghz_protocol_somfy_telis_parse( + SubGhzProtocolSomfyTelis* instance, + bool level, + uint32_t duration); + +/** Outputting information from the parser + * + * @param instance - SubGhzProtocolSomfyTelis* instance + * @param output - output string + */ +void subghz_protocol_somfy_telis_to_str(SubGhzProtocolSomfyTelis* instance, string_t output); + +/** Loading protocol from bin data + * + * @param instance - SubGhzProtocolSomfyTelis instance + * @param context - SubGhzProtocolCommonLoad context + */ +void subghz_decoder_somfy_telis_to_load_protocol(SubGhzProtocolSomfyTelis* instance, void* context); \ No newline at end of file diff --git a/lib/subghz/subghz_parser.c b/lib/subghz/subghz_parser.c index fb50bf3a..c4ad873f 100644 --- a/lib/subghz/subghz_parser.c +++ b/lib/subghz/subghz_parser.c @@ -18,6 +18,8 @@ #include "protocols/subghz_protocol_kia.h" #include "protocols/subghz_protocol_raw.h" #include "protocols/subghz_protocol_hormann.h" +#include "protocols/subghz_protocol_somfy_telis.h" +#include "protocols/subghz_protocol_somfy_keytis.h" #include "subghz_keystore.h" @@ -44,6 +46,8 @@ typedef enum { SubGhzProtocolTypeKIA, SubGhzProtocolTypeRAW, SubGhzProtocolTypeHormann, + SubGhzProtocolTypeSomfyTelis, + SubGhzProtocolTypeSomfyKeytis, SubGhzProtocolTypeMax, } SubGhzProtocolType; @@ -119,6 +123,10 @@ SubGhzParser* subghz_parser_alloc() { (SubGhzProtocolCommon*)subghz_protocol_raw_alloc(); instance->protocols[SubGhzProtocolTypeHormann] = (SubGhzProtocolCommon*)subghz_protocol_hormann_alloc(); + instance->protocols[SubGhzProtocolTypeSomfyTelis] = + (SubGhzProtocolCommon*)subghz_protocol_somfy_telis_alloc(); + instance->protocols[SubGhzProtocolTypeSomfyKeytis] = + (SubGhzProtocolCommon*)subghz_protocol_somfy_keytis_alloc(); return instance; } @@ -156,6 +164,10 @@ void subghz_parser_free(SubGhzParser* instance) { subghz_protocol_raw_free((SubGhzProtocolRAW*)instance->protocols[SubGhzProtocolTypeRAW]); subghz_protocol_hormann_free( (SubGhzProtocolHormann*)instance->protocols[SubGhzProtocolTypeHormann]); + subghz_protocol_somfy_telis_free( + (SubGhzProtocolSomfyTelis*)instance->protocols[SubGhzProtocolTypeSomfyTelis]); + subghz_protocol_somfy_keytis_free( + (SubGhzProtocolSomfyKeytis*)instance->protocols[SubGhzProtocolTypeSomfyKeytis]); subghz_keystore_free(instance->keystore); @@ -257,6 +269,10 @@ void subghz_parser_reset(SubGhzParser* instance) { subghz_protocol_raw_reset((SubGhzProtocolRAW*)instance->protocols[SubGhzProtocolTypeRAW]); subghz_protocol_hormann_reset( (SubGhzProtocolHormann*)instance->protocols[SubGhzProtocolTypeHormann]); + subghz_protocol_somfy_telis_reset( + (SubGhzProtocolSomfyTelis*)instance->protocols[SubGhzProtocolTypeSomfyTelis]); + subghz_protocol_somfy_keytis_reset( + (SubGhzProtocolSomfyKeytis*)instance->protocols[SubGhzProtocolTypeSomfyKeytis]); } void subghz_parser_raw_parse(SubGhzParser* instance, bool level, uint32_t duration) { @@ -309,4 +325,12 @@ void subghz_parser_parse(SubGhzParser* instance, bool level, uint32_t duration) (SubGhzProtocolKIA*)instance->protocols[SubGhzProtocolTypeKIA], level, duration); subghz_protocol_hormann_parse( (SubGhzProtocolHormann*)instance->protocols[SubGhzProtocolTypeHormann], level, duration); + subghz_protocol_somfy_telis_parse( + (SubGhzProtocolSomfyTelis*)instance->protocols[SubGhzProtocolTypeSomfyTelis], + level, + duration); + subghz_protocol_somfy_keytis_parse( + (SubGhzProtocolSomfyKeytis*)instance->protocols[SubGhzProtocolTypeSomfyKeytis], + level, + duration); } diff --git a/scripts/assets.py b/scripts/assets.py index bdacb8eb..34d4c1ad 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from flipper.app import App + import logging import argparse import subprocess @@ -25,16 +27,14 @@ ICONS_TEMPLATE_C_DATA = "const uint8_t *{name}[] = {data};\n" ICONS_TEMPLATE_C_ICONS = "const Icon {name} = {{.width={width},.height={height},.frame_count={frame_count},.frame_rate={frame_rate},.frames=_{name}}};\n" -class Main: - def __init__(self): +class Main(App): + def init(self): # command args - self.parser = argparse.ArgumentParser() - self.parser.add_argument("-d", "--debug", action="store_true", help="Debug") self.subparsers = self.parser.add_subparsers(help="sub-command help") self.parser_icons = self.subparsers.add_parser( "icons", help="Process icons and build icon registry" ) - self.parser_icons.add_argument("source_directory", help="Source directory") + self.parser_icons.add_argument("input_directory", help="Source directory") self.parser_icons.add_argument("output_directory", help="Output directory") self.parser_icons.set_defaults(func=self.icons) @@ -56,30 +56,49 @@ class Main: "dolphin", help="Assemble dolphin resources" ) self.parser_dolphin.add_argument( - "dolphin_sources", help="Doplhin sources directory" + "-s", + "--symbol-name", + help="Symbol and file name in dolphin output directory", + default=None, ) self.parser_dolphin.add_argument( - "dolphin_output", help="Doplhin output directory" + "input_directory", help="Dolphin source directory" + ) + self.parser_dolphin.add_argument( + "output_directory", help="Dolphin output directory" ) self.parser_dolphin.set_defaults(func=self.dolphin) - # logging - self.logger = logging.getLogger() + def _icon2header(self, file): + output = subprocess.check_output(["convert", file, "xbm:-"]) + assert output + f = io.StringIO(output.decode().strip()) + width = int(f.readline().strip().split(" ")[2]) + height = int(f.readline().strip().split(" ")[2]) + data = f.read().strip().replace("\n", "").replace(" ", "").split("=")[1][:-1] + data_bin_str = data[1:-1].replace(",", " ").replace("0x", "") + data_bin = bytearray.fromhex(data_bin_str) + # Encode icon data with LZSS + data_encoded_str = subprocess.check_output( + ["heatshrink", "-e", "-w8", "-l4"], input=data_bin + ) + assert data_encoded_str + data_enc = bytearray(data_encoded_str) + data_enc = bytearray([len(data_enc) & 0xFF, len(data_enc) >> 8]) + data_enc + # Use encoded data only if its lenght less than original, including header + if len(data_enc) < len(data_bin) + 1: + data = ( + "{0x01,0x00," + + "".join("0x{:02x},".format(byte) for byte in data_enc) + + "}" + ) + else: + data = "{0x00," + data[1:] + return width, height, data - def __call__(self): - self.args = self.parser.parse_args() - if "func" not in self.args: - self.parser.error("Choose something to do") - # configure log output - self.log_level = logging.DEBUG if self.args.debug else logging.INFO - self.logger.setLevel(self.log_level) - self.handler = logging.StreamHandler(sys.stdout) - self.handler.setLevel(self.log_level) - self.formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s") - self.handler.setFormatter(self.formatter) - self.logger.addHandler(self.handler) - # execute requested function - self.args.func() + def _iconIsSupported(self, filename): + extension = filename.lower().split(".")[-1] + return extension in ICONS_SUPPORTED_FORMATS def icons(self): self.logger.debug(f"Converting icons") @@ -87,7 +106,7 @@ class Main: icons_c.write(ICONS_TEMPLATE_C_HEADER) icons = [] # Traverse icons tree, append image data to source file - for dirpath, dirnames, filenames in os.walk(self.args.source_directory): + for dirpath, dirnames, filenames in os.walk(self.args.input_directory): self.logger.debug(f"Processing directory {dirpath}") dirnames.sort() filenames.sort() @@ -105,10 +124,10 @@ class Main: if filename == "frame_rate": frame_rate = int(open(fullfilename, "r").read().strip()) continue - elif not self.iconIsSupported(filename): + elif not self._iconIsSupported(filename): continue self.logger.debug(f"Processing animation frame {filename}") - temp_width, temp_height, data = self.icon2header(fullfilename) + temp_width, temp_height, data = self._icon2header(fullfilename) if width is None: width = temp_width if height is None: @@ -133,14 +152,14 @@ class Main: else: # process icons for filename in filenames: - if not self.iconIsSupported(filename): + if not self._iconIsSupported(filename): continue self.logger.debug(f"Processing icon {filename}") icon_name = "I_" + "_".join(filename.split(".")[:-1]).replace( "-", "_" ) fullfilename = os.path.join(dirpath, filename) - width, height, data = self.icon2header(fullfilename) + width, height, data = self._icon2header(fullfilename) frame_name = f"_{icon_name}_0" icons_c.write( ICONS_TEMPLATE_C_FRAME.format(name=frame_name, data=data) @@ -172,37 +191,7 @@ class Main: for name, width, height, frame_rate, frame_count in icons: icons_h.write(ICONS_TEMPLATE_H_ICON_NAME.format(name=name)) self.logger.debug(f"Done") - - def icon2header(self, file): - output = subprocess.check_output(["convert", file, "xbm:-"]) - assert output - f = io.StringIO(output.decode().strip()) - width = int(f.readline().strip().split(" ")[2]) - height = int(f.readline().strip().split(" ")[2]) - data = f.read().strip().replace("\n", "").replace(" ", "").split("=")[1][:-1] - data_bin_str = data[1:-1].replace(",", " ").replace("0x", "") - data_bin = bytearray.fromhex(data_bin_str) - # Encode icon data with LZSS - data_encoded_str = subprocess.check_output( - ["heatshrink", "-e", "-w8", "-l4"], input=data_bin - ) - assert data_encoded_str - data_enc = bytearray(data_encoded_str) - data_enc = bytearray([len(data_enc) & 0xFF, len(data_enc) >> 8]) + data_enc - # Use encoded data only if its lenght less than original, including header - if len(data_enc) < len(data_bin) + 1: - data = ( - "{0x01,0x00," - + "".join("0x{:02x},".format(byte) for byte in data_enc) - + "}" - ) - else: - data = "{0x00," + data[1:] - return width, height, data - - def iconIsSupported(self, filename): - extension = filename.lower().split(".")[-1] - return extension in ICONS_SUPPORTED_FORMATS + return 0 def manifest(self): from flipper.assets.manifest import Manifest @@ -233,17 +222,33 @@ class Main: self.logger.info(f"Only in new: {record}") self.logger.info(f"Complete") + return 0 + def copro(self): from flipper.assets.copro import Copro + self.logger.info(f"Bundling coprocessor binaries") copro = Copro(self.args.mcu) + self.logger.info(f"Loading CUBE info") copro.loadCubeInfo(self.args.cube_dir) + self.logger.info(f"Bundling") copro.bundle(self.args.output_dir) + self.logger.info(f"Complete") + + return 0 def dolphin(self): - from flipper.assets.dolphin import pack_dolphin + from flipper.assets.dolphin import Dolphin - pack_dolphin(self.args.dolphin_sources, self.args.dolphin_output) + self.logger.info(f"Processing Dolphin sources") + dolphin = Dolphin() + self.logger.info(f"Loading data") + dolphin.load(self.args.input_directory) + self.logger.info(f"Packing") + dolphin.pack(self.args.output_directory, self.args.symbol_name) + self.logger.info(f"Complete") + + return 0 if __name__ == "__main__": diff --git a/scripts/flipper/assets/dolphin.py b/scripts/flipper/assets/dolphin.py index 076bbb15..51a3cc61 100644 --- a/scripts/flipper/assets/dolphin.py +++ b/scripts/flipper/assets/dolphin.py @@ -3,53 +3,361 @@ import logging import os import sys import shutil +from collections import Counter +from flipper.utils.fff import * +from flipper.utils.templite import * from .icon import * -def _pack_animation(pair: set): - source, destination = pair - image = file2image(source) - image.write(destination) +def _convert_image_to_bm(pair: set): + source_filename, destination_filename = pair + image = file2image(source_filename) + image.write(destination_filename) -def pack_animations(source: str, destination: str): - assert os.path.exists(source) - # Create list for processing - to_pack = [] - dirpath, dirnames = next(os.walk(source))[:2] - dirnames.sort() - for dirname in dirnames: - current_directory = os.path.join(dirpath, dirname) - # Ensure destination folder - destination_directory = os.path.join(destination, dirname) - os.makedirs(destination_directory, exist_ok=True) - # Find all files - filenames = next(os.walk(current_directory))[2] - filenames.sort() - for filename in filenames: - if is_file_an_icon(filename): - source_filename = os.path.join(current_directory, filename) - destination_filename = os.path.join( - destination_directory, os.path.splitext(filename)[0] + ".bm" +def _convert_image(source_filename: str): + image = file2image(source_filename) + return image.data + + +class DolphinBubbleAnimation: + + FILE_TYPE = "Flipper Animation" + FILE_VERSION = 1 + + def __init__( + self, + name: str, + min_butthurt: int, + max_butthurt: int, + min_level: int, + max_level: int, + weight: int, + ): + # Manifest + self.name = name + self.min_butthurt = min_butthurt + self.max_butthurt = max_butthurt + self.min_level = min_level + self.max_level = max_level + self.weight = weight + # Meta and data + self.meta = {} + self.frames = [] + self.bubbles = [] + self.bubble_slots = None + # Logging + self.logger = logging.getLogger("DolphinBubbleAnimation") + + def load(self, animation_directory: str): + if not os.path.isdir(animation_directory): + raise Exception(f"Animation folder doesn't exists: { animation_directory }") + + meta_filename = os.path.join(animation_directory, "meta.txt") + if not os.path.isfile(meta_filename): + raise Exception(f"Animation meta file doesn't exists: { meta_filename }") + + self.logger.info(f"Loading meta from {meta_filename}") + file = FlipperFormatFile() + file.load(meta_filename) + + # Check file header + filetype, version = file.getHeader() + assert filetype == self.FILE_TYPE + assert version == self.FILE_VERSION + + max_frame_number = None + unique_frames = None + total_frames_count = None + + try: + # Main meta + self.meta["Width"] = file.readKeyInt("Width") + self.meta["Height"] = file.readKeyInt("Height") + self.meta["Passive frames"] = file.readKeyInt("Passive frames") + self.meta["Active frames"] = file.readKeyInt("Active frames") + self.meta["Frames order"] = file.readKeyIntArray("Frames order") + self.meta["Active cycles"] = file.readKeyInt("Active cycles") + self.meta["Frame rate"] = file.readKeyInt("Frame rate") + self.meta["Duration"] = file.readKeyInt("Duration") + self.meta["Active cooldown"] = file.readKeyInt("Active cooldown") + self.bubble_slots = file.readKeyInt("Bubble slots") + + # Sanity Check + assert self.meta["Width"] > 0 and self.meta["Width"] <= 128 + assert self.meta["Height"] > 0 and self.meta["Height"] <= 128 + assert self.meta["Passive frames"] > 0 + assert self.meta["Active frames"] >= 0 + assert self.meta["Frames order"] + if self.meta["Active frames"] > 0: + assert self.meta["Active cooldown"] > 0 + assert self.meta["Active cycles"] > 0 + else: + assert self.meta["Active cooldown"] == 0 + assert self.meta["Active cycles"] == 0 + assert self.meta["Frame rate"] > 0 + assert self.meta["Duration"] >= 0 + + # Frames sanity check + max_frame_number = max(self.meta["Frames order"]) + ordered_frames_count = len(self.meta["Frames order"]) + for i in range(max_frame_number + 1): + frame_filename = os.path.join(animation_directory, f"frame_{i}.png") + assert os.path.isfile(frame_filename) + self.frames.append(frame_filename) + # Sanity check + unique_frames = set(self.meta["Frames order"]) + unique_frames_count = len(unique_frames) + if unique_frames_count != max_frame_number + 1: + self.logger.warning(f"Not all frames were used in {self.name}") + total_frames_count = self.meta["Passive frames"] + ( + self.meta["Active frames"] * self.meta["Active cycles"] + ) + + # Extra checks + assert self.meta["Passive frames"] <= total_frames_count + assert self.meta["Active frames"] <= total_frames_count + assert ( + self.meta["Passive frames"] + self.meta["Active frames"] + == ordered_frames_count + ) + except EOFError as e: + raise Exception("Invalid meta file: too short") + except AssertionError as e: + self.logger.exception(e) + self.logger.error(f"Animation {self.name} got incorrect meta") + raise Exception("Meta file is invalid: incorrect data") + + # Bubbles + while True: + try: + # Bubble data + bubble = {} + bubble["Slot"] = file.readKeyInt("Slot") + bubble["X"] = file.readKeyInt("X") + bubble["Y"] = file.readKeyInt("Y") + bubble["Text"] = file.readKey("Text") + bubble["AlignH"] = file.readKey("AlignH") + bubble["AlignV"] = file.readKey("AlignV") + bubble["StartFrame"] = file.readKeyInt("StartFrame") + bubble["EndFrame"] = file.readKeyInt("EndFrame") + + # Sanity check + assert bubble["Slot"] <= self.bubble_slots + assert bubble["X"] >= 0 and bubble["X"] < 128 + assert bubble["Y"] >= 0 and bubble["Y"] < 128 + assert len(bubble["Text"]) > 0 + assert bubble["AlignH"] in ["Left", "Center", "Right"] + assert bubble["AlignV"] in ["Bottom", "Center", "Top"] + assert bubble["StartFrame"] < total_frames_count + assert bubble["EndFrame"] < total_frames_count + assert bubble["EndFrame"] >= bubble["StartFrame"] + + # Store bubble + self.bubbles.append(bubble) + except AssertionError as e: + self.logger.exception(e) + self.logger.error( + f"Animation {self.name} bubble slot {bubble_slot} got incorrect data: {bubble}" ) - to_pack.append((source_filename, destination_filename)) - elif filename == "meta.txt": - source_filename = os.path.join(current_directory, filename) - destination_filename = os.path.join(destination_directory, filename) - shutil.copyfile(source_filename, destination_filename) + raise Exception("Meta file is invalid: incorrect bubble data") + except EOFError: + break - # Process images in parallel - pool = multiprocessing.Pool() - pool.map(_pack_animation, to_pack) + def prepare(self): + bubbles_in_slots = Counter([bubble["Slot"] for bubble in self.bubbles]) - shutil.copyfile( - os.path.join(source, "manifest.txt"), os.path.join(destination, "manifest.txt") + last_slot = -1 + bubble_index = 0 + for bubble in self.bubbles: + slot = bubble["Slot"] + if slot == last_slot: + bubble_index += 1 + else: + last_slot = slot + bubble_index = 0 + bubble["_BubbleIndex"] = bubble_index + + bubbles_in_slots[slot] -= 1 + if bubbles_in_slots[slot] != 0: + bubble["_NextBubbleIndex"] = bubble_index + 1 + + def save(self, output_directory: str): + animation_directory = os.path.join(output_directory, self.name) + os.makedirs(animation_directory, exist_ok=True) + meta_filename = os.path.join(animation_directory, "meta.txt") + + file = FlipperFormatFile() + file.setHeader(self.FILE_TYPE, self.FILE_VERSION) + file.writeEmptyLine() + + # Write meta data + file.writeKey("Width", self.meta["Width"]) + file.writeKey("Height", self.meta["Height"]) + file.writeKey("Passive frames", self.meta["Passive frames"]) + file.writeKey("Active frames", self.meta["Active frames"]) + file.writeKey("Frames order", self.meta["Frames order"]) + file.writeKey("Active cycles", self.meta["Active cycles"]) + file.writeKey("Frame rate", self.meta["Frame rate"]) + file.writeKey("Duration", self.meta["Duration"]) + file.writeKey("Active cooldown", self.meta["Active cooldown"]) + file.writeEmptyLine() + + file.writeKey("Bubble slots", self.bubble_slots) + file.writeEmptyLine() + + # Write bubble data + for bubble in self.bubbles: + file.writeKey("Slot", bubble["Slot"]) + file.writeKey("X", bubble["X"]) + file.writeKey("Y", bubble["Y"]) + file.writeKey("Text", bubble["Text"]) + file.writeKey("AlignH", bubble["AlignH"]) + file.writeKey("AlignV", bubble["AlignV"]) + file.writeKey("StartFrame", bubble["StartFrame"]) + file.writeKey("EndFrame", bubble["EndFrame"]) + file.writeEmptyLine() + + file.save(meta_filename) + + to_pack = [] + for index, frame in enumerate(self.frames): + to_pack.append( + (frame, os.path.join(animation_directory, f"frame_{index}.bm")) + ) + + pool = multiprocessing.Pool() + pool.map(_convert_image_to_bm, to_pack) + + def process(self): + pool = multiprocessing.Pool() + self.frames = pool.map(_convert_image, self.frames) + + +class DolphinManifest: + + FILE_TYPE = "Flipper Animation Manifest" + FILE_VERSION = 1 + + TEMPLATE_DIRECTORY = os.path.join( + os.path.dirname(os.path.realpath(__file__)), "templates" ) + TEMPLATE_H = os.path.join(TEMPLATE_DIRECTORY, "dolphin.h.tmpl") + TEMPLATE_C = os.path.join(TEMPLATE_DIRECTORY, "dolphin.c.tmpl") + + def __init__(self): + self.animations = [] + self.logger = logging.getLogger("DolphinManifest") + + def load(self, source_directory: str): + manifest_filename = os.path.join(source_directory, "manifest.txt") + + file = FlipperFormatFile() + file.load(manifest_filename) + + # Check file header + filetype, version = file.getHeader() + assert filetype == self.FILE_TYPE + assert version == self.FILE_VERSION + + # Load animation data + while True: + try: + # Read animation spcification + name = file.readKey("Name") + min_butthurt = file.readKeyInt("Min butthurt") + max_butthurt = file.readKeyInt("Max butthurt") + min_level = file.readKeyInt("Min level") + max_level = file.readKeyInt("Max level") + weight = file.readKeyInt("Weight") + + assert len(name) > 0 + assert min_butthurt >= 0 + assert max_butthurt >= 0 and max_butthurt >= min_butthurt + assert min_level >= 0 + assert max_level >= 0 and max_level >= min_level + assert weight >= 0 + + # Initialize animation + animation = DolphinBubbleAnimation( + name, min_butthurt, max_butthurt, min_level, max_level, weight + ) + + # Load Animation meta and frames + animation.load(os.path.join(source_directory, name)) + + # Add to array + self.animations.append(animation) + except EOFError: + break + + def _renderTemplate(self, template_filename: str, output_filename: str, **kwargs): + template = Templite(filename=template_filename) + output = template.render(**kwargs) + open(output_filename, "w").write(output) + + def save2code(self, output_directory: str, symbol_name: str): + # Process frames + for animation in self.animations: + animation.process() + + # Prepare substitution data + for animation in self.animations: + animation.prepare() + + # Render Header + self._renderTemplate( + self.TEMPLATE_H, + os.path.join(output_directory, f"assets_{symbol_name}.h"), + animations=self.animations, + symbol_name=symbol_name, + ) + # Render Source + self._renderTemplate( + self.TEMPLATE_C, + os.path.join(output_directory, f"assets_{symbol_name}.c"), + animations=self.animations, + symbol_name=symbol_name, + ) + + def save2folder(self, output_directory: str): + manifest_filename = os.path.join(output_directory, "manifest.txt") + file = FlipperFormatFile() + file.setHeader(self.FILE_TYPE, self.FILE_VERSION) + file.writeEmptyLine() + + for animation in self.animations: + file.writeKey("Name", animation.name) + file.writeKey("Min butthurt", animation.min_butthurt) + file.writeKey("Max butthurt", animation.max_butthurt) + file.writeKey("Min level", animation.min_level) + file.writeKey("Max level", animation.max_level) + file.writeKey("Weight", animation.weight) + file.writeEmptyLine() + + animation.save(output_directory) + + file.save(manifest_filename) + + def save(self, output_directory: str, symbol_name: str): + os.makedirs(output_directory, exist_ok=True) + if symbol_name: + self.save2code(output_directory, symbol_name) + else: + self.save2folder(output_directory) -def pack_dolphin(source_directory: str, destination_directory: str): - pack_animations( - os.path.join(source_directory, "animations"), - os.path.join(destination_directory, "animations"), - ) +class Dolphin: + def __init__(self): + self.manifest = DolphinManifest() + self.logger = logging.getLogger("Dolphin") + + def load(self, source_directory: str): + assert os.path.isdir(source_directory) + # Load Manifest + self.logger.info(f"Loading directory {source_directory}") + self.manifest.load(source_directory) + + def pack(self, output_directory: str, symbol_name: str = None): + self.manifest.save(output_directory, symbol_name) diff --git a/scripts/flipper/assets/templates/dolphin.c.tmpl b/scripts/flipper/assets/templates/dolphin.c.tmpl new file mode 100644 index 00000000..633a374e --- /dev/null +++ b/scripts/flipper/assets/templates/dolphin.c.tmpl @@ -0,0 +1,94 @@ +#include +#include +#include +#include + +{% for animation in animations: %} +{% for frame_number, frame in enumerate(animation.frames): %} +const uint8_t _A_{{ animation.name }}_{{ frame_number }}[] = { + {{ "%s" % ",".join("0x%x" % i for i in frame)}} +}; +{% :endfor %} + +const uint8_t *_A_{{animation.name}}[] = { +{% for frame_number, frame in enumerate(animation.frames): %} + _A_{{ animation.name }}_{{ frame_number }}, +{% :endfor %} +}; + +{% if animation.bubble_slots > 0: %} +{% for bubble in animation.bubbles: %} +const FrameBubble {{ animation.name }}_bubble_{{ bubble["Slot"] }}_{{ bubble["_BubbleIndex"] }}; +{% :endfor %} + +const FrameBubble* const {{animation.name}}_bubble_sequences[] = { +{% for i in range(animation.bubble_slots): %} + &{{animation.name}}_bubble_{{i}}_0, +{% :endfor %} +}; + +{% for bubble in animation.bubbles: %} +{% + if "_NextBubbleIndex" in bubble: + next_bubble = f'&{animation.name}_bubble_{bubble["Slot"]}_{bubble["_NextBubbleIndex"]}' + else: + next_bubble = "NULL" +%} +const FrameBubble {{animation.name}}_bubble_{{bubble["Slot"]}}_{{bubble["_BubbleIndex"]}} = { + .bubble = { + .x = {{bubble["X"]}}, + .y = {{bubble["Y"]}}, + .text = "{{bubble["Text"]}}", + .align_h = Align{{bubble["AlignH"]}}, + .align_v = Align{{bubble["AlignV"]}}, + }, + .start_frame = {{bubble["StartFrame"]}}, + .end_frame = {{bubble["EndFrame"]}}, + .next_bubble = {{next_bubble}}, +}; +{% :endfor %} +{% :endif %} + +const uint8_t {{animation.name}}_frame_order[] = { {{ "%s" % ", ".join(str(i) for i in animation.meta['Frames order']) }} }; + +const BubbleAnimation BA_{{animation.name}} = { + .icon_animation = { + .width = {{ animation.meta['Width'] }}, + .height = {{ animation.meta['Height'] }}, + .frame_count = {{ "%d" % len(animation.frames) }}, + .frame_rate = {{ animation.meta['Frame rate'] }}, + .frames = _A_{{ animation.name }} + }, + .frame_order = {{animation.name}}_frame_order, + .passive_frames = {{ animation.meta['Passive frames'] }}, + .active_frames = {{ animation.meta['Active frames'] }}, + .active_cooldown = {{ animation.meta['Active cooldown'] }}, + .active_cycles = {{ animation.meta['Active cycles'] }}, + .duration = {{ animation.meta['Duration'] }}, +{% if animation.bubble_slots > 0: %} + .frame_bubble_sequences = {{ animation.name }}_bubble_sequences, + .frame_bubble_sequences_count = COUNT_OF({{ animation.name }}_bubble_sequences), +{% :else: %} + .frame_bubble_sequences = NULL, + .frame_bubble_sequences_count = 0, +{% :endif %} +}; +{% :endfor %} + +const StorageAnimation {{symbol_name}}[] = { +{% for animation in animations: %} + { + .animation = &BA_{{animation.name}}, + .manifest_info = { + .name = "{{animation.name}}", + .min_butthurt = {{animation.min_butthurt}}, + .max_butthurt = {{animation.max_butthurt}}, + .min_level = {{animation.min_level}}, + .max_level = {{animation.max_level}}, + .weight = {{animation.weight}}, + } + }, +{% :endfor %} +}; + +const size_t {{symbol_name}}_size = COUNT_OF({{symbol_name}}); diff --git a/scripts/flipper/assets/templates/dolphin.h.tmpl b/scripts/flipper/assets/templates/dolphin.h.tmpl new file mode 100644 index 00000000..405af187 --- /dev/null +++ b/scripts/flipper/assets/templates/dolphin.h.tmpl @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +extern const StorageAnimation {{ symbol_name }}[]; +extern const size_t {{ symbol_name }}_size; diff --git a/scripts/flipper/utils/fff.py b/scripts/flipper/utils/fff.py new file mode 100644 index 00000000..e44d3430 --- /dev/null +++ b/scripts/flipper/utils/fff.py @@ -0,0 +1,103 @@ +import logging + + +class FlipperFormatFile: + def __init__(self): + # Storage + self.lines = [] + self.cursor = 0 + # Logger + self.logger = logging.getLogger("FlipperFormatFile") + + def _resetCursor(self): + self.cursor = 0 + + def nextLine(self): + line = None + while self.cursor < len(self.lines): + temp_line = self.lines[self.cursor].strip() + self.cursor += 1 + if len(temp_line) > 0 and not temp_line.startswith("#"): + line = temp_line + break + if line is None: + raise EOFError() + return line + + def readKeyValue(self): + line = self.nextLine() + data = line.split(":", 1) + if len(data) != 2: + self.logger.error(f"Incorrectly formated line {self.cursor}: `{line}`") + raise Exception("Unexpected line: not `key:value`") + return data[0].strip(), data[1].strip() + + def readKey(self, key: str): + k, v = self.readKeyValue() + if k != key: + raise KeyError(f"Unexpected key {k} != {key}") + return v + + def readKeyInt(self, key: str): + value = self.readKey(key) + return int(value) if value else None + + def readKeyIntArray(self, key: str): + value = self.readKey(key) + return [int(i) for i in value.split(" ")] if value else None + + def readKeyFloat(self, key: str): + value = self.readKey(key) + return float(value) if value else None + + def writeLine(self, line: str): + self.lines.insert(self.cursor, line) + self.cursor += 1 + + def writeKey(self, key: str, value): + if isinstance(value, (str, int, float)): + pass + elif isinstance(value, (list, set)): + value = " ".join(map(str, value)) + else: + raise Exception("Unknown value type") + self.writeLine(f"{key}: {value}") + + def writeEmptyLine(self): + self.writeLine("") + + def writeComment(self, text: str): + self.writeLine(f"# {text}") + + def getHeader(self): + if self.cursor != 0 and len(self.lines) == 0: + raise Exception("Can't read header data: cursor not at 0 or file is empty") + + # Read Filetype + key, value = self.readKeyValue() + if key != "Filetype": + raise Exception("Invalid Header: missing `Filetype`") + filetype = value + + # Read Version + key, value = self.readKeyValue() + if key != "Version": + raise Exception("Invalid Header: missing `Version`") + version = int(value) + + return filetype, version + + def setHeader(self, filetype: str, version: int): + if self.cursor != 0 and len(self.lines) != 0: + raise Exception("Can't set header data: file is not empty") + + self.writeKey("Filetype", filetype) + self.writeKey("Version", version) + + def load(self, filename: str): + file = open(filename, "r") + self.lines = file.readlines() + + def save(self, filename: str): + file = open(filename, "w") + file.write("\n".join(self.lines)) diff --git a/scripts/flipper/utils/templite.py b/scripts/flipper/utils/templite.py new file mode 100644 index 00000000..8af57d7f --- /dev/null +++ b/scripts/flipper/utils/templite.py @@ -0,0 +1,196 @@ +# Templite++ +# A light-weight, fully functional, general purpose templating engine +# Proudly made of shit and sticks. Strictly not for production use. +# Extremly unsafe and difficult to debug. +# +# Copyright (c) 2022 Flipper Devices +# Author: Aleksandr Kutuzov +# +# Copyright (c) 2009 joonis new media +# Author: Thimo Kraemer +# +# Based on Templite by Tomer Filiba +# http://code.activestate.com/recipes/496702/ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + + +from enum import Enum + +import sys +import os + + +class TempliteCompiler: + class State(Enum): + TEXT = 1 + CONTROL = 2 + VARIABLE = 3 + + def __init__(self, source: str, encoding: str): + self.blocks = [f"# -*- coding: {encoding} -*-"] + self.block = "" + self.source = source + self.cursor = 0 + self.offset = 0 + + def processText(self): + self.block = self.block.replace("\\", "\\\\").replace('"', '\\"') + self.block = "\t" * self.offset + f'write("""{self.block}""")' + self.blocks.append(self.block) + self.block = "" + + def getLine(self): + return self.source[: self.cursor].count("\n") + 1 + + def controlIsEnding(self): + block_stripped = self.block.lstrip() + if block_stripped.startswith(":"): + if not self.offset: + raise SyntaxError( + f"Line: {self.getLine()}, no statement to terminate: `{block_stripped}`" + ) + self.offset -= 1 + self.block = block_stripped[1:] + if not self.block.endswith(":"): + return True + return False + + def processControl(self): + self.block = self.block.rstrip() + + if self.controlIsEnding(): + self.block = "" + return + + lines = self.block.splitlines() + margin = min(len(l) - len(l.lstrip()) for l in lines if l.strip()) + self.block = "\n".join("\t" * self.offset + l[margin:] for l in lines) + self.blocks.append(self.block) + if self.block.endswith(":"): + self.offset += 1 + self.block = "" + + def processVariable(self): + self.block = self.block.strip() + self.block = "\t" * self.offset + f"write({self.block})" + self.blocks.append(self.block) + self.block = "" + + def compile(self): + state = self.State.TEXT + + # Process template source + while self.cursor < len(self.source): + # Process plain text till first token occurance + if state == self.State.TEXT: + if self.source[self.cursor :].startswith("{%"): + state = self.State.CONTROL + self.cursor += 1 + elif self.source[self.cursor :].startswith("{{"): + state = self.State.VARIABLE + self.cursor += 1 + else: + self.block += self.source[self.cursor] + # Commit self.block if token was found + if state != self.State.TEXT: + self.processText() + elif state == self.State.CONTROL: + if self.source[self.cursor :].startswith("%}"): + self.cursor += 1 + state = self.State.TEXT + self.processControl() + else: + self.block += self.source[self.cursor] + elif state == self.State.VARIABLE: + if self.source[self.cursor :].startswith("}}"): + self.cursor += 1 + state = self.State.TEXT + self.processVariable() + else: + self.block += self.source[self.cursor] + else: + raise Exception("Unknown State") + + self.cursor += 1 + + if state != self.State.TEXT: + raise Exception("Last self.block was not closed") + + if self.block: + self.processText() + + return "\n".join(self.blocks) + + +class Templite: + cache = {} + + def __init__(self, text=None, filename=None, encoding="utf-8", caching=False): + """Loads a template from string or file.""" + if filename: + filename = os.path.abspath(filename) + mtime = os.path.getmtime(filename) + self.file = key = filename + elif text is not None: + self.file = mtime = None + key = hash(text) + else: + raise ValueError("either text or filename required") + # set attributes + self.encoding = encoding + self.caching = caching + # check cache + cache = self.cache + if caching and key in cache and cache[key][0] == mtime: + self._code = cache[key][1] + return + # read file + if filename: + with open(filename) as fh: + text = fh.read() + # Compile template to executable + code = TempliteCompiler(text, self.encoding).compile() + self._code = compile(code, self.file or "", "exec") + # Cache for future use + if caching: + cache[key] = (mtime, self._code) + + def render(self, **namespace): + """Renders the template according to the given namespace.""" + stack = [] + namespace["__file__"] = self.file + # add write method + def write(*args): + for value in args: + stack.append(str(value)) + + namespace["write"] = write + # add include method + def include(file): + if not os.path.isabs(file): + if self.file: + base = os.path.dirname(self.file) + else: + base = os.path.dirname(sys.argv[0]) + file = os.path.join(base, file) + t = Templite(None, file, self.encoding, self.delimiters, self.caching) + stack.append(t.render(**namespace)) + + namespace["include"] = include + # execute template code + exec(self._code, namespace) + return "".join(stack) diff --git a/scripts/lint.py b/scripts/lint.py index 1be0c837..6537b548 100755 --- a/scripts/lint.py +++ b/scripts/lint.py @@ -4,6 +4,7 @@ import os import re import shutil import subprocess +import multiprocessing from flipper.app import App @@ -60,16 +61,29 @@ class Main(App): output.append(os.path.join(dirpath, filename)) return output + @staticmethod + def _format_source(task): + try: + subprocess.check_call(task) + return True + except subprocess.CalledProcessError as e: + return False + def _format_sources(self, sources: list, dry_run: bool = False): args = ["clang-format", "--Werror", "--style=file", "-i"] if dry_run: args.append("--dry-run") - args += sources - try: - subprocess.check_call(args) - return True - except subprocess.CalledProcessError as e: - return False + + files_per_task = 69 + tasks = [] + while len(sources) > 0: + tasks.append(args + sources[:files_per_task]) + sources = sources[files_per_task:] + + pool = multiprocessing.Pool() + results = pool.map(self._format_source, tasks) + + return not False in results def _fix_filename(self, filename: str): return filename.replace("-", "_")