From d4d87aa6a8edb051ae0a0c998ca887a095a7220e Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Fri, 21 Jan 2022 17:55:09 +0400 Subject: [PATCH 01/12] [FL-2045] SubGhz: new protocol (GSN , Beninca/Allmatic, Elmes) and validator (#958) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: add new method of obtaining a manufactory code subghz_protocol_keeloq_common_magic_xor_type1_learning * TextInput: checking for a lock on a file with the same name * TextInput: fix checking for a lock on a file with the same name * Assets: rename and recompile * TextInput: added picture and timer to turn off blob * TextInput: Fix graphics * TextInput: fix validator * Validators: Add validator is file * TextInput: fix callback validator_is_file_alloc * SubGhz: add propocol GNS (dimamic), Beninca/Alcatic, Elmes * SubGhz: fix function description * Gui: correct timer routine on deallocation * Format sources Co-authored-by: あく --- applications/gui/modules/text_input.c | 112 +++++++++++++++++- applications/gui/modules/text_input.h | 12 ++ applications/gui/modules/validators.c | 42 +++++++ applications/gui/modules/validators.h | 20 ++++ .../subghz/scenes/subghz_scene_save_name.c | 16 ++- applications/subghz/subghz_i.c | 2 +- assets/compiled/assets_icons.c | 8 ++ assets/compiled/assets_icons.h | 2 + assets/icons/Interface/Back3_45x8.png | Bin 0 -> 3630 bytes .../icons/Interface/WarningDolphin_45x42.png | Bin 0 -> 1139 bytes assets/resources/subghz/keeloq_mfcodes | 72 +++++------ assets/resources/subghz/keeloq_mfcodes_user | 2 +- lib/subghz/protocols/subghz_protocol_keeloq.c | 31 ++++- .../protocols/subghz_protocol_keeloq_common.c | 14 ++- .../protocols/subghz_protocol_keeloq_common.h | 13 +- 15 files changed, 300 insertions(+), 46 deletions(-) create mode 100644 applications/gui/modules/validators.c create mode 100644 applications/gui/modules/validators.h create mode 100644 assets/icons/Interface/Back3_45x8.png create mode 100644 assets/icons/Interface/WarningDolphin_45x42.png diff --git a/applications/gui/modules/text_input.c b/applications/gui/modules/text_input.c index 2b31f71b..e8351ce3 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,6 +417,14 @@ 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->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_clean(text_input); return text_input; @@ -376,7 +432,21 @@ TextInput* text_input_alloc() { 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); } @@ -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..7b0dc5c0 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 * @@ -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 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/subghz/scenes/subghz_scene_save_name.c b/applications/subghz/scenes/subghz_scene_save_name.c index f688d20d..c64d0d2c 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); } @@ -37,6 +38,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 +56,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); } @@ -79,6 +87,10 @@ void subghz_scene_save_name_on_exit(void* context) { SubGhz* subghz = context; // Clear view + 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); + text_input_clean(subghz->text_input); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet); 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/assets/compiled/assets_icons.c b/assets/compiled/assets_icons.c index f5f7a6d3..71316998 100644 --- a/assets/compiled/assets_icons.c +++ b/assets/compiled/assets_icons.c @@ -245,6 +245,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 +266,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}; @@ -748,12 +754,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}; diff --git a/assets/compiled/assets_icons.h b/assets/compiled/assets_icons.h index 3dac8eb1..c52821af 100644 --- a/assets/compiled/assets_icons.h +++ b/assets/compiled/assets_icons.h @@ -82,12 +82,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; diff --git a/assets/icons/Interface/Back3_45x8.png b/assets/icons/Interface/Back3_45x8.png new file mode 100644 index 0000000000000000000000000000000000000000..6cb945f6297dda14d46e8bb2e77496a572c600fc GIT binary patch literal 3630 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 XX6*+%8gHC`h)Tl}u@-r>vFqE{F~5F& literal 0 HcmV?d00001 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/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); From d4787e859ee0b1992d645b6f57fb145246c94334 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Fri, 21 Jan 2022 19:55:44 +0300 Subject: [PATCH 02/12] [FL-1506, FL-2197] Power, USB, LED driver improvements (#966) * Power, USB, LED driver improvements * u2f hid descriptor fix * variable_item_list: value alignment fix * InputTypeRepeat handling in menu/submenu/var_item_list * lp5562: fix bugs on 400khz i2c * Scripts: lint in parallel. * FuriHal: rename some USB structure to match naming convention. Drivers: update magic values in LP5562. Co-authored-by: Aleksandr Kutuzov --- applications/bad_usb/bad_usb_app.c | 2 +- applications/debug_tools/usb_mouse.c | 2 +- applications/debug_tools/usb_test.c | 5 + applications/gpio/usb_uart_bridge.c | 2 +- applications/gui/modules/file_select.c | 2 +- applications/gui/modules/menu.c | 8 + applications/gui/modules/submenu.c | 8 + applications/gui/modules/variable_item_list.c | 29 ++- applications/power_observer/power_observer.c | 55 +++++- applications/u2f/u2f_hid.c | 2 +- bootloader/targets/f6/furi_hal/furi_hal_i2c.c | 69 +++++++ bootloader/targets/f6/furi_hal/furi_hal_i2c.h | 106 +++++++++++ bootloader/targets/f7/furi_hal/furi_hal_i2c.c | 69 +++++++ bootloader/targets/f7/furi_hal/furi_hal_i2c.h | 106 +++++++++++ firmware/targets/f6/furi_hal/furi_hal_light.c | 7 +- firmware/targets/f6/furi_hal/furi_hal_power.c | 8 + firmware/targets/f6/furi_hal/furi_hal_usb.c | 93 +++++++--- .../targets/f6/furi_hal/furi_hal_usb_cdc.c | 10 +- .../targets/f6/furi_hal/furi_hal_usb_hid.c | 6 +- .../targets/f6/furi_hal/furi_hal_usb_u2f.c | 13 +- firmware/targets/f7/furi_hal/furi_hal_light.c | 7 +- firmware/targets/f7/furi_hal/furi_hal_power.c | 8 + firmware/targets/f7/furi_hal/furi_hal_usb.c | 93 +++++++--- .../targets/f7/furi_hal/furi_hal_usb_cdc.c | 10 +- .../targets/f7/furi_hal/furi_hal_usb_hid.c | 6 +- .../targets/f7/furi_hal/furi_hal_usb_u2f.c | 13 +- .../targets/furi_hal_include/furi_hal_power.h | 4 + .../targets/furi_hal_include/furi_hal_usb.h | 35 +++- lib/drivers/bq25896.c | 94 ++++++---- lib/drivers/bq25896.h | 3 + lib/drivers/bq27220.c | 41 ++--- lib/drivers/lp5562.c | 170 ++++++++++++++++-- lib/drivers/lp5562.h | 28 ++- lib/drivers/lp5562_reg.h | 10 ++ scripts/lint.py | 26 ++- 35 files changed, 968 insertions(+), 182 deletions(-) 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/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/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/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..6df2b94a 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; diff --git a/applications/gui/modules/submenu.c b/applications/gui/modules/submenu.c index 60a1b092..9d2f5f44 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; diff --git a/applications/gui/modules/variable_item_list.c b/applications/gui/modules/variable_item_list.c index f5226afd..b8d3a45d 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; 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/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/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/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/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/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/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/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("-", "_") From 23ff6723cf870b999b75caee06b9f95a34c52534 Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 21 Jan 2022 20:32:03 +0300 Subject: [PATCH 03/12] [FL-2204] Bluetooth forget devices (#967) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bt: update connection parameters * bt: set correct connection latency and timeout * gui popup: add clean method * furi_hal_bt: add connection parameters request, clear database * bt: add forget bonded devices API * bt_settings: add forget bonded devices GUI * bt: rework pin code show with view port to hide view * bt: support conn parameters for different profiles * furi_hal_bt: sync f6 target * target f6: fix build * bt: format sources * furi_hal_bt: update connection parameters * bt: update connection params, fix GUI * FuriHal: fix spelling * Refactoring: rename _clean to _reset Co-authored-by: あく --- .../archive/scenes/archive_scene_rename.c | 2 +- applications/bt/bt_service/bt.c | 70 ++++++++++++++----- applications/bt/bt_service/bt.h | 7 ++ applications/bt/bt_service/bt_api.c | 6 ++ applications/bt/bt_service/bt_i.h | 5 +- applications/bt/bt_service/bt_keys_storage.c | 13 ++++ applications/bt/bt_service/bt_keys_storage.h | 2 + .../bt/bt_settings_app/bt_settings_app.c | 25 ++++++- .../bt/bt_settings_app/bt_settings_app.h | 13 +++- .../scenes/bt_settings_scene_config.h | 2 + .../bt_settings_scene_forget_dev_confirm.c | 44 ++++++++++++ .../bt_settings_scene_forget_dev_success.c | 43 ++++++++++++ .../scenes/bt_settings_scene_start.c | 23 ++++-- .../scenes/desktop_settings_scene_favorite.c | 4 +- .../desktop_settings_scene_pincode_menu.c | 4 +- .../scenes/desktop_settings_scene_start.c | 2 +- applications/gpio/scenes/gpio_scene_start.c | 2 +- .../gpio/scenes/gpio_scene_usb_uart_config.c | 2 +- applications/gui/modules/button_menu.c | 2 +- applications/gui/modules/button_menu.h | 2 +- applications/gui/modules/button_panel.c | 4 +- applications/gui/modules/button_panel.h | 2 +- applications/gui/modules/dialog_ex.c | 2 +- applications/gui/modules/dialog_ex.h | 4 +- applications/gui/modules/menu.c | 4 +- applications/gui/modules/menu.h | 2 +- applications/gui/modules/popup.c | 18 ++++- applications/gui/modules/popup.h | 6 ++ applications/gui/modules/submenu.c | 2 +- applications/gui/modules/submenu.h | 2 +- applications/gui/modules/text_box.c | 2 +- applications/gui/modules/text_box.h | 2 +- applications/gui/modules/text_input.c | 4 +- applications/gui/modules/text_input.h | 4 +- applications/gui/modules/variable_item_list.c | 2 +- applications/gui/modules/variable_item_list.h | 2 +- .../ibutton/scene/ibutton_scene_add_type.cpp | 4 +- .../scene/ibutton_scene_readed_key_menu.cpp | 4 +- .../ibutton/scene/ibutton_scene_save_name.cpp | 4 +- .../scene/ibutton_scene_saved_key_menu.cpp | 4 +- .../ibutton/scene/ibutton_scene_start.cpp | 4 +- .../irda/scene/irda_app_scene_edit.cpp | 2 +- .../scene/irda_app_scene_edit_key_select.cpp | 2 +- .../irda/scene/irda_app_scene_remote.cpp | 2 +- .../irda/scene/irda_app_scene_start.cpp | 2 +- .../irda/scene/irda_app_scene_universal.cpp | 2 +- .../scene/irda_app_scene_universal_common.cpp | 2 +- applications/loader/loader.c | 2 +- applications/nfc/scenes/nfc_scene_card_menu.c | 2 +- .../nfc/scenes/nfc_scene_device_info.c | 2 +- .../nfc/scenes/nfc_scene_mifare_ul_menu.c | 2 +- .../scenes/nfc_scene_read_mifare_ul_success.c | 2 +- applications/nfc/scenes/nfc_scene_save_name.c | 2 +- .../nfc/scenes/nfc_scene_saved_menu.c | 2 +- .../nfc/scenes/nfc_scene_scripts_menu.c | 2 +- applications/nfc/scenes/nfc_scene_set_type.c | 2 +- applications/nfc/scenes/nfc_scene_start.c | 2 +- .../scenes/power_settings_scene_power_off.c | 2 +- .../scenes/power_settings_scene_reboot.c | 2 +- .../scenes/power_settings_scene_start.c | 2 +- .../scenes/storage_settings_scene_start.c | 2 +- .../subghz/scenes/subghz_scene_more_raw.c | 2 +- .../subghz/scenes/subghz_scene_receiver.c | 2 +- .../scenes/subghz_scene_receiver_config.c | 2 +- .../subghz/scenes/subghz_scene_save_name.c | 2 +- .../subghz/scenes/subghz_scene_saved_menu.c | 2 +- .../subghz/scenes/subghz_scene_set_type.c | 2 +- .../subghz/scenes/subghz_scene_start.c | 2 +- .../subghz/scenes/subghz_scene_test.c | 2 +- applications/subghz/subghz_history.c | 4 +- applications/subghz/subghz_history.h | 2 +- firmware/targets/f6/ble_glue/gap.c | 46 +++++++++--- firmware/targets/f6/ble_glue/gap.h | 8 +++ firmware/targets/f6/furi_hal/furi_hal_bt.c | 25 +++++++ firmware/targets/f6/target.mk | 1 + firmware/targets/f7/ble_glue/gap.c | 46 +++++++++--- firmware/targets/f7/ble_glue/gap.h | 8 +++ firmware/targets/f7/furi_hal/furi_hal_bt.c | 25 +++++++ firmware/targets/f7/target.mk | 1 + .../targets/furi_hal_include/furi_hal_bt.h | 6 ++ .../view_modules/submenu_vm.cpp | 2 +- .../view_modules/text_input_vm.cpp | 2 +- 82 files changed, 471 insertions(+), 116 deletions(-) mode change 100644 => 100755 applications/bt/bt_settings_app/scenes/bt_settings_scene_config.h create mode 100755 applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c create mode 100755 applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c mode change 100644 => 100755 firmware/targets/f6/ble_glue/gap.c mode change 100644 => 100755 firmware/targets/f6/furi_hal/furi_hal_bt.c mode change 100644 => 100755 firmware/targets/f7/ble_glue/gap.c mode change 100644 => 100755 firmware/targets/f7/furi_hal/furi_hal_bt.c diff --git a/applications/archive/scenes/archive_scene_rename.c b/applications/archive/scenes/archive_scene_rename.c index ad7669bc..99ae8be4 100644 --- a/applications/archive/scenes/archive_scene_rename.c +++ b/applications/archive/scenes/archive_scene_rename.c @@ -75,5 +75,5 @@ 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); + text_input_reset(archive->text_input); } 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..db379436 100755 --- a/applications/bt/bt_settings_app/bt_settings_app.h +++ b/applications/bt/bt_settings_app/bt_settings_app.h @@ -1,22 +1,33 @@ #pragma once #include +#include #include #include #include #include #include +#include +#include #include "../bt_settings.h" #include "scenes/bt_settings_scene.h" 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..e43082af --- /dev/null +++ b/applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c @@ -0,0 +1,43 @@ +#include "../bt_settings_app.h" +#include "furi_hal_bt.h" + +#define SCENE_FORGET_DEV_SUCCESS_CUSTOM_EVENT (0UL) + +void bt_settings_app_scene_forget_dev_success_popup_callback(void* context) { + BtSettingsApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_FORGET_DEV_SUCCESS_CUSTOM_EVENT); +} + +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 == SCENE_FORGET_DEV_SUCCESS_CUSTOM_EVENT) { + 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..33c0bb5a 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 @@ -1,6 +1,8 @@ #include "../bt_settings_app.h" #include "furi_hal_bt.h" +#define SCENE_START_FORGET_DEV_SELECTED_EVENT (10UL) + enum BtSetting { BtSettingOff, BtSettingOn, @@ -8,8 +10,8 @@ enum BtSetting { }; 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 +22,12 @@ 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; + view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_START_FORGET_DEV_SELECTED_EVENT); +} + void bt_settings_scene_start_on_enter(void* context) { BtSettingsApp* app = context; VariableItemList* var_item_list = app->var_item_list; @@ -40,6 +48,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 +67,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 == SCENE_START_FORGET_DEV_SELECTED_EVENT) { + 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/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c index 0b9bb580..67d0f218 100644 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -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_menu.c b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_pincode_menu.c index 78c2eee9..252d3a51 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 @@ -9,7 +9,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 +74,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 index 43b541ac..008d908e 100755 --- a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c @@ -53,5 +53,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/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/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/menu.c b/applications/gui/modules/menu.c index 6df2b94a..0fb95d70 100644 --- a/applications/gui/modules/menu.c +++ b/applications/gui/modules/menu.c @@ -146,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); } @@ -180,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 9d2f5f44..e9e27203 100644 --- a/applications/gui/modules/submenu.c +++ b/applications/gui/modules/submenu.c @@ -177,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 e8351ce3..bb200606 100755 --- a/applications/gui/modules/text_input.c +++ b/applications/gui/modules/text_input.c @@ -425,7 +425,7 @@ TextInput* text_input_alloc() { return false; }); - text_input_clean(text_input); + text_input_reset(text_input); return text_input; } @@ -450,7 +450,7 @@ void text_input_free(TextInput* text_input) { 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) { diff --git a/applications/gui/modules/text_input.h b/applications/gui/modules/text_input.h index 7b0dc5c0..d30fcd4c 100644 --- a/applications/gui/modules/text_input.h +++ b/applications/gui/modules/text_input.h @@ -36,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 * @@ -84,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/variable_item_list.c b/applications/gui/modules/variable_item_list.c index b8d3a45d..cf2b01a1 100644 --- a/applications/gui/modules/variable_item_list.c +++ b/applications/gui/modules/variable_item_list.c @@ -312,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/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_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..5b85d409 100644 --- a/applications/ibutton/scene/ibutton_scene_save_name.cpp +++ b/applications/ibutton/scene/ibutton_scene_save_name.cpp @@ -48,7 +48,7 @@ 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); + text_input_reset(text_input); } void iButtonSceneSaveName::text_input_callback(void* context) { @@ -58,4 +58,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_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_remote.cpp b/applications/irda/scene/irda_app_scene_remote.cpp index a19235cb..c46d2e29 100644 --- a/applications/irda/scene/irda_app_scene_remote.cpp +++ b/applications/irda/scene/irda_app_scene_remote.cpp @@ -132,5 +132,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..c55a7af7 100644 --- a/applications/irda/scene/irda_app_scene_universal_common.cpp +++ b/applications/irda/scene/irda_app_scene_universal_common.cpp @@ -102,5 +102,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/loader/loader.c b/applications/loader/loader.c index 4cb2e209..f78e5bc0 100644 --- a/applications/loader/loader.c +++ b/applications/loader/loader.c @@ -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(); } 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_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_mifare_ul_success.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c index a11af2b5..db5762ad 100755 --- a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c @@ -126,6 +126,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..83a60e38 100755 --- a/applications/nfc/scenes/nfc_scene_save_name.c +++ b/applications/nfc/scenes/nfc_scene_save_name.c @@ -60,5 +60,5 @@ void nfc_scene_save_name_on_exit(void* context) { Nfc* nfc = (Nfc*)context; // Clear view - text_input_clean(nfc->text_input); + text_input_reset(nfc->text_input); } 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_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/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_more_raw.c b/applications/subghz/scenes/subghz_scene_more_raw.c index 10e0aad4..1047aef2 100644 --- a/applications/subghz/scenes/subghz_scene_more_raw.c +++ b/applications/subghz/scenes/subghz_scene_more_raw.c @@ -56,5 +56,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_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_save_name.c b/applications/subghz/scenes/subghz_scene_save_name.c index c64d0d2c..d473fed7 100644 --- a/applications/subghz/scenes/subghz_scene_save_name.c +++ b/applications/subghz/scenes/subghz_scene_save_name.c @@ -91,7 +91,7 @@ void subghz_scene_save_name_on_exit(void* context) { text_input_set_validator(subghz->text_input, NULL, NULL); validator_is_file_free(validator_context); - text_input_clean(subghz->text_input); + text_input_reset(subghz->text_input); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet); } 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..ddd8b976 100644 --- a/applications/subghz/scenes/subghz_scene_set_type.c +++ b/applications/subghz/scenes/subghz_scene_set_type.c @@ -202,5 +202,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/subghz_history.c b/applications/subghz/subghz_history.c index b9fb90e7..470bcea0 100644 --- a/applications/subghz/subghz_history.c +++ b/applications/subghz/subghz_history.c @@ -60,7 +60,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; @@ -168,4 +168,4 @@ bool subghz_history_add_to_history( 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/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/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/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/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..06f243de 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( From e804015fea80cd535c1b9357aef87f81f3064a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 27 Jan 2022 15:21:21 +0300 Subject: [PATCH 04/12] [FL-2225] About: add serial number to hardware info screen (#970) --- applications/about/about.c | 6 ++++++ 1 file changed, 6 insertions(+) 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); From cb0369a7f369243098cd598a92a5f5a6faa0834d Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Thu, 27 Jan 2022 16:28:21 +0400 Subject: [PATCH 05/12] SubGhz: add protocol Somfy Telis RTS, Somfy Keytis RTS (#964) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: add 433.42 MHz for Somfy * SupGhz: add protocol Somfy Telis RTS, Somfy Keytis RTS Co-authored-by: あく --- applications/subghz/subghz.c | 4 +- applications/subghz/subghz_history.c | 13 +- .../protocols/subghz_protocol_somfy_keytis.c | 345 ++++++++++++++++++ .../protocols/subghz_protocol_somfy_keytis.h | 50 +++ .../protocols/subghz_protocol_somfy_telis.c | 293 +++++++++++++++ .../protocols/subghz_protocol_somfy_telis.h | 46 +++ lib/subghz/subghz_parser.c | 24 ++ 7 files changed, 770 insertions(+), 5 deletions(-) create mode 100644 lib/subghz/protocols/subghz_protocol_somfy_keytis.c create mode 100644 lib/subghz/protocols/subghz_protocol_somfy_keytis.h create mode 100644 lib/subghz/protocols/subghz_protocol_somfy_telis.c create mode 100644 lib/subghz/protocols/subghz_protocol_somfy_telis.h 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 470bcea0..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; }; @@ -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,9 +162,13 @@ 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++; 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); } From 53e7415d126d30e64c1ba275a1a725573a963535 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Thu, 27 Jan 2022 20:38:47 +0400 Subject: [PATCH 06/12] [FL-2215, FL-2168] Display long names and rename RAW files (#971) * [FL-2215] SubGhz: fix long names on RAW and Delete screens * [FL-2168] SubGhz: fix rename RAW --- applications/subghz/scenes/subghz_scene_delete_raw.c | 10 ++++------ applications/subghz/scenes/subghz_scene_more_raw.c | 1 + applications/subghz/scenes/subghz_scene_read_raw.c | 2 +- applications/subghz/scenes/subghz_scene_save_name.c | 12 ++++++------ applications/subghz/views/subghz_read_raw.c | 4 ++-- 5 files changed, 14 insertions(+), 15 deletions(-) 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_more_raw.c b/applications/subghz/scenes/subghz_scene_more_raw.c index 1047aef2..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); diff --git a/applications/subghz/scenes/subghz_scene_read_raw.c b/applications/subghz/scenes/subghz_scene_read_raw.c index aaa51c76..50edcb22 100644 --- a/applications/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/subghz/scenes/subghz_scene_read_raw.c @@ -4,7 +4,7 @@ #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; diff --git a/applications/subghz/scenes/subghz_scene_save_name.c b/applications/subghz/scenes/subghz_scene_save_name.c index d473fed7..142ba7c9 100644 --- a/applications/subghz/scenes/subghz_scene_save_name.c +++ b/applications/subghz/scenes/subghz_scene_save_name.c @@ -19,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) == @@ -27,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( @@ -67,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); } @@ -86,12 +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 view + // 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_reset(subghz->text_input); - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet); } 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: From 84410c83b54a26efbd6e7d248de8d96bdef78725 Mon Sep 17 00:00:00 2001 From: Albert Kharisov Date: Sat, 29 Jan 2022 13:20:41 +0400 Subject: [PATCH 07/12] [FL-2183] [FL-2209] Dolphin Deeds, Level up, assets generation, refactoring (#965) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Desktop: cleanup headers * Get loader pubsub via record * [FL-2183] Dolphin refactoring 2022.01 * Restruct animations assets structure * Rename assets * Cleanup headers * Update Recording animation * Add BadBattery animation * Provide loader's pubsub via record * Fix load/unload animations * Scripts: add flipper format support, initial dolphin packager rework. Assets: internal and external dolphin. * Sync internal meta.txt and manifest.txt * Reorder, rename dolphin assets * Split essential generated assets * Add ReadMe for dolphin assets * Separate essential blocking animations * Scripts: full dolphin validation before packaging * Assets, Scripts: dolphin external resources packer * Github: update codeowners * Scripts: proper slots handling in dolphin animation meta * Scripts: correct frames enumeration and fix compiled assets. * [FL-2209] Add Dolphin Deeds points and many more * Remove excess frame_rate * Change dolphin assets directory * Scripts: add internal resource support to dolphin compiler * Scripts: add internal assets generation, renaming * Scripts: correct assert, renaming * Code cleanup, documentation, fixes * Update Levelup animations * Rename essential -> blocking * Fix Unlocked hint * Scripts: rewrite Templite compiller, replace regexps with token parser, split block types into code and variable blocks. Update dolphin templates. * Documentation: add key combos description and use information * Scripts: cleanup templit, more debug info and add dev comment Co-authored-by: あく --- .github/CODEOWNERS | 4 +- applications/bad_usb/bad_usb_script.c | 2 + .../desktop/animations/animation_manager.c | 251 +++++++++--- .../desktop/animations/animation_manager.h | 23 +- .../desktop/animations/animation_storage.c | 322 ++++++++------- .../desktop/animations/animation_storage.h | 15 +- .../desktop/animations/animation_storage_i.h | 188 +-------- .../animations/views/bubble_animation_view.c | 87 ++-- .../views/one_shot_animation_view.c | 130 ++++++ .../views/one_shot_animation_view.h | 17 + applications/desktop/desktop.c | 67 ++- applications/desktop/desktop_i.h | 33 +- .../desktop_settings/desktop_settings_app.c | 2 + .../desktop_settings/desktop_settings_app.h | 4 - .../scenes/desktop_settings_scene_favorite.c | 2 +- .../desktop_settings_scene_pincode_input.c | 2 +- .../desktop_settings_scene_pincode_menu.c | 1 + .../scenes/desktop_settings_scene_start.c | 1 + .../desktop/scenes/desktop_scene_config.h | 1 - .../desktop/scenes/desktop_scene_debug.c | 11 +- .../desktop/scenes/desktop_scene_fault.c | 2 + .../scenes/desktop_scene_first_start.c | 3 + .../scenes/desktop_scene_hw_mismatch.c | 24 +- applications/desktop/scenes/desktop_scene_i.h | 7 + .../desktop/scenes/desktop_scene_lock_menu.c | 17 +- .../desktop/scenes/desktop_scene_locked.c | 101 ----- .../desktop/scenes/desktop_scene_main.c | 74 ++-- applications/desktop/views/desktop_debug.c | 4 +- applications/desktop/views/desktop_debug.h | 7 +- applications/desktop/views/desktop_events.h | 3 +- .../desktop/views/desktop_first_start.c | 2 + .../desktop/views/desktop_first_start.h | 5 +- .../desktop/views/desktop_lock_menu.c | 2 + .../desktop/views/desktop_lock_menu.h | 4 - applications/desktop/views/desktop_locked.c | 286 +++++++------ applications/desktop/views/desktop_locked.h | 39 +- applications/desktop/views/desktop_main.c | 107 +---- applications/desktop/views/desktop_main.h | 26 -- applications/dolphin/dolphin.c | 122 ++++-- applications/dolphin/dolphin.h | 15 + applications/dolphin/dolphin_i.h | 8 +- applications/dolphin/helpers/dolphin_deed.c | 67 ++- applications/dolphin/helpers/dolphin_deed.h | 78 +++- applications/dolphin/helpers/dolphin_state.c | 70 ++-- applications/dolphin/helpers/dolphin_state.h | 10 +- applications/gui/canvas.c | 17 + applications/gui/canvas.h | 17 + applications/gui/icon_i.h | 1 + applications/gui/view_composed.c | 166 -------- applications/gui/view_composed.h | 12 - applications/gui/view_stack.c | 165 ++++++++ applications/gui/view_stack.h | 53 +++ .../ibutton/scene/ibutton_scene_add_value.cpp | 4 +- .../ibutton/scene/ibutton_scene_emulate.cpp | 4 +- .../ibutton/scene/ibutton_scene_read.cpp | 4 +- .../scene/ibutton_scene_read_success.cpp | 4 +- .../scene/ibutton_scene_save_success.cpp | 4 +- .../irda/scene/irda_app_scene_learn_done.cpp | 2 + .../scene/irda_app_scene_learn_success.cpp | 2 + .../irda/scene/irda_app_scene_remote.cpp | 2 + .../scene/irda_app_scene_universal_common.cpp | 2 + .../lfrfid/scene/lfrfid_app_scene_emulate.cpp | 2 + .../lfrfid/scene/lfrfid_app_scene_read.cpp | 3 + .../scene/lfrfid_app_scene_save_data.cpp | 2 + .../scene/lfrfid_app_scene_save_success.cpp | 6 +- applications/loader/loader.c | 7 +- applications/loader/loader.h | 2 +- .../nfc/scenes/nfc_scene_emulate_mifare_ul.c | 2 + .../nfc/scenes/nfc_scene_emulate_uid.c | 2 + applications/nfc/scenes/nfc_scene_read_card.c | 2 + .../nfc/scenes/nfc_scene_read_card_success.c | 2 + .../nfc/scenes/nfc_scene_read_emv_app.c | 2 + .../scenes/nfc_scene_read_emv_app_success.c | 2 + .../nfc/scenes/nfc_scene_read_emv_data.c | 2 + .../scenes/nfc_scene_read_emv_data_success.c | 2 + .../nfc/scenes/nfc_scene_read_mifare_ul.c | 2 + .../scenes/nfc_scene_read_mifare_ul_success.c | 2 + .../nfc/scenes/nfc_scene_save_success.c | 2 + applications/nfc/scenes/nfc_scene_set_uid.c | 2 + .../scenes/subghz_scene_frequency_analyzer.c | 2 + .../subghz/scenes/subghz_scene_read_raw.c | 3 + .../scenes/subghz_scene_receiver_info.c | 2 + .../subghz/scenes/subghz_scene_save_success.c | 3 + .../subghz/scenes/subghz_scene_set_type.c | 2 + .../subghz/scenes/subghz_scene_transmitter.c | 2 + applications/u2f/scenes/u2f_scene_main.c | 2 + assets/Makefile | 14 +- assets/assets.mk | 5 +- assets/compiled/assets_dolphin_blocking.c | 320 +++++++++++++++ assets/compiled/assets_dolphin_blocking.h | 7 + assets/compiled/assets_dolphin_internal.c | 324 +++++++++++++++ assets/compiled/assets_dolphin_internal.h | 7 + assets/compiled/assets_icons.c | 136 ++----- assets/compiled/assets_icons.h | 30 +- assets/dolphin/ReadMe.md | 81 ++++ .../dolphin/animations/recording/frame_0.png | Bin 1752 -> 0 bytes .../dolphin/animations/recording/frame_10.png | Bin 1702 -> 0 bytes .../dolphin/animations/recording/frame_11.png | Bin 1746 -> 0 bytes .../dolphin/animations/recording/frame_3.png | Bin 1740 -> 0 bytes .../dolphin/animations/recording/frame_4.png | Bin 1729 -> 0 bytes .../dolphin/animations/recording/frame_5.png | Bin 1687 -> 0 bytes .../dolphin/animations/recording/frame_9.png | Bin 1736 -> 0 bytes .../blocking/L0_NewMail_128x51/frame_0.png | Bin 0 -> 1389 bytes .../blocking/L0_NewMail_128x51/frame_1.png | Bin 0 -> 1404 bytes .../blocking/L0_NewMail_128x51/frame_2.png | Bin 0 -> 1434 bytes .../blocking/L0_NewMail_128x51/frame_3.png | Bin 0 -> 1438 bytes .../blocking/L0_NewMail_128x51/meta.txt | 14 + .../blocking/L0_NoDb_128x51/frame_0.png} | Bin .../blocking/L0_NoDb_128x51/frame_1.png} | Bin .../blocking/L0_NoDb_128x51/frame_2.png} | Bin .../blocking/L0_NoDb_128x51/frame_3.png} | Bin .../dolphin/blocking/L0_NoDb_128x51/meta.txt | 14 + .../blocking/L0_SdBad_128x51/frame_0.png} | Bin .../blocking/L0_SdBad_128x51/frame_1.png} | Bin .../dolphin/blocking/L0_SdBad_128x51/meta.txt | 14 + .../blocking/L0_SdOk_128x51/frame_0.png} | Bin .../blocking/L0_SdOk_128x51/frame_1.png} | Bin .../blocking/L0_SdOk_128x51/frame_2.png} | Bin .../blocking/L0_SdOk_128x51/frame_3.png} | Bin .../dolphin/blocking/L0_SdOk_128x51/meta.txt | 14 + .../blocking/L0_Url_128x51/frame_0.png} | Bin .../blocking/L0_Url_128x51/frame_1.png} | Bin .../blocking/L0_Url_128x51/frame_2.png} | Bin .../blocking/L0_Url_128x51/frame_3.png} | Bin .../dolphin/blocking/L0_Url_128x51/meta.txt | 14 + assets/dolphin/blocking/manifest.txt | 42 ++ .../external/L1_Furippa1_128x64/frame_0.png | Bin 0 -> 1302 bytes .../external/L1_Furippa1_128x64/frame_1.png | Bin 0 -> 1333 bytes .../external/L1_Furippa1_128x64/frame_10.png | Bin 0 -> 1524 bytes .../external/L1_Furippa1_128x64/frame_11.png | Bin 0 -> 1782 bytes .../external/L1_Furippa1_128x64/frame_12.png | Bin 0 -> 1607 bytes .../external/L1_Furippa1_128x64/frame_13.png | Bin 0 -> 1679 bytes .../external/L1_Furippa1_128x64/frame_14.png | Bin 0 -> 1714 bytes .../external/L1_Furippa1_128x64/frame_15.png | Bin 0 -> 1775 bytes .../external/L1_Furippa1_128x64/frame_16.png | Bin 0 -> 1475 bytes .../external/L1_Furippa1_128x64/frame_17.png | Bin 0 -> 1428 bytes .../external/L1_Furippa1_128x64/frame_18.png | Bin 0 -> 1346 bytes .../external/L1_Furippa1_128x64/frame_2.png | Bin 0 -> 1339 bytes .../external/L1_Furippa1_128x64/frame_3.png | Bin 0 -> 1328 bytes .../external/L1_Furippa1_128x64/frame_4.png | Bin 0 -> 1383 bytes .../external/L1_Furippa1_128x64/frame_5.png | Bin 0 -> 1390 bytes .../external/L1_Furippa1_128x64/frame_6.png | Bin 0 -> 1397 bytes .../external/L1_Furippa1_128x64/frame_7.png | Bin 0 -> 1302 bytes .../external/L1_Furippa1_128x64/frame_8.png | Bin 0 -> 1291 bytes .../external/L1_Furippa1_128x64/frame_9.png | Bin 0 -> 1337 bytes .../external/L1_Furippa1_128x64/meta.txt | 14 + .../L1_Laptop_128x51}/frame_0.png | Bin .../L1_Laptop_128x51}/frame_1.png | Bin .../L1_Laptop_128x51}/frame_2.png | Bin .../L1_Laptop_128x51}/frame_3.png | Bin .../L1_Laptop_128x51}/frame_4.png | Bin .../L1_Laptop_128x51}/frame_5.png | Bin .../L1_Laptop_128x51}/frame_6.png | Bin .../L1_Laptop_128x51}/frame_7.png | Bin .../external/L1_Laptop_128x51}/meta.txt | 10 +- .../external/L1_Recording_128x51/frame_0.png | Bin 0 -> 1752 bytes .../L1_Recording_128x51}/frame_1.png | Bin 1742 -> 1742 bytes .../external/L1_Recording_128x51/frame_10.png | Bin 0 -> 1708 bytes .../external/L1_Recording_128x51/frame_11.png | Bin 0 -> 1745 bytes .../L1_Recording_128x51}/frame_2.png | Bin 1688 -> 1688 bytes .../external/L1_Recording_128x51/frame_3.png | Bin 0 -> 1745 bytes .../external/L1_Recording_128x51/frame_4.png | Bin 0 -> 1735 bytes .../external/L1_Recording_128x51/frame_5.png | Bin 0 -> 1691 bytes .../L1_Recording_128x51}/frame_6.png | Bin 1752 -> 1752 bytes .../L1_Recording_128x51}/frame_7.png | Bin 1689 -> 1689 bytes .../L1_Recording_128x51}/frame_8.png | Bin 1766 -> 1766 bytes .../external/L1_Recording_128x51/frame_9.png | Bin 0 -> 1732 bytes .../external/L1_Recording_128x51}/meta.txt | 4 +- .../L1_Sleep_128x64}/frame_0.png | Bin .../L1_Sleep_128x64}/frame_1.png | Bin .../L1_Sleep_128x64}/frame_2.png | Bin .../L1_Sleep_128x64}/frame_3.png | Bin .../L1_Sleep_128x64}/meta.txt | 0 .../L1_Waves_128x50}/frame_0.png | Bin .../L1_Waves_128x50}/frame_1.png | Bin .../L1_Waves_128x50}/frame_2.png | Bin .../L1_Waves_128x50}/frame_3.png | Bin .../L1_Waves_128x50}/meta.txt | 0 .../external/L2_Furippa2_128x64/frame_0.png | Bin 0 -> 1389 bytes .../external/L2_Furippa2_128x64/frame_1.png | Bin 0 -> 1417 bytes .../external/L2_Furippa2_128x64/frame_10.png | Bin 0 -> 1524 bytes .../external/L2_Furippa2_128x64/frame_11.png | Bin 0 -> 1782 bytes .../external/L2_Furippa2_128x64/frame_12.png | Bin 0 -> 1607 bytes .../external/L2_Furippa2_128x64/frame_13.png | Bin 0 -> 1679 bytes .../external/L2_Furippa2_128x64/frame_14.png | Bin 0 -> 1714 bytes .../external/L2_Furippa2_128x64/frame_15.png | Bin 0 -> 1795 bytes .../external/L2_Furippa2_128x64/frame_16.png | Bin 0 -> 1549 bytes .../external/L2_Furippa2_128x64/frame_17.png | Bin 0 -> 1514 bytes .../external/L2_Furippa2_128x64/frame_18.png | Bin 0 -> 1441 bytes .../external/L2_Furippa2_128x64/frame_2.png | Bin 0 -> 1421 bytes .../external/L2_Furippa2_128x64/frame_3.png | Bin 0 -> 1411 bytes .../external/L2_Furippa2_128x64/frame_4.png | Bin 0 -> 1454 bytes .../external/L2_Furippa2_128x64/frame_5.png | Bin 0 -> 1459 bytes .../external/L2_Furippa2_128x64/frame_6.png | Bin 0 -> 1465 bytes .../external/L2_Furippa2_128x64/frame_7.png | Bin 0 -> 1389 bytes .../external/L2_Furippa2_128x64/frame_8.png | Bin 0 -> 1348 bytes .../external/L2_Furippa2_128x64/frame_9.png | Bin 0 -> 1347 bytes .../external/L2_Furippa2_128x64/meta.txt | 14 + .../external/L3_Furippa3_128x64/frame_0.png | Bin 0 -> 1442 bytes .../external/L3_Furippa3_128x64/frame_1.png | Bin 0 -> 1478 bytes .../external/L3_Furippa3_128x64/frame_10.png | Bin 0 -> 1609 bytes .../external/L3_Furippa3_128x64/frame_11.png | Bin 0 -> 1826 bytes .../external/L3_Furippa3_128x64/frame_12.png | Bin 0 -> 1607 bytes .../external/L3_Furippa3_128x64/frame_13.png | Bin 0 -> 1679 bytes .../external/L3_Furippa3_128x64/frame_14.png | Bin 0 -> 1714 bytes .../external/L3_Furippa3_128x64/frame_15.png | Bin 0 -> 1805 bytes .../external/L3_Furippa3_128x64/frame_16.png | Bin 0 -> 1575 bytes .../external/L3_Furippa3_128x64/frame_17.png | Bin 0 -> 1560 bytes .../external/L3_Furippa3_128x64/frame_18.png | Bin 0 -> 1492 bytes .../external/L3_Furippa3_128x64/frame_2.png | Bin 0 -> 1472 bytes .../external/L3_Furippa3_128x64/frame_3.png | Bin 0 -> 1466 bytes .../external/L3_Furippa3_128x64/frame_4.png | Bin 0 -> 1513 bytes .../external/L3_Furippa3_128x64/frame_5.png | Bin 0 -> 1519 bytes .../external/L3_Furippa3_128x64/frame_6.png | Bin 0 -> 1526 bytes .../external/L3_Furippa3_128x64/frame_7.png | Bin 0 -> 1442 bytes .../external/L3_Furippa3_128x64/frame_8.png | Bin 0 -> 1456 bytes .../external/L3_Furippa3_128x64/frame_9.png | Bin 0 -> 1477 bytes .../external/L3_Furippa3_128x64/meta.txt | 14 + assets/dolphin/external/manifest.txt | 58 +++ .../internal/L1_BadBattery_128x47/frame_0.png | Bin 0 -> 1384 bytes .../internal/L1_BadBattery_128x47/frame_1.png | Bin 0 -> 1390 bytes .../internal/L1_BadBattery_128x47/meta.txt | 23 ++ .../internal/L1_NoSd_128x49/frame_0.png} | Bin .../internal/L1_NoSd_128x49/frame_1.png} | Bin .../internal/L1_NoSd_128x49/frame_2.png} | Bin .../internal/L1_NoSd_128x49/frame_3.png} | Bin .../internal/L1_NoSd_128x49/frame_4.png} | Bin .../internal/L1_NoSd_128x49/frame_5.png} | Bin .../dolphin/internal/L1_NoSd_128x49/meta.txt | 23 ++ .../internal/L1_Tv_128x47/frame_0.png} | Bin .../internal/L1_Tv_128x47/frame_1.png} | Bin .../internal/L1_Tv_128x47/frame_2.png} | Bin .../internal/L1_Tv_128x47/frame_3.png} | Bin .../internal/L1_Tv_128x47/frame_4.png} | Bin .../internal/L1_Tv_128x47/frame_5.png} | Bin .../internal/L1_Tv_128x47/frame_6.png} | Bin .../internal/L1_Tv_128x47/frame_7.png} | Bin assets/dolphin/internal/L1_Tv_128x47/meta.txt | 32 ++ .../{animations => internal}/manifest.txt | 21 +- .../Animations/Levelup1_128x64/frame_00.png | Bin 0 -> 1326 bytes .../Animations/Levelup1_128x64/frame_01.png | Bin 0 -> 1597 bytes .../Animations/Levelup1_128x64/frame_02.png | Bin 0 -> 1754 bytes .../Animations/Levelup1_128x64/frame_03.png | Bin 0 -> 1828 bytes .../Animations/Levelup1_128x64/frame_04.png | Bin 0 -> 1686 bytes .../Animations/Levelup1_128x64/frame_05.png | Bin 0 -> 1672 bytes .../Animations/Levelup1_128x64/frame_06.png | Bin 0 -> 1659 bytes .../Animations/Levelup1_128x64/frame_07.png | Bin 0 -> 1540 bytes .../Animations/Levelup1_128x64/frame_08.png | Bin 0 -> 1557 bytes .../Animations/Levelup1_128x64/frame_09.png | Bin 0 -> 1551 bytes .../Animations/Levelup1_128x64/frame_10.png | Bin 0 -> 1604 bytes .../Animations/Levelup1_128x64/frame_rate | 1 + .../Animations/Levelup2_128x64/frame_00.png | Bin 0 -> 1368 bytes .../Animations/Levelup2_128x64/frame_01.png | Bin 0 -> 1632 bytes .../Animations/Levelup2_128x64/frame_02.png | Bin 0 -> 1812 bytes .../Animations/Levelup2_128x64/frame_03.png | Bin 0 -> 1860 bytes .../Animations/Levelup2_128x64/frame_04.png | Bin 0 -> 1700 bytes .../Animations/Levelup2_128x64/frame_05.png | Bin 0 -> 1725 bytes .../Animations/Levelup2_128x64/frame_06.png | Bin 0 -> 1684 bytes .../Animations/Levelup2_128x64/frame_07.png | Bin 0 -> 1590 bytes .../Animations/Levelup2_128x64/frame_08.png | Bin 0 -> 1598 bytes .../Animations/Levelup2_128x64/frame_09.png | Bin 0 -> 1604 bytes .../Animations/Levelup2_128x64/frame_10.png | Bin 0 -> 1612 bytes .../Animations/Levelup2_128x64/frame_rate | 1 + .../dolphin/L1_Furippa1_128x64/frame_0.bm | Bin 0 -> 294 bytes .../dolphin/L1_Furippa1_128x64/frame_1.bm | Bin 0 -> 325 bytes .../dolphin/L1_Furippa1_128x64/frame_10.bm | Bin 0 -> 465 bytes .../dolphin/L1_Furippa1_128x64/frame_11.bm | Bin 0 -> 698 bytes .../dolphin/L1_Furippa1_128x64/frame_12.bm | Bin 0 -> 541 bytes .../dolphin/L1_Furippa1_128x64/frame_13.bm | Bin 0 -> 584 bytes .../dolphin/L1_Furippa1_128x64/frame_14.bm | Bin 0 -> 610 bytes .../dolphin/L1_Furippa1_128x64/frame_15.bm | Bin 0 -> 719 bytes .../dolphin/L1_Furippa1_128x64/frame_16.bm | Bin 0 -> 458 bytes .../dolphin/L1_Furippa1_128x64/frame_17.bm | Bin 0 -> 400 bytes .../dolphin/L1_Furippa1_128x64/frame_18.bm | Bin 0 -> 333 bytes .../dolphin/L1_Furippa1_128x64/frame_2.bm | Bin 0 -> 351 bytes .../dolphin/L1_Furippa1_128x64/frame_3.bm | Bin 0 -> 324 bytes .../dolphin/L1_Furippa1_128x64/frame_4.bm | Bin 0 -> 387 bytes .../dolphin/L1_Furippa1_128x64/frame_5.bm | Bin 0 -> 390 bytes .../dolphin/L1_Furippa1_128x64/frame_6.bm | Bin 0 -> 407 bytes .../dolphin/L1_Furippa1_128x64/frame_7.bm | Bin 0 -> 294 bytes .../dolphin/L1_Furippa1_128x64/frame_8.bm | Bin 0 -> 283 bytes .../dolphin/L1_Furippa1_128x64/frame_9.bm | Bin 0 -> 312 bytes .../dolphin/L1_Furippa1_128x64/meta.txt | 14 + .../laptop => L1_Laptop_128x51}/frame_0.bm | Bin .../laptop => L1_Laptop_128x51}/frame_1.bm | Bin .../laptop => L1_Laptop_128x51}/frame_2.bm | Bin .../laptop => L1_Laptop_128x51}/frame_3.bm | Bin .../laptop => L1_Laptop_128x51}/frame_4.bm | Bin .../laptop => L1_Laptop_128x51}/frame_5.bm | Bin .../laptop => L1_Laptop_128x51}/frame_6.bm | Bin .../laptop => L1_Laptop_128x51}/frame_7.bm | Bin .../dolphin/L1_Laptop_128x51}/meta.txt | 10 +- .../frame_0.bm | Bin .../frame_1.bm | Bin .../frame_10.bm | Bin 636 -> 629 bytes .../frame_11.bm | Bin 664 -> 659 bytes .../frame_2.bm | Bin .../frame_3.bm | Bin 657 -> 654 bytes .../frame_4.bm | Bin 659 -> 662 bytes .../frame_5.bm | Bin 626 -> 622 bytes .../frame_6.bm | Bin .../frame_7.bm | Bin .../frame_8.bm | Bin .../dolphin/L1_Recording_128x51/frame_9.bm | Bin 0 -> 661 bytes .../dolphin/L1_Recording_128x51}/meta.txt | 4 +- .../sleep => L1_Sleep_128x64}/frame_0.bm | Bin .../sleep => L1_Sleep_128x64}/frame_1.bm | Bin .../sleep => L1_Sleep_128x64}/frame_2.bm | Bin .../sleep => L1_Sleep_128x64}/frame_3.bm | Bin .../sleep => L1_Sleep_128x64}/meta.txt | 2 +- .../waves => L1_Waves_128x50}/frame_0.bm | Bin .../waves => L1_Waves_128x50}/frame_1.bm | Bin .../waves => L1_Waves_128x50}/frame_2.bm | Bin .../waves => L1_Waves_128x50}/frame_3.bm | Bin .../waves => L1_Waves_128x50}/meta.txt | 2 +- .../dolphin/L2_Furippa2_128x64/frame_0.bm | Bin 0 -> 350 bytes .../dolphin/L2_Furippa2_128x64/frame_1.bm | Bin 0 -> 385 bytes .../dolphin/L2_Furippa2_128x64/frame_10.bm | Bin 0 -> 465 bytes .../dolphin/L2_Furippa2_128x64/frame_11.bm | Bin 0 -> 698 bytes .../dolphin/L2_Furippa2_128x64/frame_12.bm | Bin 0 -> 541 bytes .../dolphin/L2_Furippa2_128x64/frame_13.bm | Bin 0 -> 584 bytes .../dolphin/L2_Furippa2_128x64/frame_14.bm | Bin 0 -> 610 bytes .../dolphin/L2_Furippa2_128x64/frame_15.bm | Bin 0 -> 740 bytes .../dolphin/L2_Furippa2_128x64/frame_16.bm | Bin 0 -> 533 bytes .../dolphin/L2_Furippa2_128x64/frame_17.bm | Bin 0 -> 451 bytes .../dolphin/L2_Furippa2_128x64/frame_18.bm | Bin 0 -> 397 bytes .../dolphin/L2_Furippa2_128x64/frame_2.bm | Bin 0 -> 402 bytes .../dolphin/L2_Furippa2_128x64/frame_3.bm | Bin 0 -> 374 bytes .../dolphin/L2_Furippa2_128x64/frame_4.bm | Bin 0 -> 440 bytes .../dolphin/L2_Furippa2_128x64/frame_5.bm | Bin 0 -> 449 bytes .../dolphin/L2_Furippa2_128x64/frame_6.bm | Bin 0 -> 466 bytes .../dolphin/L2_Furippa2_128x64/frame_7.bm | Bin 0 -> 350 bytes .../dolphin/L2_Furippa2_128x64/frame_8.bm | Bin 0 -> 319 bytes .../dolphin/L2_Furippa2_128x64/frame_9.bm | Bin 0 -> 317 bytes .../dolphin/L2_Furippa2_128x64/meta.txt | 14 + .../dolphin/L3_Furippa3_128x64/frame_0.bm | Bin 0 -> 398 bytes .../dolphin/L3_Furippa3_128x64/frame_1.bm | Bin 0 -> 438 bytes .../dolphin/L3_Furippa3_128x64/frame_10.bm | Bin 0 -> 559 bytes .../dolphin/L3_Furippa3_128x64/frame_11.bm | Bin 0 -> 728 bytes .../dolphin/L3_Furippa3_128x64/frame_12.bm | Bin 0 -> 541 bytes .../dolphin/L3_Furippa3_128x64/frame_13.bm | Bin 0 -> 584 bytes .../dolphin/L3_Furippa3_128x64/frame_14.bm | Bin 0 -> 610 bytes .../dolphin/L3_Furippa3_128x64/frame_15.bm | Bin 0 -> 741 bytes .../dolphin/L3_Furippa3_128x64/frame_16.bm | Bin 0 -> 559 bytes .../dolphin/L3_Furippa3_128x64/frame_17.bm | Bin 0 -> 492 bytes .../dolphin/L3_Furippa3_128x64/frame_18.bm | Bin 0 -> 445 bytes .../dolphin/L3_Furippa3_128x64/frame_2.bm | Bin 0 -> 463 bytes .../dolphin/L3_Furippa3_128x64/frame_3.bm | Bin 0 -> 424 bytes .../dolphin/L3_Furippa3_128x64/frame_4.bm | Bin 0 -> 499 bytes .../dolphin/L3_Furippa3_128x64/frame_5.bm | Bin 0 -> 504 bytes .../dolphin/L3_Furippa3_128x64/frame_6.bm | Bin 0 -> 521 bytes .../dolphin/L3_Furippa3_128x64/frame_7.bm | Bin 0 -> 398 bytes .../dolphin/L3_Furippa3_128x64/frame_8.bm | Bin 0 -> 419 bytes .../dolphin/L3_Furippa3_128x64/frame_9.bm | Bin 0 -> 435 bytes .../dolphin/L3_Furippa3_128x64/meta.txt | 14 + .../resources/dolphin/animations/manifest.txt | 34 -- .../dolphin/animations/recording/frame_9.bm | Bin 664 -> 0 bytes assets/resources/dolphin/manifest.txt | 51 +++ core/furi/dangerous_defines.h | 6 + documentation/KeyCombo.md | 134 ++++++ scripts/assets.py | 127 +++--- scripts/flipper/assets/dolphin.py | 384 ++++++++++++++++-- .../flipper/assets/templates/dolphin.c.tmpl | 92 +++++ .../flipper/assets/templates/dolphin.h.tmpl | 7 + scripts/flipper/utils/fff.py | 103 +++++ scripts/flipper/utils/templite.py | 196 +++++++++ 366 files changed, 3646 insertions(+), 1566 deletions(-) create mode 100644 applications/desktop/animations/views/one_shot_animation_view.c create mode 100644 applications/desktop/animations/views/one_shot_animation_view.h mode change 100755 => 100644 applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c create mode 100644 applications/desktop/scenes/desktop_scene_i.h delete mode 100644 applications/desktop/scenes/desktop_scene_locked.c mode change 100755 => 100644 applications/gui/canvas.c delete mode 100644 applications/gui/view_composed.c delete mode 100644 applications/gui/view_composed.h create mode 100644 applications/gui/view_stack.c create mode 100644 applications/gui/view_stack.h create mode 100644 assets/compiled/assets_dolphin_blocking.c create mode 100644 assets/compiled/assets_dolphin_blocking.h create mode 100644 assets/compiled/assets_dolphin_internal.c create mode 100644 assets/compiled/assets_dolphin_internal.h create mode 100644 assets/dolphin/ReadMe.md delete mode 100644 assets/dolphin/animations/recording/frame_0.png delete mode 100644 assets/dolphin/animations/recording/frame_10.png delete mode 100644 assets/dolphin/animations/recording/frame_11.png delete mode 100644 assets/dolphin/animations/recording/frame_3.png delete mode 100644 assets/dolphin/animations/recording/frame_4.png delete mode 100644 assets/dolphin/animations/recording/frame_5.png delete mode 100644 assets/dolphin/animations/recording/frame_9.png create mode 100644 assets/dolphin/blocking/L0_NewMail_128x51/frame_0.png create mode 100644 assets/dolphin/blocking/L0_NewMail_128x51/frame_1.png create mode 100644 assets/dolphin/blocking/L0_NewMail_128x51/frame_2.png create mode 100644 assets/dolphin/blocking/L0_NewMail_128x51/frame_3.png create mode 100644 assets/dolphin/blocking/L0_NewMail_128x51/meta.txt rename assets/{icons/Animations/no_databases1.png => dolphin/blocking/L0_NoDb_128x51/frame_0.png} (100%) rename assets/{icons/Animations/no_databases2.png => dolphin/blocking/L0_NoDb_128x51/frame_1.png} (100%) rename assets/{icons/Animations/no_databases3.png => dolphin/blocking/L0_NoDb_128x51/frame_2.png} (100%) rename assets/{icons/Animations/no_databases4.png => dolphin/blocking/L0_NoDb_128x51/frame_3.png} (100%) create mode 100644 assets/dolphin/blocking/L0_NoDb_128x51/meta.txt rename assets/{icons/Animations/card_bad1.png => dolphin/blocking/L0_SdBad_128x51/frame_0.png} (100%) rename assets/{icons/Animations/card_bad2.png => dolphin/blocking/L0_SdBad_128x51/frame_1.png} (100%) create mode 100644 assets/dolphin/blocking/L0_SdBad_128x51/meta.txt rename assets/{icons/Animations/card_ok1.png => dolphin/blocking/L0_SdOk_128x51/frame_0.png} (100%) rename assets/{icons/Animations/card_ok2.png => dolphin/blocking/L0_SdOk_128x51/frame_1.png} (100%) rename assets/{icons/Animations/card_ok3.png => dolphin/blocking/L0_SdOk_128x51/frame_2.png} (100%) rename assets/{icons/Animations/card_ok4.png => dolphin/blocking/L0_SdOk_128x51/frame_3.png} (100%) create mode 100644 assets/dolphin/blocking/L0_SdOk_128x51/meta.txt rename assets/{icons/Animations/url1.png => dolphin/blocking/L0_Url_128x51/frame_0.png} (100%) rename assets/{icons/Animations/url2.png => dolphin/blocking/L0_Url_128x51/frame_1.png} (100%) rename assets/{icons/Animations/url3.png => dolphin/blocking/L0_Url_128x51/frame_2.png} (100%) rename assets/{icons/Animations/url4.png => dolphin/blocking/L0_Url_128x51/frame_3.png} (100%) create mode 100644 assets/dolphin/blocking/L0_Url_128x51/meta.txt create mode 100644 assets/dolphin/blocking/manifest.txt create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_0.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_1.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_10.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_11.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_12.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_13.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_14.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_15.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_16.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_17.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_18.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_2.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_3.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_4.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_5.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_6.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_7.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_8.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/frame_9.png create mode 100644 assets/dolphin/external/L1_Furippa1_128x64/meta.txt rename assets/dolphin/{animations/laptop => external/L1_Laptop_128x51}/frame_0.png (100%) rename assets/dolphin/{animations/laptop => external/L1_Laptop_128x51}/frame_1.png (100%) rename assets/dolphin/{animations/laptop => external/L1_Laptop_128x51}/frame_2.png (100%) rename assets/dolphin/{animations/laptop => external/L1_Laptop_128x51}/frame_3.png (100%) rename assets/dolphin/{animations/laptop => external/L1_Laptop_128x51}/frame_4.png (100%) rename assets/dolphin/{animations/laptop => external/L1_Laptop_128x51}/frame_5.png (100%) rename assets/dolphin/{animations/laptop => external/L1_Laptop_128x51}/frame_6.png (100%) rename assets/dolphin/{animations/laptop => external/L1_Laptop_128x51}/frame_7.png (100%) rename assets/{resources/dolphin/animations/laptop => dolphin/external/L1_Laptop_128x51}/meta.txt (80%) create mode 100644 assets/dolphin/external/L1_Recording_128x51/frame_0.png rename assets/dolphin/{animations/recording => external/L1_Recording_128x51}/frame_1.png (72%) create mode 100644 assets/dolphin/external/L1_Recording_128x51/frame_10.png create mode 100644 assets/dolphin/external/L1_Recording_128x51/frame_11.png rename assets/dolphin/{animations/recording => external/L1_Recording_128x51}/frame_2.png (84%) create mode 100644 assets/dolphin/external/L1_Recording_128x51/frame_3.png create mode 100644 assets/dolphin/external/L1_Recording_128x51/frame_4.png create mode 100644 assets/dolphin/external/L1_Recording_128x51/frame_5.png rename assets/dolphin/{animations/recording => external/L1_Recording_128x51}/frame_6.png (85%) rename assets/dolphin/{animations/recording => external/L1_Recording_128x51}/frame_7.png (84%) rename assets/dolphin/{animations/recording => external/L1_Recording_128x51}/frame_8.png (85%) create mode 100644 assets/dolphin/external/L1_Recording_128x51/frame_9.png rename assets/{resources/dolphin/animations/recording => dolphin/external/L1_Recording_128x51}/meta.txt (84%) rename assets/dolphin/{animations/sleep => external/L1_Sleep_128x64}/frame_0.png (100%) rename assets/dolphin/{animations/sleep => external/L1_Sleep_128x64}/frame_1.png (100%) rename assets/dolphin/{animations/sleep => external/L1_Sleep_128x64}/frame_2.png (100%) rename assets/dolphin/{animations/sleep => external/L1_Sleep_128x64}/frame_3.png (100%) rename assets/dolphin/{animations/sleep => external/L1_Sleep_128x64}/meta.txt (100%) rename assets/dolphin/{animations/waves => external/L1_Waves_128x50}/frame_0.png (100%) rename assets/dolphin/{animations/waves => external/L1_Waves_128x50}/frame_1.png (100%) rename assets/dolphin/{animations/waves => external/L1_Waves_128x50}/frame_2.png (100%) rename assets/dolphin/{animations/waves => external/L1_Waves_128x50}/frame_3.png (100%) rename assets/dolphin/{animations/waves => external/L1_Waves_128x50}/meta.txt (100%) create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_0.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_1.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_10.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_11.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_12.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_13.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_14.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_15.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_16.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_17.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_18.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_2.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_3.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_4.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_5.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_6.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_7.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_8.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/frame_9.png create mode 100644 assets/dolphin/external/L2_Furippa2_128x64/meta.txt create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_0.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_1.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_10.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_11.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_12.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_13.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_14.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_15.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_16.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_17.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_18.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_2.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_3.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_4.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_5.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_6.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_7.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_8.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/frame_9.png create mode 100644 assets/dolphin/external/L3_Furippa3_128x64/meta.txt create mode 100644 assets/dolphin/external/manifest.txt create mode 100644 assets/dolphin/internal/L1_BadBattery_128x47/frame_0.png create mode 100644 assets/dolphin/internal/L1_BadBattery_128x47/frame_1.png create mode 100644 assets/dolphin/internal/L1_BadBattery_128x47/meta.txt rename assets/{icons/Animations/no_sd1.png => dolphin/internal/L1_NoSd_128x49/frame_0.png} (100%) rename assets/{icons/Animations/no_sd2.png => dolphin/internal/L1_NoSd_128x49/frame_1.png} (100%) rename assets/{icons/Animations/no_sd3.png => dolphin/internal/L1_NoSd_128x49/frame_2.png} (100%) rename assets/{icons/Animations/no_sd4.png => dolphin/internal/L1_NoSd_128x49/frame_3.png} (100%) rename assets/{icons/Animations/no_sd5.png => dolphin/internal/L1_NoSd_128x49/frame_4.png} (100%) rename assets/{icons/Animations/no_sd6.png => dolphin/internal/L1_NoSd_128x49/frame_5.png} (100%) create mode 100644 assets/dolphin/internal/L1_NoSd_128x49/meta.txt rename assets/{icons/Animations/tv1.png => dolphin/internal/L1_Tv_128x47/frame_0.png} (100%) rename assets/{icons/Animations/tv2.png => dolphin/internal/L1_Tv_128x47/frame_1.png} (100%) rename assets/{icons/Animations/tv3.png => dolphin/internal/L1_Tv_128x47/frame_2.png} (100%) rename assets/{icons/Animations/tv4.png => dolphin/internal/L1_Tv_128x47/frame_3.png} (100%) rename assets/{icons/Animations/tv5.png => dolphin/internal/L1_Tv_128x47/frame_4.png} (100%) rename assets/{icons/Animations/tv6.png => dolphin/internal/L1_Tv_128x47/frame_5.png} (100%) rename assets/{icons/Animations/tv7.png => dolphin/internal/L1_Tv_128x47/frame_6.png} (100%) rename assets/{icons/Animations/tv8.png => dolphin/internal/L1_Tv_128x47/frame_7.png} (100%) create mode 100644 assets/dolphin/internal/L1_Tv_128x47/meta.txt rename assets/dolphin/{animations => internal}/manifest.txt (55%) create mode 100644 assets/icons/Animations/Levelup1_128x64/frame_00.png create mode 100644 assets/icons/Animations/Levelup1_128x64/frame_01.png create mode 100644 assets/icons/Animations/Levelup1_128x64/frame_02.png create mode 100644 assets/icons/Animations/Levelup1_128x64/frame_03.png create mode 100644 assets/icons/Animations/Levelup1_128x64/frame_04.png create mode 100644 assets/icons/Animations/Levelup1_128x64/frame_05.png create mode 100644 assets/icons/Animations/Levelup1_128x64/frame_06.png create mode 100644 assets/icons/Animations/Levelup1_128x64/frame_07.png create mode 100644 assets/icons/Animations/Levelup1_128x64/frame_08.png create mode 100644 assets/icons/Animations/Levelup1_128x64/frame_09.png create mode 100644 assets/icons/Animations/Levelup1_128x64/frame_10.png create mode 100644 assets/icons/Animations/Levelup1_128x64/frame_rate create mode 100644 assets/icons/Animations/Levelup2_128x64/frame_00.png create mode 100644 assets/icons/Animations/Levelup2_128x64/frame_01.png create mode 100644 assets/icons/Animations/Levelup2_128x64/frame_02.png create mode 100644 assets/icons/Animations/Levelup2_128x64/frame_03.png create mode 100644 assets/icons/Animations/Levelup2_128x64/frame_04.png create mode 100644 assets/icons/Animations/Levelup2_128x64/frame_05.png create mode 100644 assets/icons/Animations/Levelup2_128x64/frame_06.png create mode 100644 assets/icons/Animations/Levelup2_128x64/frame_07.png create mode 100644 assets/icons/Animations/Levelup2_128x64/frame_08.png create mode 100644 assets/icons/Animations/Levelup2_128x64/frame_09.png create mode 100644 assets/icons/Animations/Levelup2_128x64/frame_10.png create mode 100644 assets/icons/Animations/Levelup2_128x64/frame_rate create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_0.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_1.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_10.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_11.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_12.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_13.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_14.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_15.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_16.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_17.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_18.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_2.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_3.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_4.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_5.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_6.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_7.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_8.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/frame_9.bm create mode 100644 assets/resources/dolphin/L1_Furippa1_128x64/meta.txt rename assets/resources/dolphin/{animations/laptop => L1_Laptop_128x51}/frame_0.bm (100%) rename assets/resources/dolphin/{animations/laptop => L1_Laptop_128x51}/frame_1.bm (100%) rename assets/resources/dolphin/{animations/laptop => L1_Laptop_128x51}/frame_2.bm (100%) rename assets/resources/dolphin/{animations/laptop => L1_Laptop_128x51}/frame_3.bm (100%) rename assets/resources/dolphin/{animations/laptop => L1_Laptop_128x51}/frame_4.bm (100%) rename assets/resources/dolphin/{animations/laptop => L1_Laptop_128x51}/frame_5.bm (100%) rename assets/resources/dolphin/{animations/laptop => L1_Laptop_128x51}/frame_6.bm (100%) rename assets/resources/dolphin/{animations/laptop => L1_Laptop_128x51}/frame_7.bm (100%) rename assets/{dolphin/animations/laptop => resources/dolphin/L1_Laptop_128x51}/meta.txt (80%) rename assets/resources/dolphin/{animations/recording => L1_Recording_128x51}/frame_0.bm (100%) rename assets/resources/dolphin/{animations/recording => L1_Recording_128x51}/frame_1.bm (100%) rename assets/resources/dolphin/{animations/recording => L1_Recording_128x51}/frame_10.bm (50%) rename assets/resources/dolphin/{animations/recording => L1_Recording_128x51}/frame_11.bm (58%) rename assets/resources/dolphin/{animations/recording => L1_Recording_128x51}/frame_2.bm (100%) rename assets/resources/dolphin/{animations/recording => L1_Recording_128x51}/frame_3.bm (58%) rename assets/resources/dolphin/{animations/recording => L1_Recording_128x51}/frame_4.bm (58%) rename assets/resources/dolphin/{animations/recording => L1_Recording_128x51}/frame_5.bm (59%) rename assets/resources/dolphin/{animations/recording => L1_Recording_128x51}/frame_6.bm (100%) rename assets/resources/dolphin/{animations/recording => L1_Recording_128x51}/frame_7.bm (100%) rename assets/resources/dolphin/{animations/recording => L1_Recording_128x51}/frame_8.bm (100%) create mode 100644 assets/resources/dolphin/L1_Recording_128x51/frame_9.bm rename assets/{dolphin/animations/recording => resources/dolphin/L1_Recording_128x51}/meta.txt (84%) rename assets/resources/dolphin/{animations/sleep => L1_Sleep_128x64}/frame_0.bm (100%) rename assets/resources/dolphin/{animations/sleep => L1_Sleep_128x64}/frame_1.bm (100%) rename assets/resources/dolphin/{animations/sleep => L1_Sleep_128x64}/frame_2.bm (100%) rename assets/resources/dolphin/{animations/sleep => L1_Sleep_128x64}/frame_3.bm (100%) rename assets/resources/dolphin/{animations/sleep => L1_Sleep_128x64}/meta.txt (97%) rename assets/resources/dolphin/{animations/waves => L1_Waves_128x50}/frame_0.bm (100%) rename assets/resources/dolphin/{animations/waves => L1_Waves_128x50}/frame_1.bm (100%) rename assets/resources/dolphin/{animations/waves => L1_Waves_128x50}/frame_2.bm (100%) rename assets/resources/dolphin/{animations/waves => L1_Waves_128x50}/frame_3.bm (100%) rename assets/resources/dolphin/{animations/waves => L1_Waves_128x50}/meta.txt (98%) create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_0.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_1.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_10.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_11.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_12.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_13.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_14.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_15.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_16.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_17.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_18.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_2.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_3.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_4.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_5.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_6.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_7.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_8.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/frame_9.bm create mode 100644 assets/resources/dolphin/L2_Furippa2_128x64/meta.txt create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_0.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_1.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_10.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_11.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_12.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_13.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_14.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_15.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_16.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_17.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_18.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_2.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_3.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_4.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_5.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_6.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_7.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_8.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/frame_9.bm create mode 100644 assets/resources/dolphin/L3_Furippa3_128x64/meta.txt delete mode 100644 assets/resources/dolphin/animations/manifest.txt delete mode 100644 assets/resources/dolphin/animations/recording/frame_9.bm create mode 100644 assets/resources/dolphin/manifest.txt create mode 100644 documentation/KeyCombo.md create mode 100644 scripts/flipper/assets/templates/dolphin.c.tmpl create mode 100644 scripts/flipper/assets/templates/dolphin.h.tmpl create mode 100644 scripts/flipper/utils/fff.py create mode 100644 scripts/flipper/utils/templite.py 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/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/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..d86a162c 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; + uint8_t frame_order[20]; 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..94b23be6 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); } } } @@ -161,7 +221,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 +250,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,22 +266,25 @@ 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); + uint8_t width, + uint8_t height) { uint16_t frame_order_size = animation->passive_frames + animation->active_frames; 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; + Icon* icon = (Icon*)&animation->icon_animation; + FURI_CONST_ASSIGN(icon->frame_count, frame_order_size); + 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*) * frame_order_size); for(int i = 0; i < frame_order_size; ++i) { - if(animation->icons[i]) continue; - frames_ok = false; string_printf(filename, ANIMATION_DIR "/%s/frame_%d.bm", name, frame_order[i]); @@ -265,24 +304,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 +322,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 +340,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 +429,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 +451,17 @@ 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) || (frames > COUNT_OF(animation->frame_order))) { + 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; + for(int i = 0; i < frames; ++i) { + 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 +470,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; @@ -460,10 +496,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 +507,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 67d0f218..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; 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 252d3a51..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; 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 008d908e..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, 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..1c94b83e 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); @@ -26,17 +29,15 @@ 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_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_next_scene(desktop->scene_manager, DesktopScenePinSetup); } 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..ad8a0a3f 100644 --- a/applications/desktop/views/desktop_lock_menu.c +++ b/applications/desktop/views/desktop_lock_menu.c @@ -1,4 +1,6 @@ #include +#include + #include "../desktop_i.h" #include "desktop_lock_menu.h" diff --git a/applications/desktop/views/desktop_lock_menu.h b/applications/desktop/views/desktop_lock_menu.h index 3b0fffcc..80854520 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 diff --git a/applications/desktop/views/desktop_locked.c b/applications/desktop/views/desktop_locked.c index 5a9e7203..bbb9978a 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,37 @@ 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); +} + +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); +} + +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); +} 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..b03381b9 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; @@ -100,40 +53,16 @@ bool desktop_main_input(InputEvent* event, void* context) { consumed = true; } - 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; - }); -} - 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 +72,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/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/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/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..39ffc8c7 --- /dev/null +++ b/applications/gui/view_stack.c @@ -0,0 +1,165 @@ +#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); + + bool consumed = false; + ViewStack* view_stack = context; + + ViewStackModel* model = view_get_model(view_stack->view); + for(int i = MAX_VIEWS - 1; !consumed && (i >= 0); --i) { + if(model->views[i]) { + consumed = view_input(model->views[i], event); + } + } + 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/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_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/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 c46d2e29..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; diff --git a/applications/irda/scene/irda_app_scene_universal_common.cpp b/applications/irda/scene/irda_app_scene_universal_common.cpp index c55a7af7..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 { 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_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_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/loader/loader.c b/applications/loader/loader.c index f78e5bc0..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" @@ -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/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_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 db5762ad..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); 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_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/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_read_raw.c b/applications/subghz/scenes/subghz_scene_read_raw.c index 50edcb22..481138dc 100644 --- a/applications/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/subghz/scenes/subghz_scene_read_raw.c @@ -1,5 +1,6 @@ #include "../subghz_i.h" #include "../views/subghz_read_raw.h" +#include #include #include #include @@ -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_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_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_set_type.c b/applications/subghz/scenes/subghz_scene_set_type.c index ddd8b976..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; } 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/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/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..a14b8c5f --- /dev/null +++ b/assets/compiled/assets_dolphin_blocking.c @@ -0,0 +1,320 @@ +#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 BubbleAnimation BA_L0_NoDb_128x51 = { + .icon_animation = { + .width = 128, + .height = 51, + .frame_count = 4, + .frame_rate = 2, + .frames = _A_L0_NoDb_128x51 + }, + .frame_order = { 0, 1, 2, 3 }, + .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 BubbleAnimation BA_L0_SdBad_128x51 = { + .icon_animation = { + .width = 128, + .height = 51, + .frame_count = 2, + .frame_rate = 2, + .frames = _A_L0_SdBad_128x51 + }, + .frame_order = { 0, 1 }, + .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 BubbleAnimation BA_L0_SdOk_128x51 = { + .icon_animation = { + .width = 128, + .height = 51, + .frame_count = 4, + .frame_rate = 2, + .frames = _A_L0_SdOk_128x51 + }, + .frame_order = { 0, 1, 2, 3 }, + .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 BubbleAnimation BA_L0_Url_128x51 = { + .icon_animation = { + .width = 128, + .height = 51, + .frame_count = 4, + .frame_rate = 2, + .frames = _A_L0_Url_128x51 + }, + .frame_order = { 0, 1, 2, 3 }, + .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 BubbleAnimation BA_L0_NewMail_128x51 = { + .icon_animation = { + .width = 128, + .height = 51, + .frame_count = 4, + .frame_rate = 2, + .frames = _A_L0_NewMail_128x51 + }, + .frame_order = { 0, 1, 2, 3, 2, 1 }, + .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..99cab819 --- /dev/null +++ b/assets/compiled/assets_dolphin_internal.c @@ -0,0 +1,324 @@ +#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 BubbleAnimation BA_L1_Tv_128x47 = { + .icon_animation = { + .width = 128, + .height = 47, + .frame_count = 8, + .frame_rate = 2, + .frames = _A_L1_Tv_128x47 + }, + .frame_order = { 0, 1, 2, 3, 4, 5, 6, 7 }, + .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 BubbleAnimation BA_L1_BadBattery_128x47 = { + .icon_animation = { + .width = 128, + .height = 47, + .frame_count = 2, + .frame_rate = 2, + .frames = _A_L1_BadBattery_128x47 + }, + .frame_order = { 0, 1 }, + .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 BubbleAnimation BA_L1_NoSd_128x49 = { + .icon_animation = { + .width = 128, + .height = 49, + .frame_count = 6, + .frame_rate = 2, + .frames = _A_L1_NoSd_128x49 + }, + .frame_order = { 0, 1, 0, 1, 0, 2, 3, 4, 3, 5 }, + .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 71316998..bb540f5a 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}; @@ -675,34 +617,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}; diff --git a/assets/compiled/assets_icons.h b/assets/compiled/assets_icons.h index c52821af..a8351f97 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; 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 8a91feb693991bb5198b49f34e136f036847a7a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1752 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 diff --git a/assets/dolphin/animations/recording/frame_11.png b/assets/dolphin/animations/recording/frame_11.png deleted file mode 100644 index aa900eba5bb8f8825a6e6a88e44f5979b3f40473..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1746 zcmaJ?c~BE)6km*i2y&QKw4!zma*3O4ZZ;(nNC==rVhkEQX4qsml7VDnvY3EYVpB^-oD>^zjw_R zs~4vP`p@tO03a|eRiU9)7xnNNH0qsm<^hXZ-XfEAVoDe2t&RZw~%QHDU15T#!Q$* z$ma{hd>n=lfk6NX5OExY8iabtsK;TMg&EL1{@L!g(!p|0zRY{;3&k! zVS|w`(8EHM3V#%j{V#o^ok~flFs$QjBnXZP#d?$vVS1{6L?Qu|Ry}Hja3N~siC_U& zD2QWmD2g0!=lrje#zj6wd zIRH$!nx;t9Iy)|vwXgdFW+-Ysp6m9=p3-O$Vo6BvJ=oK%`!vh{llG#a?nelNey?|* z^7+K>fxUmRJI`7*1Jz--JmujFHrA|;nBv&hA?b+%-~~4qs{5sd-76*oZfr0+DzOb| ziyCOWa%ZUVcCvbD?Wr9ya&L*}D_?rZ>5?grnL+0QJHHi|sI2E$BF`SJ=bb29ROV1c z^XB)r?;7r-7ZSS}y2vc!{3O-wVY{!aT+UW}kvDY|D9@0T)XvWmgww1bmnyU_wbvF7i z%6|?8OUh}mHeyl&W2(;Q@Ia_*g9BJr_ITGRT6PN1G%Mi46OYXS&f&akt$ly?R8DUO z80am4k>%p)OXwkshA;YU5W7Qn1p$%qu9`QNO_0raoBrM9I3Tss$VF#`m4@WVU7RBe zc7RW1rrWK@vfUU!1l%iV?%uR6LhVoi{sh%=w8{33Psljwi$B29MRR%U<4(?Q>3L$&RDQY%(9oOtg|?3dn6 zr$y8HcPp7cvg-8aA9nYa$GdBGF6okS?v!t>PJs?(PTIdOFt#p3^iz`}UsyZip}#W0 zXB+>U%K&qraM@;>i?y)oK-(qFjdJM z|7fx-#88@%HT@Z_CH#^}{w&ZnyU5xg1v2LicFbv=B-`0ipPw#fw#XunWOX&>eJu}w z=$UJoNkOqyU&ef1oD5YSyfb`A$Jnqwrl@kDz9FxQK5ug5#;}{%-<|m{j&E61l;0P| zJYRJo+T+Y$fB1H+t>?^(quY@HhHGo66X<$2-RbW-P%3S46F&6?t30{w)5;!v4A6jT WjbCwJ?Q^yFFO!zMSW%sn?fw_21B_Sz diff --git a/assets/dolphin/animations/recording/frame_3.png b/assets/dolphin/animations/recording/frame_3.png deleted file mode 100644 index 282188f7e59fd2efafe0faa3c8408be09dc45b59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1740 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 AEdT%j diff --git a/assets/dolphin/animations/recording/frame_5.png b/assets/dolphin/animations/recording/frame_5.png deleted file mode 100644 index d79345983a76e56f16c205b654ab0edd3e86f146..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1687 zcmaJ?c~BE)6#v3ej)GQHkb1C&&XhWCcC*P6Hj;{vpbr|{nz|o-_Al5$|cXs#tzPIo9-tS$r z8{eDl0}wsk&XR_7iih-6nuS)0AD=uehAc*v zcp;vMCbDsq*)l7aqvqu%=?uB)2Er(w{xKA7R|*EK6i-5SYX)so+EwB~yGmj25+h=0 zP=!xdiHAs~CMH913`aoGwCTMo^Wc9^z>yDg|G zn}M^iyoI45mqk*~Wb!JpKz1k!E1Q`3$}nvk&Xtfg#7?q^RDvQ_t1GlYZ5y9L{ZHeK z+BRJdOCc$gjmhK;LP<>FZm^KPw>xqv3T%{fIg3yiGDFQ6GOZNNYt<^T@I_*@7?rq8 zCRfNP6ei>bIV>j>Q7~!1^{`2A#7vX|CG`a6w(}-@EFL8kf{;ckG`Li%i6hjSC<52W zu^CuotSnyb#%gIBPtpd;?b{;w9>$_?#VX@CisTti$1oZ0Mo2a@JYzF6EQHA@K~M35wIpkN%wNthtyGFUICNLWgt29r## zM{!aJe+X}UEqz0sDoBJdST`FbK^bv{o|M5xz0g0Ak#ZredeQ__IBCKnQMnYCM~M-E zBI4?t*E-29657+XeKi`w;ni?av@lVeFggJ*jrWAHdnb90PBSntAQFj`6YBN=;8Cho z&(PU#H>VcU&8TnFz(8wj*3GjHt$DO%chcWWwX9$H`kklQrO%L%zFkFr{n-ms=Jr-R zzjD7fYoPS=wa#6i^rlU0`}f3yufWm92b0@lM}bbO7eY7PNC?mS%pVjiA*VUV(s!MW z%P;k{UItqN0y5iX7XbO3-bLNF3bOKRr)*mbUt@D0M<_n1+l?-}$~j{4j@vhw&-lM6 z9JjagWQ6lr|FvsZKFs_*sAkET63>Qas`eZ(Z!V5&d!DnoAM7~))4DH4VP4R~FnadN z{pt`$@y#PWM?D`$`?gNow4=`P=Xl3Nkbl89CTcZ0A9YM7MKR%rIugcqq=HaIr@YTx z95f!}VS!KbJz}<%du*vZc)n}x>ct+YH`tJIGoEem*Z?4p1;JtK^Ex~l#`vd$s9^7q z>Xbb-Q@4~q^Boz$g_UguOD4|RT6byP;j=JMm)yU5`?B}pF_D>7chCuCr!vOQP5nQ> z%MYM=O`%2JwcH5NsBhZG?5mvgRHUhD@4jAeKJQBaHr~1#>P#+asTl`lcEuh+GD^Pg zm{;esA^|jRf5OJ=>T)$xA5t7f$oKCOl{aHan;+CdWxD*mKZ2T7UX^jd-lbu6eHV%b zo_f|)&cAN2hkDvuD*PIE-}4Dv>7*a&gL~Toj$9bOcQwdT?8r;I;qzYnq7X;VxrhIV zz{@+6dYmoM@xd%u_GyQ=V@;U-T|n%t-&C*^+&}9qJa^QmynCiY1d2L+3efep*0_EZ NT1}GraO{eL{{Tlpd^rFB diff --git a/assets/dolphin/animations/recording/frame_9.png b/assets/dolphin/animations/recording/frame_9.png deleted file mode 100644 index becd0fd4095f35cae5a5f3ff5108d7f4a19fa465..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1736 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..5394851f554ca56e70e8f57060e70815d4237aad GIT binary patch literal 1434 zcmaJ>c}x^n7=IiAM6mX-t*y#rG(j3>=h~g!nXt&Rhmx{%vn+v{Qkml|Okro%*@0bb zih#9Bw82fTAghO&c1m_B7G7^ewQ|Ka7)^dGCGm z{eIs)J%Or?`MFQ!0s!(WHhF?*?L-folY!n%L$`3WtTerKX0;wR=v4kDT>1Eyag&EBe7voF2)#&p-CFuc7nDG3@gw)ws7IdprM3? zpvSjh4xOBMlW9f;l8ndWmN;wCjYg8@d7h*gl3@s>LB!fMQ%n$AY;B6c17otGMom@M zuq2}>>8+*{N6yYi5sCW!i^N)NAy+7CWI~LRw1pxgkz{Cd+A%W-|99iQ+Obf36p}$0 z(_0N0l_b121xD$6u%VhP*GjP7LP8sMxbU^c$_%;Vo_8@kYpBe6m$?g1w}$( ztqLJRyMthCvdG#bg_9UM#dAMA%X75P$Ch(muaBm^?sC4|!`k9DJw%L-J6ytA{jXj?OSsRMwtw<|oZP~!XR2d5tS0?YAC&d$zM`K~$7 z9^uH7mr9lXH94pH$LvF{yce#0^VgmqYOnM@oG8lKtxs=W)AskduDi``1p^p1@Wj7A zrH%bM*nJ{5FnBX(6du~*^3cc0f9{;Yl+NqR^C@FEfAn~1=EqCHtrhTk$BN9#!WJ-* z*V!JO+Lt|j@uQ;ta~CeAjimwY)4u$vC0G_{0_}f%xj!_%4odi=JTQl=fpCcHEcRA| z$z0I2vXeNVPJVT8XL)f^&9k6&X^=0w+%>&@^XX9f>X8?F`pS#lovUvYytnxlIMOUk zNW0xvnK~D9Akw?6Vb|pT<>KT^HA{Y5Ke%rg?Cm@Aa_06e?myFaWIgs-Pwiz_$?C7a zdrdj|K1iEBHIWUrzImm7Y{!yKfa(!ucAXy2(Vo7uSIQhMeCMH{9i%sWu>9(W;NZA=qq9KXsCsUY|^ooslXana%R-uiYIDsOF}#3F-E>gE!!cTed}?yg=BS_nd6 zud+?ZGBXn5=9X;JEIPMr*@u}eXm~N>1JjsIT!?!!+d=?w!V+D&r$Ct>h?l#2p67r6 z-|zo^$EvH!vyEGf2!dpLDx5WNjl+jol?LCTZ>BN0Jf^$+daWANqr3)?5>X8R)Fbot zpa$?_^O4J-5JA#9C7)mSd-rmJDx3JEjwvRGAsRsni(+A3I1F?&0O}>hflYn=Erv>> z1FN%mNpH9egrtfV4b-+&`Gl6k0xM!gd(grd2MJ`L^Jq+NP$FE+fz9)BaGw+t7&@<_ zA9i31PWipnXql=3)Mlb^fh0-P#+rc0(*Y*P3%gO8q$z@ew+*Lk9L;bPi!NRmG^mL| zuEyzJGzU)(ETrpUjv%7Zs42>rRIQ$%Se7M7nxJVMYT%J(MdxF<64{<&aDs@SNnu@5 z6*S4n2h>L0fk9^%qL9O0?-H>RS1z>);Fr@%0M4>y!lgx+xbGzr#)Z*ZzYqYMS`pUhS9PzbZ4EUh-x&lD_Nn1fSo{- zntI zgmB6ejtmCOc8g$xIRpXR%$OmY#lqvPEoc^kRx4w(nK1&oNF=-Ffi6mkU~49~OJe~K zOM?XzI87QHo3Xg@035lM)q8!eL?QvV&s@CPh9HJh9%qR!Ha600So0#9<+?Z7{^yP^ z^r^o$xynDs>C*Q`XE%-99~_(bWbo&?qxWtYr_cV|y{c)pXxr(D_TupQ1lNDLt>;kY z^H+9%cXjsZi{onL3J;QZd}Z!PPJ8zGiNILrOTT>jQ&#-`KV1B?jM3JN{`FDngS1e7 zuHP{C=3iv%7Ia;=Fq1d@=z8Sf)*sjXdIuTPEg2_|U74(pPB*-E{oNPRL$~@beU(!j zO83PvSAKD(Hk4tG-%aGkZ{IZfD+j*ZtfysP%f$O+cYoJAXD3gbT0QO0_m5vU87@4I zN*#T#Zb5XaC$i1DBL^#xH!@ROFMagH54i=keQQQfKAYEA*CoA@_mCAIEbNkm`&MY75=_+_b+cSI(F(Ms) zSuva$yi_^#i#uByQ}B8xYX+2-|S$pgH-+^th^= J=SmNC{s%XK{D1%e literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..396ec251af3b8daf90ef7cd0a210deb6661e4d79 GIT binary patch literal 1302 zcmaJ>Z%iCT6yF0PP)ik3Z9yfQB~6NDZ~xuh-mYBX?)DC@vOwtB68Rv*?ksHJcDH+r zcaWwcYC=O43A=5;a9@O|WR1oUoA>r$XM0PXeIV_0KT)&j~PbnrgduNxua z?$jj$*VPcQ*Duqu6@>$O>!=NPkG3b3(LqH}iKd-+V^%~4QqTc-HZ^3V#cYUJu`8mr zE2ap1Ma3Bm5qVPGawi@&ZHV(;hE!;p#(BXDRlxRf8c-T=mS!1>K@U$dyvTAQBjBrp zKn`tH6T77Nsynm`5d)56i4>K|WV{*9Yuf!3BM1UTvlPpcNP|p|7!JsiM!K$GL4s+; z)-6Xj4cxT|`pjV`L?E*HC{mUzuNgMdtGPm1qq4xF7%xqwQf_D~+G(c?{!e3F?R0X) zf>akwo5Qw(u0*RVfKmD$?Z{O`Y{U**NB07TBvTnqLBmN%Ap)IvRb3VNc$A57w2uq; z!weIPhPhxs3Jd;-KkAFd_&~wNdRQjFMHycp&d0)>iw#DEcr+e}aN%f>572x8n=sN2 zFcetut0TXw*w`bnV$_DfG3}&j4i$=^bHH@W^nhvMEa#>1?J`hw!g!SPX|&2hjbwdvfCRutlR`icNKW&?pdauW4N&-by!ue;@>Pl?C=9E> zMpXQo5L7sY070suSLJ;`LpvnmVay|%!AVDFDlv_0qRZ&5NO4D7gwFTO&H5N2b zH`%Cdj6G~AYPrWc+mf+dE{B#cUH<+6hIzIoq;N7jzj%D6>Iz;a-OA;DtDQepUODyc zxg*8T_LSBRZdTvEkRKma8^@me;2(L*iC=bY?0B%_iL)&qPCj1VdXp`h|7@c7%9%HN zub(byj_=ra@MTX))zAyl8SGxw^y#a5)%3L+El2ijd-C<8vGS|64drcjH$RhGeEJT& zH(c}HvANQ7dP`;R*0K7ThM)1G{qHVq`}1~t@m#HZe6MHW{+H)B{`7g>_M+vlD?HfZ z^`YPIPX;1?UE2Rz?x>#+&u$v~>gFs_Qcr*LPUg^-rHb)g@b9rrhdOQ(Qxjh-UyN9j zZ`?XSUuc@S*faab;fa&fi5~1uwS4(k?Z>5s_POW3J6rRE^Y4w0S03#Aq~T}&KR6dtyf5)7qcBo?hsr)eTTv-7vRvomE2%gzFuvXq~#t_DqKXYRlVJ2TD< zy9+^sJlG%=`d|~aF_1QrzG!?>Y^{Z2)M_kNADY^<_)}u4HAouc3wFK3ve*aGo0+-y zo_oG?zH{z5GuqbLR8m|~j37u!q*>^I^Dunti?+b;Qqe>dPCM;z-0svBJ1v?33Cel` zppm554LX1*54>~{)FQ~15j7UK9KSRD;qaO%W7)Se#;cn&Bx9T^|^9 zXvzxTAvCVLgS!CMW7`H#5b1QJ;aBD!b#SE@ld-4_pU`eKG z*s89fjzuw{_uByslFdbtG@{WB!4G&a??Vgm*s zI)J73n-aVdWltUq(|3PIjv{2kA2d~XFJhmdOZ`cp*%2Xt!4tQv$~@Z`q8b>|!}z>G ziVBB`dFWr4F?$q%XvLME=)B91%`60=CKjYvPDe- zdA}<3yN>nT7t4oCAlkYa)Ahc55w!K_wr=(421+w-5`8KvN~-2aDxDk31uOtlO#!*l z)RX91ig|T23Lb@&X`tY=hxFm1=pk{=$8k8Lc!1w4vI;4}@N;46iQ$iMxG5X zc@@qtF%r(mjDkywN5MJ2=*9gq!-;_L0KoY%0#YQLs=23%@*-H8&T^wI;AW$-fCjtC zgl#i_bLSPr-3aggb%dFRsV^!%MOu9eTvo1ebmTIxDIY~!8v`^qchMs@p#H)B}+ z^wYnT{Zm-KV+0(TVUfGLhc8cz5{KCrjg07#vkb#{_EFC zw%o2bd2Zp~nyE7nj?7KIdcxIKQLyWQmurW{tH%HIh7SMKp4e)azqs=AF_%)-^2f2x z?U%O3SKs)42Ai5#tp2us-`iJRN0;>e!Z)k3jTgI~On+QZ*0g)-w=2uz^P{B~4y9A6 zG31lgZ`3PvJ^R?0E~JjPm%M*`aZW9L^jgzUko^^g?k#MWr8B3E9x;9d0ARGM#8HOUI`kE$C!_z>^aeLt#_3M4K3i4v8c~D5CaZpkxk6$E zEQ6w4yXZK~2OzmV;PL8S_Y6T&Lk2OfV~B+!2n|4fK`bIlRZz$Lup$t);x`W+!LfjB z#piNv${n%8%0S5y4bEON(<3dZl6V;}coEBw3CKVQ>LL~k1;bGxX2l2W3TPh}lQ=e@ zqE}h*K~i3KDP~tSh?xyEAyE{CnRx@0MaIu6qLha*6ho6Vdd&oF78q8bd2HyxkwZ;Z zgfd6*kUMm;;+47{5lFJ8rp8di8dR-Q z0X2-pEsB1%TDRhe>|hk3h}-?pa5y@YE0i@dCPqlwK#`$PJhTDrs9pyDr}0?rsHZjp z$ubyKt2GIgM9E2jQTm?jD6WXu2rp{^R2MPmP^Ib+4C^k36-PG)IUoz>Vmn>LQbyLq z*=X8nx3LzJ!^U$(oZV=5noS8CkHZ=rMjLBmO=hQ!jbkk)j&j;KB<3u3Gsh&bu5eTr z!xBvR4IsZmSni2f!LC73S2d5S1`|zCTB+)4v{H>=3~QjUT(>9%!g0xzc!dT7c0et# z7|O+(8o~xrECe1yfi^0X%s_=;jFgEGMI%Mu*Sh!rF=-vatf1x@=bt!odK%M2v=5tQqh?d)7Y>%E?81H>^U2cQX55;N_hg=3 zy))Z)X=2mZ;Hn2ng>SF8x7^oh-#58rO!rj&_}GqHdtQR2=g$N|SMPxfrF&s-P5!bU zuan0|&Dy(sbwL-5jr(@ZXV3e*;Cx5p{vB7&_1rP1tlhe=;LiJbZM*z^YXF!!G9$a^ zXYlu)>|wx9Yf0cp;XUkfXO{Tt7H8Yd6?~ph)|{R8F4(B0um8SnZ;I=Jn)Z7two0hG ztz=neEnc{+;FYT4*5tcg;F4GVXBt@Fk}PWr-|bB@PWX67 zL6XlaUT+L?AEw;;^Iv-M=(^p{t=`mkpwqv2(bmsXaeGVdi4#{Il-G5h+kXG4*NUAz zZJ+J|ncGi|5~_1s=S>;^QR?)T`8RP_%k<47K)uzUQP)1V@CL};i1)0?{O)AA+3}6e zWo|BMZitzF>h|vYpyQb@f#vqfywu=(v5Tp#!ng$$S(oS7#sIowL58mczxege-keC+ z#LNj>DzmQs@Yh*zY+Hs&O^^+2c2o77rv9b|kPNmRPM&mm;TI=SBLJ6krlYCISN|U&Y$b63 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e5ee82f701219ba4b592bc559354572cb96198ee GIT binary patch literal 1782 zcmaJ?c~BE)6#v34f{NmSa%`h`)g+s2Zh<5uL4yV&qGEx{X0wqHl8u{H5_D_^5YVD{ zQ$|;!ATAlCfMfCNVH&F;J94N*l1?6bd;k*;c#M5zQR5E2Z~tF^35as!--= z<`AhAtqxKWBo2w#TowkyFeH+&aRbWJBSsXP2k~GYm&2uR5sNF5@(?Lk0u5hG+97E$ zN|RJ^!|v!)G&7T;Y*G#O0bVv$;b3}QuUwOFZC3gW~f zp;GV>tFhWC)QaIFeoeIBVXWwXu~H?8qZC0V6GZk%6X-Gtim+!AHi(C?VQ97%#Y|SW zWRAN+LjkLB(zFgY#F2yr8cea&^cf0Vz7aO?a3hPyhlMN@<-;tAP$FR=Mm{bUpdurT z(jg4t4WFcLs7q-H9foa$jT93YC1MQ0Scm~JvM?jx$dZUr0ZVK^Bq)yXaaVinFfc%GmtDTS5de?38kHj1 z(SB#&O7aglKy~ZQMQZN08F~|_m{j%q{!)!Ts5E0jxmV(bN3XcDiioHMFK2@0Rs!?~ z^?z6&CjZ)_&F|*;4(H^6)Du8{|J}^`t8Wu*Y0b}yn(oj0P>iMpiDeHaT6qz*UZR2r z#-PrBI=_101&3F!csHS;%lC!Hdc&gLgTAEClDu&z8ea7+IG=bgH@_neY&To3Z<7Cg zqpicH@tje;(5ETgwwy8FW0WQ2(mLBH`ONMs+S^`N@ivB>QF~+$W@Wlcn(7&Ob)9C! zOIIg~Us4#5o;AZf$NmfGj^DZK{tXu+RPo!rzZj=-8zvXV1Q*x)oa`=|2<9w`35zK5 zC<8Eg?Q+-34ZD>^X0QO1kKQC{*go2`W@=4uvm$;%0a@5k-#z10>do2KHGS3Ls!@mg z!(wZ1PKmm`-dW(EQE{|RReZiZAt(z>JAF2|;ON7rescrHf|IP*y)47&R`L6_;CSdw zYF+@;6f+ClDN}qS>#2NhcJ|Kq?l{!b)U{W6Z_z2v^|r){s`vi4()Wxpe&8NBDPzc| zZ)L__bI$UU0!3wq`A~?fqU_?X!)L=*`M7pbJD$Hh;7jQzrFqv=QEBO5!1M6IZ95$? zV_lokyLr#*9z9`v*LXc9Egs%;tu@HiB5j*e@-+I_xSg3_g7P1ev8!jQW~apn(@mp6 zE7_JMY=5IYp##fKmx1i5Cm5GQoI9TV*|gW-bNF0nZM;9D`EIvgOYwWzyNt%OPVbH* zi5E)0f1KZ{Tcn$~#mbQJCN!Sim+kquBY$_+g~|YJ+5T~rpk{yP)m3NmXZzH|&I}F! z)p)UQeAm{+uW#u*x3qdT_FpLpDfy`-GOJLM+-2Od`Is{!RVeFu_%J^B7$n^P1;~cf ze0kBdjlFRVp%HbFeWTJ-vs0L^c3EtVpYy@bmlDTBmZvWd*NxY=1RgT^Y6To`DR>=z z+-W{iU@A?0@-ST9b9co~_2r((hW5U1^*>ze9PoodgJx`1d|-jy{U_3>6I9i)8F~K# DYC4#k literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f3059dde7389447105b97d75b62613662d28d24c GIT binary patch literal 1607 zcmaJ=c~BEq7~g=XrQ(4yt!V4IprfOkY_hpFBqbpSL`fO}6*|_k?7kdAvT?JRpcPY; zQEEq9wG><1VQj@ZRicMKFt;H1H4;fM7!(IdF~_?kQi`G^giIon;ZOq)l=%cYg!=+1Q41yzV0e#T z@NhmfVv#Q5N(CJT$qq!}_1kPu4Eq9uxq?}fglNA+DkdaeZzQyS?SPO2{-^Ow?Lc0c zA4qaQfGg!0SQ2MS6b#e%d`A&Q$VT%z?}2rpOH3S7>IFW*YSLlwM$CFxjmlz_W{`xO zR4NQoso7{C)k>3rQe-HMa-&(LjM{h>R-uB)QW%sfvw@6YDYZpumK%%&AI(?8j{#A?9_V)vt9UL}W8?uXaC{!el|-As;pPM`;O6|Oj1&{-G#kx$d=bg?NQDLh zHUZwV1h5vK^P>GJ)_9&lK`M6=tPD7DnVeAKG%Y7^N=Z>T>68Ptf>t>R8iqfBXP-*l zK$k)Z48tE~qhSJ#%eVg@ zZi}!Xer0NU8PZ3KX2cVVj(U?0-`^V^O59qQ z5I(1HXsp9>$Xh%g8PV8Y8fI2+=su^vd3EPM%_C~ZZfko;Yma^U z;yBSY^_gLZZ@Ns{n`aE)PLXs>nire>Zu@cBgwzWc@w&^Zs?hk`X+H1DtsA>yS`V-N z@~s7{CMOq+d_Pfde0zZl(Qoe5>H`l;*B!OvsZ-9lW#4q=Hm#rZSM8NYEkwO2Np+!mOhesFk^YkdEguw=?igCaPV8-b zd`%W6m#x}-y%DQ68+P{~=!~CIg`Yj;iM7 zwS~p*KTJn{sj(%Eo|Qf7`*HfDxNC)Vi8VVKr%hS%TSA4YnN!7VJW+djnmb-UPy1us z$nAS}H?&Pma41r!cf|Ko!`35vW({xHeulkTS$z3X*}>0F7`C=gS)O@db@HOD=>^-i z+*x5QSh!sM>zGrg_9ZH>*t3L#X}a0^q_kr_2XoU;Hm1#RmNZYsPGjL0)Nk~hoQnvS eWwS-)LtaLjgqP~?eC^_4Zy{E*-Bh1ZSn(fjV@>`5 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..5d1ff45be8dd5e6679795bd041798bedec2d9f5f GIT binary patch literal 1679 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 p*P7!{4){{XOEewP3M literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..ec11dbd035180df5121aac86b2cb9e92506014c0 GIT binary patch literal 1775 zcmaJ?c~sMO98Zf!1usB6HisejoCj^vrdKMZ^pvWVTI;}TBQyyu(59xr7Ei>9!c-KM zsn01YUXv*@byMF2_co@^dCqH_icB4w2YBLzEERG4!)IQS-|zR$_w)UJzSm2kbhtWZf%l^6qGUl8YzAt;s2 zV0!J2JEk-l zY$JVi4&&fTLdCX&x%9o;QBaX%qe^C6TwU;N1MSFhlOEP=P($1o5#b_K3X@)}LlG$| zmubafqh5C934z}P9mnSG060A^L zzy^|WO(O{tL%YFODOS1OLP0F05JEyyLWvZS3vpbE2r)T^2~kQ)DrLBWLU1npHazja z)U|afC*i{IwzE+=WE7@!pbjBQpp?)-Nhu+w#AQMyfnqp`N=Xt^LNG@W4tCA|x~N^m zwPtYpW-PeFo53PI+%z%V*c1&s^@JO_PS(+OV{2nsLUzpPhMVpI(Kfxov>uh;|08~4HYjS;NV>u zkU6h%B>cdCpfjNqoZpod1(va=uK+c-KQ69d_-TSfOEZv`F(moYq6JO!B9-#`n3CJA zf->gC`8m~wY)b3BGzvI$2;v<$v2=Uf=8-G%c`JHN{A;WydABTYrS{XIQG2^QOAu^s zx!i&swgA4OD_7P>q#Z4cpTTRIaHlc(a-Zllu>9(r9?hCvrubjFBwpp!EidiLyW3;v zGEv_4kg6veTVvuY+jKRDpl@r2}W$TJCvXZfDShRmNDV_bWA z)3+1@TZ`!E3!RbC=cK*P3(J2lC3Nz0aS?(B0F9 z8K1Acbh&g(%mw4qolDC%t=yMT`RosTc_i@nwmj>mA2u8-NczIn0rYh8Uq3WR+Ns38 zrm#N=oIulsv%;Nsw5Pw+nPLhx&GwYRtD5KY%Ss1tD~awcuUQw_4_Nrg%j&LXUEQPp zJi)pn!^5UNVCPH;a{_(WhvWV#+vb&;@jzYffQ=7VM(plCYR|EQlaD=q5oq`*bJ5~{ zjp->v6UvvxWZyLHFxbYX;iYcvYOreP!XE!H*syDf_i3^7$8~4IDbb?$EH4)U1q$$$31WB06k#c+re0!C#QsIL5G3mzMu8i=&kV literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..720e95f9e0b3efdd30bd0d9bada7ec76ab34518e GIT binary patch literal 1475 zcmaJ>eNYr-7+(+&`3f?quyk7($icnc+r5w7jRTJRh*ORjq$H<;W%s>fNAC98Tet&* z$qN}jDogud%9zQ(97AW68q;VXo5;-6D4l_^24>WP7|hHh9i{hxGyibh+1>YjpM8GM z^LxH_b9vd5$qAVW2!bR#N~{%deHlJQ@eAPlLi{!-Tpm_!RqATlr3QEfAZAgn1*pTr zyFmru#ikd(1NjKDAS6{*sa4KWPLMqsKCGh&dVCO#Ao+zsA1|x}Dq0KNlGlV?`l260 zCDDYf(K|_}&jRYCl4b?0ZZ4}7n%4=eh!qx~`9TgE@Bo!ZgPwY?p9`9>S-TwEhs6Yj z&Z?;EOxPT$DrY%rkrjX%HCkLCNfI@(8X)piE$!lk6(~hgT0#qNBd#@a6wPT_bpFDi zLq&9P6;}JaJ9si-b*k#)2qF*&XaclGR@{V^Wm$rx2#Ug?2JUb2s(cXl`m-VytiUfQ zl24UnFB-PU*UAm534>(kqVV{f&fA8){`p+NtPw%pM`$%9;qin+o7MKK72tmwch&Y+ zHu(Ti0sL}5o+;1`W3iJZ}H(H7IB zjyCAcTCL4urWu3P%<7Bv7M;arG(>FN4QsG4c6+hjZnT-{FqWZMi;(?@@5MUbd(99DB>aAdM$RrD)plC|kt zzxv=v#)h`+xO2yj?*;blr3Kx6e>{Kbcy)dmaz6Ll5r16#?@O4SF?FNPkKY=PO+SXn z%VRSGkA(J#r&9-(5QlDd+s_(`29};nyuYIbIUC=Y`Retfr8S|kUFE|_Z!727Uq85!knoY z*&I9Vem(D0+C%X@9al5bYNp@sS=Ufjwk(_VmVi&h4ok^#+cm@{^bRQV&-1OnkH$FY| zWsI*Yw7;&nBqt^Mo!sXN14DoPn8U5?dBJ{UQN}W|i|Lj2Z{PIQ*72SPP8?kO@1DWS zE7FG-hs-(YXLe CnGm!9 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7debe764fd0a0229d825208e2b4437ebc0661934 GIT binary patch literal 1428 zcmaJ>eN5D57%v_(_(3*57M(L#3Ui|L+FtLtYr{>C_LyflU~o)C6D{pqX}D`|Z5aoP zgqh8VGwL*h%{bj;Gde%OkT8uH7d0fB&1{b$84f@B7k^A&Jyh0n4K8+`wou{{Wv7fgS(S*gipqo4!CCuy|+ z4Mc?XpaKX|(;F8+A%fU8Dxqq#I#|MrTEs3`I`&v33egBsxHJ|O#Cl+&wP3xXda;31 zXE0Qeyx2-tkPJpSP^TCZmW%gTZmbsxg);m^C6MLn`S~BARs4 z1uh>&`8gl$Dd2sKtH{MUIlsFgWn)4t#keSsk9Yfhw1s6T563$x3g*!5b}-HqHlP}& zpo$>nSF!vivD{O!ET;p()bx<1g;PyXUZ}IS05a}yk_EURI7yr-U>Ka1oxtM~+%hS^@RNAyiPR;#6iQ$i z(G(k2bjgfIq(z*TXc-q}r;IZm!G(Jynh^l)1c32i1f)na~V$a(PL}KQb}`w^e7av>-@Ydw}GC7CoU-(zN59!OOYhqB*{Le>@^CzN^XvsL7YYq))4rYm zPWINsu7kDu;yk73z?RaS-KYBD#sErFFJvy5|heSzIO$ z8$|1V*FvPb*fsL1Y&-80{RJL~)S zJ)yVESCrd%dkccDeR1~m8wVy$`D&oF>b3Y}HO#i2mJXU-gdTgZo$flEptjr)k&D z&z>>&!HkRPxO4dLPG2}{0Ia-wGxzb=mlHcXe@tvIy|(j^dVI>>KOe5nuIm*lows@- z*r$0NApO{-54cuiQ@|J;>M5R;cKG?UIV~;ebCEkklk((8pTw>IWWZm_A1hk7@jtSo B|H}XX literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d3674a02b4d464401e7ef842b8abb289dca43740 GIT binary patch literal 1346 zcmaJ>eN5bB7%zed1U52dZjP8*Mgq8Ad)K?`wQ_^I>)klR0lA%kI+MM$Z=u4qwb$(q z#AVr%B`#B!F&xA{mi1*-d4A7VUvFyIS5)vs0fu2k!8##~)}!dD&C5pb-}2rHp=GD(Z#DO8vKa>k#5|JL z2Jv7Nw8Jn2Quiy@VKs(jA5$W&W^1UP7qzGbq;xEasE*JWR$Y_Of!GO6ybZQ1s++hy zHcsG*+aCWO>~&1&Qnx89=F69i)OS_R*vH++D6%IB+?*b-Kq%^q#7&BSP)=L zG!)%bG!;)-1Z~8_4_=G%PDv`hu7h=`~0jkV`EdS6X|+cj`e$(HLTa+5WGUbBXBO3^LaDapc*rQ zD#DCkCFM7bbv+Qv`wR$7&4_4PSEdP?Iy6&@b!a+nV=OdY5dxy3rX-cA3Z(-UprIUw zQozun_*#m2WfKZkyG%dliU ze*bvx8q;^ZICtnhd48et=loKb3#)3bF6}z*K8>Bd*}Ur~qV52@JYD*NwAlRVAEndZ zU*1tE-&yvYeQe-w{mF@zhfA)MWtWe-H|;qTR2$tl;hb?R&L}R zU-DPHz3tX(MW^m%-CCTQdS-IC>Y>P`5zDmvPs!CQ(aF)pBaeLk;g-NTEmk<(eB!eg zPu<&h(l@`9%vsj#S&i&VKb%`(?+%P#=wJEwyYZR$w%MG5y{4Y*8Jzg`{bczB*7tJO UX!F$J?Ww<7(BB|@;5~TkKMW<;eEYfKzf6rMt9kOY31M#WeerZtwp?7Vh%b|x%z*%{iUEL~wuH!&*1%pDkE9?T47 zAqs?~#+n)vwOVPbRuio;QsbjFm5S2Zh9Ey|Q)Aj-o5sd8twF^`YQXg_%VK|!-ptIs z_uTWH^PO|gnLY8Qt;IzT79j{y9Ni{1!+8k4TMF~x_gdl0F*ucaQqpU&G_O~701{TM zHh@MAxg9hES?%kd1l0(VKddK`UNY7wD3;-qGdjMMVM8>6RM)0#S?L5G+6LNnGlb24 zHIAXW8p3w6F*0UHK!?7q-vKTCO$nvHQ{h#twg#$l=D%zLXsrP@jjr+bQ`0|N)<|zG(}MG;c$u*XhxuTba`OV zp`&U-vsl0E4(>u&hv(S>LG43f=8Vc4Z-uiN2of6^fLiA zOi@xK%mf2sm}l$Qh(986ft-!iur$<{sJc2%3NuUC2wxvzxu7IPL^dFCIc(H)J=s)1 z&aV#rE@Q)Y#R?Gz$e!gSEUPP51n~~bv)m5LMrp=JqMKu~qMI2>MdpUG0gJ%VcLBBD zu?%!6#e%*H1wnwr5a$fxx7{RanY#>h059^p@aRNB2^?Xj!- zCeHr;O#6@D$H&=&wgU2GIp6rPHfrdmX zENF*G2$b&E&qF_kt?1WMX*(_L5M?9l0*;QWm^Bd^!~9!{CXhR!jb~uHrU!_*iPHqG zDFLF@Bhiu>h8C1K9U zTQa&5wXO_C>ASxpM-j0RcUl^{7tj?k0N!Cq!NdVk5DR>2eu4{0EJ(|EBBDVzWx=Y~-55fq|GIaPB{6_rJ(G@a#ATcFKSV?iBtlZD!5 z=4!)s)N+-H9jWO2{5)E|c=l2+hE=ffNHA6W>E_V2N6+C^`-HjqnThn(^pg*N_-Rw+ zdHwSKKkl?dqcf$^`~CEl*YX$k`nwx`2z8%pIpu%m%x}YuZMIZLH$4Bi@8@LI%gyze zd-uVnn-aF+A${P=$9?~-+4|$)k<=yVg6h`p)d#xi1DrKfu+e-&wov!0h_l&kc#kzwTP; z8~x>2<72xjYBO(}e}41%s-u&&o2K7f-*BwWPmUcOy!~Zla(v^ieAh`{X#KY4SM9qK vhc?&m+&_Qh`ui6LCdLjv(YAVOTVDnC-l2+_XWdPwoPSt6+8h}Rwe|l8@=ndx literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..ecda8127499047c22c2dc2216fa68a4be335c8b7 GIT binary patch literal 1383 zcmaJ>YfKzf6kfnmXnD1!QT(C9&=`o!&g{&-X37?pou#a0fo!+9wGq5KbC(@qXO`K4 zT@YJrv9(3(BZf9MO&Y7gANHZv7F!dfm{e>uY4MSe+E&|QqE+z)vDKZpFq&8HS{Fd0`uaTl=Wdty0<3W27mUPWn1HbGrb(UeF~31c*)r?4V75F|OFDNdZwe8N0b zrFJM*s!9l(D={Z6LBU`QP$CTj1Z||u1OP^gU{O8<6EH%n30MLYK$wb%O)kR4aYR!bWI2LHL zI9O0d)1;!Yxin+>2#s8NUA5O4kH?X?`P}F>oi0Uk@pf-)?3S-LXBf-)dp6#`zvP$n zzNR&2;p@gNVe44let(k#=VM(9C32e~|LlXz#YE1LMm-ytDV=e0k&b)7bD@ z=hXODKb^7tT)BMcKqL3~)^+P{FYCJ88~<)%V9o5+i>;4MdsA~$(sh4HX)90WK7T#& O>vK74_+u4M@Awb%ls@>Ox*G*bua%k=SShp77Vc2S4H6K807y2r*v(W!)_N#uhJgj*_TD>f3aiBuXCCW_@ z_eDT63_u`uwtorBFf40VI2h7G{;ixKM~on?W7H!GLStB2g{}ah6>4}BYz{}A#Es-I zfrmvW@r2b+`xQ5A30EgnSf8i~3W-*M6^V*+yiDhife6$9u1DIUF-~_9^L9D3Pm3u6 zpI6aZox}pEkiQOh%PPd}MiVK}G>zL?BNTzTiIIS?88_2r6JxSU ztY~35il;4tCb>g%5{T?V6cNSmUosqxE#?YkjnaWanT#|QiKIiD*N$lc_&<$hwPV3f z1yTVRlRH!al|(AafKmGH?kKH@*l@LK7}W)|@v_hnflzl&JQU9p^7g+P_6vH1HGGn zBhJ>JiGEP*@7w-qp5Z{?l|oj%^2KXK!zJUQedyPx9{J?$Z@v2GKWZ~Oa*m(5<*J|U zKe!)^J#?8l)?NKsZIj_b;XdeH*LWaOP-^nx_s#LPL|NAw`lSh9@G#uI3Gjc+>c=W`7oPHkKJ_oc$( z-L3bE8+VW8-6KuL^XSRispRatdUtQvzGq&LA6WV3#F`daS~>FX!J98#yIj&$HCtQQ z7jG^;&*^j0AK>uxxh>44Ck19_`?ZSq_x^OMH?c1CUY4FLxc>XebGgq>L(=^88@FZG z%a6aFShfEv`1}rrw%kn33>KumnHtQWn;0L=-?6E?7t6wid$RHmzg0AV PN`U!1HT?0a#$Epb%nSD7 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..29cadd14eb86d70e7731057ce93d2ead1de6f545 GIT binary patch literal 1397 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 GvHt*X#JFMr literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d192f2e344e7c9416b8b6c07fd5e249c99248ab9 GIT binary patch literal 1337 zcmaJ>YfKzf6rKf&1cT*=LZG%x2Q^}y_r7Lih25Q{tg;lBHN`|DcW3Uv2=j1uRu&p< z)3ouCV$)WljZvd9tu~EK>`Ht@NNLhotTm>sKOixsO^r1gYLx`VcD)NM_6O-?X70Ub z&UemtUh`^4`{s)B+HwrTDx$4Y9IZRh(_B`J-dD=@#?VsZM7o?#Q*{P_4Y8nNCLtcx zK@W^WpbS2L8a85B@lGw#<#ff`MA_6Skk_Fyx`ogf*4UJ>fZPWiJPCU=BS6f4HBR7~ z5+JsEVob~m!(Od*$cCLm?Fo6PPZkuS=~28fBO(JjbO4^w`;C;C2@s2RMYPY0X#!tV zary$p5~;3O2Oc(Ui2Ep(lo^J>eF6m)z$JMV$PeQj!?84rZXe0|M2;6(0bjldZ`qejXBh71dS zHRN|08@w%64BHSmrkya&{z4OU^qP*D>NPE#<0%GzFa~7J$V(dX6sRHCA@M=>Xy0`Nl+M8fsH78 zRKYLvGRZ5vO3JERB?Uk5kbZ?10OZ{e3Vwn{6zP1|+|oq_5o*o+c4aKkVP&wOfu_ku zV{>fHkt7}`#LFUqT<+Yr`;Dm!wYxWY z4>ryPuUNtCp{zbVs!zWQoB#Owm5uwF-n?4b+B|yX-V6KAM8DUbq23ri!Jnren)&g- zt{I|X&-}Ie^VcW8xnAZPtK1{KTy=4iH2(QVu3ysItIia6PlKoE`xcCB_H@am*PCaV z;gX-<`RahP}+0jX|?1gn_jzR>#4VglXT@s?u*Z|H#YxMUDTg@O_LU$ zUB7)kHhLL!2j}Pb59=mhyysZaUv)=&e?7boo4a%OTI`96aIUy=>RRCb@#kibbN^mC z+^=6=`15Sth-<^fB9?HU4Nn-IRYfD^zrXk8p=$c%<2zi~hJ&vCo!L2<|CvQ2?b0Wq H?w$VuqvX<8 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..ed0f030b8777cc20b29d6ff3ef785b572cfb53eb GIT binary patch literal 1752 zcmaJ?c~BEq7=PieLJLR{td7f)QBgL#xk&&?AVH}FnUGer9d)zWz#5WGlO+U{LM_Du z&{kViEZW-EK|BW)br><7A{09m6-2AFUbTo?4+_ZORJ!4?{^7W@yYIbkzu)h>XE&s$ zEeM!2Z4v+=AZ4LS%dW-jBlPoR-`S0iVRi{;)R{~MZDjIr8wr#KT2DeLW;~13lDHxN zqgFBw0MAlNm&s&mQso3~=HYG~p3`h)(E!9HIITEgA{j_eW>J=S_))_d7@`dE@Di~G z(^!+pY-(YFjm#)W(-8$GLS}#y=0kB#IZI$B860w&b1ZhbGaer0m9u-d7=@ux6~+_~ zk2#g8Nr#eX8wp8ye1yO-43f%tqyZP`g+`o+h6I>^kMh}Ditwd!fl$tuLE{(98nhXV za;++P+#Gv~hqD>RDo4@0ygXi>kVo6HP`*qiLoop=5Fo4uV$ZiQxD&D1BPSSCq@A!) zR)(T2ked^WAY~pLN@+2FHGqg=d(>W83ke*F5v^|@)LINQVgXU;( zg0i?JQSK^@1+5}&l!G)R+h{X1nr1om3Ks-20YMN_Hhi&|M8rmsj7@|s#KHn%Y z;9`t`$MJ@j(l^$rtb`52I^m66MjFIYJuXBHdbWQg5)sR*$BhUn#*G3ACgO`lF)+%y zh`KxHrB0dXDHV4u>P3esUK89$hIa zrOtV^DYMLRAM;BZ8R>YMqcL+!{^rK^7)?FL-<%WYHES)p=I{_YweNVhaWJ7_J^VXS`>?&xdg3tBmf&MaIt4cp=D_OLT%?eZ!6E-hVIJJeYho!6)pRpg!>fBgBF|;(B4Su zgG$BGnKx8LgPo6CG0!UQ{x3F_QGJ_|05|eZMBSGMc7Glfl&(NBPVklfi*FBqhDB|8 zFfWerwN3_i=3V@5g~__caI^K@oNAPTtX_(mXii`|oT2txJ*6xF_>$gJ-#fpR3vTtU z;)HY+`W2T&al#%Upn&FF(RS+WK7k*An*f}1wD>)Dd8C7_x(oGh7KMAR06P+cd;xc| zt3107oZm9PkFz5(G;~gCY(D62FYyL**LXl`t!MGDD|-5crsNQ>?!cP7S^XZ0u(-O0 zpS{k4-$FZ?aIoR_rTyYzLFJ#-wbvhHm3BRDsy{PuY(B@zj{{KU^3a;z#CwGpA=4FI zT-&XSDEew6_iEEyy)pZS7L{KP8H~kDvn3U+doKUj=Q`TWU!|;A*C>^=b?vlshHCP= zs&-n+whj1Q-CbVdTiaTYR*JqKswk2id*k{R#me4gwXF}gQ{R)I;gG`IQNOvg>RJos zUli!y7O+&Ca<77w6F*wyT^gS%zD2cw;SuKq^4W#E&4PUqG=?;oD+0$j6ie(=F_ QM)$uaMV+QPl(=&3e`D>68~^|S literal 0 HcmV?d00001 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 c4bac1947c4d52d1e16de9294939cd21a5484886..f3b3f8a977f357187cbe110fc5f5f3429141dc2f 100644 GIT binary patch delta 132 zcmX@ddyaQQB9nrffw7yTv9YDOv4Mf1p{ui#qmi+TtC6{Zk)yM-qmjkrMkX1UA`6^~ z_A(`_7+D%6CnuX5=vtbZrs|renON#tni!eu8k?9I8m5`0B$^r|Pj+FRz>=_h3fJZv H%-@&*srVxP delta 132 zcmX@ddyaQQB9nrprIWdVv4Mq|xvQz6p{ui{qlvkri;Iz&sjG>Jp{euaMkX1UB6FOI z_A(`_B&Jy=CYmOv>YAFGChA&Rni%UQnWQG_8m1Z~rx}|h8JH#-O?F|Pz%pn5yU@)y In7=Ur0MgAQ?f?J) 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 0000000000000000000000000000000000000000..a474c21479d42198b80b6e5c29005440d8ebba61 GIT binary patch literal 1708 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 literal 0 HcmV?d00001 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 f14fc60c764c84ad1943d4e215cb0c1e9076871a..f61e59efd34b111b72877660b6715ca48940bf7f 100644 GIT binary patch delta 132 zcmbQiJA-#aB9nrfsiCQbtGThcv4Mf1p{ui#rL&ong{h^htEH=@lZDIVMkX1UA|srN z_A(`_7+D%6CnuX5=vtbZrs|renON#tni!eu8k?9I8m5`0B$^r|Pj+FRz~X!JZNTOm H%m4PxvQz6p{ui{iJ_B=qlYAFGChA&Rni%UQnWQG_8m1Z~rx}|h8JH#-O?F|Pz~aU4BER_t H^8qFRpN%4- 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 0000000000000000000000000000000000000000..87e297b2a7292eb0a93ec9b426d669a76476c949 GIT binary patch literal 1745 zcmaJ?eNfY87=J;l2r^WLU$`v`pfG5grY$9r3fNL)P$Xbe19Od#Tu2!cQ|OhD-fR4djKWB`OBs7NT{ZW&)B!%;CV!l20u<_t1A zJsz)AO`79QayXS`&A3pQlanLJ5esN0MJU2BOo*UD6y~#+;x)yfq%0(3 zFtY~Q1lbu0EuF>6Vb0l!D2!&cdYaf|namZJHKCO-3q=A%Xf)bG8`rk5@znoryjI(i zU^7#~c*;U&F(g+Kz1I|&OW&If*%di&@L0yc)rH7V(qxvAGO>|LIm~?#=nOhsDi%v* zVhZ775>mpKV6q@SK}xlJy;g_nDH%d&F?5ROb$AsfMkSaiP$otYktke&DOLxmR7%xq zSr~#U!ltp2CJRfLNNUQqfwMh{mA(;+D;SDkX(oZDGo~6rlS;F+C6zWqs91nNzG{Lr znCucidzB`FR#J>1o6@Nm+6axO88^Jf1r$R`l9X}bOQjTFs+V9~B2XD$ED02e^np4; zijeRmUiV7+COVaqaABCIyumR_CzWXlF<+idNdG`h@_GrSjf33 zw0F)coirul+S9(B9u4j=JzSKDn<$1GodtUfi@33yrHM`m9~&EUaB#qv)mH-G*dD12 zOR)ZYsmz6GMx2zkp+>f5n^$vMtDQcci+D9Bx1-Sf=Yj9i|Fk2Zb8EomwjWAQBNtX; zK56mJU8?Derr)%+?YA(+y92W)$!)^#R(Cm}5>??)enEf(73T+$_~a&%EapB;|I2 zwO##SuD=b`?Oh0Z8+e*~d9K}OoZl&^=goTy_yaAk$=&tT+@_I7i#GPSLi2}BO`C3j zG?gR{tnY{juEH+9ADVl{*A|*x$P4w`=m>dsz*U2vmSMMsRnbmqimI*y**-maULVTc zJ))gk&-$wOILv#veZzMumk$m$Iz3W+E?-o1=$LN?vp&S3Q(F(9K(KFlK!aP2u&^yQ zzE$lp^6e+yFT4ubeTRmNceKk7)bt$R-wo=YWYu3^&%bMV*f@u6)bZxzNLuO^&eNVuC{B~32%jJpDf0}-w2gs)# zdzOCHzs%9SYDCkzdw6$#Uw2S-RT=F9h92C@j;*sr1ncJ%e7)}Yj*7#h&||M_yk=AK zX(_OjS4Ra55DVk_-Hx6BgO+o)>OnTTMXlYbNt8dUowb$czIkP^dc;$-z5225rmNlf z-7Ul&y{I&=w4x()#M37vAWyn^$*&(?4sRjghHZ2EjgS|)Hf@k-{?2kRz;|DIRI^mX`I?@pmkUw)VaBZI*Z=Siz#r~6t M43ANsSe^XYfA0;5ZU6uP literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..62428a4055a629a59736231282016f0b6154297a GIT binary patch literal 1735 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 I1z)cG4^f_N?f?J) literal 0 HcmV?d00001 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 ea73c361f984dd7b9698df741934d0c0be9a6ee0..942f082b83af4a2228227f53134ca6b9ab3fb391 100644 GIT binary patch delta 131 zcmcb?dxLjFB9nrFsiUc@p{b*}v4NqXp{ui#qlJmHi?M~Hfsu)kqq)oEMkX1UB1@c# z_A(`_7+D%6CnuX5=vtbZrs|renON#tni!eu8k?9I8m5`0B$^r|Pj+FRz~b1nEo|`( GW@Z3`Rw5Dr delta 131 zcmcb?dxLjFB9nrXi<^;?tD&=*xvQz6p{ui#k&(HZxvR0Wi-C!uxrx){MkX1UA}5@R z_A(`_B&Jy=CYmOv>YAFGChA&Rni%UQnWQG_8m1Z~rx}|h8JH#-O?F|Pz@j9o_ImLR GW@Z50Nh2Wu 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 23c31d54bac6f803029c3918534d466876790518..84ce00d235ae404761b0edf5259fa1c9e9cdc197 100644 GIT binary patch delta 132 zcmbQqJCk=qB9nrFg`1g+ql=Nbv4NqXp{ui_qp78t z_A(`_7+D%6CnuX5=vtbZrs|renON#tni!eu8k?9I8m5`0B$^r|Pj+FRz|wuPv3m0j H=7UTCnSUd2 delta 132 zcmbQqJCk=qB9nr%iKVl-fvcmLxvQz6p{ui#tA(?xtCOLVfuXaxiGkDPMkX1UB1@c# z_A(`_B&Jy=CYmOv>YAFGChA&Rni%UQnWQG_8m1Z~rx}|h8JH#-O?F|Pz_QQVA$Ic( H=7UTC%7`Q8 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 63e29fb64e2e065b940f3e981371a06a755372c9..f6f45552bfd5cc6c864455298f50ab080d91da53 100644 GIT binary patch delta 132 zcmaFH`;2!(B9nrFvx$MRxtWW(v4NqXp{uinxvQInn}wmXiLr^1xsmbYMkX1UB4?b6 z_A(`_7+D%6CnuX5=vtbZrs|renON#t0*%l$HZe0aOfySKG&M+`?7}>OCBHRXaq|sk GK4t)%86lYAFGChA&Rni%UQnWQG_8m1Z~rx}|h8JH#-O?F|Pz+$HLRCx0Z HWqppjAtyD%}9F{&3vc-S7L}eV^yOXV)bq z#*Xp!_XYr9j3!Q<%&!jq!93mgcXnN$h+q7;=yWcHHE;!ll?Id)tEWMYiO8apX@V-u zy+lU)@>oyC|VMZLA(i$I2o6s5_u zu-2lYvzfSMRyt)_qK;fY8Dt_$9V!1%@Ls8lw-Ex_DInXFV63sVn_rIsc^+2wkxRrIv{D8< zSsgQCjz2|;vN_IzLr_6MfusPFu+}UHQ79A;j6x_X<~78&LNiC$#b#Tei$P7>NGoIE z7}g9r83{d`$3=>GXNRLOS+v^M#Ae$_uK27$cESQ75*RX>oS_YA+qh)dK$ZPOK6 zXegPsv3XXKFNq=01?JQDZbME*-Wz9Og>G;SXmP|lxCcHiwmd%B}r1whcA=SVwpjz;1hw$#h5eE^lxJP08eX0uxhuzJJ2Pq&%;lFo zbdpQNx2JRadNlaM>*1o!{6ty#(V=Fusr=Y^Bqivg2L}fQ0s$UydN%-!YSgHeI(vK5 z_Pd+9K+ocr9fM^@dh+!S^R?!#3-qCrJB4NLOg-}I*qX;TJtsVTFmL|~_q)B@TGHw| zYbxKrAJg9w@#yIXUDK1&D%A+(~~^&LCeaf8^v&2E9MySj@)_X3;l=0wgZ*{H5qbXhkoblhsMDY!>wtuj=7fGJNlc_dAZm&8Tq zAKu!xWqu-ay?@r^AI=5ctg%e}96#97yD#%bLsilF3(BRJ{c`n}E@T>et7A&=)#D;Q z(rl=nfJ>%&h(U=WLNOc=Xk;6$9aujy!YkFV_f==>_-Zsyq9$ecJP5 zx-#S?=WS<=hhr90Y%t%LjMqXrC0#Q^0uugOj0}u*Fj)%`_i3M=>Xz?nzcO(&uz1UQ zq*PFI#5*2r%^)h>L0v;x<&xOCXDjq>^-sM*m?!T6?O)l_8_Ql*rbd1IumXF<_N;wz z0Cxui{(Tg5eXJv}Fyl-)S-83FVjWWyH`s42ChEqVtnd+#z%0-#}FCIM)tOuILk6xqmmlQewE1Kv;b@iMjtNsJ* CzKN9p literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..43b26283e99bb75acf822e411a22373c78b8f4b7 GIT binary patch literal 1389 zcmaJ>YfKzf6rS>^fQtl)6iL*{KuuLz!9d?ABS!Rds zE-8hSYP2-c606l}<0I-1wb-UfYa1Slw33jBw6V2KfFCyTm6T|V#8mJuu-G4@lRI}ECfNaYpPv-IQPQ0G9wj!Z)Xg6;q<8PZq#?Gk{;zXfH*|8 z1)wz{z7_ZZFUC72K^cOi9+Vpz^+xXwPEbQeKA~fbg~AYxAY~P?FfX(L9c=-vvSP>X zTpGntS+rw&%wEzPc7mW>-KBw@U3CpYSDV0!SVcKn7UQ6S5YTxv7HU@_T+EKG*yZ3l zAto?%MMZD3W2>YZy*|{bY5=twDO?~)61B2MAo8XbTH=Kg)I^#nf`Y?}Q&!GIa}{j=>Y7D2trcxMpy@9wLlnYbvtY;Sd-hrIvoxM4vJx!B(_G0 z=)59;q+c2OUB$AV`(in#26$c78dSACSp>eIs;iNp8b(dDkwmw7c|leZlBW_kv>LDr zX!1TFdNehJuB4cgH=sZ<5-FO1gqs-Bg7Z8>;;e;baav-4&CFXRl8521;>CMXw_2r8 z0>cO=*>HkcVr>E~;Iv3fxF9hS&f0i0ZWC#i2Q&i!Yr_agkw{d{Jynzx!O~1D*V_Va z)*A~bu$wg4Hi61LJ+S3A`*t+AmzS5}a@W^a4XbBl+l6XQJx=0}F|19Lr6 z3RWEWCc8AVEA!X=N47lvIWqjj_aCOl|NJptS+eP`f&B%6-Fwe^ijVjHQTo7JGe773 z^zAvlFoZ;4MHYEGGO+?e7fI`9w1-Uyz_$s3*lGgEV0-Wwbva<>|8 zq?4t`EjS~Ob_F7IyYb}4=J#}{sPA@#r2J@{C> zmGoqdSSMe*)|WF{u6;VvrcRe1Te{TzZ|(B()tt76ww^ES9~;WOkVzsZOH+!!4Bft! P_yN|q>s+U+0tf#C(`@H9 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..fecba5ad5980606b225b44da816122cf0d773a98 GIT binary patch literal 1417 zcmaJ>YfKzf6doSZl}BQw5u_^Plr(Ma?9A-!?(B@L>po$nixen=jleK-2S(VPWp?N; zgwmB@Nz(=sF=-oukeEi(O4S67Neh_zNJxFOLfVMYK8)6;Hc-K;Pj;CuGT6PNelBTKz7OmJTCLiewIzf|M+@XSsj?zk@qgh}@%=Q9W7~!A+KhStI;%^CrxQG>7vCF}A zTufl-ii*~3#a2mG`^r$Kq5_oBQ@B8qB+9UQAo7L=TH=M>sDU(41O*=krx?yaa}-Y_e07+i9mQW|y5cIZRHY)6JL@Ha5cAS=wc^m@SOkZi!LDrsPX|IdQ`=auB4cgH=sZnB~mm12{#x?GtToy5@*dUi_?-3SWG-4kvt546)!%J zy45O$5*S7>!G;q|5^E7?0jEV;!Uf4F;jD!>;TDl*c|aQhU@aH{DH8Fjd7z3CB3PR7 z<$7Dd&3a>j0PH3ew#|}cT81r`R<@_o9gD@_a^HoiE(A$B>UG&GBQt+hUw%8~SsfjV zOwEp9f7|z7JVi=51@A6= z;@Hx8d^#nz{8C;DbFV+;tF7M5&ZUz1x`l$Y&0X0GHJRP-Jf1IS&d=55>#j9s1V?Op zqnVF>d^4>kbv*UANKekIbab|8?oZ_4y-6;*JL#L=Uo%muuHQ2~a`Mut;fXJEcWys8 zJn+bw?I&&*r=2czPNZhXMou@N)UnqxdXd8y9KNxp&vXCTlAkd=UvQ;oNG)nj$Hktq~>yZ7oPoQbc{b>{xPikR%*GGnq$N2rTcTX&pf@+{vQrc2;ZHk zO1i#ylwR68m^8EL=H!RRpT9lb6G;8J@q^k{a_;Fn`=1(;$B==dp}t+8CcmHDoFv|u z{N=Ib+|lzkQaaRZ%&MAuqU8HNopbi5=FTHURfA0R-A!k+uruEAb2TRyZ|ooKCKhI+ pwyrnM-|20v8J&>k4(XP3B=X+o!c4Q=|Q6O&A3L80##um!P!`yZbizCU5^Mc#kLGdB;zcE>6Jk2LXfTY>0OaLI!-7}=HOvRg{2>c|Emola3}tilQ(Rr-PEf_*hvGb1{ZuXp%;+iJ(n9!}2tT4L>+?s7f+l zVlNzahfWr}T+_llNmf-=>8eQvPMRQFiGnuG8l}7HmDuZO5p!A9;qF1SBD{4 z0wYSLDx#9e*>NyR-{T#{6cHQ#Mb(e$A_VM;SQ&&N&1tvb=td{`CEiqMqo=c!o;4b* zH0`iiS+mh@`{mAbymVPXjx2aIj6xFRLfp`-Xmn)hQDObW6!|Et3$0dmVP)ss4R-vJQ?NIeE zg;Jra1hK&s^ZrLrp!G5(F;FHLJ!K>WK~E8!k>dzf) zV8IZYCKZj%tdG8_Mldly8 zo-P=9^lDGzACor_OdYjAzwr2xQ!|(bqJ6|1D>augJ=a{CvR6uen?ccr(>c3?`;xSnZT=lG7B`(A*>=S~Meci+MD#rt7jRo;pp zuaTW&=Imd&Cchg-GrwK?>9bxBIM=bRao6Ruy|+zC>$e}szx{4*+a6#4S^%bvPRr{3 z8T`F3YXtDoY63V?a2LDOl_9*m&CzzFj?3jsnzB;f2AkE?jo-KJPja4DQhrayR`WHt zR?|Me;5x|JjQ6fh|L#Po$^Nxw zNZ(r2R3A0|)Z;nuUdK~k0Q0R?xygZdq8E}|`OHOS8JFf+#{s%yQJS|1zwp)WzU*-K zr1Xi~$}_I~@Yfk|Y)6_=Nm=B0qoJieeaDyP)3wdlGZNM{Ih$X7@@mee<-bhYeA*qY u`EC87z4!VT_Z+@ky`^$q!$3nlNCZ0$Cr-Y!`12E}5rES%+uktUTl*ihIwm#% literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0f293281fa28434898b3c4a81126d3ba3a071210 GIT binary patch literal 1782 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 Coo9Lg literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..1efff0f21bd9b9a3d6a7b0f8c53623174008c8d6 GIT binary patch literal 1714 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..87357012697d8989ae5e66e0c10747a5d529782b GIT binary patch literal 1454 zcmaJ>eN5D57_YJk^Ao4r#0~9ABHOgruls7psmJvW&T&AF6HiSBrG3j)yz9{`-oYZG z#%)f;uSNM|0gW^6L%}(ck9YK&;?tI=0*9Q2kOiO|9fwa9IxMb)~zh0usdQ{K=VwcnkfVzW1 zCGY}4s;xc`au6hCo8t59eop}>szHO0&@seEC>EW(Fz8T| zWX{XGCf&i44GZXcm?Ma2G-`-4234yhD3)ajk|t;xhZ=aKHlzzNJQT@FTHrxM)ReHU zs3A0AQK(RBbQ=cAPDBw5dpwT}ha!`?f>|SCLYSZoBoPcILL1kP=w9$YjVEeHe6?Xf zctJ$1(L`7hIV%Z<>3h1Pgd$|a6=@2ri?ESb#hM@p>2BVJ!7m0$kvNOXLFF=}kujU> z6ykdV9 zAtZvNUj_P|#9E$;c(Uf6bDpYjRe#%N;3u$ea$0?N+=6c@C59CMV+4S;Vg#f}B)aCYE=r1EYbLgj#sVH5 z4HgK&Y0}`>bf&)SfFn1pxWMO($K!Cj`rPGu1etQ$&D(vk{yR5tKU8MUjf-=Fj6i|MI14n0WO-0JDy zbbjfKt4R03_A0umYaS9_P`vii{N1hbH@^MkRIa&!-jCd=8%Ryxv*WkXD@fm`b1n|t z3_ibjNrQLy{@J%@AbBH4r`}q#*ssf!_{qLWfy)g9o@3# ghf_C?B6FrpL$=vcj^#)X_{1O7?JVS5bIZ5=2VyD>V*mgE literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..dbbeb1fe16a90746301b8f10a46a9c67059a2242 GIT binary patch literal 1459 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 OA7G8UjyqlDKlmS`0O%V4 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..30b97cdf54c42b02607c803d0c6b2c4dc3fae9d9 GIT binary patch literal 1348 zcmaJ>Yitx%6rQzd-4rRsD2<3POn(5;*?H~m?2NnZZg+O+Vz=Ft1sfj;)0sQnX*-Y3 zPP^MR+K0p9{aGFw(10zXS*=q~^VtBlWS58Q zf|$V2B^A3PfGv}1i6_voVF8qNQMg2sB+7CwAd7S>qlnT|C{5B7LBWT`DVC=hp5oAz zfkB6stnkf3bj2Oq1+bKDn>;~eG8tEfaT!({L2(>MkTgNlIMl$?y}B)CaXnpKv><@A zWT~dD8ai6AD7G5ib^wE9m!r_kczo5co?gin%o>puO@eZfgr*fjThdP3&ES6;Yig&H zy(S=xo{fg7I)-#J zUQdXkBH<9@^9mu(Q|Af0!x7e7w6PX8EQAG*m!#N8$XCE}jE@U@Lmn@~)?+*Qa=-$x z)E*#5Eki?>Qp~GsP@vojDbql~X*cP`MbS;-oR{NpMsWk5M`RUJgyApa<$F@MT%}L~ z!!V0%c*&!1K8cZVMrIUTQrrs8`9u%ylNn9~j2i&XhY^q>QK*`Gs;DS}rCC_6wgud* zHWtufH(9W4@C5NVY`L;TLo$-j=izeS)a)w=;)uqCP%?Y<)>}V3d=Pa;zRKrkpVp?^ z)iKAf4YyN22gV-Q^T?*9v7Z^$#&hk~$fsT(HMj3b^reFngBzxPSr|T5-}krPFthE- zn?c%jY5R*GoY^>;BFcCB>juyA2d=XZ*)wKvVu8GNxblg<%R>|EuFg8z92cM2bozQ@ z?Kt*FX`g8Zk6rmc(J&LkP{?zTlj$diVIN zJ-0Hsn$VNKe;Jtn=fbv`@|Q2Jd+v=xcTOHz{OJ4Nq`wwt^Cb^{vn6=vv%A%kNO0J3 UgZ=Zn?!td97HJedsXH+EAK;(UI{*Lx literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7ceead056debf20ddfb783cd21f49cb053171ddf GIT binary patch literal 1347 zcmaJ>eN5bB7(a$t@C(_m>4ae>7dcaK%&f^BBV`im&3l**{ZIJ_$ z<%TnvTb8+Gks0-zWM*Q_wvdQ17$CST&Miu|M1$MnMKHgOMJNqB)X9mM;`K zG$fge@wLnD;K_@2T9(e?cwb+iqmOoIMh8x^EQ=EqPEi=tz|4Nt5>l9IRu(Mqz!VKd zw-il9au$Vlt=ICRknB z6#OdC?=seNPb?QSfM97xT+_M>O%UzWEY0lHbcCWE1oCu55EV5i*_x}+QouYgl$U{2 zYiLO%pJGl~g#zi635fzSMmY&LCJ0UfW8Ex^(XtaTF2N%c0t|l%FWr^8r7ndM7=~V8 z!-+1LWkg!UXo;3FQFh80%Lp!vk!V%`v=ac9L2*bC&vngRT~rXk*34~J#sVHz1`DWg znhZEL;j`nX;K;3wHpD~OY!+^JPG8w;vlWHHyg#1$e*XBy4X+Xrir)H*qKKk zDN*10?b@NEQ;8PKUc4{;?f!w?J5TI5(e%R`r!Nzpp)=wynT1{15&QfBx_A;~;^$lT z96Y+cr|iRB8?Sx5n;-7(snnVE&2-}GFm`A$G3i?4t9k0lm+BU79GN59S{G-Yiy8M< z-Dz9%fN%Qn?Csf`O%oSB+Pt=GdZ^<-=GZ^aILc-oY-zt$7fJtGZhyRJ&`5mVcC-1` zJD)aO?t1Ui!Yg}Ej@8`$>ucYQ`%?Q$F0KDb+D!fK2Ew`zrWc#8Z#_8l#k1)m+neE{ T(RK4Ldr%a09RHyrpqLujRF1eVp`q;U>t4Hhz`c-bJRm%kXc}*C_jj8Vf?N-vMX-;kdKAzu)h>-_Q5^ z`M&nq(&FVaradqX05HQ<Yh9UmjN)jQTCK;|?HhgEV>y$V;>7kk9|YLS!h{5)(~ghvJfP!q67pe7jRBNlwjE|2zcF^OYi zDq6J#A177rF2(GM3Ne$8CPa#&FcYVPlEC;_zaZvf48_nSjcyY`n|OxhX%3sXaO6;x z{Ct_CaKarrS@0@N3-KgbTU)EEWp#>LNzxq0krYER41qL=a9vOnB1ABpm9XG|VNsPs znydt|xJALItkWzwB0C;MAmn!6G#m_1?p2?*zhH)jOrrPI23VR00uRe!-AtPI!TszQ=y%6{<=A8%r@S--ZH3F(_`@Oc(?sL(rn0BRB)Y5q>{yV)UFz6wE$+0x#W?y74YW z5)?)#!G;$Ne$FhiBEd?mpAh|eKf##=17Vg}PJpZ)Le7knh$0#9np?UkAwsPg-`*Sx zbhtTKFo>o}jgL+JPrK2`O)XvFamHdXv|V+gKMFunhs$C0L@xZk>#MetSgMnY#rl`N zvT*7>6*~%gW)59w`8zb{ZBC4ceA+ZLRCbvg-f85cx#Y%?xpvEE2ai_f zr#Rj?+B|Zu`L|iuHVt>~zfs;O}^x$1)wE!(})H9=vn(=@+t6s``UMt zD|%}|3G>~gJy%)>pRw;v-ZjVl#oX#Ha3!fC2zCFQX9B};1mCoiABI9;BfeqVQXjh?z_O(B@$}4wttkyh-t75Ry&LRX^!A=J<|*?J9=BZXT>qR0)VLk1 z{81MucAoh;4dZSyw%2gdaO+yDRo literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7af08829b8c67bb7e5625d6e367612c3077c1374 GIT binary patch literal 1478 zcmaJ>eM}Q)7;mA|`Zd1XWRB_Wn1)5K_tnzgg^HzDl#j9w%f}KGj_X^wLGQZjVGA=@ z(M0DaqR!1N*@kl@Ml#fGE{a4zaZX((&d=ZU8{Kzv__MW8S?W&6;P21uu7Dy=$}VB zQAG4u(GruBaQf|_Qe0Z6fMsKWh+S3yVm6SNKoA6CW(>f?Qx&wA7ZxHEL6JBKZ!<=kS&C*!1{uFl z=uq)^*+MRR+#Nhw(MnbIvp60M1`R>lAS6|bu1;%p)vxbLwKTaA5+~4PLJAn8aCa+SZowwH#=pIAc}W0KzasQIj?H=|mbEK@S7pU5%hk~)a8=5x9H^B22t^wRB+bbSq7;$59;wh+ zz#LG-)xeXj$UbB=#jN-g3IsvHxJe6U;?pUN6pReUm?#GGdPy^7WXu9@sX)i^o+nZ_ z)}>Ga!|+Ghu!70USOi+YXb5kW`d?*UQ}fp`rA^(5F5A({IQF&N@LzlHcWj^kz6M*@x53r9t!7f%VDIYP>Xez< zi(JFB&BY78)L$-6JCvLd-$i1Z+g^A+`8)m;aaG&8ueANzt4SqI54*!{3(38WYVcM; z>TtcQL7m<>vuKuiLpWv1puFPtTm6SF?l)?$r}QQC0_D!m;*M5b?m>O;)~Sa23~k=c z_%++|A1CaZV;w%*axgV~Eb05qmme34*;}65TOaR(G@!S4M^1s1_ z{lL-t3)Yl{PM7_B`J=pnBdzT{J)f;8YPq!KTd5~j_gI&#xpW}r>=$dvYmq-|j-!BU I%PMd959gs4Y5)KL literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0ef6d471df6c00a27ae6135757b3fd98337e4f84 GIT binary patch literal 1609 zcmaJ>c~BE)6kiBfbfmU+P)c=Jmtwt=-Q3xgG$h%?KnW%oDvqP=X0w5nBpZ`O0#%#A z18`8hT5YM8dg0Kb=-@TZh^QSE3srlJrHmuB*j8Im${>hJzW}lR;kdKA-}k+JzxRIc z+Hy9bMhM*Kpz)R8j3=i9xT-KvTx=%MEFzZkw z3*~0a?A0@Qtf|p33-D@9@> zhm*)6jic_sNsZ+3yq7@H!oosPp;W~Aa#1mk<0vLUB@!Xf5c-QeJQWan{7GR8B;%)j zte0mw4;->c*|`EnN_%u?DfG;8k>mZayy;vv3 zWKxA(D;68{TB%AwYH_(vu9xWzN=4Yli?FyJ;EXDr(x5eluqwS#r&1a*Osv8&rA`vY zrg{84<)N9dUl#Zs#cE%QCGp_rE8LR>Dvg-)kfDUsnyno`-3QM}{1 z)Qxm0kbp3}VKxLUcj78qN(-e9sZ&ThWlkZkqU1uALyA+3RK_s43PAxyG}JZEbx~LZ zS~IkLHWuLUY_J#)m?j?>8*^~E5scgzONPxbG&BUZ+2?*(4MCCbrIA`&pzXqEi?*JJ z$CE`58+(7;u3vA^wcL3yZ&uvJYkQ+Nk`r4#x%>6t!J+2z{7YB0?Qq`AiYi0<;;1iE zFB=10$GSy--C7$cO|5c0jCf@2A(}S-se!VN>7K5uzTVN7et$~GTLV|q5B{^ia#{87 zC*sS0iHKRayI}6crKSC=HvM5}{dn879@D2YdM1=t5~s7L-I=4`qILRzUVUkUHTPak zTetDve0b-UuS`QhSkYt@ELm^A)kQ|h$Hp~91~0cX%dUq!1i`o7wm4*#SLt2W_- zlOvjMRMZ@auw<7GLgpf@;ioeRc+~xhL8~UxR58JL;bucpG?} z*&A--qb9*^^{dh%s!?if8k3Bk!_SX_R%n#2wrKM^QSsF`%xkckV!_q}OB27(@z|{= z8~VQS){Q-KVqY|5ta@;0e+<;Wzol+(mG$wrT`ObH_RbZ}LpNUP`*qhEWWd{bul?`u z4pi4|JN{%Flra>wFe?6w2k^c@IC!m;&z;=2`$}?N&jb l;q4O_7imw4KF~ytht5O^>Z^8?#f5(EX@*SlknY2h{{TjCTkrq? literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e6f397eb8e756f678dcffb65395c194e23b20cc0 GIT binary patch literal 1826 zcmaJ?d05kC7*7ihs3H#C=7A#=_J~T`w53f`1$%1;by#7bvPno&DA1;+0ji?w&`nS$ zht7fXKqgZ>7~nNj6anX)$Kx>(#fwK|b0})Pn4&D@aQ@+Ao+RJ*y?KA{`+Kh^xlz-n zdb38e008jTPE+aW)j>ZpPdEB~+cQr`FQX`R95s_LQkf`;19AhAh=W=)nuP0d)G&YE z34AgDxMiE7?z^kWV@6$V8$sFw42i`HmN;~-D_7$?_FXZ8|+n~ zQp4DNq~df@ppqbQ5a#kZ7z9BejBs%SDo7L>Q7i-$KmtCGPv0%g6A%fz%qb;^fZz5*mSq6V0z@UM0>57rBdW1uz!POAgXfVbP80JCaa2P^$qs)QxY-H9Hu<%K?_w{AVI z;{d1ps;d_6x>bI?b=g87379kZn|fB|qsUyoNbg_iTp3X2r6`PcEZe6+9YAFX;c+&m zrON3WI}BXm_W2!!a&NWuz53PoF2?uUn|uSDDU+Dnu7r40&e#zl5AImxyu7s43*1*0 zt{782+cf(K6L_)Yq2F05WC(aN{3GD;oh`gmS*GW+H@@UDy7qThE6L!6+Na09&Dy(g z1gj{0hxeYprZ(<9Jzm3rx`lXvHb<((VHp864QI1aQ*$Ly_p}EHcLj#{a%cuxRxORvMp3bQ-6s+mk z{mSIIU2%?cbE=U&3tnw5@yp8BpWeS_^Bw*0(h)#Y(u;>b+yj?0cIJBxa&x4PDwUt8 zDJTmcog$l&0v6vW;xCz(V#`^F4o%M#9&;a`m-VD`{f$8~jkT$3CnyeA0?o4JUBFmN z*X1$Zwyd_bcgIoYDl`{J=_x6%Vwo0`!I$q=pLdV}O;;ZjXFMox*O$0OJxe~ltC);T xwahvg=4iVVTd1yg7NYlGl@k=@7Rh`86083$lk+8}Et4W7|8#(9UG?c}t$Ru$k znWi!*6lSA=RHvB?v?^0&R2t1xTGYnVum)wCfgmXZWj0s_uoS7V;AW*7S6V0wt&C!= zzJSE|SU&341N;tQ>Ho!Qj3UoSf|xG|rO_sExCKcFxCK8k3CzU);s}T%P#3EhuL>EOxpfw}g z$72Bwj|YqQfoT%K*bvpVFc`Vvj+}gRe}6yN&j0Rg1q8)dttLZ$sPlTQRjk5C#dY0j zl{Ut&PR%HX`We}*cznt64`xnj2|+K0NA$=-P|KL`oxQrOziiO@s_tw1`@+NVn~M{| z=Xb5TU(#!X1mMnxuHFcDQ*|i&c&gpMl+4XnJsJijn+aEC6V;?;` zL3UMrX2jteE|d1g8N=7pu+Aw9VsqZ=I8IDTz3?kqe~GFNO}v%v^RC{usXM0a@Vd`l zTeN0sa^dKA67|N{7r7w)mM*P6@Stq{Q9GJCJ+A$zJOIUXB{?@6!m@k5sk`~A+V>Bw z_~T;A*3vfqz6GD&-SADU|J90NZ5`G7FXkL7-yLl2+_wakOcllu}-XKe&F4T-`te-8@e|Vtv-NLe+!%MlzeNB(9 z5@B-1nl0CwkQ%dLPcH<|`XN>N(NmFFM^AsV2JXD@TOV<*J_V9Kcf7rGZe@F6BWGGy zRO0^KbmXU6ThiD$Ib*(^pihdsT2!A{yR&J=v}L~}RGL}@DrVD(x=SsOeysOkUdG9$^jXf*mZ`{TB>ar}mEM!{A<430 duB>9%^H8(&T*K`zTq5W#$ZEEm8ZwJ2{{_<>OVI!T literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e43b1edb862f1f9b0385570683d28d64f80f3f73 GIT binary patch literal 1679 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..96b19669673d0eb6642adeb63c53d5c4546b010d GIT binary patch literal 1805 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 CQA6wi literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..49aa979d745313982d58025ced17c4219ed36138 GIT binary patch literal 1560 zcmaJ>c~BE)6kkk4M7+j&!ldgmSQIw9o6WUbgCv_oqC{v26{b#cv%7&9vKx~X0=1ra zqIk4ZwX|qwI@TGF!ReqKv5Hpg_=ipvr>#~Qnc~rU;5}9==@%f@KOA><_xrxL@AuyC zUAwMu&dlM-lae6_8t%xmy1=>&Jh@2<@V=h3$qAN;vaLielDu*?8xkNhFL?ym5n#&& zm%#Eh3(pACAxN>p=Pr>;ocS~-1=MUzM;!?S0UCm)&xizB&M(NYM=1A+CZwnJI0E~4 z6Eaul#GOG#sPN_0hJ>QpIc~1j&rv)wBL|)yp@D&bAhU2JP$`D#hzaSlOM`t(j3IEJ zitINb{iI5qg)k$91lXV^P!7j&*g&ZTp4E6rFUw`a8eBtQ1h@?-VW2f6O;GT_g#d>k z-b=fz_5pX`WI`%rIY?tzb#=A6np8`na*UuT3d1#+MuP$kG+ZOfYy=g<>2V8IAkrv4&1d#2IA`o;sUl|s|1GxfO!y;@DBh)w+2*g6`(+Wo!n0+{T-*7Ohpo=nQs)&1{chEsWh_(c0~L3!%5$twbE_ z5W_Mnazfm%5BMFx+TMz#nUKKBQphbymGLGhtdL|WTpqzyd}tu`u6li$NPYWGu}W9*F~5HceB?$1Zg)@IpNUqQR}CVodDg7tf-IlJ-H75rRx zT}s-atz2%^(BhQ=m+d+;BsF(sY0tEs9=&2;`iHvHt9EqVADJeO`}olZge%e)`TV^+_mCxuzp?9{huCY1OvY)opU))kDM((HYTl? zd32T8le+0~(zBj2_j+y4^VFT#`Ppl^J4j_wSvq{Lw<&r{ zb-xR)?OK(8L$`5$`;((vE?j{2{qo7`B^Prh+&g$h6n<-%kbJBb9ow#YdHb7rPnF$M zmS6qsz~^5a&!~KuH<5WiX>s&H4z=yrj3q1U{_*b~zkF)**7iG0+blMtb?Bwcx;%IX mesgvHhPv*JCBMHMJs(n}4LZ}juem7puXfnxSPxj{ulNsC?K+$Q literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7739e294ac6ec6d9d6daebb993b38f8c2e693474 GIT binary patch literal 1492 zcmaJ>eQeZZ81ER6-ExEBrhI6ibQ4Fk*RQ+lweDcI`(Ov$Ty6&roUpEaZ!7GsrR})e zLY8BIY%0zP5fn_w$TY|Vf(}2B@G&9IXfU7{QA2<%0mS)%AJc*7d)p5AgV3~n-}mYB zd!FC()%J?=1v%L>vJnKy@t1jma81CcBr6lX2eLW>aG7p+tBgt|Y{Uc&ATCL%1*ktF z)PW!nq^33fpcp|iTjfxdQ59Isi%P^Iq;xFthzijNQanGd3gT*DptYb*jykcQj~v5L zS#n}e+X7@jb%T1jtXTt<&E+And9}z%*!+2Dah!(+BES&Pc%&h!^KmCOVwZ>el$gNK z5fx*#6B{K}6{tYniUv^DLg6Awk|@hrfF#hhOjr<~KxvYu2nyaTPO&`A@DzuRT^Mwz zNnt+d@r}8ICnr{K7%EQ?u~^I!V=RhRM^GHc5hP8}G!8Xzy(wx4aXhLQq%C-WE^4xB z$VwDVSrlrOM#G6gvZGN%)Ii{l;ix{AE0{GRE~o@$A&E#N721flZUn*qH14UbhniGC z1c9zJY9cI2xF8LN>ASz9lpp2~ zQIyy1VjOmli?fy5+*Y@jwWn>|3tQ?SefCn?$9i495iDtC-JF&4xx6e%mwMA!e^fVw zs0h-2W$1Sd>%A|QcWXc}6fLAE4e2JRs8-RcJI|576Yb zK=Nry1RY5+FW-X#NzyQG%7NPiJB?GKmBTq3&EerN#nM)e6$M8vHinn(O5JFeLJ15* zO|#)eTbOf*jEFN56UN1`HH>o(!G=2|h7$l|1%Pv41f)o$y5_DfN{e7?rnYy+0v_%R z7Kp-W(%{(a0o`UeauX{ShrG#T5^k5AJlBFC8Rz{TS15kr#%n)L+CXM)8a|p_L{K|l zedv+kj`n5A>yFKRU+?ct_Rs$%Ki)F5&sw?nH~m1e|Mbi<&>upYv$huFK#2ajfrDJCYgB z$$Z_LFj0Fg=A8u@`NhkHtu;NulO&B*th%{#s{akC9f*u7!O>B)Tl!o!Fu{?FMP(UO$?Eg{18?s8yzhs<6Q-r~%VKhE%Z_J+7lT))=k`kvWPSNDn_HP*6%I%>@Tfp{SUt87d`+0 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c36e54b2fa31dfe36c236ecb570729dbe8a0d267 GIT binary patch literal 1472 zcmaJ>eNYr-7~hj9AZ^OZveLF?D420?zwT>yIN`XxlN&i;0F$PY_IBTu3-%w3^@;uZNN;))89m9VUZXr{qI0}9Xu)KDrz5zcU8lXf|{j)@5j zom9~)oY)kpQhy=pRyBay%@i(@B#GKtGmr#2z{rBQ0HsNqA}BcQIA!N(hND zO_I4H-aG9M?wnY;u7^2-sI9Fv*D_{RTTW0c%Mv6_&@>J;@JL-q7YsZUNsU|JK}6Jo zVLhmZ(3nLbpjPWn43eFSLJ9l*Hw}j()476KBMc!-P-c=)lvrq!+7Z17{7>Vy+L4mF zFd&LRM6K3DcqMXb91PQUXGbwb$c8J>g7991N?sMK6%f*Wyc2^bW+^CfcCVYtVMq&O zv$`nC<90C)8}DMRIaasD?Xlb9Hg1Qtxos5GC+!}WH->dsToj+fdvbCdHpXSQ#<9Lo zL>EFLi2Dsfzf)Md_l{W3tpPz-wGvgWj2A&+xvHy?ay5+7jG08!{el<_#UvTA8=4B3 z2U@TONM21<(8&~Y!P`(ENgBpYIdH3Bqj5^KusCa_SzMMWJ8fa@qTmQ%(|GBY)J;_> zl)x~;aWg_$9*}UqD{a3`^w+?4nPE@czjgAcB z*qemE?}cNT$)^VNfB$Up)h|L4nMI}pv$H+l7iJeD_qFg18A#POVkEIMG5SD5w|Qvj zK!Oovq}3bK9_buDhd1v{T-TFs`l@ej-SM_dFZ1(KK5E>zWAm@&BW=|tIWfIs!?#K6 z^HPz6Z&*eu)uWfJhvs{qIr*u1<k>fG0XvX|NI`0z-IF<$o2d(RJCew?Xaxuq;Qd-Q$p?wPBeYs^hUT7PGjbvNI2 z0pEHt?+`meM}Q)7(YHHl_?IF&1l4&rwc6E^}Z#XD87ZD*NR*clX95!oYC6p#_3GaSXDvlj*( zs-mAOcerNV!IK3GXqv(iL^K-JM;X1W)({lSvII#JG>tkt@*-=svvf;L<608ef>yU-I5D04}4hsgq=tW87j4nH6W5`0L z$Y7-?r`^h!iX2wfU^CbY?M`D+%Er7{nld<@Bx`h9T}iBsrWupVZgd&!CWp=8N?}XF z5seQEAmvv|`kld=o`~h_D&RF)^~!Q>stG&+S(76HSwU$=Pof2GUXa2`$&1Mf%>?WK zs`MrhU8)>Hr&G*H^H3m38pchTa06dNr5mPa9h!LWjBJPoh@-#y|L?e-`ml;m()4gsnPr1 zt6jNEmA1woHa+OnOpG3=+O_rd^agcWH53^=QEoN7Ddw>W~BE0^%pKq01PSHvYoXbyWH>scRfA2+WX6C z;ZOEaE^_$UA^P^>-_EOF+kD@qmu|S}TQ;?3DF04FvuudIPZt)uA-lryar3E(anYf(UdVDljx$)@W!mZ!kY;PFeyZ`$p@~2bY)i)T>(Q}VE{P1Ld mj%~Lt_FOz-y^!%B*N2?=EM2YG{9|VFZ(8CkbDXmI8vg^(c@A;_ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..2c096689a8a945696d57da9e0f3ada1f10cb5b16 GIT binary patch literal 1513 zcmaJ>Yi!e26gH(mno&SQtbky+X0X9<{7T~3G^I(LG!ae7LIx3&*c`{9fhIP#OHv>O zK^f1M@`Hk4(gtgV&;}EO!gz=x*cfP=3abRwV5}6z8&Ntj7-DocZNvD1um4bs~@e0ASl=4=KNq@4!$B?e=z>3+vo+;D9stvW=at)!7CzU3risp_Qd#k zqF?00l?%^`1rXGKMKlo9g5DBVkYWZttz$^WWPpaCf@w*a7Z!*b91`b6<5uLs(PjjW zhONkKlNa~O4zVoiUaW{S7ncTv#R~)`j7%$p3z94_5EC^XPR7dPDx0(-J$6~JPKz-F z?orVeSdm^*L9Y*XNQwy41_Bju9EWMfAclD|L`8UE3QXc8ff3-PQG#YkiX|Ah??He= zB^+V>oU6|r*jbS>O_Ny+OC%D81Z9wvc^JVk42F{!NuodlRV(8fpG4#8_>2WkR0Sm} zYf&iVVK}b#Gx+mm{>C}ScSG!h|b(#X&PZwVoN`0z`q>#b5C z0b$4)HmqQZFcyIlP%2DCP$6QBpp1n#p_VYk@FHatMaF_)fFhQznwP35BLbzFUcP7x zuzAr~VjOgn0@|j!bkh*fasz!O0cUr2H&}jnvb73=`rY+#wm|Z?dt1-fpMrJV;qLC% zB}cY%oZA@MKlEzj&4xWxZF>=SC3&re21E0JWe?$FOV3pfdA_oy7CW{6_vfd1>y}t* zMwNc;<|l7<{M7GQ?aAZ#t|xa^ukRe2HS%ZE;JP(XZijwgb++6YTqEVcrH>k?7nKwp z?7F+Dy%5WtKjOs7%hNB+t-o9d4VZcV%X2$672W={MQzBESAE^MZ}-(P`a{&PyQiD? z22;g#rq)%qrmSFI7w&(5_*cAV%IwIcZ%dXOoHa5vi9UWWHPM`FoOO%zHLkvHMt`i| zIN>Avqnd?z)1D4`inQsMx8)Tq{de&9#IIiV51n(FN1fQ-)RMn@c-F9~4;KyzO}KR; z@x`|KLyr!wgN_W{qubD4oIPiJj&6-HyDtCPoiXQcd{F4p$$8Dlur~9S;`RgY?7I2! z)p0pj3Tt$}i`j1acvXD#fSu)jarKeGlO6Z2G!r@R{&SLQdpzU*pfkGX4dW2&Ul&*G z*sQe79eQK>-`|W{I<~o?s%3jlhdU&%ebBn~?JWle?z;52$-VWWucAG%?K{Vu!;8qS z&hp5H&en++_E%!_Q~p7-PInci!k>FP&Q88=dscmI$!FcqnhN%DHv-xl)}xb>`c$xb pgtYheTl_EU)u-GU$z7E_68d3k|D9O=nEdq5*W)bZ_S!#L@gKt+D2M<6 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..792719974b8f9fd47ea7180e8d635612b9df10ce GIT binary patch literal 1519 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 Uat0f1lj46(m!rVmmRDN)9}k%S>;M1& literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e9246c0b7ef0569d13ce7cd90ad126c82351a2e4 GIT binary patch literal 1456 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 GZ1@jf+6?gk literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7d3f3dcdf40a3cb632670a9ffae7338659714644 GIT binary patch literal 1384 zcmaJ>eM}o=7(eJhvJE3sGa!y#j+n6E^}hOb7b>u}j3$(owv(b8>-Fv}y+QBJyTcY@ z7$YRhbjcPHv&85?)GV?El?69tZV1LjFq;d588u6cnP0>C7gOV0eG3%#2ifKB-uHd( z`906?`MM+i#$AOQOE)42Qs}LB2jJQZAELkn-%pLuQ*bFUJYgfK#Ec}b0i;$`q5$@lE)bXMyEPE(ZVUCA4Fz8Sd zV_d*px9Sd_oLJm2RE{8$$)q{Sm=&#!pjehANSdH&9BSZtmu&DUT-M987TiD=G)Xli zMMg6g`KZ!qI59|eC5nXV^Q{?{_0?R#tPv?*B`7mVBodj>mbG;w0RE@3uC^ZPQUMVF zy3(l$uq3haEEuNm;f^wjkPWw6lVDx=4!0t7CV*^s-A)XCF^iJOMFj@fNZ`O(67aal zSVWu$b_Y&d1)i}+MO&1nvUb+PQ&zX#!dNYKD{ZAHkITW*jK}J#C8;`Ur-!y=v0hm> zcv%2h-xBn_ie(;(*CkxV2c2qANA|tKym505<`9qHm|7<<^O5bRkJaF<6bI$RS^EY$NCKGn=Si@fn zxvgczSNbE@bNkiXFYpVwN>Sdlu-T0`-s(MdheN5bB7%zjt!VZNPrXXr9%ap`kKks^NI44~BQVx+Fa+{3MYv1EKxNFxd-a!I8 zZ-g*|Zc8+qGwKY>%-o`hB3YbMM7P8tVaYO+F*T@LfYPEkTq@J_kH^O zo{!)2Jl$7YQ<0UKpNSwyR#l}~2iF*Uhz+UmUGP3V0+&3q%xiAb{ANTl08*l8K7dvQ zr4~>JB&B2bH=r0nQsb(}YkJ+)f~*CtQbNZX4eAh$AjMmwx+J#(6ZL@>HRQx*&wPQQ zs^Y{NY;Mx6yFfs#>@>i(&Ki&0*(&o2w)IK0I4VE`L10Q~G}smj3sEPwWLJRugqXn4 zB^9&Pi7f}^b=RUU%>XE8rEr-fNtENQK#^!4z^%7X}>~ zieIP`%U9gNlM@S=rY;afBoeVk7^`Nq5ERez1W6M#jYADQ+z~RRC>{zICM}2{EE}qB zs#*w5Sd@HPyXnMWu*+Elb+>!fa45XO6=aQwN;*MVNg^0bq_(6THtWFuVXUbg_H^ig zr~_fG-H>5P{Dny{r0?#I5{fVy;aNk4b&=XcO>Pf@kXa= z(36n}vgD)e3@72N!t=OdXKlE{FFSCS12V~TiX!m!O@t@e~HE-u1t{m7+m1WD1W#1c<*;y3TrO?y#G>%!uDk>f*y zvHSM-+$d=p`l*LK#)p?}DmRbwNu?e!lPY}uC|%kO*pviJJ>oul7xcHYyt4rTPNw8r#w@%AGJ ze;-@_nd9PXl`RLe`x|4EvzNb)H%`usmMk3X5wttS9$ZJXZ9RHns3@RBDaiq*C&54 zgPT*M@vc|@9ghdv9=e778emVIEO}#ap|f}X%BRntRL_6sd^)TC^Vxf+zfB*#@Otpi z-lmO?bAy)C*SZf|c5eD|n!VY8qd%W}YwCrCfpyJW{(9i4j%(ZJJUzQcBQNz{+&xfp ziJTm7*pY<>hA$lXF=uM7#lj-TJ5s9O@%__}Oy-Pb9LVi^cxExD8Rh1sl literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..bf97f8d6ea7ee9d0df8714b06ceb37d5231d9444 GIT binary patch literal 1326 zcmaJ>eQ4Zd7|&g6?MkbT;lNE?$Og8M!GJD&u*4t@s!)f0n@AX1^NtUGE zwXE(eMNn}?w!u(_-xWbhL2;;HYyB7sbt+TrT-gM5)wQVqtVr4Fd%a%WA7vrQ`@CSAqj0<8t~M5`;%`?uBAdLU1l?)I_;8M>Nd*q&jT zc+nzItv)YIAhM+>vUWVaX4rIBbA_@-=YdVL6hmjT#n4u?T`vLur?IZKo9wqCoq(>@ z=V+)T>Fs4OO5e>L6%`R1=^@8JbpgGyrS)Z@>BZzQfxb|>p-VvkRRDlWY5|rdIVfl( zP}4lA1{nhYvZ6Hdfl!OWwKOwjY|L~$U}~`J z+d#fov5hyyO05nAp5-JhtGC<;9U05B+>B-898WQLeWzjSR?clG)~FP+3?1W1sPA&D zEWVOt$ykQ~;2RrxPK2b2I-L|$9Z9+xBt?M-X+h8gRz(4n@cIqOEA=TlK|$DME)v7S zbUFuXLm!ooP;(Z=wZTA}wb6nmnkNSh z&fzcZ4QS}9I`$?Nv@S0%zcus9EQa~0nB1JqpPxVZ%WYG5?eNcwM-1)m-TP;{=EwHW zU*o8MK6xZ_yPS9@x%0&Cx;@Xoeqr{kur%s_Z20uc2Oi#d_3Bpt^b>x}MeXBcF|a?fYY3 zU*Ux}E@Q7IW`dK~Dvw=1z3Fg!bc-_Hf7Um5{tMXm@6vSS7`7+(_V4dD%<|2PKXh(9 t_vj_AuwmrN!R4ChpjYcZd2uuCtHQXETaTW4F5FZ6gT<6~d90;t=s&rU%P0T< literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..39c910d3a41314c985e4ce79337cbbf30d1ae79e GIT binary patch literal 1597 zcmaJ>eM}Q)7{5}5%D^dpRi@)O7`W*5?s^B;R;rYKC`z%G8Y+Q}>)l)EN_*Y)Sc`6o z=qAjeQ#WD)}yh;LPt4dw`DnG9mu!RfIf~Wx+2mqNwqk+0$*bp^hBX$i?jvW&i zI-(-`jo2tDx7~r7MG2s+hQfK0BvDqc0RpG>&|Z$8hiXYJMNsf&af&r)X#=H4$1V&y zlmxHAX|avDgF7QuE6X7RK|~@EO@!8nQVl`r^?HKT5?U<|HSlmlQ0Ag|Fq{>)U;$xX z@`Yrd7(`SmTZhvAp7#_;NdvV zgY$V5g=+!BA+9YtBqdTWuzYR#wf^hH)} zk%^3Bi-TdA3-TcD+XsD*VNK7)8q5;lWKnX7VqLru9JQh>hHJ$Ts--m~I;Y$h6vRmQ z)mV*2L$(0P_ZARrk{Ccol5Frjg8)b8=hIpi;2zlNIO7qZBzSZ<%g~&cVR(k}zyL<^ z!c)l`?NfLHg9ydB7)T0u^LR2J2Y}JzJj+nHhbFbSmt$F)CMg}muowX;60yE{s*mDF zusLJmlfi(SC!+;|aGoSMIBLq(1&1!tQR1?~b$EDq|K+_`5G27^Y%#f_f823bZBb^b zgnx(k{&b_X%C@ij%eKlR1xz4AxW=oeHrzdS@wL@=Po(b|Y|8y{=6&U!_b23JK6qSl z=Ul(3U+Z>w81&36ROoa>Vw};AiR+k0+1z%t8NFY0jwL6AiTw!i~cvHBP6VAaH(t%~zvICA{Agl`I%Vxu z68zSrmC0!dz3ofM=AK;@KX*2Lw5i2p+ufM1m_OK}@82}P>xjFuZtgeW@!@ny9%#*) zwmG$JIs3-vs-E7n-E*90d}+P&5)voBGI-Sa>GrGlauUsV&W&$Ps>}&tmW&aP|S$*a?s)anPWU)!;^ zL#VILC2LNl&CYCZzS55@y|-=+x*uu2(bC40EMboCNF}Cqe)a1irm04ewgSz*9By^% z53in~QmPX@4W{I>O!-`%ZUS=a#>U^Lq$RausA>A~+>cfMi{lcGP4_BNmUXd;&QI)Z z==qd;({~>{d1mb{bt%%QGTu(SaN34cx>QKxEJgeM{Y=w%WCnXCBX!LKlhR`U;qFB literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4975adf8627b62a22d002bfc1d7be423dcc5e83b GIT binary patch literal 1754 zcmaJ?c~BE)6kiEqM1gwIQV`cr5o$NPn}ZyZawR~JAjTlrk&(@2V^T;qCJO`*jYwN? zzJ0&UL^uF2iuI~ADov3n#z_MkbLz0I1`~}2fba;b3Bxl93RDvt^hOD5;Pe?5sMknX zseA>ZFvSo$eSE%|Se>7w!t*n6k%krVDHv`Q(*_I#g@IN>meC@%N>~$i#kA}^hFRc* z3Y95gO_EAeB!e-enE(ZB6v7b%0R;fhfaICZgT zhh~jdtdz!1xubUymX4xKVi?ZN&1L6u*`#>`jEY1e7~#Mi4n%7}mOLYcSs|k($YnuF zSa7r6MCnN*=(LEb$!to(qRCE1VK6BaZwwnPQ@NtE23s)`jIt5fU~q;up>3g*#D6s2 zscli^nFv@(SjcQMPM1U*c(#EsQgW$;MSo#y^ct}c zBh(m%sUe(?q7aAR;Si?Qav`-4!7-r*!?^;X%g(#-B9TB8%jHA~I5HuM%3?&aXsJvV z#^sBmWt`|J#D$d`Efi+N372m@?RyF<`d_R##!O%oX;zVBma7qxbtFYvbfgL7aM=hL zlBzdq$XrXPvqqC4O9`_+htR~DNdq{MWU>Ao1Tbz`7?&d;AT{0T5Kpb4C5>7L33yyg z%j4lZR80pkiPyZ9yvaVLPv{^_E-qpOCA54T34;iNCxUPR4~5iRgac_Yfq=_JP$7>e zV8Jv+*x5I4^^xm{ZceB8W-#c@o6#bS^gNmA!MWz%;YAOfM{=S{Mz0Qs<3MNiJpgd) zl1rmh)~^1wcgr6m%w~t9I_nxTE`~My=&O-8 z^gpbe?g8|F%k{EVr;;O0dg4dtG7da+A?1Toh{ro$cLX)S$u4NTs#)APzctwFBm`J-;zH4 zG~j+QWNYc%rB@myO~`n2pzYl30R}T3&QPu?0OthkE<)vN@N<2Uvm*Pq+pGAEmix8S=nd9m#njz_o z)mNE70C33D#l~~-VT%Zg)r&~Gj>xJv@@N1ER9KB9wTj_D4U?=h$b~)C7lfdWmJ8$j z!;mmz2$P~)kZEFKGQ(r3%vF?(7Aod~fmVVypl3J|wCYn0X2L2LzP3y7vi%qqg0EG$ zRdV4Vsrax+FoZQRATB~73PBJMmx&mf#57_pNzDc^1Vdqzzi|k~2~13&GH~b;@(xY3 zmWWoWhurZyxiE#}j06l@EEbVPEMiT`Fe;PDU<89P4B|B)bB2Kugd(LhNr`dku$_0|Wini*7Go+LQ%O-&6(UmwD^;ohvA--> zg$2(;hOwarGe;UIX4tom_dSGFz86b`m>7~{O|dMSI@}16DJ;jDQ&=O2iA4zL8>chS zti|kSuhC%0O2(v1XK1yF)q}5-Oz7T0fD{J=h%uajG<>H+5)I8uv_=Zy5;3WjNGJ)a z;R6`N({Ckjuuu6DJ_zG57Xm>Utv`hXKnx?1K@=`QA&nTpAT5dGVljeBB@$c+^Aurw z-@MgF!$*8`+Qm16!EfG-7GvP&$;1!Nn#4Z)*f~WmidFIJz`#IRsv7#R+qh3KqUKV$YLpsF+-C>Ad1 zW5>=dVf}1sI?^UO=z_-BRDvKiqR!gx~J?s>wfxY|O9R z=3<%TTyv!--`al0bHepClGHZaLthvA+^UGKm8UDa^XhJ&LO!34xwW?BwHEl^*cY-~ z<8`=PGTBGH@UQB_-Fu367GaZe+zy?sU%%opS!1ew<>HilXz7!K%hYRTwIl^?#-}*f z1@ul;6k?`QBD!{0eq6!w)V()%oo;Mv&+BX<;EJruyw*DRnNDc~;QgB4(jyyYOl#V4 zKjtX6d&H=T8#b$@NiiP<{E*-MHL}KC;E)jSZWDr^Y&Z%6BZIC-Z|b#-?HQLFTsSJS z@$Q#_w%gOBZtV~6c9!ORQ`9$FQ0rII=XiRz?nsY&dH2H2<^3{|#OCdI(@=P&b)sPW zyMOp7w6(KXWo40nJ zY|eY}PX@?#b!4yazvau+ju3P#d)l$6(`iE4%ZY-9f5|pwy$K*30`J*m9hcRstx#3CvLZO?i~j&Y CQO3gn literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e6c88df92b73b89f1ad31810be1a653c3fea5d6f GIT binary patch literal 1686 zcmaJ=c~BE)6we_o2w0(7EJ|I2w$PgFkwB7#KnMwk5ag0$7>>iMhk9}@h1G@VD8w4dC-Ij zQz+w2lFCpgLXotYg2V!pPa+5ciKPNcOJEwIjvyC97=ocN3SKcE72}u?N2Soz!vg`$ zS{ z2o0YMLQy_OiAX-7(Fyq)2|^MQEkO#!5~rUR;iXcsG)gGM#F$EgqN+%#N}*J#f`vg+ zg$h$dAWm$o(ZUc$l5)n@gVBBu}%3uuP66woFJ6ABP0AYE_N z(pF2L=2MhN$|uDll&=vY7+*(-#X=#1N<<gi@&~&dP#;2;lXt&#&t~K0bu{c{|l@Y17 z>-RHn7{7%);{LVo+jqBhkqhwFC4EtW3*T<$zCId!FiEzI1fFWbckNm0!wC`F3?{`-k_IuBzxtei%cnRJ}L)M0R{}2G+6F zZG*9Y7OSOh-!=B>@A8IMxp8A|xO=x=!2Y(+gJ-d;8f8QB1>^h2=QL`k^?dIQyM-j| zc4sTxD_T;{yi;1W<)2XO1@7zLRZQU{WAjPZ3s_`D;x8k!Rx(r zKja`3H`3xc5OAPI-m|UaXIjwS9Q;g z|NJ!wnLSd#RzRm}F3x!OXko;eggHLEjEeb+)zxy`<>_YMQx@?^U1w9t;}c1K@m{7o zOMYbiaeBb(0uyc-z1&v+X;R|B+QqeBmLg>`K?T>>PuurH!->W=`<=?xPu9n?my3`3 z&mOS$&p(%)uDO_#>eK7qD+r0I9N;9mtXS)}Fnc&`tj4{o`pL{(#jZ!9gTHL`??_vJ zfKzP`85l_E${B5GU~kg*br<+>+p_$N<2uSbpn2@F!~NZyb)lDw!Z{wSWiB%sx(wTa PLRqX>Rf6(}B5%!qVpw+j literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e7bae4d6c8e7b60de8cb5d4751ae8d9259a39338 GIT binary patch literal 1672 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..32e864e9827420142930083d480d331024d033f9 GIT binary patch literal 1540 zcmaJ=eM}Q)7(ZwQL|`a!rcUQsm~or;U3zV$($W^GvxQU^s++UdySJr6@4EJ&1vM*% zeI;gS%*lpcNfsA0gc z;4`?ar4Pfwol#va%OL|nM59qW%HUGiPf&Wjo*-$0rZK32MH)nzi(z6UKk2~=B78Uy zk^_>6COmRpsZKVkA=u$8f+2_Fkz+CPuvV~YM2rg&6iyPsU?R04?TG9G|HF8qcBHZ) z1PB+1NOfTzw#1j8G=}ASdZ2_NL}Mrq2Vh^gTC2p@1%W8rtwuGx!G(Ze&~d=aahw<9 z3n>btfriI8uaCjJI+Evf0>?9~F6rk<_9djw!f16imbU3A%4X5qN~|`UmMPSi*ys{7 znY6Ww5t$Qtkc=IGvCV7=tEKhkr`j4UVZg~!xKfg8lSHVfmSibXErn2;!AW##RX`M^ zXynC2kA_pWf^eW72&G{uhz=Fm5O@Lrj?rovngy5_G9A-+1tgoGE;=1Mw!5dLIL>q&-FN=xw&*uC4Znihe$~NUAEd-L-0kus zvktd4b)`E?wVS_whgh+2EWSyhisJ_sDkr2?m?x%AIPEvRi)_AFgWT)A-;$?9Zk`oV zLVYi%ps58@;_dEc&+@jWF$=~m*faKDX(zHZXH?WP`ciFt`c{|Fvuq@?>tuWXt{Vb! z&3Wz*d$02K6q9mm8tck5QLDT1*md>GvZ{VYZ1vUYuDk-xr(((|(;@q++&ZNF1LPs~qy>5Nmh?FjI;C+jq@u}~$RyFRM)b3xp;ltj4 zUf7$r<(&U% zE4lk;thumebThty%=r6+vRkAVy);)DQv5hN>$`!&x?{7-dKcfxHhtdGbotBIkc-zp zt~M^wT)%m*{C>Ksr98cC%PMNJYx@)?@A-Qd8ZCi=E6$PI?~k0V=*Uv$A3kUNA@v~h zY7sUVMW+zEytcAL|>t;DnRKT5(UD*ylh literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c692f48952c106373b56ecafd4bce7ba1295f5da GIT binary patch literal 1557 zcmaJ>d2ka|7=JXS#89*jgNP!m+d9ax$sTDpS(;usXn;T{(Nd zzTbE48t1HOBQ$Sl001NG#g-DZE=Ny+T7}*n>U9pZj8Uv*%3Rr}MENiTgNH=xd5nEiLNrG%rTP_l7>HN@+n_tNGvR(k32{1IG#b@L8Lb?y)KNyGQAg4`nkJA25vh?BK1N89%%lYij0j;d zq=>SFB`oqDxmq#di0nWV!H~o8)UXs8%oWO-F2;v+l$O*5gNe}kwIfOi{GY~iwIi;Y z5Y&~xh+G{OP)U55Nia&^iyb8t5gTrHSVVQ<7g}VYItV4jZZYBLi`FZ8IRg(pJkNUw zA)BHI8tMgt_xKpXV;}|I;N=B|H6-mk4_`zY%uJ4vW@)Q|qO4}4wa8+%<}lgDA}d`~ zNG7p%DWdR_0F%B&&{G~1zyRL+ zO!5Z$6rG?TLP;(hNkLz>K;{q->WzfJ>M6p*kTl`rS(af)%AnV?xDHX&CHm%>K1v>; z=1hoB2Lo-Mjuw>AJcZHVd_T8g6B@cS=S-Ist?_t#_wU>O03c^_Er#$s`}2At6RG*kH%iwIIOcLFlAe36?42` zd`H8NV|%w=Ik>{cJos)yU)9OG6WtnTd|p~cdKc)+S^(;2&%4_4jr#TWo~>!v`$I_3 zvoG$iyP*Gc$nt#$mMrTc?^4j2(rjCMyj&wy2`SEwopXM!ZT;kwq%d6%v)^Xy1k%`}eLa8Mr}TBFU}|SM{nDF;MJcVm>CKkZ6<_sg3WvFCvsz!Sm}nk; z;m#rV%4Nqss3XP{gY-=s0@>?ZeiF@xx#8B{Yx# literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..fb1c8bb9042d28b4e0ace883ea20e23cccf7ea52 GIT binary patch literal 1551 zcmaJ>eM}Q)7=Mf4pjZ{>2cnT%+5Eom(yxI)X$1^*rPK(UPOf)vp+fJv>tTx@P{C{x z7j+8*M>1q)W|_;Tna=494i}Q?<~E~o4s_87i!pv~IAl}Ty#?z0!+5#7_j%uYe$VrJ zzOLD^yg;K)Qv(1rMTJ%;TEpncO&o{bzbEdnqh+RID^p4(j}qi$2=WBU4Y490R|%bv z6YAbL1+xGcx5eu!Q_AecW?u3UTvUe$`TPhCKvqu3&+*kz!Q8OYD`so&9Q#I#d4+84 z%1k?D_vgbZZ{d0wmabp!;@4O6CPACC1j`DUkpUl6I4tC=5d-E>wsyp>8OhOOQj3kK zDAn28QBq}g2bM3%5Hk=o&QlbH8B7EeIL6I-IDRq4Pz+7d=r-WA!OXB`+Juc=TI5g` zJZ7hL>6kmT%hpyYir-9nh*_}0055y} zidPb`s71~#)hgLqM0PX^pWkkOY*-A8WX{!11iX7_;*z}Sp5ZOb>=ELNLM&t{q|HpY@i z#jr(UK;c9l#(aB`?=fuVGqL7;8FGpwyCkV5)(DO&Ns$6ok{@GOg2Lvn^ooKM3@nJ& zXf$Lil)dYquvC_O*hrGi-lq`YSiPQQ3=nstPRDg_0ZD?}h#Pb)=h5kS9qmQ|jN*kS zk~i9?=mZ7fk8v?mH1uThlpcprXTo`dj>g?A#o!*!U|?B_HtKW+Er}?S(Y|@2k77rt zIiup^!9bhGqXk7YPcj;ug-XjH8oKe0VwVlAkw|23@9y6Kh?`Vo&2xqNZtm(8d$0+% zO_9jQpB_#MsmK?EIdfYV)-q`ukAyO;`@4qvs`q!TJ8>5RcITglq=Opk&~U@?{DE^;_1llqliLGZRej&B2oJ5Y-l+L8Lv-mYLFW&f=i7EQB={S+xXl-~vyGoLpQ$=L&avb2>+15<+t)RgaQ{GG z$@h0tU%s~bTx-8E{e95Y@lJea$&$5T=GLp_ny@jvlPm82Af-BghU%wE!OX{ZZ#eO7 zN)@M}g&w83w zbA0>$O}oEEb3XOYmU+IqeodbE-t7Cq2L)3qUYlXnZQpkzNj#qM*XF?duaEAzL^kD2 zYCpC%OH(1Xjdu=~M)q9on0U5)a$gNTtiD2odp#Q?L|#G#aW4Z53@LxVdSd#}iZFJ% zXY$3$Wx-RDV^;JdtWS8P5mQB z<5=8O|5fjzTuWo}<<_*4or!J7&w)e0(NXZGRImwL%4+-N;lT^-#~#iDtx5IqsbImj Wr1E>Se{G5WqKjdrT8|9RIadL8l1B%@^QV_b40J-t~2DXD76!z{bl;v?f!z-u(`0A6Ku36qdNc zd~9kFCi=%WN^zDK6nTv78nl$Y6OF#BzLe z33Nc3tyuFjTnK<{y}QUMI`eW(4DVCY5gld77eHtL7A^_}XvPCY%mqu_ezW}U(N;O; zX3g?tx;!E;V1=db>`DPHsmw28Dm{#ml`nb=TNpAS13oCySjgw~2TdWfeAKQ9$&q7~ z92->;J!bhBDQ8|GX5|HlQA!eL2!g;UqY|>T+NI%WCJj>)YEng_o5D%Tq}G^7BQ}1? zkwbyyOb(lU+#TAP<)xw+FsW4K<>kt9jgl8iRHV^pR1s>GT8$$OJXqlu=@9M@E{IyN z!5|~J1EQPvV-btAi!T$+azu743SS^E?}=f5a6DHiYpM_(P?1VPjnrr?WE&LRYaweFcpo;JWRv?D1UMJeaU^TNDaNJ8wFW|myGSE}>s=hj&_<1x zWOed!Jo{Ag#`+YUpdbQKE+&G6oQ@&%ID}dw&QMwscWDSU&e0U5(Ga9TtEJ>BL{Sy# zo2U9HdW4!YB0d=mw0SaG(2wRxK!ejYZ|P+;bh8R`i!$r#>X0}xGSc4O&T(9Se?Li* zgM))#GRr3dAXVqsGKxayZ*T8QJWj-Bc0C@cS)24jy0j{-S#@XMp5Bhst_?%GH`Uyl z7?P|E&m2I@(w8o;1lO)60GevKapT{qh4`z}ALU=XUiIDKE5m2P!=UZ>Drdv;(;Zcp zUTNLXaQ~1b)R>XdmwfM5!DeCL4`3QDuB+Y`(6xEF z^Ximv?PE4ey2VkG9L}|^@yCS?;lKy^ZJ#E1tee5%-_Cd6lnkyU;;L#BW5PSmdD{L? zUw1PlURWTm(A<@7*}k_C^qk&Xzj$iGAlRv{t*+bCm)l`YNbKFZ?rihcjKuq1&(M#W zf{}Q6hhnbp;jeM+k}x^@s|&lDKvMtwpFqp~$-Dagv@Z)JEooMiT#O$AHSc{BKfL?! z@mVp2_Rf2DI4ikHrue+FxTNIZ`AOefh~`z3^%8H^C28B46O$AN4kbKT0qQwDsNxfj zF7_uh?AUWOTLdrf=$aI+{N-TG_H{;ZOtuYNN%=4fbhn&5l@vQOBfhwKO5?}G1Y*Ce zK$hD%aO6VMP&EU(cNUkO*l)i!!*cu0n6MsL{>qm1TuM%s4GbPD?mku#^fHQ5+BSWA aR#*bwkfy%NiRRUj|9VblzU`o;xcWa;e@A@) literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..77b531076df19b7a04056d7ec88284c29ee33421 GIT binary patch literal 1368 zcmaJ>e@q*76hAD#$1f9?fm_&lB#eb!?^nyUCza7&8Fec(r5V)($M^2Or4{b3UJqLc zZb;M#aT|#yBN`n{mY8g!G25IP1I8?7@sF8kV&-&dVsviKFwG<;1najzaet6q?(TiR z@80LV&wJnZZamPjue|ipQVhe&eeGfp$x-y|Ew-TdFU2SPNYt3#u-T2u6bpsTu>XJ{>#7xGZLBFZj?fs^+>(j|xgVOi1p8u|i&*?@ zp1@;@i|DrdX@A@Uqp|j319lB}gyi9V*{KjMPvFfd0Xa~i3GkFUpe2Nqi&*t5pmkPF z5%{W!+3zCONQM0Y+@l*1=dBDW(=?6qPAgOZD{&DZ@4;D`Whe&SJjw6^%L$AVU%voPA5gP6w8vxf=mo)CPtWPK1Wy zkP5qKPqAm}rP&0j^i$GtjN=y+P07?J=iInXO zL$c5&lR%1aq~xGw;81|f@s6CI&G2?xYpdJMb3EJTU>L8*>2-@F(V=&NW zW3-@#=E*>VGq;QbG<1c510gSxnM~%)wNpP~SYFsCwuVwa+?l#w@g-j7`8kuh_wejG&>WbN^GdD&mUcXv1T{-jDQ_Ucsz|W3J%eAv7 zUio*a)_%DEcG1HNOEo$sR^gpTJT0T?$qVC{R`SSPLp^r&^O=$HylFDMeEof&fAXs< zooye~7dZBu;^x2pbVn4cSWI$li}GQK5L_Kipn zbp{91D*^TB%iEV~LglS5lzy1LSk*UFd24@B$s1Uc%d)iCMQ`gpUut&T$d(ZxN%2swiG*YNp{(1MF m{QbNoef)R=n>%@V-)J7T*jVI!`&-GA{nz=t9paq3ckDkK+0xqp literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b53437265966c6367911b3c54d172284822e39c5 GIT binary patch literal 1632 zcmaJ>dr%W+5I;yntOYgyG!7bD-jbCAVLr!BdJp4%iRS|NG>D?iBKvc z(~_a%V{|I@NvE~GT5DT;*HK5OVzo-^qoPGeDivxi{-KtNN-sdHe>mRU-G1NR{&s)6 z-|qQxveP5O;=&*ZiZo{Eb46JzK664P;=3z!l}Qv61%pM%<86WmxL8Qb@KzQ!+Ced! z%K~O;`587Df+Y2v*&SrpCNWx#JE^V*#v8iJBjyiP!uvI1;ni#dk|={<4`fjLHl zRIs~I$gNR>b498F^z*+$S zR+LV}ag<<{GzzRX1!`4cG*B^sR*Yjn5;;Go$+Y)*_lj7@qamP&Q8K;T_wo-YeDLQV-U@a_`c2@?t#1}Efm4uISK5$a zJo7^FhWb?0h)FmDTqq1@ZHY9NgtDwsjnbqNN39BsKy82|6$%VjiNO%LNKx+Zn-}^h zpc0$YzkEIz;^z5iu?}&bT;kv)|AvH$Ll=^hWj2U%U|?Wd`_>K!3NAA0wPx?NzbrwH zdMu)GV4%l1vZZo^E;am@X;jZC++Ke1YW9*xU-30}7u|gPb$GA-#KxcNo(Az<(${A6 zY5u-@*_}|_oKg68ea*@Kbkp%?pQL>8;MuCCw)C*-+mc4fI4CUYhn8c@cEqjx@_O%f z-{P&+T@C%0W`;gel|OlUJ(sAPvSi)l+Q{pQO}AHf^vOmxwǘR?xI&JHpJ@9)bR zC=9#b5S$>1$?R%X=%k>wXJt=jYkl?VwkK;%_Lj%*_wJmIKpuBz%)`}37M3>WpMKW3 zsKJ#zcJ0%sv{6N1f8>X4%+c3tyDh)3*sS}!#H5}enc!O^jZsw2Y8u(rQ1h^`A$&tH zyuR?8>IMJqoiYZRcIE7~Q_Yd(HMNp4r%uO572Ut1?eJ}hZPe~Q+jLRelsVgdBP0A! zUYXB__pV8~75(eCmn0=Eb2{IA??=)jyL&@=W=sEgZ{|R^_fY)USX^ECaQle0Ymy3z zL+cis{#g-UP_-Od-bXWy#^h}=Co8dp`jBgv57{c3w@Z&k6yz^B{6_fqCmv6#A+6!_mmw`DBJSs`kGG6H@+k;izOVnn=yUTI-J4#wJL2FU z+`^Ufd{gG7H-$xcQ|AU@S9}|ZS(|rw>hQ^%Vx#wT9{4Fex;ASjhkSf~mq(7hHKI9l z-?_-RgWZ2(Nu#0jDLc0AEr-?xO)}rQy7QwFyr6zb0v#RO!cpxvgW5Fh4+y4pOvrbW z#&>r{g`XS;6;01SEa^C{gBF@&A*fmkUC895(u2S&; literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9623af7d87422a4d538f5b2359bf5a59d7651444 GIT binary patch literal 1812 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..677a3367e8d4ec943c88097d48abf95fcd29510f GIT binary patch literal 1700 zcmaJ?e^AqQ6fYG4QDCSjaHyd=C)2b^T1b;?q4WpPjUr-I1azcn3KiOvHeE~c2QqZZ z6#O+Ox|^anCo1zimP;@qYdox16qa-vf=C&FMUQ0E_>xg_uVeR-evKJR_s zyR1!5OAZQ*4CHV)LFyD`1}jV1M;0)Geg7U%rC~(`qsnCF(gwysSSe1Tp4L%-+C=10 z85E%}E^4DB9L|Vxqc)St)TH7hZQ>Ii8@|(IVbL6pB*AGR$O4K1bX11VI3b@hLrl=!6D>oCP2d0t;aFMnM?G5g`s^!0^Rm z16uV4JVTi@9FE;ddHD=u!36?`!@+k5`Ls1p0Am;?fDi$KfUE^*D>gHP6ExeVdOav9 z8)-FK7$a>4JRS)hZD*uBmh4a#CW}V%!m-&lTr0L}0w-Y+z%Pw6-xB)c-VI zX>HRMTPQ&WWuxs@l06c`R4*rN?41*L1mY9elNn#jQDKM2>sZzxW zV==i3ktaf4tlDg22s24}V;kAn!&vOKSX^PH2!^(5X}Zwc2cs>QGQb5^VCQUI-Ef0>%)r z0fI#a-Y{POQt^iRl-00FSiD?t2&N3NBoqfyln4V!R0M-MA%uVi0!4*F2o|%!cmkH9 zz|%J`^^sS_Hm7I#Vlddvi_xOY>^xc7!Remy^-^}|{L)jkDpn2*4D5C9{Ds5e)~c0> zT4(3|h1r$gK><+@R^0o!PTfvI8)~~|FWTQV{i~Hee)mT%SA_ITxv^!S|M~hG$HI~x zcT14SGeG~8lwUttitUUFY5pi;yW9FizQy^E+;w~G{K(DIc68jC+%YlmOaE2DSr?D5 zY&BJXQId8!yS)0%K;6EqWm^vCwk+C%GRGQfKMXx&xw^5(y>(vKu8h)_it`gE#INQ4 zwj_7D-%m}MOUU zdRcY)y;C!bi$?vc<(4&m+*h|75SW9^ilbZ4ge_awy(x^B=lFgS={puEgyvLt&j`Ol z_pV4GDih*tXiWO(MI z;Lf%U0XY!?KBm-$1I{t$Lf81eu|3eS#7EJ(qoX6ZtSCXGYJKmmgQG*QuacC@7W-DX z`X$`IuC-6mS&R?5Co%rnzMRg`)j$4V4|w+PxvQ0Je;=$WTfDQjnz<2D(Zu~cKXpS8 zx?=w3ngREy{T1s{e6H_k7~L8-xv#TnT*=ejO+||#*F8+;8m*jJDmfh-u%NlB|5n*! z-SRbbH1upt^R1BN(g)!xS(fNH)!h<^6|AVwE6wY)AWaoM=1a+`*{vmGN~3(19TK&1 fou7qQCiwVqK7AOxBD>a-==pD`RcXq4d2ZQ%RqlP+ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..fb58fed1e0fbbe7bed41ff7ab0e676ae7067edaa GIT binary patch literal 1725 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4f3dfc8c4a875a8b9eda2c87337cb46d984a93b9 GIT binary patch literal 1590 zcmaJ>eNYou5Pt+eKt#b>N3r60Vv*|Q?vlVIXCj0oV5-3sV~uvKUhXcCf!xL9AOW=? z#j!Hh@3AOV)M~Y@1E{q_>lfN~uyrh08B1-8jOZ|m)~eY0Rp|>5>mQCccen5D?Qi$D z`*v@&H7hfENZb$rK(u*=F&oNK_@qUI!}qm_brvYbNG7{9M|4Vl#>)deCpvh<>}GQK zY@XqYmi)kL0SGU5+3b?tGK*$Kx10&u$OCQKL_IvvplXz0MrOAHcl=LQnW%zlNzM|LSaBJ z=cKcZ8U5klPKV}7l844|zuzzSE9Ig$2PZWe4NfRXn6F5Xm;fgDCWbs1c^~U_ zc_f!8AVH6eLoASVC?wmLh1+AXJaa7g`fCNNh6flAPRa?~?GC2aYweS=`TuFW(AsA! z^6+>z?-L8WEIbnD#1I&k@8yAlhL8 zU~Do;VhUcxVvNJ7#2jjZWz-zQDk*iy&x`Pe6eFcJ7*Z%jhMFWz28}7*XfmZJlQrok zMY^5{VabaO%(G(jbP0cCDE5FdJu(DP9T%# zxdcx1`;vlZ)R(f6_qqysF2gIjk=`QHt``t+vMLot@hXg=92BNv8JIl9DKW;$kQ#;B zNsuZh+K=a+D_&opLJds96XHS>B=1aSi4=_IRT_+?R3zq55(>=8P?SXxtnYKZb62{rk^X?YV!p^-x&gm!oa>Yy8WPJy1M398q^5547C4 z(=`pGR&3LMcXjcZs!O%&TUU0T9UD9OwB@P3et@<7$a@poKcu7XkC(Omybc7eJ={95 zeVAT`oY3Wg%ij#!8CQz7e+E?1k2v+d-@09!H^lt)TH2jsceBLCC1C47eZ~&3zv!t} z_&4Eh`Hhd>SvsNsSpR8Dyuz-ccFIjNa2a%(+3mscgKUD)(#(t zw8@O~>&LHHfBxd!(XU?lRI{OFd+U~6#H8u9DWd+|)cGYU`CDfXm+#1=%jz6d{CZe-=ON2ixnVKdliTcNt1Fg*&2?Ebx{I5+ zgpH|Do0=|$7h61qiQNx3j(i0l9JO7py?yRc`IK?OnrzMDL2(Y~0!7l1CXt2ypeH8>Q% zb;N+`8eso=**r(niYY6c;q3Ck&G#}t!8=PTXR2$!mp9!Qduq?dd+#O#l~Z%5`#E*!qQWH533d`rguo=FX$ X{(3~&sLLIZ!9Tg#lx3_*UtIPdOIt_2 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3a5a28805a856668c4d05c0824cb8253f9dcc732 GIT binary patch literal 1598 zcmaJ>eNYou5Wghyr80hi)uN+k)Pm?GcbC8=R|142NRZG>Oe<&|xm;c(1G$U2qlst{ zg&DPek2;Oj7O=G++G*`bty2`y>Qt~++WJMO&QPpcuo}l1Ypr1V0>t`<?RQM*LO_6fcXW5^(|V68(%1AbKb70I1o+ zECV*cI9Duh2U!Rrt9RQ=#1cyp&GH@v6R}YQJYI-KkgS}5mtiY_h&sSBH>Z<_T29DO zw^Juym|?*!UIQq17gYPeg6d*BTV26wo${P)G%G+u2Oc0YXuwm+33NawAM{JZbwsU{ zqk|@5g-$+1s>EVN4ZIJal!Cxm9LG^gs{l@hbf{bmI~OH!l28)xrZ9q{Nfk|K(cw!D z1NxjU+Gflj4hMHSdATThX{FNd_bdD=1@Bv?B(z$s5+{`;i9riYSiy-*0ON!iQ4dBS zus*j}bn_e<@yIy%Dp4ngWQVfwcrBKvjyYktR3S8;&L{b~H7DOBPpT={o z1^WswP}+dNSNT|YB(51zFf8AT14RrW8~Qb$8=ebOY2?`|58yoD8d?G*Lg#!y7VMjOFe&WpTI&U;Z(rNGg&g>KHt z`-Rz&Ga5?S2z>6hfHU96d(gom)9&XGaItDNMFBO&P!0-HvkXk0a;h-K#SmIjZJp~YUy*edrd-mqm19gXFNgFzmz6J_Ojw54`LgeQ8`Hz=h&riUQ zeIhwqg&da#&Zi~VGJlX*XT9H*b9};YNgd5E)&668*zwGD!Iw&Nb^`))|R<#+{L8v+j=E&C@}2K>3MYP zQJci7HLb)h)i>V%>Q4XeCl>w8&D}+&ZVp*J>9$aIPMkaK?O+EV)5%;v7y4=4f|^g0 zuYNwpAC?@P+AAFEq4q78xgNA1UN;J>QS@Gz)7Dwv)W7P~rh6y%CVaTqJ1w`!8v8ZU zxW#!kRO%8(m#yUN-8H3gmGa15eNuDEJ;zw{z^vL*;@!H=V*U13t)x^_c(eaaF)>%S z>vYqP`&xy$dt$8N^u577^I~_n3L6H@PwofvTf(UldZS7gKDvW{W&J$i@ZVL3T1QMm YrcO_Iys{zVX5^1AGk|J(*OVf literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..76267a2a8d6689a04241f432e55501ae91231b2d GIT binary patch literal 1604 zcmaJ=eNYou5Wggq5*0tH)fA~7hYsp+$=xMzNhC_h1%V-m5eKBT<#M^00LjJNX#%w6 zL~*EJwAC^|tx&1ejx|$T99yvpezdgJ4q98Pt$;)Ahg#IBR2-es7a-O@9B=M!-`lsp z-QVupeLW|8an#u8u@D4BWu#M9AVu({M9RSbYGjQCi01@zzOamQ2!7hfLPk4hW8n-p zy^6K6w7qoo*K9Hb$u_uh^M!m%mY(6rz^e8$1W?&&SlDq8J!(jv=B}X=z#+_E6{MjUE<;O0RuAZR}a=9 zwF-fUO@v|tGD0ffk^`GK9}AO89Az*JgGrr|wbO)6?Vya^sAMeZ2xZLP!R+QEKt7GBhUfV!^ed^ zP%O{*TwcM&dEk&o+QzLB3Wo?u9O)IA)ET^#~c10RbmUyUVWE z(yWc9X&cHU;y6mM8V03p4mE1iVhpXd(~O$bhW$JaZ%U#_t;u92i8L*an@u`%DrGh& zsS|anW+K&yg|QhPUZ6b;8;tJI2etFBv}nglQt67Ff>S>w5w6tLE}0? z>%ef00~y8JA1U5Qp8^d?!W-tI$8gq>$Y4n*%W8BeLuzo;rp5@=L6f9fjp14l3{e4! zs!-oN(nnzxXwJ~`;b4Hx!_i_rV4i$naBABQE(Svvk&~5c26AXNb1T^#gXkl)z)r?=GDGjbhag<;X+I^Ym6=HYV95f`oAcqZx2a(kL`jA zr>s0$L{0pyV0JGRm@8{^D*hcDh-o7WYI0u`+Yr<;XkD>Bc%qXNp|hDh*D`Ll^weakq7Hv%jfw#W(x{ z=>21dVzb(Jb&K-P`lF*|_1(Sw2F1rMeMe`;O7=9r1CxGOXl`#sJ>e>%0zNo z{oWJK{^YpC8Xi()+wY(6oPTMVVdBL7FY3A`96tB%M(4hThr65ka}VURX5_fG22Zb! zcq^M47(6xZcJrzFd!+pM4pEviX5EQh*}FXl4(^5Isfc=M7VK`2DB^yND1>?ggrqn2 zLQJ|$tT-#tMy-|?>SV$AowIgI^S@8AXPU*T`EN9Lbx!TG47NX={%ZU{f_Tqb{pHHo z*@Xqy$CN3mFIgKZtNdrl?MA6~-iAGQ?Z}O496dg+|aOkG? j&5o)3_*?4sMo0#=U6ZG6`PBUh=qxD1oJ|E&3oHKv!xl}j literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..bda1bf44ce0a0cab9a03d15fd284b709590f3b4d GIT binary patch literal 1612 zcmaJ>c~BE)6yI=2qGGYkSZLK*mQuBJv%5)PlP!USBxuxN3{-Kf%4YYAte9-vT}r@q z07osJIOy08Whx#_J*u_UX%#K!sJ-lXRA;0Y?dWI~j}}`UmC`RjtbaJ}?0)C_z4v?9 zu5ss2jUV~qNCZLRozv_dI9J2ZqK<~+6?L5pPRWX+NGT9~N;xY5#LA0afI9u`V&DNR zU$N|KkcA-8D}}-$rN}jt;Y7cd4a;al{vbpnNLEfL$a1AXLA_wH5HMr6kF{Z_z?-qT z87|Tlw1E;~TBQUED)S4u%2Lk6V>#JqR)~QL{6JyRkbh}FWh1MvVxuL4wkfgx?=_ZBSZPJm7yCPnDJnD}sRV z09h=PIG7S&Y6J|!_iRI9LCA)gB?&Mu>{7ePmH9zHaoWuoywUOk&lp+YWm(pXa~Twc z>wtm7S+7rzdyOQ=8hMt})5eINr{PV8JcrSdLDG3NNl^}))#|Y4*^MTf&2BY19QFv- z8ITn=z=4Qu0ooqI8uFfrWo!~)6;Ub_#ifx#aF>XRD3^#qRHxUH=;XOVfEUZ&-y0-Xp(xG*FId>I^>i34CT;T&zCaIc=!;XamzW=P6tFwhtQDH7qjd7_RYN3b}< z%g2oYH;-Ej1Ykc&uyN|D@^`|f8{wW==z#OUz(Dh*Z9gMO)J&({S{Ul?Ez)f4BGoGg zsw$gzeSWkf(6}URzWLmo_{1b%5c!_D@$n%zjjp3!yE2Vq!)Av$d{+5rR!L=3i)*VDMSr|DmPI(qrLg% zbd@mTSlqeMhu^*06+@(@T$sIAq>$o6h4Jku-hL#%!+du?8SVZfHz_x!IFxHl**QD) z*8UXDnjVvFEPf(;!irny#qOiFo`Qs!-{=jea{qdC=h#V^+PKH|ilMG$>;t4_OUIp4 z3xrJvKDw@L>-?tmBEEAT61+5t-gh=H?ZbhBG) d`Wa$Lk9CK2LLbCB`HWC7-b4J-I(2#5*^aR#jFO37OA^}lG0 z+|rGb0(J=^42cT^7&dV~QQ$D>eXOc_{ROn zF@fr@3~l#CYqA>JnHt;}--j?xV@OjHWH4R8=5nZ+`OXCc$HW5%-!TYew6i2RaBQex qY<|G*k(2y_nIWe@{^$!y!>R_h^8##l82@^(f12R{$K;eQ(miEr(rzy}T-4@vmuCID3D#ndPOCK}D<0GEJ3z=sR83SEjo^TZX!IK-3> ziNINn5C^BCGGK6e{VeAfmnYNr-w(X}2yp-9oF4V?A^-pJuzS}*>FzTkF3V*x;2tB9J0MLWRxxj&o+Jp}~{F*?nWid2Jyde1>pZ*FDh=qV2UziX+ zED^wYUSK5g2etzS1TFe?zy&~B9{?XR02xcc=YWHh6b4apN=5XjI9KX?h!Y8XA|2#F`05eA_3Di@J)Nb`;Ym%t`9dA(X8 z2xA!h!RrWO7=TX<4>Yid1Rr#W1wpVVVUYvoKo7<-s>ojD@ogA9WF`fO0g{*xBzr)@ zLIoR`JYp*P;9np(2!R2B2Oz(L#EyUig8+xIdw|dZ_vE;P#t1?X1b+8pA;ANu0sP;Y H1;juD{u;iw literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c91ed2fd23efc317a9fec7f9244f5ecf26bfdaf6 GIT binary patch literal 698 zcmV;r0!94+0JZ}EfFeKmfrIjX59|Np9uLp{LL3k1U_W#*kbcNuF#vwR<^cS;@vIO) zd(Z#CF}ve9B@qX-JRV&5#tfn=$M69PXF`dC-_IZZ0Sk>X2aoI?k-rCw2tNFDh(7RG z1aJsF{OCR-a1Q{$x3&;_+0i069sK5s4--KE3qB7Yqr`7u@&FI;)>rrp1JI!=ED16{ zi|2eOP$&mL2sL^*JbV9r{(!)9X&8`x@E~~0{Q&eFj|1S45O~kx-2i$rMgb51`=XFY z{7@c~_&7X%AB}K5FZveQ1B3uPee_r!fBx`1X5jOjOTpql6S(+u|M*Be_!7x95WXpK zPLKW!4>$%49$ov|$bZxR2|R!U30bH0tOFAfIQ$(2*5D`?RtQVL>}ORfY^cfK@wo4#6MrnKs|tmU<0WTLH;XP z27sI(^o9V%@FvkNl$ajh@M$c>{x_Jwy*v;P#4Z6m2#gaC7YC$sfA@mGI8b;bBL5Hv zl>>p}ulg3lJ^Tm<|BIl5$ALfoSM3lU2l@jagnjXN6H#zK_4KgJKlR@P9)Acv7K8uq zuhJkK&-_qkJ@}dkx*z}k{!f7M-}}L#m&pO;={q_P6AHB35AhFN`%)TJ2HpaDrD0~`qk(=2CEZ z0f)!)C5Sy^VDfDd6n=P6c!CNF4@>zJeV5sIJm5g`(0}*gLcxQ{tS}II8iWXe@eB|E zXaM&oh#-OHDi9%W;4^FixNpGtzyG;6_}9XI3LFReE(ABI%&-txX8^(=_6Q6zF#`F| z%pwXHSUm6OQH)?em-v`H|E9r!(1@c42fM^ULUj;%Vgc))|K1Fy>Kb?a9=!ZL{EAT6 z1w0;~ugGj@5C#axa1?NQe1YPw7#HjRdiZJo@l^SIcmMtl`T!3dm;X)wiUZI8-@skq zAn}sVy5IRje7^$Wz<=Pt@uKiS==&f4;{o%GgT|Nt_kZdD@qLIqwsLTI)$jj*{(v4o zPrv8!!7vCsb@%_@{(}R60SDkA5P1JeqyPQ^#q2GC2cG?kAOw2~a6#jN_us+G|A+7a f<$u2eTmSC}k$89X5PN_N?%5stv_aF0B#1shQS}MQ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..aa5353e988d02785f45759a024931abe7d580086 GIT binary patch literal 584 zcmV-O0=NAE07L@+fII=<4*+-rz#ahb2Y@^IANT|F;Rk?x!S}#`z&(Kbz(C*~0DZs# zKZbz<@kP z-_ZGk-W5OxmVe$YUN}5vRseX=FaHn!_#S((c=Kc+^8fh5iJ!HD#(O>ojswBL|KI=9 zyXAl$Ey0L`%fG>Z-}v0Uoqw17zfWUvCftXMrUwwc* zFdOIv=nzr}54)K^iv!95wSa!G^7S~tJCHd1P#$^^c)jswmy;2(?+ml*DY%6Tpaje?1R4~z?+C+R@JB71OJ%^j$i~g#Q}fdP!0e4@$U+bI{^s# z3(Nlv;0TA07lYt1>XG_?f57p%{4ekc#4b7D#lRpxNFUrDAR+mp#tHC`{fFbU28aM| z{|{g!U}Yi1z%rjedF|ox@OZ&E5DPI#e_na`JbB{LzW^w(J#=94pcIrmEe`+y literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..837c6c71defd8be280776e7881817fc68276b5d0 GIT binary patch literal 610 zcmV-o0-gN<0A2$B|KVUk{Q*P)Fi?2?0rvt2kDwoLFnIg{_W=j^KOjHgdBMT)0R98a zDj@jq1I#KQ_}~M|;Q;Id;{Xp%fIlVx`hWxc9=`B>kL(_GhKz#+o><3>gVG5B{Tt>8 z4;U5;!}CwXJVamY_&z)lfe}FLAMe0Dt_H!Nasoqr`-9r~&_@VJU>l>0Krj6W95O)w zgJlpe;FN#haR>y*&>wsRUrhppDF-nZ{sYsG|A@(;VDX@2Js+@oPGA%6%nc+tE0kSi zuxJH>Lj(tm3qcDYD|B!X2tYh=AoBP#)&UWmL9h@2c-lSS_KA8RbO;895vb?`+9^1J zKqL|g{UbmRX+$ywAO;Ttt3U_0LJkiYg@OTE2b}yKQ3wz`aF!;BgU_B1DFg(5A@ZVV zdEoJzgVn$w5#o2S;PHin%RrqGp+G;L5P3mC<-mYJ58@9VCwyLBV0pmdiSdjD2SN@Q z8NBEa$N2-wgZ=&g0qGDH4O%!v8W;Zm|NDc@SRg@@1ImB)|6{@DKq!m?&N3Yo|NZ%| zgUlq?4N0o0xY&yEj|qzoQt^FED>06iEa;GRJCuV4t{^!eXG#1C2(0)+vGdoW=5 z-AFJnC>}#T4`yhz^{KA$Q(_^4>({vevs<0996^* wNHeH?5Gg=DU|{j6KxP1O`UB1b0N_Ay5Dfv)f$A(Dg8+f^cz{o!766F@+?Nvri2wiq literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4cb6e53325ca82bc1ba52fafee1ac42a1860a50b GIT binary patch literal 719 zcmV;=0x2edpMFaQvP#()oKH^LrM60rl^I503^{{iLsHy|)^ z0P@TO$c~T*6avV`F91BQ2NQrnAQ7N>U;*j-2b3ZK1#_7gbPDB+U69S%_nXL) zC-VRZJnv)jfk2!FPbpLAzn>Mrz?udRAJnuSUypGxMd<{tLA* zrXFq&{(Uec2t8nMZU^Um&;LikL=Pb#gU11WpyB_e!8i^9U?f3-fro8?!+z!9@{kxt z1Au`*;1$q#@xkK^fn+M+^1?tt<^J!N#5gpGLDXAf4;s)scmMbcfMkji;6cIZe>Vs` zWDyAj0>L;3j_JTF@t8;f0&ac3Iqm7QxJHZ1_AZpe1D;lp}-`8@&O7E zf4~2Td|(6-v^gM1u%*MM5rYZhlmIgItVWU zM*v6&Tz~M)@I2@cw)t=ZxC7z zA2bOE00<&62h@N_MMD3>!RtVd0SE*!_y@oqya2gi1HuX-s!%Wq5(kL{%Bg_BK>)`F z0hGWVuplXB7K?0mW9)pqY1KH}Ok%5B<9%eKGis(y(512t1 zV1o5Im^_lA7$AJa0isACd4S9wN1+GifZ8p>2hD&2D1rsA;Y>{dhy%&&jsbR%2w?#C za0n!fqF@vd!9nLh_()r-01$a420;v=I8aJZka|FG^IL|R3GfZ_(Gk1Pbd4kST{ zMsfi11Bg7X2ZO{(1R}5@neYJv=m)TLP6L3zL7)(Ddpk-XLm%(`ia3bCJkmrDD-itP z9{_m_j2T6gp61a(gZ{ZM1zPgjQn6h8mzDgPw@^3 zz}F@lG7%UECQ4EVmjV2M^?I5VRtF3sqyij97+5^uQ9ycvN8SY{0Kl$5kq4*%+69tk z2m(_@KO~R>1LeVjgXn4{VF%kx+rka7e&8S}(IJomV8H&oCqy1_6AdOzA27gr0I%$+ AWB>pF literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..02af0bcf325201270bdfadedbec283ef88d23ca3 GIT binary patch literal 400 zcmV;B0dM{R0E__u6hI%*fPX>)+z)6lKcGPUz(7I#PwD_arU3pz{4gKTMmK;k_{2d3 zDe-;_GJ(K9|L_=t*8Igk0EA=6#lS<%$2b$10XzUQ!9pRyf*1$@!z2$7S_H`=&>jM< z!s7x5oq?9d6#|P{0)!VvvyBn0Ld9!N0es2xXIKD?hHNkcf>bJ^nHs1)f5le^scc3> z4<_k=4fG(wLZAU;7sx;mVIRmiJ>nnuh!AlQc;G$qANZIMe+_j29wYxF0t`96e+YOy z`5!qud`_ZP5CH#(h7U6`01AE&KlnW>;6u0r4{JaeiG>Chtc7q; zL13H+9^e56h;T+EH$XAiJOEMf2b8WMQ;(nw0EJZm6mSf&0DG5>a9{?&7mP;0180j7 u0|XCSfDp`V06IWm_y=K9vXGzv!6FDmf$)kW1cS%`P~bR%6du3>^KMRlm@CSfA0hhpbq?iBy zfrHw>1U~>!W5JH5eJR~-y#2rfd}y7oJamf1Q>IQc^^4Dd`_ZWV0xQm9$)Z!SHb(hAEy8x69Iam zOBw%{f(jT9T;K?EQ}fZl!RiVqqNK+He{2K-RC^G)$P4e(0vmi)@u~tG3IP}gy-;dn zF%XCWtpGA66d7V;Ljw#DSa2}=fCL&L!5EMNEFJ)0_yN)z82IHt7aRxi1V9;pFHiv4 f;sD!#KdAuzRg>(&`v8E*0s8e2eMA64*bo4KNFID{ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..94357802fc84c61ff65389b3e8e592c882f7dbf8 GIT binary patch literal 351 zcmV-l0igZ?09ye7cmu#50PqKZJOSVj0C)qy9suwMfII=<0ssHtVC(QeU=iSb&HzL3 z2i!OWI01zM&?Z0!-~kRW51RlG<^cHxAW;AcDnX(E78q1Oe8BN!R}iTkwCZr_kd6iL=zu`d>--(%?dhyEu35Rdu>4}3@dMx-zKoNNH~<27iUx!LC*lA+s1!%z z06$O$N8q_n<%^kOb)bFk~5wa1*0=zys#M xtsVp)fDe)2|J%Yg5C*>#0W3lQWN;tNQvg>1!5{>@3%Md74DbuO_)Y8hDgXv`km3LU literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b0d0e691407afc3067f1adb44437407fb75e695b GIT binary patch literal 324 zcmV-K0lWSI06+l%cmu#50PqKZJOSVj0C)qy9suwMfII=<0ssHtVC(QeU=iSb&HzL3 z2i!OWI01zM&?Z0!-~kRW51RlG<^cHxAW;AcDnX(E78q1Oe8BCSxu9Tz!-0d`03gv02*iL9VDJM6zz&eu$Iu1<*x)~l&@y86 W01ciX4Y&jPkPqb`gZv-h{{T3j6M%aF literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3413e507294a89aad208259baae4b7e14c2fed36 GIT binary patch literal 387 zcmV-}0et=e0Dl1hcmu#50PqKZJOSVj0C)qy9suwMfII=<0ssHtVC(QeU=iSb&HzL3 z2i!OWI01zM&?Z0!-~kRW51RlG<^cHxAW;AcDnX(E78q1O89{;T1P7!C`45Bx)GV+V zJmMe^SP&IBa2WtSlS^`dND1uC5CO)4_5N5S{2t}8859eE4|oLt2{}X@+NBsi_q~snrkNk~DU-LNF0ppx47bE8< zU>E)9K=FoP%)$>&1^fm#3k0eihX3V`WjVd+2l)@g z1Jtar7(C)2rw{?afT_cP$N}t{TakIiA_Yj$KEKNZpM%`CBO-xt0q%z*kc7wK9|ydG z`3MP@;vNi1zzAX=_=^y~kbedK%>c|wLF17B#NYxE|3Ja%IR}m-|07Zt{LVH2c;^d6 z$oa|G1^;>wJYkqKFoV;9e*ulc!77Jg!R7x4mw^0Ji-f8S-5`1&jy*V#LDb?8Q}K8q z@#usO7z!L`{$2zV@Poz&4u%8IH9tm)_?6E9iUx!LC*lA+s1!%z06$O$N8q_n<%^kOb)bFk~5wa1*0=zys#MtsVp)fDe)2|J%Yg k5C+%*{KOyzM*;lRFa>ZN5&%oUyOJUR&j7oxgxI3xgWa$Lk9CK2LLbCB`HWC7-b4J-I(2#5*^aR#jFO37OA^}lG0 z+|rGb0(J=^42cT^7&dV~QQ$D>eXOc_{ROn zF@fr@3~l#CYqA>JnHt;}--j?xV@OjHWH4R8=5nZ+`OXCc$HW5%-!TYew6i2RaBQex qY<|G*k(2y_nIWe@{^$!y!>R_h^8##l82@^(f12R85=KBE9Kzz`}J1UMKzV8BQKC}{+U0724`4BWs}hy&t)1xbKDEC5uH1K<*& zRTR5KMyg4E8C8uffcQXg0QiI$i}?cw%4DP;=sp7je+RS>9*_@-1=%GK{KMc8_mjYZ z>eUyM1JC{s5HN$-3_$!F5IoR=C?I?Pf%_N-od6!d0-8@2g)j%qq7d{bKt5`UGE0a) zbq1q=o7g^JqF)NVgXRh;0{y@RP&u1@&}{^;1L=Bm0DZv)qLLs4#wQR6U_Sg1ba;d9 hyh!N)A-cc^a0l^w00j;Q@jIEc5A$+^{2$%`d;q4lY*+vQ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..114b26391f8643130725f03b5209d97ec8e791d7 GIT binary patch literal 312 zcmV-80muFU05kyrcmu#50PqKZJOSVj0C)qy9{}J$VSx>WL;?FSkOOc32Y^r@AJ6zg zZx9F%f(HPHgW~}KfkyzNa2Lb^4S){_RDtggh*$vU0tdhTK^Oy^5FZeDFdX3k_{WZp z;FNgzz<>q#kb~H^GXOFDBxnd6r_zQGf^u~z?r{gO9X^zK;9Vc&1y3g)261O<@i6EY zJS-vXAoYj=mJsj|Ldq8l&;blEKCOi!lqlUm^1wnt34j}{f)QXGEdl`)1Ej(@IC8r1 zAYk=-xgo*uNEd996aa-)W57N~3{_FYl~hqM61xf{{eTGI0o&ki(y)of90xeSK4K_) z2dQviVEsC|Jjdk(up4#=_JONI0s9aqI03v1&Y%PP0L{2Vx5I>AjsawYgnx+xAb><* KfO)#k4i8}640;Rz literal 0 HcmV?d00001 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 356eeb1c57aec1a840e74bdfeaf97eb63ce89d7c..7684384fdfb09f1dc5e2dde7b898fa11630b8d79 100644 GIT binary patch delta 224 zcmV<603ZMS1oZ?10RVBa1E2wa90D02X^uP|BJl@}!5Siwi37#~ivQo>5D<8Xh6aHd z2t2TlK@A8zVgiwY@B!!O4~+r^fQo#Kd74;XZV!Q;o{ z`1$w{WaNPHi2wdSe*b^pzkq|zDS*&xq!%l{Z?SIOz!B*{&}y|)DYs{_Y}r5;;s6*R aJayWj`vcT}0QHa;;2!7qfI)r~qF>fJBHGUc(TQ1JSZT^1wQVA>{vn88Sx!f`{Z<9(RZ&B1sOA zcszLge;+=nHSobCkstrZ@89qH_v({Bj1Nh!kX)|)zQwzCsW=DH0i@Mxrc-XuV%f5Q hFT`F@4HmmpA7FaOhwcw)34Oute|Q8S9(V@efEbd4Ud8|b 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 804dca320581e4d7a4d6b297bb4ef5fc19fdc854..478c1e8b5cc4472f7f4cff2611ffa7678fdd93f3 100644 GIT binary patch delta 222 zcmV<403rXF1(O8>0RWG&1Hb`)Fv$c1{f`Ha;vaxFj{*QI7?3<*7_a^Q0Rac3aseR+ zmJwn+0C^0C0#Fcn`UB%Yfdj;HP!0tI9$NtT>7kei&?JpQ4?h7sV=)kV!yV!UFZ_NJ z62L-1CkF?h09`^4P6i(U4^~MgLpq#h3*KOe`> zz=7p>k^{yg|M>m;{r`Uc0x3AA13|8kT(14T#k+R^Kcxdfs?|)U-JZp>WdMi+$_Nh~ YcBnqU^&h}JWCi#Kx&7b}fO*6d@TIp|FaQ7m delta 227 zcmV<9038351(*c`0RWV-1Hb`)An|~IvEcFiL+}Ri;6Mdq1P6=*75~4$ARzRPFa#c0 zMTqbLEug2E(Lkm(15$B)PH z^XZekK_HSykN@NM@Av)t^vRpX2c*|XE?0ivV%@ud1JCII(rUF+DYs{_Y}r5}0P=!B dG+OOYeSzyDAGkfFCHDup{ooLQdEgs@0ATJ|XGH)2 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 4ecea338754834029b7f2c59b7129627fbe96f8a..eb4b3644b23406fa7b4516d854cc861fdd65e226 100644 GIT binary patch delta 171 zcmV;c095~x1&##+0RW1z1MUHThzeT(`01g5^@an_z)u*=M*$fJoE#o-5Bz=;62L-1 zCBO%$0AE9ZM2HxF0P#wQ0YT@0|AWR2{{S*%lS2hoj0ir!^SnVBqYsdHJb3(nA3muy z@WwC^AOFYi-|zeP>XSc=AAzorT(14T#k+QCPox7us?|)U-JZp>WdL6uoDo<$?NEJz Z>nI<%J*1H0`vclUpLhfy9(WH5eZVs8Oj7^= delta 174 zcmV;f08#&r1(5{<0RWA$1MUHThrk6bfP8e&z7^K2P`olO&oLD1Jfbc!EMCkm(15$B)PH z^Xijd3=&BZ|NMUa{{O#zsWbS%^qT1f%J19kTeoVHfPEkuO;)O9HthBxEt@C;{NRuc c7Q0j*V0y@h?hk1ReZlU3cmyCGcn08r7ziRwOaK4? 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 241cf66bec367cc8f73c9fc23532a7a1055cbe57..e0db66ffe303381a4cee87351807509ea9dfe0b2 100644 GIT binary patch delta 177 zcmV;i08amt1(pQ^0RWP*1MmTVKvLKT$4v|etS}ya0(iz^I0(o*;NbIsf8+3&mI4w9 zE&x1Gq5wD0;1MDQAHY0d$T0vQJn$d*I&^=Z@B*euG%!`@!2|3MJH!$(0Efan9z1?O zkDpYSaA4R7kN@NM@Av)t^+~`nj)B)gE?0ivV%@turP2YQ)oP|wZqH&Q*|LBy%$Pe3 fcBnqU^^_0X9@0p0eSz&GKPmiR5P*5`8-f5}!`n}5 delta 174 zcmV;f08#&z1(O8>0RWG&1MmTVJ^(3f1LLNK1J)T3kbwulPZ-Qc0T~CJ9w8zEm;OHq ziC`fh^56s10574yB18;7fOyFP=-D87U_apT@_)b#nIzD`L-G$h#1auChe$jgJbpiq zpH!OoV3J6W|Ks=X_x=0zNuS0Cq}NC;SAO4O-Mdtr1L*+LYPC}-w`Z{-Y}r5;=LCRg cwc4Qj1J*=8aC=Bg?hkYOz##zhz&8W{z)q-5djJ3c 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 876d6e373c7be7ffc80d6c391b9a1875f625bac0..9265ef6d6c23bf6be2076d3bea86cc961b2d1626 100644 GIT binary patch delta 170 zcmV;b09F6;1nvX_0RU>T1J40}5EQln@zX;A>kJ2?* zZ~^K77%;q1A_f<*fP@~3q6d}%)FF}ofEhAK0fMB)1Rr2|-XM$-hsZo0JbpiqpH!Oo zV;BgJ|Ks=X_x=0zNuS0Kz}HAFSAO4O-MciW(gC2=YNk_e&tloKfG^G+2&^4;s6N2; Yln>k<(nxWAf$btsyaEspJO_n7;EO>^82|tP delta 174 zcmV;f08#($1o8v}0RV2X1J40}4}c0=0Ql*lfc1t%Bp^ZX6UH+Uz(zsm2Z%_3rT>q@ zVps@BJh%Y$01OyjD3JpT*kTeudMbz>SO-wVJfH9bCP@G=Q2c|=@dSiPA<_>Aj~|cY z=hY^@7$lM-|M>m;{r`UbQfKjj={3>|mEX76w{F!Z0Qx{QnypmIZQ1N0TQ*Py`N1F> cEq16r!1a+2+#b>r`-9y6@CZOW@D0HLFiJyDPyhe` 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 0000000000000000000000000000000000000000..65b723203c3cba419975bb816eceab751c8021f4 GIT binary patch literal 661 zcmV;G0&4vM0FeR!d;1$^CSV+fPOF#cm;xmA%K5?!V4I9JZF#y zWCMXgkl-L7VSquV0P%-^qvBDa$ZQY^fEZvr0C@4>HvmA(q%jBu00K}94gzKtECljH zh=b$c5(xD31%QT)ih&rA(J_%23_?Rf!f+r!@q|zTBO=Gi;8=+U3lYG8gT^61hDh>Q z`g{tJAc10h2ttrhFmf(VKR*PLP9fPNIDiI$fVfD#KmGVTf06Kdz$yAKBp-hWi5JI3 zW?CFF!J_&=|G@EwPBd3wdD|j7PoxI;4;VkgLzaMi3?pqG57OfV2ag^jpa+aH4FG!x zJZd2Fql3%d7R?fd}vp5#WFt z2oD?w{*E7zc^n3c4;XZV!Q;o{`1$w{Jg*W!c*KAIAHRRU@87^hCltVFHPQ=}-?!Me vZr}&>plCH(sg&EZ*tTq-5de8X0pqUK2iP8?_y??jzX10?yaEspID&ovpRo_7 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7e83e14a5ae80fed0dfe4163d65bc5bb431613e6 GIT binary patch literal 350 zcmV-k0ipf@09pY6cmu#50PqKZJOSVj0C)qy9suwMfII=<0ssHtVC(QeU=iSb&HzL3 zgM;h+e}H-;fa$RjDQco7?di^51Rl;u)Gj_%m726q2vr=0C>O%Y7!X&24R8n zh)|%w_<{$@5kvxz0fQxIgkl7w0B8|NsF;XAJ_#fLl;I)@34o*qEd+qX!Sf*hMj;#& zDFfXWF*roRK%kmL0!a{t1L{e9q$h?!{DXtuDgUUHhd~E0#!LT`0uSM?UKtQA-7L0R1hYVN712hFV6ap|Gd#F&xVj&O%T7YCsC@?+hkO&~K){|ERc09Xc%RjDQco7?di^51Rl;u)Gj_%m726q2vr=0C>O%Y7!X&24R8n zh)|%w_<{$@5kvxz0fQxIgkl7w0B8|NsF;XAJ_#fLl;I)@34o*qEd+qX!Sf*hMj;#- zhvFU&bXdgU6A1)8g%pSck|7N6Kvv`cStat2o)xIj0q+$5)Jj5s8V7>@4_uf3CUraT zJ@H@t8^mB33H#*02g>>B-i6?ggY0}i1Nhtl?f=u@2gCe>zz{4CAjyA%LmmgftZ*Ol z2&`Kd|CfOWfNUQCgg^&?$xq9oP8t32KJijWfCur9ql23PCV+uU{r_LbGzf9{;63me zpdoND@G$&cKxN>#t6Ts!pc!5v&W~N`v`S)hAOpq;!UQk`SUd+J7>EKe0pf8G f13UojemDXL)Ive`i@Ey%2ET*(n*auOz(3#s%S5EX literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c5312e5e5a820aa4379d24bfda9c4e3a6c296f8b GIT binary patch literal 465 zcmV;?0WSUl0L=ma|KJ!1JOBb92k?KvV|ai<1QYz9hz1J~2hIcX0~p1CgIV|t0%5=@ zSun5w`-VUukO3HgE-(-8gboCi*f7LHlA#oMki-Dc9wdEcFgU`3ATxj=M-Bu3hlAJe z1_Bj>;eQ(miEr(rzy}T-4@vmuCID3D#ndPOCK}D<0GEJ3z=sR83SEjo^TZX!IK-3> ziNINn5C^BCGGK6e{VeAfmnYNr-w(X}2yp-9oF4V?A^-pJuzS}*>FzTkF3V*x;2tB9J0MLWRxxj&o+Jp}~{F*?nWid2Jyde1>pZ*FDh=qV2UziX+ zED^wYUSK5g2etzS1TFe?zy&~B9{?XR02xcc=YWHh6b4apN=5XjI9KX?h!Y8XA|2#F`05eA_3Di@J)Nb`;Ym%t`9dA(X8 z2xA!h!RrWO7=TX<4>Yid1Rr#W1wpVVVUYvoKo7<-s>ojD@ogA9WF`fO0g{*xBzr)@ zLIoR`JYp*P;9np(2!R2B2Oz(L#EyUig8+xIdw|dZ_vE;P#t1?X1b+8pA;ANu0sP;Y H1;juD{u;iw literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c91ed2fd23efc317a9fec7f9244f5ecf26bfdaf6 GIT binary patch literal 698 zcmV;r0!94+0JZ}EfFeKmfrIjX59|Np9uLp{LL3k1U_W#*kbcNuF#vwR<^cS;@vIO) zd(Z#CF}ve9B@qX-JRV&5#tfn=$M69PXF`dC-_IZZ0Sk>X2aoI?k-rCw2tNFDh(7RG z1aJsF{OCR-a1Q{$x3&;_+0i069sK5s4--KE3qB7Yqr`7u@&FI;)>rrp1JI!=ED16{ zi|2eOP$&mL2sL^*JbV9r{(!)9X&8`x@E~~0{Q&eFj|1S45O~kx-2i$rMgb51`=XFY z{7@c~_&7X%AB}K5FZveQ1B3uPee_r!fBx`1X5jOjOTpql6S(+u|M*Be_!7x95WXpK zPLKW!4>$%49$ov|$bZxR2|R!U30bH0tOFAfIQ$(2*5D`?RtQVL>}ORfY^cfK@wo4#6MrnKs|tmU<0WTLH;XP z27sI(^o9V%@FvkNl$ajh@M$c>{x_Jwy*v;P#4Z6m2#gaC7YC$sfA@mGI8b;bBL5Hv zl>>p}ulg3lJ^Tm<|BIl5$ALfoSM3lU2l@jagnjXN6H#zK_4KgJKlR@P9)Acv7K8uq zuhJkK&-_qkJ@}dkx*z}k{!f7M-}}L#m&pO;={q_P6AHB35AhFN`%)TJ2HpaDrD0~`qk(=2CEZ z0f)!)C5Sy^VDfDd6n=P6c!CNF4@>zJeV5sIJm5g`(0}*gLcxQ{tS}II8iWXe@eB|E zXaM&oh#-OHDi9%W;4^FixNpGtzyG;6_}9XI3LFReE(ABI%&-txX8^(=_6Q6zF#`F| z%pwXHSUm6OQH)?em-v`H|E9r!(1@c42fM^ULUj;%Vgc))|K1Fy>Kb?a9=!ZL{EAT6 z1w0;~ugGj@5C#axa1?NQe1YPw7#HjRdiZJo@l^SIcmMtl`T!3dm;X)wiUZI8-@skq zAn}sVy5IRje7^$Wz<=Pt@uKiS==&f4;{o%GgT|Nt_kZdD@qLIqwsLTI)$jj*{(v4o zPrv8!!7vCsb@%_@{(}R60SDkA5P1JeqyPQ^#q2GC2cG?kAOw2~a6#jN_us+G|A+7a f<$u2eTmSC}k$89X5PN_N?%5stv_aF0B#1shQS}MQ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..aa5353e988d02785f45759a024931abe7d580086 GIT binary patch literal 584 zcmV-O0=NAE07L@+fII=<4*+-rz#ahb2Y@^IANT|F;Rk?x!S}#`z&(Kbz(C*~0DZs# zKZbz<@kP z-_ZGk-W5OxmVe$YUN}5vRseX=FaHn!_#S((c=Kc+^8fh5iJ!HD#(O>ojswBL|KI=9 zyXAl$Ey0L`%fG>Z-}v0Uoqw17zfWUvCftXMrUwwc* zFdOIv=nzr}54)K^iv!95wSa!G^7S~tJCHd1P#$^^c)jswmy;2(?+ml*DY%6Tpaje?1R4~z?+C+R@JB71OJ%^j$i~g#Q}fdP!0e4@$U+bI{^s# z3(Nlv;0TA07lYt1>XG_?f57p%{4ekc#4b7D#lRpxNFUrDAR+mp#tHC`{fFbU28aM| z{|{g!U}Yi1z%rjedF|ox@OZ&E5DPI#e_na`JbB{LzW^w(J#=94pcIrmEe`+y literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..837c6c71defd8be280776e7881817fc68276b5d0 GIT binary patch literal 610 zcmV-o0-gN<0A2$B|KVUk{Q*P)Fi?2?0rvt2kDwoLFnIg{_W=j^KOjHgdBMT)0R98a zDj@jq1I#KQ_}~M|;Q;Id;{Xp%fIlVx`hWxc9=`B>kL(_GhKz#+o><3>gVG5B{Tt>8 z4;U5;!}CwXJVamY_&z)lfe}FLAMe0Dt_H!Nasoqr`-9r~&_@VJU>l>0Krj6W95O)w zgJlpe;FN#haR>y*&>wsRUrhppDF-nZ{sYsG|A@(;VDX@2Js+@oPGA%6%nc+tE0kSi zuxJH>Lj(tm3qcDYD|B!X2tYh=AoBP#)&UWmL9h@2c-lSS_KA8RbO;895vb?`+9^1J zKqL|g{UbmRX+$ywAO;Ttt3U_0LJkiYg@OTE2b}yKQ3wz`aF!;BgU_B1DFg(5A@ZVV zdEoJzgVn$w5#o2S;PHin%RrqGp+G;L5P3mC<-mYJ58@9VCwyLBV0pmdiSdjD2SN@Q z8NBEa$N2-wgZ=&g0qGDH4O%!v8W;Zm|NDc@SRg@@1ImB)|6{@DKq!m?&N3Yo|NZ%| zgUlq?4N0o0xY&yEj|qzoQt^FED>06iEa;GRJCuV4t{^!eXG#1C2(0)+vGdoW=5 z-AFJnC>}#T4`yhz^{KA$Q(_^4>({vevs<0996^* wNHeH?5Gg=DU|{j6KxP1O`UB1b0N_Ay5Dfv)f$A(Dg8+f^cz{o!766F@+?Nvri2wiq literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0000a886313b8c265743efe166ccfd156492d830 GIT binary patch literal 740 zcmV2edpMFaQvP#()oKH^LrM60rl^I503^{{iLsHy|)^ z0P@TO$c~T*6avV`F91BQ2NQrnAQ7N>U;*j-2b3ZK1#_7gbPDB+UsoNaWG5dPb%aa%Ma{d z|DEDsz@&x(4~zyiF!OMK^XY*gSOo$Hj1CRJ{O`H{==f-1o&bS^#{qtz;s2(wI1VBV zR2T#eE<0=n8}}~2CKq!|)qA>9R0!Kjw;7H&PBItkNnc#WQA#nkC@B-!W2amiSaeM(VZUFM|55zur z3vdiz5rDaP0mKg|26UD%2yi^UB;p606xKKhI6S}qaC+Xa&=0^Es2%ZpVYol}I2f=O W5qn`E9|>4I?g03JC zA2bOE00<&62h@N_MMD3>!RtVd0SE*!_y@oqya2gi1HuI$kb}V0E5g61P?e66wYH9giI33j52{(AdrB`gVf+cal;Nwlp<4z0LlXagupw1_IjTN zArTdbFoEVNECQfnMiC(pJ>mfYBMcB;p<UWSb^&U9gP8?HUvQ}Q-S!Aj0Rwr5P2)idN68af)NZK2tD!;9ESo92@?RI zh6)clN5Vq^MF;@_GKB&s2`okA)ew0}AXG>YEJP^P6xl@}IEWEAK;n-a1iZRX z2$W|b1X>6jLFI4qM!wUzT z3Mdau03?0jVqgpk5>2tL|o-Vkkr_W=P; Xi41@f1_$-wIw13am}x#>`Gy0~KbO0F literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..edccc7396ec68d5dd2a861017a681b2763c1a4c1 GIT binary patch literal 451 zcmV;!0X+Tz0KWkM6hI%*fPX>)+z)6lKcGPUz(7I#PwD_arU3pz{4gKTMmK;k_{2d3 zDe-;_GJ(K9|L_=t*8Igk0EA=6#lS<%$2b#|96X)?8DOCw>-+=J90#Cef#ZOI;2`rr zNu*W-zzdWr%n2f(z=7vr0gnR~(2t^UO zA(FI0F%QWy6vBy!gahH8Qk*0~K(B;I3|a{RiG$`r{)|F6C{hQyEMjnpgn_!C1EfGC zkqBTsfDa_TQWL`<{z1X-6#vvpL!g70V9{3ED{Pb`z z{6$QLp%MGwB+w8k2!*2@&>_PW@qo<%P6Ysrd;zFN8>kq@Vj&QFT7bk%C@{HXFbbps z2rLtU1Ka>0(GCd2hUf-62Y?DM5-X@w>^KMRlm@CSfA0hhpbq?iBy zfrHw>1U~>!W5l;g-C!L zl0W%Q5+I;30>DxO7J@)xVEK@LqY#b?6oKxG7@Q(uAZRcEsSpVyLKqJ)14%EGgz(5e zkZ^m&KlKuj=pg18$$#=-LHsq$0JyLIj0iCIxqugy^V7gQ1=t6u@PYIH)8HS)UkBB| z3OoV&8U!AM(Ju(SP^F9i%fST<2d;7ffXPqKM*|0_D59#990~of7zs24E{z!Gfesk2 zj0R{5a3};|KKD?ejKo492DJdlm{4VjjSi^*f(s2~KnDhha7H8miwA%hFA@Mo0zNrV r1;+vWK@bLD3)BEMcz`zG59&Zam1IO9e?TBI0DiqhA5j1hwgdnmDfpDF literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..ade67d1016ab61cb52596c9cc607f61b30ea100a GIT binary patch literal 402 zcmV;D0d4*P0FD6wcmu#50PqKZJOSVj0C)qy9suwMfII=<0ssHtVC(QeU=iSb&HzL3 zgM;h+e}H-;fa$RjDQco7?di^51Rl;u)Gj_%m726q2vr=0C>O%Y7!X&24R8n zh)|%w_<{$@5k!K2A>j55m7)=dhC$9x0x1;}5y*hZ0qjX1{HF;JzCZ!*0Z0s52?33R z=0X09LO3Q-pM%{NF*roR1;7Wq0+9fcL@|&bgnSO2M@{~-Pg z`;~HE{G0+20RKS2?~4EE)P?_Wjes7!ub!O9I1l(BLGqFw1^f^<3jjTT`f_mi55+jR z1Km0&ija90cgzFaY_m wD@TC`afymcg5DYcK17NS<{sClcm>^jCiVOk07yZoxc~qF literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d05e8ae2b4715a5e6ec362ef63a96ac6b1ce0895 GIT binary patch literal 374 zcmV-+0g3(r0CE8Ucmu#50PqKZJOSVj0C)qy9suwMfII=<0ssHtVC(QeU=iSb&HzL3 zgM;h+e}H-;fa$RjDQco7?di^51Rl;u)Gj_%m726q2vr=0C>O%Y7!X&24R8n zh)|%w_<{$@5kvxz0fQxIgkl7w0B8|NsF;XAJ_#fLl;I)@34o*qEd+qX!Sf*hMj;#& zDFfXWF*roRK%kmL0!a{t1L{e9q$h?!{DXtuDgUUHhd~F9crWf%$$#=-LHr>E9{8{R zj0iCIxmW?~%K7Qw9sn@V0rs9Cc-#a+4^RG|0RAfc0&#E$xFEOz!H-S>?oAT#&^!?M z@I5hq`FIqefboIDfyaQ!PuYh9Cx`)}s*_NOaYN-MfPqLvEg0s34j2(2`(}Wr0)R#X z?{x|o%tRspYfub{g$4(`QUL@O8pwbS4G`drNC6fP05D!80E`5E0ALM{1NglICNEF` U+2R1(fIq1K{-6W=AK?E4z^3n-*Z=?k literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..5aef127622c6a77c35d1a33e111aca2f49d2cd7a GIT binary patch literal 440 zcmV;p0Z0A;0JH%Bcmu#50PqKZJOSVj0C)qy9suwMfII=<0ssHtVC(QeU=iSb&HzL3 zgM;h+e}H-;fa$RjDQco7?di^51Rl;u)Gj_%m726q2vr=0C>O%Y7!X&24R8n zh)|%wQ2`JD;DPdlQ6Qhld>|g7Vzfdr5Xd~@AP-m(NT`^OL^FU;NF#G0!h2Z~y z1R(cN8C*Xf{P;cXKr)^X2ObZ4qyh;5PLIO|QJBX8IyZ~}K5Pon;6dDCVv^vuhJX)| iB7^yeKn#up`Kn+F;5Z-vw}E#gL;;=wcV7v;e+58OX1XQ- literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3be1790d74ca3b2fce974f633aaa7e01de7b81dc GIT binary patch literal 449 zcmV;y0Y3f#0KEYKcmu#50PqKZJOSVj0C)qy9suwMfII=<0ssHtVC(QeU=iSb&HzL3 zgM;h+e}H-;fa$RjDQco7?di^2q-W;Yyl#|@IeI_2duyZItm^@#xMy0JwnA$ zkjM}vKnJWaK2Zt~@UX!3f(ObGM1p@I_<(wbO3?_!Lm=~rfee5J0x1;}5y*hZ0qjX1 z{HF;Jz89VW0Z0s52?33R=0X09LO3Q-pM%{NF*roR1;7Wq0+9fcL@|&bgnSA&^yK02ABu5sl|h@N4$1{oLzFaIwB3HU+d1BXKa<$%dg$HIOkbHE~@p#TZ^fDM3?0*L%z2j+mt z{9*Ua0Sm$Z00=?upfb3AKl$)`+JI#|APzhp^+*H~0G%I(45KlQ0(5T}0DRaLqrii> r#Kk4SZw&w+B1H%D5P%sR2lG_G6~J&n0dE5CNQeVG0`9&Odj1N48I-`J literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c457e78771463e34c9357d1c8dd27ddc2984d33c GIT binary patch literal 466 zcmV;@0WJOk0L}pbcmu#50PqKZJOSVj0C)qy9suwMfII=<0ssHtVC(QeU=iRsfe-*w zfDrs3;Bv47+x>rldLw{xzzM_vcnBT>4>S>w0AN7$;0#I?W&{)(2oFKAa4@_OK}G@V zFaZvNhmakVf)Ec#zzAv*83F{T0QH6k${|970Y?oG2cXod5Q-!d`47Yc)G}6xMj{yp zoJ1lZ^g5KniHPJtWB~RgkN#7Hh+hlBu4oECV$etoY#%ZY^kNagGK~Bl=&^~yCJ-(F zJ>V3G1d<_)fczui_mW>J5(*px@ec+gprW7pj{%53$UlPqrmA>d!Z<8ZJ_q1bSFfAr+x@E?kC zaFs!uqz@$MpN>5^kU`GLIxQa1~30F0txs*;{%670p)fI+{{RRR literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7e83e14a5ae80fed0dfe4163d65bc5bb431613e6 GIT binary patch literal 350 zcmV-k0ipf@09pY6cmu#50PqKZJOSVj0C)qy9suwMfII=<0ssHtVC(QeU=iSb&HzL3 zgM;h+e}H-;fa$RjDQco7?di^51Rl;u)Gj_%m726q2vr=0C>O%Y7!X&24R8n zh)|%w_<{$@5kvxz0fQxIgkl7w0B8|NsF;XAJ_#fLl;I)@34o*qEd+qX!Sf*hMj;#& zDFfXWF*roRK%kmL0!a{t1L{e9q$h?!{DXtuDgUUHhd~E0#!LT`0uSM?UKtQA-7L0R1hYVN712hFV6ap|Gd#F&xVj&O%T7YCsC@?+hkO&~K){|ERc09Xc%0uQ)60v!(r zR{%IO3BW$C0V41N>M#Q=83LhzGJ-(C^9BKwAP8Uv4IDx~4vYZk^aVmUI1ua{fP7E@ zhakcO;=ltb^g{%2i2(?>Fo=jgCIcd#L*yt3hzN^^2B5%|)sXl>LGuU!4I}vrfdk=u zQjhdr1%S2iy=^F@Sx>ClCl=KKu}Lc!TT!I0STn5Zzz{xC8jTfC7gD R_?^t!2l=@{{txc}J^=C5d%XYv literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..269e5b1d860d851c52cc46fe88b260d4ba0f9a9b GIT binary patch literal 317 zcmV-D0mA+P0675wcmu#50PqKZJOSVj0C)qy9{}J$VSx>WL;?FSkOOc32Y^r@AJ6zg zZx9F%f(HPHgW~}KfkyzNa2Lb^4S){_RDtggh*$vU1_!_XK^QuqJ|N+vyhMTVj~yS< zRu5?Tz<>q%l!Mr|GXOFDX=n(91Jb4sgGzO3?r{gO9X`5w;sv+>RPy2AV{`xuwRpaA zI)DZs1xQicLF*6$EGgh1g_J=6$94!I?6c8+M zaHrubuL1@SQ}U7|9|VDR$ss@pRaQI$8=1_lq)tCP%rP)h-~V2@}Tv@jpB0&{>Hz`W`JKd=njggbmVMfl(rNH|CM PkTM7aMhFL+tl;4G_Y8T; literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..07a63d6424edfe232cc55faf2756cca9485384c3 GIT binary patch literal 398 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 K0l^!}zz-0n&QtRM literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..392905a559e718552e9db176de5b7cc96aee167a GIT binary patch literal 541 zcmV+&0^2HpaDrD0~`qk(=2CEZ z0f)!)C5Sy^VDfDd6n=P6c!CNF4@>zJeV5sIJm5g`(0}*gLcxQ{tS}II8iWXe@eB|E zXaM&oh#-OHDi9%W;4^FixNpGtzyG;6_}9XI3LFReE(ABI%&-txX8^(=_6Q6zF#`F| z%pwXHSUm6OQH)?em-v`H|E9r!(1@c42fM^ULUj;%Vgc))|K1Fy>Kb?a9=!ZL{EAT6 z1w0;~ugGj@5C#axa1?NQe1YPw7#HjRdiZJo@l^SIcmMtl`T!3dm;X)wiUZI8-@skq zAn}sVy5IRje7^$Wz<=Pt@uKiS==&f4;{o%GgT|Nt_kZdD@qLIqwsLTI)$jj*{(v4o zPrv8!!7vCsb@%_@{(}R60SDkA5P1JeqyPQ^#q2GC2cG?kAOw2~a6#jN_us+G|A+7a f<$u2eTmSC}k$89X5PN_N?%5stv_aF0B#1shQS}MQ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..aa5353e988d02785f45759a024931abe7d580086 GIT binary patch literal 584 zcmV-O0=NAE07L@+fII=<4*+-rz#ahb2Y@^IANT|F;Rk?x!S}#`z&(Kbz(C*~0DZs# zKZbz<@kP z-_ZGk-W5OxmVe$YUN}5vRseX=FaHn!_#S((c=Kc+^8fh5iJ!HD#(O>ojswBL|KI=9 zyXAl$Ey0L`%fG>Z-}v0Uoqw17zfWUvCftXMrUwwc* zFdOIv=nzr}54)K^iv!95wSa!G^7S~tJCHd1P#$^^c)jswmy;2(?+ml*DY%6Tpaje?1R4~z?+C+R@JB71OJ%^j$i~g#Q}fdP!0e4@$U+bI{^s# z3(Nlv;0TA07lYt1>XG_?f57p%{4ekc#4b7D#lRpxNFUrDAR+mp#tHC`{fFbU28aM| z{|{g!U}Yi1z%rjedF|ox@OZ&E5DPI#e_na`JbB{LzW^w(J#=94pcIrmEe`+y literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..837c6c71defd8be280776e7881817fc68276b5d0 GIT binary patch literal 610 zcmV-o0-gN<0A2$B|KVUk{Q*P)Fi?2?0rvt2kDwoLFnIg{_W=j^KOjHgdBMT)0R98a zDj@jq1I#KQ_}~M|;Q;Id;{Xp%fIlVx`hWxc9=`B>kL(_GhKz#+o><3>gVG5B{Tt>8 z4;U5;!}CwXJVamY_&z)lfe}FLAMe0Dt_H!Nasoqr`-9r~&_@VJU>l>0Krj6W95O)w zgJlpe;FN#haR>y*&>wsRUrhppDF-nZ{sYsG|A@(;VDX@2Js+@oPGA%6%nc+tE0kSi zuxJH>Lj(tm3qcDYD|B!X2tYh=AoBP#)&UWmL9h@2c-lSS_KA8RbO;895vb?`+9^1J zKqL|g{UbmRX+$ywAO;Ttt3U_0LJkiYg@OTE2b}yKQ3wz`aF!;BgU_B1DFg(5A@ZVV zdEoJzgVn$w5#o2S;PHin%RrqGp+G;L5P3mC<-mYJ58@9VCwyLBV0pmdiSdjD2SN@Q z8NBEa$N2-wgZ=&g0qGDH4O%!v8W;Zm|NDc@SRg@@1ImB)|6{@DKq!m?&N3Yo|NZ%| zgUlq?4N0o0xY&yEj|qzoQt^FED>06iEa;GRJCuV4t{^!eXG#1C2(0)+vGdoW=5 z-AFJnC>}#T4`yhz^{KA$Q(_^4>({vevs<0996^* wNHeH?5Gg=DU|{j6KxP1O`UB1b0N_Ay5Dfv)f$A(Dg8+f^cz{o!766F@+?Nvri2wiq literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9ff56a5b6bd83d39c6585dafb084113387bf309d GIT binary patch literal 741 zcmV2edpMFaQvP#()oKH^LrM60rl^I503^{{iLsHy|)^ z0P@TO$c~T*6avV`F91BQ2NQrnAQ7N>U;*j-2b3ZK1#_7gbPDB+U69Vy z2d})|M3D~)2*KxjACw9NtPlv3%2fI<=fqYpC`JMNAOZbLLFM@O69xpR5TL;;kZ&wM zv48$|iGu=y7zjQv7}Uef!T-;u1c9OhgeEXZ92#R14<0x?VUR4PTpn0R2t2>t^7yL9kti^WY(e8% z2af;$0dNeKDo`E-93GeRaKs{72$D!_6M%T`oC3cYgo1+sguF|DVj0x`W)B_(0t2Li zLmEV1AFl)B{S1u`0c1CcR7V2<{{Q|V@qlR{6sUUupb^dk^nd z`{45EK&FvLi4;m6ARtKSAiN120pwi|{4+ccIs`5tFCG9~z98}UgU&C2CJn$IUIF-r z&jD@$i~=whF90}!d04o9jcmu#50PqKZJOMC(e@*~H;Gcu)Kp-FI{sIrE!~!3HfrIK{fDVi> zA2bOE00<&6fJcGxAQBVFfe%V z2?Po(1P}^v0C>zG2xA9~2ufh`6Nn_h0*o^N!C(S$6qr3?0P+rtY{w!sFnNW<3O&Gk zC9wT8f5ItaOfd_~*OhgYk2s}k& z0iYO!9@H2I{!R!IaNrw+4_FxNU{(lyfXFOW;C>`v@t9B|0P2CSOq13hXmkeVx$Jlghm1hk|1&b^56rE9-u*b zk`z`43?iih97Y&eJm674dC)Kbk@t^KHL{N x0tncHk_Vv>zzCfd@UEO1VEw>AQ=&RRdj|v`*MLBS&H_(>K!T0}e_#N^0q7Yl$LIh6 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..80cb06fd3cbd753e5bf6f00f85a67bee5a0590ad GIT binary patch literal 492 zcmV)+z)6lKcGPUz(7I#PwD_arU3pz{4gKTMmK;S{sc4Q z5e5Umrk^9=vnU*SF-SfRq7N02#{ta&$w0Dd;runk9{8*#h#oL? zpn`|t4+otp@uYxyFYqOpfCv0UAb8RN;~c<20p|dpgVzBAfI@5F^SA(p1TP>la);yq zKzQLakl--Rh3F4FUyEM>0}MDG_)L^!Tu=xYJ>Zd5NxcMq_(?FdlcdpjPc#Z}#e8CO zMO1)BJ^*vTP$E}QF^t4QAoY-1fW%BFFu7zj3ZaNaf^Z;vQUGEN5a5hRZjc-Rw7dYp z@GDp(AySW^3;=~uQ?zglu?Pg@5T)Z>8J(~N;}N1AS>nV%!5)YJPa`p_olv4@E&zNWkwRctC_R7$4g-w>^KMRlm@CSfA05|Yd-vDL6 zrh}m*mk*cyGWGx=$00Bbd_3^slEc9uABn*Va1<7}%{%~tpfJ~gKoN{-w5JrATcm{vup{D1Q;0w-&W_W-d nPOl>XE1giJZ<8y6l#+*4fXD!a1qaL2M1)X4c|-t0*bo4Ks86b< literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c014858502e8d153d61a39604e4128198513b5df GIT binary patch literal 463 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f46aabadf6b1ae21e3d61fe50b3691c7d6c063cd GIT binary patch literal 521 zcmV+k0`~m@00ja7cmu#50PqKZJOSVj0C)qy9suwMfCl~!-UT!tw-1;80uQ+4CIOF! zfyz7&Y&;SH_?!XCzz$pm1_c0`cmW1AUIhRSF`!xn!~k{xc|%|jFhIeE;s7}SJa7s*c2Y|^a2<$=eApaMJ1^j@| z!R>*_Kw@C=fpCHE0HnYqkPIjP=^qEYn)yh8Q6L}Kcrhml0>RW^6G#X858%Jqpc#ot zXmU_2n)tuaFnUfwJ=1rhkb4GHFf2>f6M#O8p7;QxRG9?>hP z5UwAO{(K(N3s4ZJgaOBc+JRIt3;{Yn3>ZDB03nQU6Qg)(hyg(5U{;R;55Nb=@PF;$ zpby**&oKZjYfqw_UW%0@E literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..07a63d6424edfe232cc55faf2756cca9485384c3 GIT binary patch literal 398 zcmV;90df8T0Ez(scmu#50PqKZJOSVj0C)qy9suwMfCl~!-UT!tw-1;80uQ+4CIOF! zgX<3jfPNA+B6Pzk4iom2tn#;^n#umj2)0D*(zKo1-Q8UO(h1Iz*AKn{saKo1xP zj)D&Wh99IJJP5=B5D$o;JZusHD1+iHh=9~65D0)iBuBB7U;*_bz<=hjC=9?K6dnWu zJph1^L?03l@i1UO`M~5LF))3=DKH5lctQ0hzET0@{85TQ@O2P)tcExaXbwsRlUEPn zt|0ftVKhMTgRKM}^sB~_0qDQLmSPWjKs;lZ2p~T25I6)Tz7J>+ysiLY@6g zO6mkG0L(-p09gg72t>kz1KNR9F$l2MLI7Go2tlG85s3g704*;7Fnj>!2c7~xfHC`l smN*Z2$Qet{2y6j)(Cp6;1F6;IUcmu#50PqKZJOSVj0C)qy9suwMfCmBpkAw5U0GI>vco7%~KIHHT z1UwyF2?#uA0Q$H{0pdas1jYg55Woy789)b&0yYnrFg&mmpnSl=;|QQxQ?mgFj3+_D zH%LT7<$*}RbV22y8i+mb03m?St`HayJ>`HQ!0=-bC@?+bz#*YeA@E2bJ>)?_LF)kn zj#5D@pd-aX!1M3}$K?YDxMXsX30DFi3Q$SHKg+Wz(67Z8-P9y0uM6tm<%3p;CwCweq`t<5GWL?94Aeas{f2wnmn4S)O| z0YKn1MNcxw0z(|^5sxL?E_DWKtbc>!Jr~=4-}B)a6tGph%)1~B0Iz@!4=gh~K|3LmQUL&XqM4gg-Ku?-MBWDtu45FU!Lnhgj>GYI4e z{Gs!Z0Y`xY2dQ*Ny* dI7Rs27DoVFD1bfW41$AzguwvwjseIfKm^${pj`j} literal 0 HcmV?d00001 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 315d585f7c5669131cba4646bb1e8ecc06185b95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 664 zcmV;J0%!dJ0F(j%d;1$^CSV+fPOF#cm;xmA%K5?!V4I9JZF#y zWCMXgkl-L7VSquV0P%-^qvBDa$ZQY^fEZvr0C@4>HvmA(q%jBu00K}94gzKtECljH zh=b$c5(xD31%QT)ih&rA(J_%23_?Rf!f+r!@q|zTBO=Gi;8=+U3lYG8gT^61hDh>Q z`g{tJAc10h2ttrhFmf(VKR*PLP9fPNIDiI$fVfD#KmGVTf06Kdz$yAKBp-hWi5JI3 zW?CFF!J_&=|G@EwPBd3wdD|j7PoxI;4;VkgLzaMi3?pqG57OfV2ag^jpa+aH4FG!x zJZd2Fql3%pC2cIJ~4^+`WJwQ(4-I_;{0Hr2!2XAc!NVO5DFt?f6eiPdLVe1<-iOl0ep-L z{{I+669I^acq0e`gh}9^*o+1t1fXF!-UuTAq4S7D2N?j6K_(a}H;mXUA%sXGAL<+2 ze-Qi(TgiY=jQAcl2n4`PFdha1E$HAwd=PMWg2x&EpTVXW2>0WG@Xx?O;{g9-!Qw9* z0lat+0a(ES;{e5f@9+o+JtK?(2bK}&JOFtNh5}F+2t2(3@t{C~;yEY>1Hcb0fP8e& z%mio>MxlsEK!e~XjAkMaSY$#(1uy)56B58eLFWetpa5M$4^99)WPtQ!k|dxXfOz>o z;08pN1O6YR$^W3Ri6lBf;PK<}{CxUk?+{2Nk|Y24{rmm@e*H3L@qy_z(hHT}x7fFC y-~jXbKs1`IRLX7H>{~Wa2!K4GkPQ~QR3Bh^$cOF^X$gJ7?tgd$ARc%I;D8v3p%UW& 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/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/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..d085678d --- /dev/null +++ b/scripts/flipper/assets/templates/dolphin.c.tmpl @@ -0,0 +1,92 @@ +#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 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 = { {{ "%s" % ", ".join(str(i) for i in animation.meta['Frames 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) From 6264ee8c3b2c13a215fdcf643a8d1541dad1f990 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Sat, 29 Jan 2022 12:39:10 +0300 Subject: [PATCH 08/12] [FL-2212] File validators and archive fixes #972 Co-authored-by: Aleksandr Kutuzov --- applications/archive/archive_i.h | 1 + .../archive/helpers/archive_browser.c | 1 - .../archive/helpers/archive_favorites.c | 49 ++++++++++++++++++- applications/archive/helpers/archive_files.c | 8 +++ applications/archive/helpers/archive_files.h | 1 + .../archive/scenes/archive_scene_rename.c | 10 ++++ .../archive/views/archive_browser_view.h | 1 + .../desktop/scenes/desktop_scene_lock_menu.c | 8 ++- .../desktop/views/desktop_lock_menu.c | 20 +++++--- .../desktop/views/desktop_lock_menu.h | 2 +- applications/ibutton/ibutton_app.h | 8 +-- .../ibutton/scene/ibutton_scene_save_name.cpp | 9 ++++ .../irda/scene/irda_app_scene_edit_rename.cpp | 10 ++++ .../scene/lfrfid_app_scene_delete_confirm.cpp | 7 +-- .../scene/lfrfid_app_scene_read_success.cpp | 24 ++++----- .../scene/lfrfid_app_scene_save_name.cpp | 9 ++++ .../scene/lfrfid_app_scene_saved_info.cpp | 8 +-- .../lfrfid/view/elements/string_element.cpp | 15 +++++- .../lfrfid/view/elements/string_element.h | 2 + applications/nfc/nfc_device.c | 27 +++++----- applications/nfc/nfc_device.h | 4 ++ applications/nfc/scenes/nfc_scene_save_name.c | 10 ++++ .../view_modules/text_input_vm.cpp | 8 +++ .../view_modules/text_input_vm.h | 4 ++ 24 files changed, 194 insertions(+), 52 deletions(-) mode change 100755 => 100644 applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp 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 99ae8be4..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 + 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/desktop/scenes/desktop_scene_lock_menu.c b/applications/desktop/scenes/desktop_scene_lock_menu.c index 1c94b83e..7a3d51bb 100644 --- a/applications/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/desktop/scenes/desktop_scene_lock_menu.c @@ -18,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); } @@ -30,6 +33,7 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { case DesktopLockMenuEventLock: scene_manager_set_scene_state( 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; @@ -39,12 +43,14 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { 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; @@ -57,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/views/desktop_lock_menu.c b/applications/desktop/views/desktop_lock_menu.c index ad8a0a3f..d65aa30d 100644 --- a/applications/desktop/views/desktop_lock_menu.c +++ b/applications/desktop/views/desktop_lock_menu.c @@ -4,6 +4,8 @@ #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, @@ -22,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; }); } @@ -51,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); @@ -60,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); } @@ -90,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 80854520..e9928a38 100644 --- a/applications/desktop/views/desktop_lock_menu.h +++ b/applications/desktop/views/desktop_lock_menu.h @@ -28,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/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_save_name.cpp b/applications/ibutton/scene/ibutton_scene_save_name.cpp index 5b85d409..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,6 +52,11 @@ bool iButtonSceneSaveName::on_event(iButtonApp* app, iButtonEvent* event) { void iButtonSceneSaveName::on_exit(iButtonApp* app) { TextInput* text_input = app->get_view_manager()->get_text_input(); + + void* validator_context = text_input_get_validator_callback_context(text_input); + text_input_set_validator(text_input, NULL, NULL); + validator_is_file_free((ValidatorIsFile*)validator_context); + text_input_reset(text_input); } diff --git a/applications/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/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_read_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp index 70dc208c..46ff90ef 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp @@ -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_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_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/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_save_name.c b/applications/nfc/scenes/nfc_scene_save_name.c index 83a60e38..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 + 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/lib/app-scened-template/view_modules/text_input_vm.cpp b/lib/app-scened-template/view_modules/text_input_vm.cpp index 06f243de..05e5ed1d 100644 --- a/lib/app-scened-template/view_modules/text_input_vm.cpp +++ b/lib/app-scened-template/view_modules/text_input_vm.cpp @@ -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 From 2b2a7984078d33aa91dfdbde2543491d5f487d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Sat, 29 Jan 2022 14:20:55 +0300 Subject: [PATCH 09/12] Pre-RC Bug Fixes and Gui lockdown mode. (#973) * Rfid: fix incorrect StringElement parameters * Gui, Desktop: add lockdown mode, integrate with desktop. * Gui: fix runglish in doxy --- applications/desktop/views/desktop_locked.c | 12 ++++ applications/gui/gui.c | 64 +++++++++++++++--- applications/gui/gui.h | 10 +++ applications/gui/gui_i.h | 1 + .../scene/lfrfid_app_scene_read_success.cpp | 2 +- assets/compiled/assets_icons.c | 4 ++ assets/compiled/assets_icons.h | 1 + assets/icons/StatusBar/Attention_5x8.png | Bin 0 -> 1690 bytes 8 files changed, 84 insertions(+), 10 deletions(-) create mode 100644 assets/icons/StatusBar/Attention_5x8.png diff --git a/applications/desktop/views/desktop_locked.c b/applications/desktop/views/desktop_locked.c index bbb9978a..d8102f57 100644 --- a/applications/desktop/views/desktop_locked.c +++ b/applications/desktop/views/desktop_locked.c @@ -208,6 +208,10 @@ void desktop_locked_lock(DesktopLockedView* locked_view) { 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) { @@ -219,6 +223,10 @@ void desktop_locked_lock_pincode(DesktopLockedView* locked_view, PinCode pincode 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) { @@ -232,4 +240,8 @@ static void desktop_locked_unlock(DesktopLockedView* locked_view) { 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/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/lfrfid/scene/lfrfid_app_scene_read_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp index 46ff90ef..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(); diff --git a/assets/compiled/assets_icons.c b/assets/compiled/assets_icons.c index bb540f5a..409f7034 100644 --- a/assets/compiled/assets_icons.c +++ b/assets/compiled/assets_icons.c @@ -522,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}; @@ -749,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 a8351f97..3b756c1b 100644 --- a/assets/compiled/assets_icons.h +++ b/assets/compiled/assets_icons.h @@ -135,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/icons/StatusBar/Attention_5x8.png b/assets/icons/StatusBar/Attention_5x8.png new file mode 100644 index 0000000000000000000000000000000000000000..137d4c4d054227f27ad6a7e3e374b100d975d9af GIT binary patch literal 1690 zcmb7EO>Em_7aL~8bUpz^|omTDs`GNSf+{#+5sqt{|hGs2M~O=v!q!&5C=eV3yqN$cH8pR6>G`RwG(RWBWbEkJK-^_v zfiiGJ)Gcee&AJ@s*Ja^vFHB&lPjTirEXNCI!mt3!;0#V;V*_a1k`*?Se7T(rPaIZq z9Frx8YPE`2qqt!e2`Uzg5hP8}bObUYc1?FgH=^77yb?i;B(Nn*H67K^QLm<0Fe(m* zVGu{##eu7KtLt`qd?*CrAq0h!#Ado#G91G$8D^)Wo}3Q6CDBopN8IBfTj)@}?Qd{J zb2~E6|2w^0?is^&CeJ`2+M@Q1@ZbVFTQdQX0k%=GBrtgf=*~W02~QU`VQ7Xm4Xpt< z>=465nJy%#F3@sGwG4C{3eRB=V>6quBYs{-wxBL=$gnK+5R^_N1j|rV4PwVEP_rdb z189;VeV(Txn=Xq*a2)7Gr^I1F>2Ca#DtqCe8$av~r&T<6oX}M$2i>id>tY;sm?nZ| z{H&R6A^5^r9y(hV9Wg07ut%DN&LpV_9m`UqEJ?9cbcBquWYDkAH)K_*{TJJFGa83{ zo@Z04?HE?g4+R#V2CoOF;Has-w>@`zd{OeI<1o`QtkQxz>RQG_p- z!zL6(g*wzw!818Z;S`CF_GVN|09M;PS(IfMc9d>UMr_-Q@3u$w5}^O5mmp(nFTE6#P!fSmv-=dmoM}mdU2?9`nd!3^}k+g Date: Sun, 30 Jan 2022 19:45:08 +0300 Subject: [PATCH 10/12] Desktop: fix crash caused by unconsumed back button short press (#974) --- applications/desktop/views/desktop_main.c | 33 ++++++++++++----------- applications/gui/view_stack.c | 9 ++++--- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/applications/desktop/views/desktop_main.c b/applications/desktop/views/desktop_main.c index b03381b9..83d561df 100644 --- a/applications/desktop/views/desktop_main.c +++ b/applications/desktop/views/desktop_main.c @@ -35,25 +35,26 @@ 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); + } } - return consumed; + return true; } DesktopMainView* desktop_main_alloc() { diff --git a/applications/gui/view_stack.c b/applications/gui/view_stack.c index 39ffc8c7..d790b801 100644 --- a/applications/gui/view_stack.c +++ b/applications/gui/view_stack.c @@ -105,13 +105,14 @@ static bool view_stack_input(InputEvent* event, void* context) { furi_assert(event); furi_assert(context); - bool consumed = false; ViewStack* view_stack = context; + bool consumed = false; ViewStackModel* model = view_get_model(view_stack->view); - for(int i = MAX_VIEWS - 1; !consumed && (i >= 0); --i) { - if(model->views[i]) { - consumed = view_input(model->views[i], event); + 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); From 9f1a2f2d99a46ee88cea84ac882ae063081a29e8 Mon Sep 17 00:00:00 2001 From: Albert Kharisov Date: Mon, 31 Jan 2022 17:09:15 +0400 Subject: [PATCH 11/12] [FL-2237] Fix animation frame order, increase its max size (#976) * [FL-2237] Fix animation frame order, increase its max size * Make frame_order variable sized --- .../desktop/animations/animation_manager.h | 2 +- .../desktop/animations/animation_storage.c | 41 +++++++++++++------ assets/compiled/assets_dolphin_blocking.c | 20 ++++++--- assets/compiled/assets_dolphin_internal.c | 12 ++++-- .../flipper/assets/templates/dolphin.c.tmpl | 4 +- 5 files changed, 57 insertions(+), 22 deletions(-) diff --git a/applications/desktop/animations/animation_manager.h b/applications/desktop/animations/animation_manager.h index d86a162c..74f31b8a 100644 --- a/applications/desktop/animations/animation_manager.h +++ b/applications/desktop/animations/animation_manager.h @@ -26,7 +26,7 @@ typedef struct { const FrameBubble* const* frame_bubble_sequences; uint8_t frame_bubble_sequences_count; const Icon icon_animation; - uint8_t frame_order[20]; + const uint8_t* frame_order; uint8_t passive_frames; uint8_t active_frames; uint8_t active_cycles; diff --git a/applications/desktop/animations/animation_storage.c b/applications/desktop/animations/animation_storage.c index 94b23be6..f9a76959 100644 --- a/applications/desktop/animations/animation_storage.c +++ b/applications/desktop/animations/animation_storage.c @@ -209,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; } @@ -268,7 +271,24 @@ static bool animation_storage_load_frames( uint32_t* frame_order, uint8_t width, uint8_t height) { - uint16_t frame_order_size = animation->passive_frames + animation->active_frames; + 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; File* file = storage_file_alloc(storage); @@ -276,17 +296,10 @@ static bool animation_storage_load_frames( string_t filename; string_init(filename); size_t max_filesize = ROUND_UP_TO(width, 8) * height + 1; - Icon* icon = (Icon*)&animation->icon_animation; - FURI_CONST_ASSIGN(icon->frame_count, frame_order_size); - 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*) * frame_order_size); - - for(int i = 0; i < frame_order_size; ++i) { + 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) { @@ -453,14 +466,15 @@ static BubbleAnimation* animation_storage_load_animation(const char* name) { 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) || (frames > COUNT_OF(animation->frame_order))) { + 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) { - animation->frame_order[i] = u32array[i]; + FURI_CONST_ASSIGN(animation->frame_order[i], u32array[i]); } /* passive and active frames must be loaded up to this point */ @@ -488,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; } diff --git a/assets/compiled/assets_dolphin_blocking.c b/assets/compiled/assets_dolphin_blocking.c index a14b8c5f..9ea09e2f 100644 --- a/assets/compiled/assets_dolphin_blocking.c +++ b/assets/compiled/assets_dolphin_blocking.c @@ -36,6 +36,8 @@ const uint8_t *_A_L0_NoDb_128x51[] = { +const uint8_t L0_NoDb_128x51_frame_order[] = { 0, 1, 2, 3 }; + const BubbleAnimation BA_L0_NoDb_128x51 = { .icon_animation = { .width = 128, @@ -44,7 +46,7 @@ const BubbleAnimation BA_L0_NoDb_128x51 = { .frame_rate = 2, .frames = _A_L0_NoDb_128x51 }, - .frame_order = { 0, 1, 2, 3 }, + .frame_order = L0_NoDb_128x51_frame_order, .passive_frames = 4, .active_frames = 0, .active_cooldown = 0, @@ -76,6 +78,8 @@ const uint8_t *_A_L0_SdBad_128x51[] = { +const uint8_t L0_SdBad_128x51_frame_order[] = { 0, 1 }; + const BubbleAnimation BA_L0_SdBad_128x51 = { .icon_animation = { .width = 128, @@ -84,7 +88,7 @@ const BubbleAnimation BA_L0_SdBad_128x51 = { .frame_rate = 2, .frames = _A_L0_SdBad_128x51 }, - .frame_order = { 0, 1 }, + .frame_order = L0_SdBad_128x51_frame_order, .passive_frames = 2, .active_frames = 0, .active_cooldown = 0, @@ -128,6 +132,8 @@ const uint8_t *_A_L0_SdOk_128x51[] = { +const uint8_t L0_SdOk_128x51_frame_order[] = { 0, 1, 2, 3 }; + const BubbleAnimation BA_L0_SdOk_128x51 = { .icon_animation = { .width = 128, @@ -136,7 +142,7 @@ const BubbleAnimation BA_L0_SdOk_128x51 = { .frame_rate = 2, .frames = _A_L0_SdOk_128x51 }, - .frame_order = { 0, 1, 2, 3 }, + .frame_order = L0_SdOk_128x51_frame_order, .passive_frames = 4, .active_frames = 0, .active_cooldown = 0, @@ -180,6 +186,8 @@ const uint8_t *_A_L0_Url_128x51[] = { +const uint8_t L0_Url_128x51_frame_order[] = { 0, 1, 2, 3 }; + const BubbleAnimation BA_L0_Url_128x51 = { .icon_animation = { .width = 128, @@ -188,7 +196,7 @@ const BubbleAnimation BA_L0_Url_128x51 = { .frame_rate = 2, .frames = _A_L0_Url_128x51 }, - .frame_order = { 0, 1, 2, 3 }, + .frame_order = L0_Url_128x51_frame_order, .passive_frames = 4, .active_frames = 0, .active_cooldown = 0, @@ -232,6 +240,8 @@ const uint8_t *_A_L0_NewMail_128x51[] = { +const uint8_t L0_NewMail_128x51_frame_order[] = { 0, 1, 2, 3, 2, 1 }; + const BubbleAnimation BA_L0_NewMail_128x51 = { .icon_animation = { .width = 128, @@ -240,7 +250,7 @@ const BubbleAnimation BA_L0_NewMail_128x51 = { .frame_rate = 2, .frames = _A_L0_NewMail_128x51 }, - .frame_order = { 0, 1, 2, 3, 2, 1 }, + .frame_order = L0_NewMail_128x51_frame_order, .passive_frames = 6, .active_frames = 0, .active_cooldown = 0, diff --git a/assets/compiled/assets_dolphin_internal.c b/assets/compiled/assets_dolphin_internal.c index 99cab819..373a2873 100644 --- a/assets/compiled/assets_dolphin_internal.c +++ b/assets/compiled/assets_dolphin_internal.c @@ -104,6 +104,8 @@ const FrameBubble L1_Tv_128x47_bubble_1_0 = { +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, @@ -112,7 +114,7 @@ const BubbleAnimation BA_L1_Tv_128x47 = { .frame_rate = 2, .frames = _A_L1_Tv_128x47 }, - .frame_order = { 0, 1, 2, 3, 4, 5, 6, 7 }, + .frame_order = L1_Tv_128x47_frame_order, .passive_frames = 6, .active_frames = 2, .active_cooldown = 5, @@ -170,6 +172,8 @@ const FrameBubble L1_BadBattery_128x47_bubble_0_0 = { +const uint8_t L1_BadBattery_128x47_frame_order[] = { 0, 1 }; + const BubbleAnimation BA_L1_BadBattery_128x47 = { .icon_animation = { .width = 128, @@ -178,7 +182,7 @@ const BubbleAnimation BA_L1_BadBattery_128x47 = { .frame_rate = 2, .frames = _A_L1_BadBattery_128x47 }, - .frame_order = { 0, 1 }, + .frame_order = L1_BadBattery_128x47_frame_order, .passive_frames = 2, .active_frames = 0, .active_cooldown = 0, @@ -260,6 +264,8 @@ const FrameBubble L1_NoSd_128x49_bubble_0_0 = { +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, @@ -268,7 +274,7 @@ const BubbleAnimation BA_L1_NoSd_128x49 = { .frame_rate = 2, .frames = _A_L1_NoSd_128x49 }, - .frame_order = { 0, 1, 0, 1, 0, 2, 3, 4, 3, 5 }, + .frame_order = L1_NoSd_128x49_frame_order, .passive_frames = 10, .active_frames = 0, .active_cooldown = 0, diff --git a/scripts/flipper/assets/templates/dolphin.c.tmpl b/scripts/flipper/assets/templates/dolphin.c.tmpl index d085678d..633a374e 100644 --- a/scripts/flipper/assets/templates/dolphin.c.tmpl +++ b/scripts/flipper/assets/templates/dolphin.c.tmpl @@ -49,6 +49,8 @@ const FrameBubble {{animation.name}}_bubble_{{bubble["Slot"]}}_{{bubble["_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'] }}, @@ -57,7 +59,7 @@ const BubbleAnimation BA_{{animation.name}} = { .frame_rate = {{ animation.meta['Frame rate'] }}, .frames = _A_{{ animation.name }} }, - .frame_order = { {{ "%s" % ", ".join(str(i) for i in animation.meta['Frames order']) }} }, + .frame_order = {{animation.name}}_frame_order, .passive_frames = {{ animation.meta['Passive frames'] }}, .active_frames = {{ animation.meta['Active frames'] }}, .active_cooldown = {{ animation.meta['Active cooldown'] }}, From 0acea5b25f506732c074afd72aeeb3023bb30a8a Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 1 Feb 2022 10:43:38 +0300 Subject: [PATCH 12/12] bt_settings: fix incorrect switch to forget devices (#977) --- applications/bt/bt_settings_app/bt_settings_app.h | 8 ++++++++ .../scenes/bt_settings_scene_forget_dev_success.c | 6 ++---- .../scenes/bt_settings_scene_start.c | 14 ++++++++++---- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/applications/bt/bt_settings_app/bt_settings_app.h b/applications/bt/bt_settings_app/bt_settings_app.h index db379436..5b4a8d13 100755 --- a/applications/bt/bt_settings_app/bt_settings_app.h +++ b/applications/bt/bt_settings_app/bt_settings_app.h @@ -14,6 +14,14 @@ #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; 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 index e43082af..c0b0c80a 100755 --- 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 @@ -1,11 +1,9 @@ #include "../bt_settings_app.h" #include "furi_hal_bt.h" -#define SCENE_FORGET_DEV_SUCCESS_CUSTOM_EVENT (0UL) - void bt_settings_app_scene_forget_dev_success_popup_callback(void* context) { BtSettingsApp* app = context; - view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_FORGET_DEV_SUCCESS_CUSTOM_EVENT); + view_dispatcher_send_custom_event(app->view_dispatcher, BtSettingsCustomEventExitView); } void bt_settings_scene_forget_dev_success_on_enter(void* context) { @@ -26,7 +24,7 @@ bool bt_settings_scene_forget_dev_success_on_event(void* context, SceneManagerEv bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SCENE_FORGET_DEV_SUCCESS_CUSTOM_EVENT) { + 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); 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 33c0bb5a..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 @@ -1,14 +1,17 @@ #include "../bt_settings_app.h" #include "furi_hal_bt.h" -#define SCENE_START_FORGET_DEV_SELECTED_EVENT (10UL) - enum BtSetting { BtSettingOff, BtSettingOn, BtSettingNum, }; +enum BtSettingIndex { + BtSettingIndexSwitchBt, + BtSettingIndexForgetDev, +}; + const char* const bt_settings_text[BtSettingNum] = { "OFF", "ON", @@ -25,7 +28,10 @@ static void bt_settings_scene_start_var_list_change_callback(VariableItem* item) static void bt_settings_scene_start_var_list_enter_callback(void* context, uint32_t index) { furi_assert(context); BtSettingsApp* app = context; - view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_START_FORGET_DEV_SELECTED_EVENT); + if(index == BtSettingIndexForgetDev) { + view_dispatcher_send_custom_event( + app->view_dispatcher, BtSettingsCustomEventForgetDevices); + } } void bt_settings_scene_start_on_enter(void* context) { @@ -72,7 +78,7 @@ bool bt_settings_scene_start_on_event(void* context, SceneManagerEvent event) { app->settings.enabled = false; furi_hal_bt_stop_advertising(); consumed = true; - } else if(event.event == SCENE_START_FORGET_DEV_SELECTED_EVENT) { + } else if(event.event == BtSettingsCustomEventForgetDevices) { scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneForgetDevConfirm); consumed = true; }