diff --git a/.ci_files/rgb.patch b/.ci_files/rgb.patch index 7108901093..51a305aec3 100644 --- a/.ci_files/rgb.patch +++ b/.ci_files/rgb.patch @@ -1,5 +1,5 @@ diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c -index d4c5b91..8b43599 100644 +index 35d2fe6..1af97e2 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -9,6 +9,7 @@ @@ -10,16 +10,16 @@ index d4c5b91..8b43599 100644 #define TAG "NotificationSrv" -@@ -588,6 +589,7 @@ int32_t notification_srv(void* p) { +@@ -616,6 +617,7 @@ int32_t notification_srv(void* p) { break; case SaveSettingsMessage: notification_save_settings(app); + rgb_backlight_save_settings(); break; - } - + case LoadSettingsMessage: + notification_load_settings(app); diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c -index 7576dcf..ae022e2 100644 +index 2462b32..8e045ce 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -3,6 +3,7 @@ diff --git a/.editorconfig b/.editorconfig index a31ef8e753..1fdc58bc6f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,6 +8,3 @@ charset = utf-8 [*.{cpp,h,c,py,sh}] indent_style = space indent_size = 4 - -[{Makefile,*.mk}] -indent_size = tab diff --git a/.gitmodules b/.gitmodules index df5bf648fa..c9373c0939 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "lib/mlib"] path = lib/mlib url = https://github.com/P-p-H-d/mlib.git -[submodule "lib/littlefs"] - path = lib/littlefs - url = https://github.com/littlefs-project/littlefs.git [submodule "lib/nanopb"] path = lib/nanopb url = https://github.com/nanopb/nanopb.git diff --git a/.pvsoptions b/.pvsoptions index 8606eef154..4040dcb91a 100644 --- a/.pvsoptions +++ b/.pvsoptions @@ -1 +1 @@ ---ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e lib/mjs -e */arm-none-eabi/* +--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e lib/mjs -e */arm-none-eabi/* diff --git a/.sublime-project b/.sublime-project index da2ef41a12..0ae007b341 100644 --- a/.sublime-project +++ b/.sublime-project @@ -10,10 +10,8 @@ "clangd": { "enabled": true, "initializationOptions": { - // Use with toolchain version 39+ // Set `"binary": "custom",` option in LSP-clangd config to use toolchain clangd - // "custom_command": ["toolchain/current/bin/clangd"], - + "custom_command": ["toolchain/current/bin/clangd"], "clangd.compile-commands-dir": "build/latest", "clangd.header-insertion": "never", "clangd.query-driver": "**/arm-none-eabi-*", diff --git a/.vscode/example/settings.json.tmpl b/.vscode/example/settings.json.tmpl index 5e0da68977..5e5b5dcf41 100644 --- a/.vscode/example/settings.json.tmpl +++ b/.vscode/example/settings.json.tmpl @@ -12,7 +12,7 @@ "SConstruct": "python", "*.fam": "python" }, - // "clangd.path": "${workspaceFolder}/toolchain/current/bin/clangd@FBT_PLATFORM_EXECUTABLE_EXT@", + "clangd.path": "${workspaceFolder}/toolchain/current/bin/clangd@FBT_PLATFORM_EXECUTABLE_EXT@", "clangd.arguments": [ "--query-driver=**/arm-none-eabi-*", "--compile-commands-dir=${workspaceFolder}/build/latest", diff --git a/.vscode/example/tasks.json b/.vscode/example/tasks.json index c0b9e8867e..681544c321 100644 --- a/.vscode/example/tasks.json +++ b/.vscode/example/tasks.json @@ -75,12 +75,6 @@ "type": "shell", "command": "./fbt updater_all" }, - { - "label": "[Debug] Flash (USB, w/o resources)", - "group": "build", - "type": "shell", - "command": "./fbt FORCE=1 flash_usb" - }, { "label": "[Release] Flash (USB, w/o resources)", "group": "build", @@ -88,16 +82,16 @@ "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb" }, { - "label": "[Debug:unit_tests] Flash (USB)", + "label": "[Debug] Flash (USB, w/o resources)", "group": "build", "type": "shell", - "command": "./fbt FIRMWARE_APP_SET=unit_tests FORCE=1 flash_usb_full" + "command": "./fbt FORCE=1 flash_usb" }, { - "label": "[Debug] Flash (USB, with resources)", + "label": "[Debug:unit_tests] Flash (USB)", "group": "build", "type": "shell", - "command": "./fbt FORCE=1 flash_usb_full" + "command": "./fbt FIRMWARE_APP_SET=unit_tests FORCE=1 flash_usb_full" }, { "label": "[Release] Flash (USB, with resources)", @@ -106,16 +100,16 @@ "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb_full" }, { - "label": "[Debug] Create PVS-Studio report", + "label": "[Debug] Flash (USB, with resources)", "group": "build", "type": "shell", - "command": "./fbt firmware_pvs" + "command": "./fbt FORCE=1 flash_usb_full" }, { - "label": "[Debug] Build FAPs", + "label": "[Debug] Create PVS-Studio report", "group": "build", "type": "shell", - "command": "./fbt fap_dist" + "command": "./fbt firmware_pvs" }, { "label": "[Release] Build FAPs", @@ -124,10 +118,10 @@ "command": "./fbt COMPACT=1 DEBUG=0 fap_dist" }, { - "label": "[Debug] Build App", + "label": "[Debug] Build FAPs", "group": "build", "type": "shell", - "command": "./fbt build APPSRC=${relativeFileDirname}" + "command": "./fbt fap_dist" }, { "label": "[Release] Build App", @@ -136,10 +130,10 @@ "command": "./fbt COMPACT=1 DEBUG=0 build APPSRC=${relativeFileDirname}" }, { - "label": "[Debug] Launch App on Flipper", + "label": "[Debug] Build App", "group": "build", "type": "shell", - "command": "./fbt launch APPSRC=${relativeFileDirname}" + "command": "./fbt build APPSRC=${relativeFileDirname}" }, { "label": "[Release] Launch App on Flipper", @@ -147,6 +141,12 @@ "type": "shell", "command": "./fbt COMPACT=1 DEBUG=0 launch APPSRC=${relativeFileDirname}" }, + { + "label": "[Debug] Launch App on Flipper", + "group": "build", + "type": "shell", + "command": "./fbt launch APPSRC=${relativeFileDirname}" + }, { "label": "[Debug] Launch App on Flipper with Serial Console", "dependsOrder": "sequence", @@ -157,16 +157,16 @@ ] }, { - "label": "[Debug] Build and upload all FAPs to Flipper over USB", + "label": "[Release] Build and upload all FAPs to Flipper over USB", "group": "build", "type": "shell", - "command": "./fbt fap_deploy" + "command": "./fbt COMPACT=1 DEBUG=0 fap_deploy" }, { - "label": "[Release] Build and upload all FAPs to Flipper over USB", + "label": "[Debug] Build and upload all FAPs to Flipper over USB", "group": "build", "type": "shell", - "command": "./fbt COMPACT=1 DEBUG=0 fap_deploy" + "command": "./fbt fap_deploy" }, { // Press Ctrl+] to quit @@ -192,4 +192,4 @@ } } ] -} \ No newline at end of file +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bd2bf2516..b51403f7c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,64 +1,39 @@ ## Main changes - SubGHz: - - **Novoferm** remotes full support - - Fix Decode scene in RAW files - - Add manually -> Add Sommer FM238 option for cases when default option doesn't work (named as Sommer fm2) - - Remove broken preset modulation - - Normstahl, Sommer, MHouse, Aprimatic -> Fixes for button codes and more in Add manually - - Custom button improvements for MHouse, Novoferm, Nice Smilo - - Hormann EcoStar -> Add manually support, and custom button support - - Hormann HSM 44bit static -> Button code decoding fix - - Choose RSSI threshold for Hopping mode (by @Willy-JL) -- NFC: - - OFW: Ultralight C authentication with des key - - EMV Transactions less nested, hide if unavailable (by @Willy-JL | PR #771) - - Update Mifare Classic default keys dict with new keys from proxmark3 repo and UberGuidoZ repo -- LF RFID: - - Update T5577 password list (by @korden32 | PR #774) - - Add DEZ 8 display form for EM4100 (by @korden32 | PR #776 & (#777 by @mishamyte)) -- JS: - - Refactor widget and keyboard modules, fix crash (by @Willy-JL | PR #770) - - SubGHz module fixes and improvements (by @Willy-JL) -* OFW: Infrared: check for negative timings -* OFW: Fix iButton/LFRFID Add Manually results being discarded -* OFW: Event Loop Timers -* OFW: Updater: resource compression + - OFW: Added protocol for Dickert MAHS garage door remote control + - Fix rare crash when opening Read mode via Frequency analyzer + - Refactor frequency analyzer code for better readability (by @derskythe | PR #782) +- 125kHz RFID: + - OFW: Add lfrfid GProxII support +- NFC: + - OFW: Fix plantain balance string + - OFW: Now fifo size in ST25 chip is calculated properly +* Docs: Remove not printable symbols and update docs (by @derskythe | PR #783) +* OFW: Fix cumulative error in infrared signals +* OFW: iButton ID writing (Enable ID writing for ds1971 and ds1996) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes -* OFW: HID/BLE Keyboard UI refactoring -* OFW: CCID: Add CCIDWorker -* OFW: Disabled ISR runtime stats collection for updater builds -* OFW: VSCode fixes: .gitignore & clangd -* OFW: ufbt: synced .clang-format rules with main -* OFW: Code formatting update -* OFW: scripts: runfap: fixed starting apps with spaces in path -* OFW: toolchain: v38. clangd as default language server -* OFW: NFC: ISO15693 Render Typo Fix -* OFW: tar archive: fix double free -* OFW: ufbt: added ARGS to commandline parser -* OFW: lib: sconscript todo cleanup -* OFW: Intruder animation -* OFW: Desktop: allow to close blocking bad sd animation -* OFW: Updater: reset various debug flags on production build flash (was done in same way in UL before) -* OFW: Fix PVS Warnings -* OFW: CCID: Improve request and response data handling -* OFW: Furi: count ISR time. Cli: show ISR time in top. -* OFW: toolchain: v37 -* OFW: NFC: Cache plugin name not full path, saves some RAM (by @Willy-JL) -* OFW: copro: bumped to 1.20.0 -* OFW: input_srv: Put input state data on the stack of the service -* OFW: Coalesce some allocations -* OFW: updater: slightly smaller image -* OFW: Updater: Fix double dir cleanup -* OFW: cli: storage: minor subcommand lookup refactor -* OFW: LFRFID Securakey: Add Support for RKKTH Plain Text Format -* OFW: NFC: Add mf_classic_set_sector_trailer_read function -* OFW: Separate editing and renaming in iButton and LFRFID -* OFW: New js modules documentation added -* OFW: Update link to mfkey32 -* OFW: NFC: Desfire Renderer Minor Debug -* OFW: RPC: Fix input lockup on disconnect -* OFW: Thread Signals +* Misc: Fix typo in comment in QueueTools.py (by @eltociear | PR #785) +* OFW PR 3840: GUI: NumberInput small improvements (by @Willy-JL) +* OFW PR 3838: SubGhz: Fix RPC status for ButtonRelease event (by @Skorpionm) +* OFW: scripts: improved size validator for updater image +* OFW: Desktop: seaprate callbacks for dolphin and storage subscriptions +* OFW: Make file extensions case-insensitive +* OFW: Remove internal storage folder if corresponding flag set +* OFW: **Added a text input that only accepts full numbers (int)** +* OFW: FuriEventLoop Pt.2 +* OFW: Images linting: ensure that all images conform specification +* OFW: **Storage: remove LFS** +* OFW: NFC: Change the plantain last number display from "?" to "X" +* OFW: CCID App: Refactor +* OFW: Refactor detected protocols list +* OFW: fix: Ensure proper closure of variadic function in `mjs_array` +* OFW: **Added** `-Wundef` **to compiler options** +* OFW: toolchain: v39 +* OFW: Furi: update string documentation +* OFW: Fix typo in "charge me" screen. +* OFW: Reordered VS-Code Tasks to follow the `Release` > `Debug` schema +* OFW: Remove unused entries from .editorconfig

#### Known NFC post-refactor regressions list: - Mifare Mini clones reading is broken (original mini working fine) (OFW) @@ -71,21 +46,21 @@ [-> Download qFlipper (official link)](https://flipperzero.one/update) ## Please support development of the project -|Service|Remark|Link/Wallet| -|-|-|-| -|**Patreon**||https://patreon.com/mmxdev| -|**Boosty**|patreon alternative|https://boosty.to/mmxdev| -|cloudtips|only RU payments accepted|https://pay.cloudtips.ru/p/7b3e9d65| -|YooMoney|only RU payments accepted|https://yoomoney.ru/fundraise/XA49mgQLPA0.221209| -|USDT|(TRC20)|`TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`| -|ETH|(BSC/ERC20-Tokens)|`darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)| -|BTC||`bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`| -|SOL|(Solana/Tokens)|`DSgwouAEgu8iP5yr7EHHDqMNYWZxAqXWsTEeqCAXGLj8`| -|DOGE||`D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`| -|LTC||`ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`| -|BCH||`qquxfyzntuqufy2dx0hrfr4sndp0tucvky4sw8qyu3`| -|XMR|(Monero)| `41xUz92suUu1u5Mu4qkrcs52gtfpu9rnZRdBpCJ244KRHf6xXSvVFevdf2cnjS7RAeYr5hn9MsEfxKoFDRSctFjG5fv1Mhn`| -|TON||`UQCOqcnYkvzOZUV_9bPE_8oTbOrOF03MnF-VcJyjisTZmsxa`| +|Service|Remark|QR Code|Link/Wallet| +|-|-|-|-| +|**Patreon**||
QR image
|https://patreon.com/mmxdev| +|**Boosty**|patreon alternative|
QR image
|https://boosty.to/mmxdev| +|cloudtips|only RU payments accepted|
QR image
|https://pay.cloudtips.ru/p/7b3e9d65| +|YooMoney|only RU payments accepted|
QR image
|https://yoomoney.ru/fundraise/XA49mgQLPA0.221209| +|USDT|(TRC20)|
QR image
|`TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`| +|ETH|(BSC/ERC20-Tokens)|
QR image
|`darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)| +|BTC||
QR image
|`bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`| +|SOL|(Solana/Tokens)|
QR image
|`DSgwouAEgu8iP5yr7EHHDqMNYWZxAqXWsTEeqCAXGLj8`| +|DOGE||
QR image
|`D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`| +|LTC||
QR image
|`ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`| +|BCH||
QR image
|`qquxfyzntuqufy2dx0hrfr4sndp0tucvky4sw8qyu3`| +|XMR|(Monero)|
QR image
|`41xUz92suUu1u5Mu4qkrcs52gtfpu9rnZRdBpCJ244KRHf6xXSvVFevdf2cnjS7RAeYr5hn9MsEfxKoFDRSctFjG5fv1Mhn`| +|TON||
QR image
|`UQCOqcnYkvzOZUV_9bPE_8oTbOrOF03MnF-VcJyjisTZmsxa`| #### Thanks to our sponsors who supported project in the past and special thanks to sponsors who supports us on regular basis: @mishamyte, ClaraCrazy, Pathfinder [Count Zero cDc], callmezimbra, Quen0n, MERRON, grvpvl (lvpvrg), art_col, ThurstonWaffles, Moneron, UterGrooll, LUCFER, Northpirate, zloepuzo, T.Rat, Alexey B., ionelife, ... diff --git a/ReadMe.md b/ReadMe.md index 7eb98aeed3..b2911d14d8 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -139,21 +139,21 @@ Our team is small and the guys are working on this project as much as they can s The amount of work done on this project is huge and we need your support, no matter how large or small. Even if you just say, "Thank you Unleashed firmware developers!" somewhere. Doing so will help us continue our work and will help drive us to make the firmware better every time. Also, regarding our releases, every build has and always will be free and open-source. There will be no paywall releases or closed-source apps within the firmware. As long as I am working on this project it will never happen. You can support us by using links or addresses below: -|Service|Remark|Link/Wallet| -|-|-|-| -|**Patreon**||https://patreon.com/mmxdev| -|**Boosty**|patreon alternative|https://boosty.to/mmxdev| -|cloudtips|only RU payments accepted|https://pay.cloudtips.ru/p/7b3e9d65| -|YooMoney|only RU payments accepted|https://yoomoney.ru/fundraise/XA49mgQLPA0.221209| -|USDT|(TRC20)|`TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`| -|ETH|(BSC/ERC20-Tokens)|`darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)| -|BTC||`bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`| -|SOL|(Solana/Tokens)|`DSgwouAEgu8iP5yr7EHHDqMNYWZxAqXWsTEeqCAXGLj8`| -|DOGE||`D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`| -|LTC||`ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`| -|BCH||`qquxfyzntuqufy2dx0hrfr4sndp0tucvky4sw8qyu3`| -|XMR|(Monero)| `41xUz92suUu1u5Mu4qkrcs52gtfpu9rnZRdBpCJ244KRHf6xXSvVFevdf2cnjS7RAeYr5hn9MsEfxKoFDRSctFjG5fv1Mhn`| -|TON||`UQCOqcnYkvzOZUV_9bPE_8oTbOrOF03MnF-VcJyjisTZmsxa`| +|Service|Remark|QR Code|Link/Wallet| +|-|-|-|-| +|**Patreon**||
QR image
|https://patreon.com/mmxdev| +|**Boosty**|patreon alternative|
QR image
|https://boosty.to/mmxdev| +|cloudtips|only RU payments accepted|
QR image
|https://pay.cloudtips.ru/p/7b3e9d65| +|YooMoney|only RU payments accepted|
QR image
|https://yoomoney.ru/fundraise/XA49mgQLPA0.221209| +|USDT|(TRC20)|
QR image
|`TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`| +|ETH|(BSC/ERC20-Tokens)|
QR image
|`darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)| +|BTC||
QR image
|`bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`| +|SOL|(Solana/Tokens)|
QR image
|`DSgwouAEgu8iP5yr7EHHDqMNYWZxAqXWsTEeqCAXGLj8`| +|DOGE||
QR image
|`D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`| +|LTC||
QR image
|`ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`| +|BCH||
QR image
|`qquxfyzntuqufy2dx0hrfr4sndp0tucvky4sw8qyu3`| +|XMR|(Monero)|
QR image
|`41xUz92suUu1u5Mu4qkrcs52gtfpu9rnZRdBpCJ244KRHf6xXSvVFevdf2cnjS7RAeYr5hn9MsEfxKoFDRSctFjG5fv1Mhn`| +|TON||
QR image
|`UQCOqcnYkvzOZUV_9bPE_8oTbOrOF03MnF-VcJyjisTZmsxa`| ## Community apps included diff --git a/SConstruct b/SConstruct index 48baaa95ef..298954fd6e 100644 --- a/SConstruct +++ b/SConstruct @@ -322,7 +322,12 @@ firmware_env.Append( "SConstruct", "firmware.scons", "fbt_options.py", - ] + ], + IMG_LINT_SOURCES=[ + # Image assets + "applications", + "assets", + ], ) @@ -359,6 +364,39 @@ distenv.PhonyTarget( PY_LINT_SOURCES=firmware_env["PY_LINT_SOURCES"], ) +# Image assets linting +distenv.PhonyTarget( + "lint_img", + [ + [ + "${PYTHON3}", + "${FBT_SCRIPT_DIR}/imglint.py", + "check", + "${IMG_LINT_SOURCES}", + "${ARGS}", + ] + ], + IMG_LINT_SOURCES=firmware_env["IMG_LINT_SOURCES"], +) + +distenv.PhonyTarget( + "format_img", + [ + [ + "${PYTHON3}", + "${FBT_SCRIPT_DIR}/imglint.py", + "format", + "${IMG_LINT_SOURCES}", + "${ARGS}", + ] + ], + IMG_LINT_SOURCES=firmware_env["IMG_LINT_SOURCES"], +) + +distenv.Alias("lint_all", ["lint", "lint_py", "lint_img"]) +distenv.Alias("format_all", ["format", "format_py", "format_img"]) + + # Start Flipper CLI via PySerial's miniterm distenv.PhonyTarget( "cli", diff --git a/applications/debug/accessor/accessor_view_manager.cpp b/applications/debug/accessor/accessor_view_manager.cpp index 955c0b2867..aeb90c2974 100644 --- a/applications/debug/accessor/accessor_view_manager.cpp +++ b/applications/debug/accessor/accessor_view_manager.cpp @@ -5,45 +5,49 @@ AccessorAppViewManager::AccessorAppViewManager() { event_queue = furi_message_queue_alloc(10, sizeof(AccessorEvent)); - view_dispatcher = view_dispatcher_alloc(); - auto callback = cbc::obtain_connector(this, &AccessorAppViewManager::previous_view_callback); + view_holder = view_holder_alloc(); + auto callback = + cbc::obtain_connector(this, &AccessorAppViewManager::view_holder_back_callback); // allocate views submenu = submenu_alloc(); - add_view(ViewType::Submenu, submenu_get_view(submenu)); - popup = popup_alloc(); - add_view(ViewType::Popup, popup_get_view(popup)); - gui = static_cast(furi_record_open(RECORD_GUI)); - view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); + // set back callback + view_holder_set_back_callback(view_holder, callback, NULL); - // set previous view callback for all views - view_set_previous_callback(submenu_get_view(submenu), callback); - view_set_previous_callback(popup_get_view(popup), callback); + gui = static_cast(furi_record_open(RECORD_GUI)); + view_holder_attach_to_gui(view_holder, gui); } AccessorAppViewManager::~AccessorAppViewManager() { - // remove views - view_dispatcher_remove_view( - view_dispatcher, static_cast(AccessorAppViewManager::ViewType::Submenu)); - view_dispatcher_remove_view( - view_dispatcher, static_cast(AccessorAppViewManager::ViewType::Popup)); - + // remove current view + view_holder_set_view(view_holder, NULL); // free view modules furi_record_close(RECORD_GUI); submenu_free(submenu); popup_free(popup); - - // free dispatcher - view_dispatcher_free(view_dispatcher); - + // free view holder + view_holder_free(view_holder); // free event queue furi_message_queue_free(event_queue); } void AccessorAppViewManager::switch_to(ViewType type) { - view_dispatcher_switch_to_view(view_dispatcher, static_cast(type)); + View* view; + + switch(type) { + case ViewType::Submenu: + view = submenu_get_view(submenu); + break; + case ViewType::Popup: + view = popup_get_view(popup); + break; + default: + furi_crash(); + } + + view_holder_set_view(view_holder, view); } Submenu* AccessorAppViewManager::get_submenu() { @@ -65,16 +69,10 @@ void AccessorAppViewManager::send_event(AccessorEvent* event) { furi_check(result == FuriStatusOk); } -uint32_t AccessorAppViewManager::previous_view_callback(void*) { +void AccessorAppViewManager::view_holder_back_callback(void*) { if(event_queue != NULL) { AccessorEvent event; event.type = AccessorEvent::Type::Back; send_event(&event); } - - return VIEW_IGNORE; -} - -void AccessorAppViewManager::add_view(ViewType view_type, View* view) { - view_dispatcher_add_view(view_dispatcher, static_cast(view_type), view); } diff --git a/applications/debug/accessor/accessor_view_manager.h b/applications/debug/accessor/accessor_view_manager.h index 66e54e41ce..c0a12cbe8e 100644 --- a/applications/debug/accessor/accessor_view_manager.h +++ b/applications/debug/accessor/accessor_view_manager.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include #include "accessor_event.h" @@ -10,7 +10,6 @@ class AccessorAppViewManager { enum class ViewType : uint8_t { Submenu, Popup, - Tune, }; FuriMessageQueue* event_queue; @@ -27,11 +26,10 @@ class AccessorAppViewManager { Popup* get_popup(void); private: - ViewDispatcher* view_dispatcher; Gui* gui; + ViewHolder* view_holder; - uint32_t previous_view_callback(void* context); - void add_view(ViewType view_type, View* view); + void view_holder_back_callback(void* context); // view elements Submenu* submenu; diff --git a/applications/debug/battery_test_app/battery_test_app.c b/applications/debug/battery_test_app/battery_test_app.c index 5f9934e777..363c8f4d52 100644 --- a/applications/debug/battery_test_app/battery_test_app.c +++ b/applications/debug/battery_test_app/battery_test_app.c @@ -42,7 +42,6 @@ BatteryTestApp* battery_test_alloc(void) { // View dispatcher app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_set_tick_event_callback( app->view_dispatcher, battery_test_battery_info_update_model, 500); diff --git a/applications/debug/bt_debug_app/bt_debug_app.c b/applications/debug/bt_debug_app/bt_debug_app.c index 109feee602..56c67e3e66 100644 --- a/applications/debug/bt_debug_app/bt_debug_app.c +++ b/applications/debug/bt_debug_app/bt_debug_app.c @@ -36,7 +36,6 @@ BtDebugApp* bt_debug_app_alloc(void) { // View dispatcher app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); // Views diff --git a/applications/debug/ccid_test/ccid_test_app.c b/applications/debug/ccid_test/ccid_test_app.c index 46a1237f93..abb8ad3dd3 100644 --- a/applications/debug/ccid_test/ccid_test_app.c +++ b/applications/debug/ccid_test/ccid_test_app.c @@ -6,10 +6,13 @@ #include #include #include -#include "iso7816_callbacks.h" -#include "iso7816_t0_apdu.h" -#include "iso7816_atr.h" -#include "iso7816_response.h" + +#include "iso7816/iso7816_handler.h" +#include "iso7816/iso7816_t0_apdu.h" +#include "iso7816/iso7816_atr.h" +#include "iso7816/iso7816_response.h" + +#include "ccid_test_app_commands.h" typedef enum { EventTypeInput, @@ -20,6 +23,7 @@ typedef struct { ViewPort* view_port; FuriMessageQueue* event_queue; FuriHalUsbCcidConfig ccid_cfg; + Iso7816Handler* iso7816_handler; } CcidTestApp; typedef struct { @@ -63,6 +67,15 @@ uint32_t ccid_test_exit(void* context) { CcidTestApp* ccid_test_app_alloc(void) { CcidTestApp* app = malloc(sizeof(CcidTestApp)); + //setup CCID USB + // On linux: set VID PID using: /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist + app->ccid_cfg.vid = 0x076B; + app->ccid_cfg.pid = 0x3A21; + + app->iso7816_handler = iso7816_handler_alloc(); + app->iso7816_handler->iso7816_answer_to_reset = iso7816_answer_to_reset; + app->iso7816_handler->iso7816_process_command = iso7816_process_command; + // Gui app->gui = furi_record_open(RECORD_GUI); @@ -92,174 +105,26 @@ void ccid_test_app_free(CcidTestApp* app) { furi_record_close(RECORD_GUI); app->gui = NULL; + free(app->iso7816_handler); + // Free rest free(app); } -void ccid_icc_power_on_callback(uint8_t* atrBuffer, uint32_t* atrlen, void* context) { - UNUSED(context); - - iso7816_icc_power_on_callback(atrBuffer, atrlen); -} - -void ccid_xfr_datablock_callback( - const uint8_t* pcToReaderDataBlock, - uint32_t pcToReaderDataBlockLen, - uint8_t* readerToPcDataBlock, - uint32_t* readerToPcDataBlockLen, - void* context) { - UNUSED(context); - - iso7816_xfr_datablock_callback( - pcToReaderDataBlock, pcToReaderDataBlockLen, readerToPcDataBlock, readerToPcDataBlockLen); -} - -static const CcidCallbacks ccid_cb = { - ccid_icc_power_on_callback, - ccid_xfr_datablock_callback, -}; - -//Instruction 1: returns an OK response unconditionally -//APDU example: 0x01:0x01:0x00:0x00 -//response: SW1=0x90, SW2=0x00 -void handle_instruction_01(ISO7816_Response_APDU* responseAPDU) { - responseAPDU->DataLen = 0; - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK); -} - -//Instruction 2: expect command with no body, replies wit with a body with two bytes -//APDU example: 0x01:0x02:0x00:0x00:0x02 -//response: 'bc' (0x62, 0x63) SW1=0x90, SW2=0x00 -void handle_instruction_02( - uint8_t p1, - uint8_t p2, - uint16_t lc, - uint16_t le, - ISO7816_Response_APDU* responseAPDU) { - if(p1 == 0 && p2 == 0 && lc == 0 && le >= 2) { - responseAPDU->Data[0] = 0x62; - responseAPDU->Data[1] = 0x63; - - responseAPDU->DataLen = 2; - - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK); - } else if(p1 != 0 || p2 != 0) { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2); - } else { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH); - } -} - -//Instruction 3: sends a command with a body with two bytes, receives a response with no bytes -//APDU example: 0x01:0x03:0x00:0x00:0x02:CA:FE -//response SW1=0x90, SW2=0x00 -void handle_instruction_03( - uint8_t p1, - uint8_t p2, - uint16_t lc, - ISO7816_Response_APDU* responseAPDU) { - if(p1 == 0 && p2 == 0 && lc == 2) { - responseAPDU->DataLen = 0; - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK); - } else if(p1 != 0 || p2 != 0) { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2); - } else { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH); - } -} - -//instruction 4: sends a command with a body with 'n' bytes, receives a response with 'n' bytes -//APDU example: 0x01:0x04:0x00:0x00:0x04:0x01:0x02:0x03:0x04:0x04 -//receives (0x01, 0x02, 0x03, 0x04) SW1=0x90, SW2=0x00 -void handle_instruction_04( - uint8_t p1, - uint8_t p2, - uint16_t lc, - uint16_t le, - const uint8_t* commandApduDataBuffer, - ISO7816_Response_APDU* responseAPDU) { - if(p1 == 0 && p2 == 0 && lc > 0 && le > 0 && le >= lc) { - for(uint16_t i = 0; i < lc; i++) { - responseAPDU->Data[i] = commandApduDataBuffer[i]; - } - - responseAPDU->DataLen = lc; - - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK); - } else if(p1 != 0 || p2 != 0) { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2); - } else { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH); - } -} - -void iso7816_answer_to_reset(Iso7816Atr* atr) { - //minimum valid ATR: https://smartcard-atr.apdu.fr/parse?ATR=3B+00 - atr->TS = 0x3B; - atr->T0 = 0x00; -} - -void iso7816_process_command( - const ISO7816_Command_APDU* commandAPDU, - ISO7816_Response_APDU* responseAPDU) { - //example 1: sends a command with no body, receives a response with no body - //sends APDU 0x01:0x01:0x00:0x00 - //receives SW1=0x90, SW2=0x00 - - if(commandAPDU->CLA == 0x01) { - switch(commandAPDU->INS) { - case 0x01: - handle_instruction_01(responseAPDU); - break; - case 0x02: - handle_instruction_02( - commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, commandAPDU->Le, responseAPDU); - break; - case 0x03: - handle_instruction_03(commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, responseAPDU); - break; - case 0x04: - handle_instruction_04( - commandAPDU->P1, - commandAPDU->P2, - commandAPDU->Lc, - commandAPDU->Le, - commandAPDU->Data, - responseAPDU); - break; - default: - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INSTRUCTION_NOT_SUPPORTED); - } - } else { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_CLASS_NOT_SUPPORTED); - } -} - -static const Iso7816Callbacks iso87816_cb = { - iso7816_answer_to_reset, - iso7816_process_command, -}; - int32_t ccid_test_app(void* p) { UNUSED(p); //setup view CcidTestApp* app = ccid_test_app_alloc(); - //setup CCID USB - // On linux: set VID PID using: /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist - app->ccid_cfg.vid = 0x076B; - app->ccid_cfg.pid = 0x3A21; - FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); furi_hal_usb_unlock(); furi_check(furi_hal_usb_set_config(&usb_ccid, &app->ccid_cfg) == true); - furi_hal_usb_ccid_set_callbacks((CcidCallbacks*)&ccid_cb, NULL); + furi_hal_usb_ccid_set_callbacks( + (CcidCallbacks*)&app->iso7816_handler->ccid_callbacks, app->iso7816_handler); furi_hal_usb_ccid_insert_smartcard(); - iso7816_set_callbacks((Iso7816Callbacks*)&iso87816_cb); - //handle button events CcidTestAppEvent event; while(1) { @@ -280,8 +145,6 @@ int32_t ccid_test_app(void* p) { furi_hal_usb_ccid_set_callbacks(NULL, NULL); furi_hal_usb_set_config(usb_mode_prev, NULL); - iso7816_set_callbacks(NULL); - //teardown view ccid_test_app_free(app); return 0; diff --git a/applications/debug/ccid_test/ccid_test_app_commands.c b/applications/debug/ccid_test/ccid_test_app_commands.c new file mode 100644 index 0000000000..1daaa70c39 --- /dev/null +++ b/applications/debug/ccid_test/ccid_test_app_commands.c @@ -0,0 +1,123 @@ +#include "iso7816/iso7816_t0_apdu.h" +#include "iso7816/iso7816_response.h" + +//Instruction 1: returns an OK response unconditionally +//APDU example: 0x01:0x01:0x00:0x00 +//response: SW1=0x90, SW2=0x00 +void handle_instruction_01(ISO7816_Response_APDU* response_apdu) { + response_apdu->DataLen = 0; + iso7816_set_response(response_apdu, ISO7816_RESPONSE_OK); +} + +//Instruction 2: expect command with no body, replies wit with a body with two bytes +//APDU example: 0x01:0x02:0x00:0x00:0x02 +//response: 'bc' (0x62, 0x63) SW1=0x90, SW2=0x00 +void handle_instruction_02( + uint8_t p1, + uint8_t p2, + uint16_t lc, + uint16_t le, + ISO7816_Response_APDU* response_apdu) { + if(p1 == 0 && p2 == 0 && lc == 0 && le >= 2) { + response_apdu->Data[0] = 0x62; + response_apdu->Data[1] = 0x63; + + response_apdu->DataLen = 2; + + iso7816_set_response(response_apdu, ISO7816_RESPONSE_OK); + } else if(p1 != 0 || p2 != 0) { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2); + } else { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_LENGTH); + } +} + +//Instruction 3: sends a command with a body with two bytes, receives a response with no bytes +//APDU example: 0x01:0x03:0x00:0x00:0x02:CA:FE +//response SW1=0x90, SW2=0x00 +void handle_instruction_03( + uint8_t p1, + uint8_t p2, + uint16_t lc, + ISO7816_Response_APDU* response_apdu) { + if(p1 == 0 && p2 == 0 && lc == 2) { + response_apdu->DataLen = 0; + iso7816_set_response(response_apdu, ISO7816_RESPONSE_OK); + } else if(p1 != 0 || p2 != 0) { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2); + } else { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_LENGTH); + } +} + +//instruction 4: sends a command with a body with 'n' bytes, receives a response with 'n' bytes +//APDU example: 0x01:0x04:0x00:0x00:0x04:0x01:0x02:0x03:0x04:0x04 +//receives (0x01, 0x02, 0x03, 0x04) SW1=0x90, SW2=0x00 +void handle_instruction_04( + uint8_t p1, + uint8_t p2, + uint16_t lc, + uint16_t le, + const uint8_t* command_apdu_data_buffer, + ISO7816_Response_APDU* response_apdu) { + if(p1 == 0 && p2 == 0 && lc > 0 && le > 0 && le >= lc) { + for(uint16_t i = 0; i < lc; i++) { + response_apdu->Data[i] = command_apdu_data_buffer[i]; + } + + response_apdu->DataLen = lc; + + iso7816_set_response(response_apdu, ISO7816_RESPONSE_OK); + } else if(p1 != 0 || p2 != 0) { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2); + } else { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_LENGTH); + } +} + +void iso7816_answer_to_reset(Iso7816Atr* atr) { + //minimum valid ATR: https://smartcard-atr.apdu.fr/parse?ATR=3B+00 + atr->TS = 0x3B; + atr->T0 = 0x00; +} + +void iso7816_process_command( + const ISO7816_Command_APDU* command_apdu, + ISO7816_Response_APDU* response_apdu) { + //example 1: sends a command with no body, receives a response with no body + //sends APDU 0x01:0x01:0x00:0x00 + //receives SW1=0x90, SW2=0x00 + + if(command_apdu->CLA == 0x01) { + switch(command_apdu->INS) { + case 0x01: + handle_instruction_01(response_apdu); + break; + case 0x02: + handle_instruction_02( + command_apdu->P1, + command_apdu->P2, + command_apdu->Lc, + command_apdu->Le, + response_apdu); + break; + case 0x03: + handle_instruction_03( + command_apdu->P1, command_apdu->P2, command_apdu->Lc, response_apdu); + break; + case 0x04: + handle_instruction_04( + command_apdu->P1, + command_apdu->P2, + command_apdu->Lc, + command_apdu->Le, + command_apdu->Data, + response_apdu); + break; + default: + iso7816_set_response(response_apdu, ISO7816_RESPONSE_INSTRUCTION_NOT_SUPPORTED); + } + } else { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_CLASS_NOT_SUPPORTED); + } +} diff --git a/applications/debug/ccid_test/ccid_test_app_commands.h b/applications/debug/ccid_test/ccid_test_app_commands.h new file mode 100644 index 0000000000..ca3275aec1 --- /dev/null +++ b/applications/debug/ccid_test/ccid_test_app_commands.h @@ -0,0 +1,7 @@ +#include "iso7816/iso7816_t0_apdu.h" + +void iso7816_answer_to_reset(Iso7816Atr* atr); + +void iso7816_process_command( + const ISO7816_Command_APDU* command_apdu, + ISO7816_Response_APDU* response_apdu); diff --git a/applications/debug/ccid_test/iso7816_atr.h b/applications/debug/ccid_test/iso7816/iso7816_atr.h similarity index 100% rename from applications/debug/ccid_test/iso7816_atr.h rename to applications/debug/ccid_test/iso7816/iso7816_atr.h diff --git a/applications/debug/ccid_test/iso7816/iso7816_handler.c b/applications/debug/ccid_test/iso7816/iso7816_handler.c new file mode 100644 index 0000000000..97214d1b22 --- /dev/null +++ b/applications/debug/ccid_test/iso7816/iso7816_handler.c @@ -0,0 +1,68 @@ +// transforms low level calls such as XFRCallback or ICC Power on to a structured one +// an application can register these calls and listen for the callbacks defined in Iso7816Callbacks + +#include +#include +#include +#include + +#include "iso7816_t0_apdu.h" +#include "iso7816_atr.h" +#include "iso7816_handler.h" +#include "iso7816_response.h" + +void iso7816_icc_power_on_callback(uint8_t* atr_data, uint32_t* atr_data_len, void* context) { + furi_check(context); + + Iso7816Handler* handler = (Iso7816Handler*)context; + + Iso7816Atr iso7816_atr; + handler->iso7816_answer_to_reset(&iso7816_atr); + + furi_assert(iso7816_atr.T0 == 0x00); + + uint8_t atr_buffer[2] = {iso7816_atr.TS, iso7816_atr.T0}; + + *atr_data_len = 2; + + memcpy(atr_data, atr_buffer, sizeof(uint8_t) * (*atr_data_len)); +} + +//dataBlock points to the buffer +//dataBlockLen tells reader how nany bytes should be read +void iso7816_xfr_datablock_callback( + const uint8_t* pc_to_reader_datablock, + uint32_t pc_to_reader_datablock_len, + uint8_t* reader_to_pc_datablock, + uint32_t* reader_to_pc_datablock_len, + void* context) { + furi_check(context); + + Iso7816Handler* handler = (Iso7816Handler*)context; + + ISO7816_Response_APDU* response_apdu = (ISO7816_Response_APDU*)&handler->response_apdu_buffer; + + ISO7816_Command_APDU* command_apdu = (ISO7816_Command_APDU*)&handler->command_apdu_buffer; + + uint8_t result = iso7816_read_command_apdu( + command_apdu, pc_to_reader_datablock, pc_to_reader_datablock_len); + + if(result == ISO7816_READ_COMMAND_APDU_OK) { + handler->iso7816_process_command(command_apdu, response_apdu); + + furi_assert(response_apdu->DataLen < CCID_SHORT_APDU_SIZE); + } else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LE) { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_LE); + } else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH) { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_LENGTH); + } + + iso7816_write_response_apdu(response_apdu, reader_to_pc_datablock, reader_to_pc_datablock_len); +} + +Iso7816Handler* iso7816_handler_alloc() { + Iso7816Handler* handler = malloc(sizeof(Iso7816Handler)); + handler->ccid_callbacks.icc_power_on_callback = iso7816_icc_power_on_callback; + handler->ccid_callbacks.xfr_datablock_callback = iso7816_xfr_datablock_callback; + return handler; +} diff --git a/applications/debug/ccid_test/iso7816/iso7816_handler.h b/applications/debug/ccid_test/iso7816/iso7816_handler.h new file mode 100644 index 0000000000..d67118ce6e --- /dev/null +++ b/applications/debug/ccid_test/iso7816/iso7816_handler.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include "iso7816_atr.h" +#include "iso7816_t0_apdu.h" + +typedef struct { + CcidCallbacks ccid_callbacks; + void (*iso7816_answer_to_reset)(Iso7816Atr* atr); + void (*iso7816_process_command)( + const ISO7816_Command_APDU* command, + ISO7816_Response_APDU* response); + + uint8_t command_apdu_buffer[sizeof(ISO7816_Command_APDU) + CCID_SHORT_APDU_SIZE]; + uint8_t response_apdu_buffer[sizeof(ISO7816_Response_APDU) + CCID_SHORT_APDU_SIZE]; +} Iso7816Handler; + +Iso7816Handler* iso7816_handler_alloc(); diff --git a/applications/debug/ccid_test/iso7816_response.c b/applications/debug/ccid_test/iso7816/iso7816_response.c similarity index 100% rename from applications/debug/ccid_test/iso7816_response.c rename to applications/debug/ccid_test/iso7816/iso7816_response.c diff --git a/applications/debug/ccid_test/iso7816_response.h b/applications/debug/ccid_test/iso7816/iso7816_response.h similarity index 100% rename from applications/debug/ccid_test/iso7816_response.h rename to applications/debug/ccid_test/iso7816/iso7816_response.h diff --git a/applications/debug/ccid_test/iso7816_t0_apdu.c b/applications/debug/ccid_test/iso7816/iso7816_t0_apdu.c similarity index 85% rename from applications/debug/ccid_test/iso7816_t0_apdu.c rename to applications/debug/ccid_test/iso7816/iso7816_t0_apdu.c index 3de5555f49..216f2582f1 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.c +++ b/applications/debug/ccid_test/iso7816/iso7816_t0_apdu.c @@ -61,24 +61,25 @@ uint8_t iso7816_read_command_apdu( //data buffer contains the whole APU response (response + trailer (SW1+SW2)) void iso7816_write_response_apdu( const ISO7816_Response_APDU* response, - uint8_t* readerToPcDataBlock, - uint32_t* readerToPcDataBlockLen) { + uint8_t* reader_to_pc_datablock, + uint32_t* reader_to_pc_datablock_len) { uint32_t responseDataBufferIndex = 0; //response body if(response->DataLen > 0) { while(responseDataBufferIndex < response->DataLen) { - readerToPcDataBlock[responseDataBufferIndex] = response->Data[responseDataBufferIndex]; + reader_to_pc_datablock[responseDataBufferIndex] = + response->Data[responseDataBufferIndex]; responseDataBufferIndex++; } } //trailer - readerToPcDataBlock[responseDataBufferIndex] = response->SW1; + reader_to_pc_datablock[responseDataBufferIndex] = response->SW1; responseDataBufferIndex++; - readerToPcDataBlock[responseDataBufferIndex] = response->SW2; + reader_to_pc_datablock[responseDataBufferIndex] = response->SW2; responseDataBufferIndex++; - *readerToPcDataBlockLen = responseDataBufferIndex; + *reader_to_pc_datablock_len = responseDataBufferIndex; } diff --git a/applications/debug/ccid_test/iso7816_t0_apdu.h b/applications/debug/ccid_test/iso7816/iso7816_t0_apdu.h similarity index 81% rename from applications/debug/ccid_test/iso7816_t0_apdu.h rename to applications/debug/ccid_test/iso7816/iso7816_t0_apdu.h index 50eb476a9c..a21dfbafc3 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.h +++ b/applications/debug/ccid_test/iso7816/iso7816_t0_apdu.h @@ -31,12 +31,11 @@ typedef struct { uint8_t Data[0]; } FURI_PACKED ISO7816_Response_APDU; -void iso7816_answer_to_reset(Iso7816Atr* atr); uint8_t iso7816_read_command_apdu( ISO7816_Command_APDU* command, - const uint8_t* pcToReaderDataBlock, - uint32_t pcToReaderDataBlockLen); + const uint8_t* pc_to_reader_datablock, + uint32_t pc_to_reader_datablock_len); void iso7816_write_response_apdu( const ISO7816_Response_APDU* response, - uint8_t* readerToPcDataBlock, - uint32_t* readerToPcDataBlockLen); + uint8_t* reader_to_pc_datablock, + uint32_t* reader_to_pc_datablock_len); diff --git a/applications/debug/ccid_test/iso7816_callbacks.c b/applications/debug/ccid_test/iso7816_callbacks.c deleted file mode 100644 index 6c1bb106a9..0000000000 --- a/applications/debug/ccid_test/iso7816_callbacks.c +++ /dev/null @@ -1,65 +0,0 @@ -// transforms low level calls such as XFRCallback or ICC Power on to a structured one -// an application can register these calls and listen for the callbacks defined in Iso7816Callbacks - -#include -#include -#include -#include - -#include "iso7816_t0_apdu.h" -#include "iso7816_atr.h" -#include "iso7816_callbacks.h" -#include "iso7816_response.h" - -static Iso7816Callbacks* callbacks = NULL; - -static uint8_t commandApduBuffer[sizeof(ISO7816_Command_APDU) + CCID_SHORT_APDU_SIZE]; -static uint8_t responseApduBuffer[sizeof(ISO7816_Response_APDU) + CCID_SHORT_APDU_SIZE]; - -void iso7816_set_callbacks(Iso7816Callbacks* cb) { - callbacks = cb; -} - -void iso7816_icc_power_on_callback(uint8_t* atrBuffer, uint32_t* atrlen) { - Iso7816Atr atr; - callbacks->iso7816_answer_to_reset(&atr); - - furi_assert(atr.T0 == 0x00); - - uint8_t AtrBuffer[2] = {atr.TS, atr.T0}; - - *atrlen = 2; - - memcpy(atrBuffer, AtrBuffer, sizeof(uint8_t) * (*atrlen)); -} - -//dataBlock points to the buffer -//dataBlockLen tells reader how nany bytes should be read -void iso7816_xfr_datablock_callback( - const uint8_t* pcToReaderDataBlock, - uint32_t pcToReaderDataBlockLen, - uint8_t* readerToPcDataBlock, - uint32_t* readerToPcDataBlockLen) { - ISO7816_Response_APDU* responseAPDU = (ISO7816_Response_APDU*)&responseApduBuffer; - - if(callbacks != NULL) { - ISO7816_Command_APDU* commandAPDU = (ISO7816_Command_APDU*)&commandApduBuffer; - - uint8_t result = - iso7816_read_command_apdu(commandAPDU, pcToReaderDataBlock, pcToReaderDataBlockLen); - - if(result == ISO7816_READ_COMMAND_APDU_OK) { - callbacks->iso7816_process_command(commandAPDU, responseAPDU); - - furi_assert(responseAPDU->DataLen < CCID_SHORT_APDU_SIZE); - } else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LE) { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LE); - } else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH) { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH); - } - } else { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INTERNAL_EXCEPTION); - } - - iso7816_write_response_apdu(responseAPDU, readerToPcDataBlock, readerToPcDataBlockLen); -} diff --git a/applications/debug/ccid_test/iso7816_callbacks.h b/applications/debug/ccid_test/iso7816_callbacks.h deleted file mode 100644 index 6b408c7f50..0000000000 --- a/applications/debug/ccid_test/iso7816_callbacks.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include "iso7816_atr.h" -#include "iso7816_t0_apdu.h" - -typedef struct { - void (*iso7816_answer_to_reset)(Iso7816Atr* atr); - void (*iso7816_process_command)( - const ISO7816_Command_APDU* command, - ISO7816_Response_APDU* response); -} Iso7816Callbacks; - -void iso7816_set_callbacks(Iso7816Callbacks* cb); - -void iso7816_icc_power_on_callback(uint8_t* atrBuffer, uint32_t* atrlen); -void iso7816_xfr_datablock_callback( - const uint8_t* dataBlock, - uint32_t dataBlockLen, - uint8_t* responseDataBlock, - uint32_t* responseDataBlockLen); diff --git a/applications/debug/crash_test/crash_test.c b/applications/debug/crash_test/crash_test.c index ae0074fe1c..2b2be13d62 100644 --- a/applications/debug/crash_test/crash_test.c +++ b/applications/debug/crash_test/crash_test.c @@ -66,7 +66,6 @@ CrashTest* crash_test_alloc(void) { instance->gui = furi_record_open(RECORD_GUI); instance->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(instance->view_dispatcher); view_dispatcher_attach_to_gui( instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); diff --git a/applications/debug/display_test/display_test.c b/applications/debug/display_test/display_test.c index 3028a13b90..3b742906d6 100644 --- a/applications/debug/display_test/display_test.c +++ b/applications/debug/display_test/display_test.c @@ -126,7 +126,6 @@ DisplayTest* display_test_alloc(void) { instance->gui = furi_record_open(RECORD_GUI); instance->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(instance->view_dispatcher); view_dispatcher_attach_to_gui( instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); diff --git a/applications/debug/event_loop_blink_test/event_loop_blink_test.c b/applications/debug/event_loop_blink_test/event_loop_blink_test.c index 5c7e0ce558..7f00e63f2e 100644 --- a/applications/debug/event_loop_blink_test/event_loop_blink_test.c +++ b/applications/debug/event_loop_blink_test/event_loop_blink_test.c @@ -82,7 +82,8 @@ static void view_port_input_callback(InputEvent* input_event, void* context) { furi_message_queue_put(app->input_queue, input_event, 0); } -static bool input_queue_callback(FuriMessageQueue* queue, void* context) { +static bool input_queue_callback(FuriEventLoopObject* object, void* context) { + FuriMessageQueue* queue = object; EventLoopBlinkTestApp* app = context; InputEvent event; @@ -144,7 +145,7 @@ int32_t event_loop_blink_test_app(void* arg) { gui_add_view_port(gui, view_port, GuiLayerFullscreen); furi_event_loop_tick_set(app.event_loop, 500, event_loop_tick_callback, &app); - furi_event_loop_message_queue_subscribe( + furi_event_loop_subscribe_message_queue( app.event_loop, app.input_queue, FuriEventLoopEventIn, input_queue_callback, &app); furi_event_loop_run(app.event_loop); @@ -154,7 +155,7 @@ int32_t event_loop_blink_test_app(void* arg) { furi_record_close(RECORD_GUI); - furi_event_loop_message_queue_unsubscribe(app.event_loop, app.input_queue); + furi_event_loop_unsubscribe(app.event_loop, app.input_queue); furi_message_queue_free(app.input_queue); for(size_t i = 0; i < TIMER_COUNT; ++i) { diff --git a/applications/debug/file_browser_test/file_browser_app.c b/applications/debug/file_browser_test/file_browser_app.c index c3e7c898bf..a502a8a90b 100644 --- a/applications/debug/file_browser_test/file_browser_app.c +++ b/applications/debug/file_browser_test/file_browser_app.c @@ -33,8 +33,6 @@ FileBrowserApp* file_browser_app_alloc(char* arg) { app->dialogs = furi_record_open(RECORD_DIALOGS); app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); - app->scene_manager = scene_manager_alloc(&file_browser_scene_handlers, app); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); diff --git a/applications/debug/file_browser_test/icons/badusb_10px.png b/applications/debug/file_browser_test/icons/badusb_10px.png index 037474aa3b..2b5a3bf973 100644 Binary files a/applications/debug/file_browser_test/icons/badusb_10px.png and b/applications/debug/file_browser_test/icons/badusb_10px.png differ diff --git a/applications/debug/file_browser_test/scenes/file_browser_scene_start.c b/applications/debug/file_browser_test/scenes/file_browser_scene_start.c index 9eb26944ff..0ff6303bf5 100644 --- a/applications/debug/file_browser_test/scenes/file_browser_scene_start.c +++ b/applications/debug/file_browser_test/scenes/file_browser_scene_start.c @@ -19,7 +19,7 @@ bool file_browser_scene_start_on_event(void* context, SceneManagerEvent event) { bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - furi_string_set(app->file_path, ANY_PATH("badusb/demo_windows.txt")); + furi_string_set(app->file_path, EXT_PATH("badusb/demo_windows.txt")); scene_manager_next_scene(app->scene_manager, FileBrowserSceneBrowser); consumed = true; } else if(event.type == SceneManagerEventTypeTick) { diff --git a/applications/debug/infrared_test/application.fam b/applications/debug/infrared_test/application.fam new file mode 100644 index 0000000000..bfd7cd5d45 --- /dev/null +++ b/applications/debug/infrared_test/application.fam @@ -0,0 +1,8 @@ +App( + appid="infrared_test", + name="Infrared Test", + apptype=FlipperAppType.DEBUG, + entry_point="infrared_test_app", + fap_category="Debug", + targets=["f7"], +) diff --git a/applications/debug/infrared_test/infrared_test.c b/applications/debug/infrared_test/infrared_test.c new file mode 100644 index 0000000000..0187bd49d1 --- /dev/null +++ b/applications/debug/infrared_test/infrared_test.c @@ -0,0 +1,61 @@ +#include +#include + +#define TAG "InfraredTest" + +#define CARRIER_FREQ_HZ (38000UL) +#define CARRIER_DUTY (0.33f) + +#define BURST_DURATION_US (600UL) +#define BURST_COUNT (50UL) + +typedef struct { + bool level; + uint32_t count; +} InfraredTestApp; + +static FuriHalInfraredTxGetDataState + infrared_test_app_tx_data_callback(void* context, uint32_t* duration, bool* level) { + furi_assert(context); + furi_assert(duration); + furi_assert(level); + + InfraredTestApp* app = context; + + *duration = BURST_DURATION_US; + *level = app->level; + + app->level = !app->level; + app->count += 1; + + if(app->count < BURST_COUNT * 2) { + return FuriHalInfraredTxGetDataStateOk; + } else { + return FuriHalInfraredTxGetDataStateLastDone; + } +} + +int32_t infrared_test_app(void* arg) { + UNUSED(arg); + + InfraredTestApp app = { + .level = true, + }; + + FURI_LOG_I(TAG, "Starting test signal on PA7"); + + furi_hal_infrared_set_tx_output(FuriHalInfraredTxPinExtPA7); + furi_hal_infrared_async_tx_set_data_isr_callback(infrared_test_app_tx_data_callback, &app); + furi_hal_infrared_async_tx_start(CARRIER_FREQ_HZ, CARRIER_DUTY); + furi_hal_infrared_async_tx_wait_termination(); + furi_hal_infrared_set_tx_output(FuriHalInfraredTxPinInternal); + + FURI_LOG_I(TAG, "Test signal end"); + FURI_LOG_I( + TAG, + "The measured signal should be %luus +-%.1fus", + (app.count - 1) * BURST_DURATION_US, + (double)1000000.0 / CARRIER_FREQ_HZ); + + return 0; +} diff --git a/applications/debug/lfrfid_debug/lfrfid_debug.c b/applications/debug/lfrfid_debug/lfrfid_debug.c index 13c0b299fa..962afd1c30 100644 --- a/applications/debug/lfrfid_debug/lfrfid_debug.c +++ b/applications/debug/lfrfid_debug/lfrfid_debug.c @@ -17,7 +17,6 @@ static LfRfidDebug* lfrfid_debug_alloc(void) { app->view_dispatcher = view_dispatcher_alloc(); app->scene_manager = scene_manager_alloc(&lfrfid_debug_scene_handlers, app); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_set_custom_event_callback( app->view_dispatcher, lfrfid_debug_custom_event_callback); diff --git a/applications/debug/locale_test/locale_test.c b/applications/debug/locale_test/locale_test.c index 1ca077db1f..51d45a6b05 100644 --- a/applications/debug/locale_test/locale_test.c +++ b/applications/debug/locale_test/locale_test.c @@ -61,7 +61,6 @@ static LocaleTestApp* locale_test_alloc(void) { // View dispatcher app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); // Views diff --git a/applications/debug/rpc_debug_app/rpc_debug_app.c b/applications/debug/rpc_debug_app/rpc_debug_app.c index 5e53c221e1..1536b8918e 100644 --- a/applications/debug/rpc_debug_app/rpc_debug_app.c +++ b/applications/debug/rpc_debug_app/rpc_debug_app.c @@ -99,7 +99,6 @@ static RpcDebugApp* rpc_debug_app_alloc(void) { view_dispatcher_set_tick_event_callback( app->view_dispatcher, rpc_debug_app_tick_event_callback, 100); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - view_dispatcher_enable_queue(app->view_dispatcher); app->widget = widget_alloc(); view_dispatcher_add_view( diff --git a/applications/debug/subghz_test/images/DolphinCommon_56x48.png b/applications/debug/subghz_test/images/DolphinCommon_56x48.png index 089aaed835..9cdc2e448e 100644 Binary files a/applications/debug/subghz_test/images/DolphinCommon_56x48.png and b/applications/debug/subghz_test/images/DolphinCommon_56x48.png differ diff --git a/applications/debug/subghz_test/subghz_test_10px.png b/applications/debug/subghz_test/subghz_test_10px.png index 10dac0ecaa..77dc6d3829 100644 Binary files a/applications/debug/subghz_test/subghz_test_10px.png and b/applications/debug/subghz_test/subghz_test_10px.png differ diff --git a/applications/debug/subghz_test/subghz_test_app.c b/applications/debug/subghz_test/subghz_test_app.c index 6eba864f6e..dccdac213d 100644 --- a/applications/debug/subghz_test/subghz_test_app.c +++ b/applications/debug/subghz_test/subghz_test_app.c @@ -30,7 +30,6 @@ SubGhzTestApp* subghz_test_app_alloc(void) { // View Dispatcher app->view_dispatcher = view_dispatcher_alloc(); app->scene_manager = scene_manager_alloc(&subghz_test_scene_handlers, app); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_set_custom_event_callback( diff --git a/applications/debug/text_box_view_test/text_box_view_test.c b/applications/debug/text_box_view_test/text_box_view_test.c index 7bbcb285b8..4d63e37793 100644 --- a/applications/debug/text_box_view_test/text_box_view_test.c +++ b/applications/debug/text_box_view_test/text_box_view_test.c @@ -126,7 +126,6 @@ int32_t text_box_view_test_app(void* p) { Gui* gui = furi_record_open(RECORD_GUI); ViewDispatcher* view_dispatcher = view_dispatcher_alloc(); view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); - view_dispatcher_enable_queue(view_dispatcher); TextBoxViewTest instance = { .text_box = text_box_alloc(), diff --git a/applications/debug/uart_echo/uart_echo.c b/applications/debug/uart_echo/uart_echo.c index 8e1884e9a2..bf38ba4c27 100644 --- a/applications/debug/uart_echo/uart_echo.c +++ b/applications/debug/uart_echo/uart_echo.c @@ -242,7 +242,6 @@ static UartEchoApp* uart_echo_app_alloc(uint32_t baudrate) { // View dispatcher app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); // Views diff --git a/applications/debug/unit_tests/resources/unit_tests/subghz/dickert_mahs.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/dickert_mahs.sub new file mode 100644 index 0000000000..9737b71a69 --- /dev/null +++ b/applications/debug/unit_tests/resources/unit_tests/subghz/dickert_mahs.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: Dickert_MAHS +Bit: 36 +Key: 00 00 00 01 55 57 55 15 diff --git a/applications/debug/unit_tests/resources/unit_tests/subghz/dickert_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/dickert_raw.sub new file mode 100644 index 0000000000..544fc7a1d2 --- /dev/null +++ b/applications/debug/unit_tests/resources/unit_tests/subghz/dickert_raw.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: 112254 -62882 64 -8912 798 -844 416 -418 806 -850 396 -45206 440 -428 794 -442 804 -422 822 -810 414 -414 824 -832 412 -416 808 -848 376 -446 792 -846 382 -448 816 -828 410 -416 810 -844 382 -416 834 -818 410 -414 810 -856 408 -810 412 -836 384 -442 808 -814 402 -844 414 -834 378 -436 808 -844 396 -422 798 -844 416 -416 814 -404 812 -440 810 -842 396 -422 798 -840 414 -414 806 -850 398 -45210 450 -420 796 -436 780 -446 802 -848 380 -434 806 -846 400 -422 800 -840 410 -408 836 -812 414 -410 826 -840 378 -440 804 -848 396 -426 812 -810 426 -394 826 -844 414 -810 420 -834 378 -442 808 -832 412 -812 416 -830 410 -406 810 -844 400 -420 832 -810 414 -416 800 -446 798 -440 812 -808 426 -410 800 -836 412 -414 806 -836 412 -45216 450 -420 798 -434 806 -414 802 -846 382 -438 814 -832 410 -410 838 -834 396 -430 810 -842 394 -392 826 -840 414 -414 802 -850 396 -428 812 -842 394 -394 828 -842 414 -810 424 -812 392 -434 812 -844 398 -848 380 -844 408 -416 820 -810 414 -406 816 -836 412 -416 836 -414 816 -398 816 -840 420 -410 802 -844 416 -416 804 -824 410 -45232 446 -400 802 -442 810 -432 804 -842 396 -392 826 -842 410 -410 834 -818 378 -442 804 -854 406 -408 806 -838 408 -428 804 -844 396 -392 826 -840 410 -410 834 -810 414 -832 408 -834 380 -440 802 -826 410 -836 412 -838 396 -424 796 -842 414 -414 804 -848 396 -426 812 -412 814 -414 824 -832 410 -416 806 -848 382 -420 834 -814 422 -45228 416 -422 802 -446 810 -420 790 -846 382 -448 818 -828 408 -416 808 -848 382 -418 830 -816 410 -412 812 -856 410 -382 834 -846 382 -418 832 -818 408 -412 812 -856 408 -814 414 -838 396 -428 810 -808 424 -836 380 -844 404 -416 802 -840 424 -394 826 -840 414 -382 836 -412 822 -436 812 -806 424 -394 826 -844 416 -382 838 -816 402 -45228 438 -430 796 -444 806 -424 822 -810 412 -416 822 -832 412 -416 804 -844 408 -414 824 -812 412 -408 812 -834 410 -414 804 -848 408 -412 802 -840 424 -412 802 -834 412 -842 384 -848 396 -426 814 -808 424 -816 392 -866 382 -414 838 -816 414 -428 792 -846 380 -440 810 -438 812 -412 802 -846 380 -438 826 -840 380 -416 838 -814 404 -45226 450 -404 820 -408 806 -452 792 -848 382 -440 814 -832 410 -416 810 -846 378 -450 792 -846 380 -446 816 -830 410 -386 836 -846 376 -410 828 -846 380 -446 814 -828 410 -814 414 -836 396 -428 810 -842 394 -816 410 -836 406 -430 812 -810 426 -394 826 -838 +RAW_Data: 414 -414 808 -416 826 -438 814 -816 420 -414 834 -814 418 -418 808 -848 398 -45218 412 -438 824 -412 812 -418 832 -852 378 -446 782 -862 410 -386 838 -848 384 -420 836 -820 418 -414 814 -854 408 -388 838 -814 418 -422 836 -816 394 -434 812 -846 398 -850 380 -848 410 -418 822 -812 416 -850 368 -854 412 -418 810 -850 384 -422 834 -820 416 -414 812 -428 836 -412 804 -848 382 -450 818 -828 412 -418 808 -850 380 -45228 452 -420 798 -434 806 -416 834 -818 384 -440 810 -820 404 -420 834 -814 416 -418 834 -824 386 -442 810 -818 404 -420 834 -814 416 -418 834 -820 410 -414 810 -850 406 -812 414 -816 404 -420 818 -838 386 -848 394 -828 414 -414 838 -814 406 -420 820 -842 384 -446 794 -438 810 -412 802 -848 394 -432 812 -842 394 -392 830 -842 414 -105578 64 -1760 130 -196 130 -832 160 -128 62 -1278 194 -1316 230 -96 362 -64 64 -398 diff --git a/applications/debug/unit_tests/tests/furi/furi_event_loop.c b/applications/debug/unit_tests/tests/furi/furi_event_loop.c index 4eeecb2b83..291181c77f 100644 --- a/applications/debug/unit_tests/tests/furi/furi_event_loop.c +++ b/applications/debug/unit_tests/tests/furi/furi_event_loop.c @@ -19,25 +19,24 @@ typedef struct { uint32_t consumer_counter; } TestFuriData; -bool test_furi_event_loop_producer_mq_callback(FuriMessageQueue* queue, void* context) { +bool test_furi_event_loop_producer_mq_callback(FuriEventLoopObject* object, void* context) { furi_check(context); TestFuriData* data = context; - furi_check(data->mq == queue, "Invalid queue"); + furi_check(data->mq == object, "Invalid queue"); FURI_LOG_I( TAG, "producer_mq_callback: %lu %lu", data->producer_counter, data->consumer_counter); - // Remove and add should not cause crash - // if(data->producer_counter == EVENT_LOOP_EVENT_COUNT/2) { - // furi_event_loop_message_queue_remove(data->producer_event_loop, data->mq); - // furi_event_loop_message_queue_add( - // data->producer_event_loop, - // data->mq, - // FuriEventLoopEventOut, - // test_furi_event_loop_producer_mq_callback, - // data); - // } + if(data->producer_counter == EVENT_LOOP_EVENT_COUNT / 2) { + furi_event_loop_unsubscribe(data->producer_event_loop, data->mq); + furi_event_loop_subscribe_message_queue( + data->producer_event_loop, + data->mq, + FuriEventLoopEventOut, + test_furi_event_loop_producer_mq_callback, + data); + } if(data->producer_counter == EVENT_LOOP_EVENT_COUNT) { furi_event_loop_stop(data->producer_event_loop); @@ -61,7 +60,7 @@ int32_t test_furi_event_loop_producer(void* p) { FURI_LOG_I(TAG, "producer start 1st run"); data->producer_event_loop = furi_event_loop_alloc(); - furi_event_loop_message_queue_subscribe( + furi_event_loop_subscribe_message_queue( data->producer_event_loop, data->mq, FuriEventLoopEventOut, @@ -73,7 +72,7 @@ int32_t test_furi_event_loop_producer(void* p) { // 2 EventLoop index, 0xFFFFFFFF - all possible flags, emulate uncleared flags xTaskNotifyIndexed(xTaskGetCurrentTaskHandle(), 2, 0xFFFFFFFF, eSetBits); - furi_event_loop_message_queue_unsubscribe(data->producer_event_loop, data->mq); + furi_event_loop_unsubscribe(data->producer_event_loop, data->mq); furi_event_loop_free(data->producer_event_loop); FURI_LOG_I(TAG, "producer start 2nd run"); @@ -81,7 +80,7 @@ int32_t test_furi_event_loop_producer(void* p) { data->producer_counter = 0; data->producer_event_loop = furi_event_loop_alloc(); - furi_event_loop_message_queue_subscribe( + furi_event_loop_subscribe_message_queue( data->producer_event_loop, data->mq, FuriEventLoopEventOut, @@ -90,7 +89,7 @@ int32_t test_furi_event_loop_producer(void* p) { furi_event_loop_run(data->producer_event_loop); - furi_event_loop_message_queue_unsubscribe(data->producer_event_loop, data->mq); + furi_event_loop_unsubscribe(data->producer_event_loop, data->mq); furi_event_loop_free(data->producer_event_loop); FURI_LOG_I(TAG, "producer end"); @@ -98,11 +97,11 @@ int32_t test_furi_event_loop_producer(void* p) { return 0; } -bool test_furi_event_loop_consumer_mq_callback(FuriMessageQueue* queue, void* context) { +bool test_furi_event_loop_consumer_mq_callback(FuriEventLoopObject* object, void* context) { furi_check(context); TestFuriData* data = context; - furi_check(data->mq == queue); + furi_check(data->mq == object); furi_delay_us(furi_hal_random_get() % 1000); furi_check(furi_message_queue_get(data->mq, &data->consumer_counter, 0) == FuriStatusOk); @@ -110,16 +109,15 @@ bool test_furi_event_loop_consumer_mq_callback(FuriMessageQueue* queue, void* co FURI_LOG_I( TAG, "consumer_mq_callback: %lu %lu", data->producer_counter, data->consumer_counter); - // Remove and add should not cause crash - // if(data->producer_counter == EVENT_LOOP_EVENT_COUNT/2) { - // furi_event_loop_message_queue_remove(data->consumer_event_loop, data->mq); - // furi_event_loop_message_queue_add( - // data->consumer_event_loop, - // data->mq, - // FuriEventLoopEventIn, - // test_furi_event_loop_producer_mq_callback, - // data); - // } + if(data->consumer_counter == EVENT_LOOP_EVENT_COUNT / 2) { + furi_event_loop_unsubscribe(data->consumer_event_loop, data->mq); + furi_event_loop_subscribe_message_queue( + data->consumer_event_loop, + data->mq, + FuriEventLoopEventIn, + test_furi_event_loop_consumer_mq_callback, + data); + } if(data->consumer_counter == EVENT_LOOP_EVENT_COUNT) { furi_event_loop_stop(data->consumer_event_loop); @@ -137,7 +135,7 @@ int32_t test_furi_event_loop_consumer(void* p) { FURI_LOG_I(TAG, "consumer start 1st run"); data->consumer_event_loop = furi_event_loop_alloc(); - furi_event_loop_message_queue_subscribe( + furi_event_loop_subscribe_message_queue( data->consumer_event_loop, data->mq, FuriEventLoopEventIn, @@ -149,14 +147,14 @@ int32_t test_furi_event_loop_consumer(void* p) { // 2 EventLoop index, 0xFFFFFFFF - all possible flags, emulate uncleared flags xTaskNotifyIndexed(xTaskGetCurrentTaskHandle(), 2, 0xFFFFFFFF, eSetBits); - furi_event_loop_message_queue_unsubscribe(data->consumer_event_loop, data->mq); + furi_event_loop_unsubscribe(data->consumer_event_loop, data->mq); furi_event_loop_free(data->consumer_event_loop); FURI_LOG_I(TAG, "consumer start 2nd run"); data->consumer_counter = 0; data->consumer_event_loop = furi_event_loop_alloc(); - furi_event_loop_message_queue_subscribe( + furi_event_loop_subscribe_message_queue( data->consumer_event_loop, data->mq, FuriEventLoopEventIn, @@ -165,7 +163,7 @@ int32_t test_furi_event_loop_consumer(void* p) { furi_event_loop_run(data->consumer_event_loop); - furi_event_loop_message_queue_unsubscribe(data->consumer_event_loop, data->mq); + furi_event_loop_unsubscribe(data->consumer_event_loop, data->mq); furi_event_loop_free(data->consumer_event_loop); FURI_LOG_I(TAG, "consumer end"); diff --git a/applications/debug/unit_tests/tests/rpc/rpc_test.c b/applications/debug/unit_tests/tests/rpc/rpc_test.c index 63ea706ed6..5d26bdb306 100644 --- a/applications/debug/unit_tests/tests/rpc/rpc_test.c +++ b/applications/debug/unit_tests/tests/rpc/rpc_test.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -35,8 +36,8 @@ static uint32_t command_id = 0; typedef struct { RpcSession* session; FuriStreamBuffer* output_stream; - FuriSemaphore* close_session_semaphore; - FuriSemaphore* terminate_semaphore; + FuriApiLock session_close_lock; + FuriApiLock session_terminate_lock; uint32_t timeout; } RpcSessionContext; @@ -92,8 +93,8 @@ static void test_rpc_setup(void) { rpc_session[0].output_stream = furi_stream_buffer_alloc(4096, 1); rpc_session_set_send_bytes_callback(rpc_session[0].session, output_bytes_callback); - rpc_session[0].close_session_semaphore = furi_semaphore_alloc(1, 0); - rpc_session[0].terminate_semaphore = furi_semaphore_alloc(1, 0); + rpc_session[0].session_close_lock = api_lock_alloc_locked(); + rpc_session[0].session_terminate_lock = api_lock_alloc_locked(); rpc_session_set_close_callback(rpc_session[0].session, test_rpc_session_close_callback); rpc_session_set_terminated_callback( rpc_session[0].session, test_rpc_session_terminated_callback); @@ -112,8 +113,8 @@ static void test_rpc_setup_second_session(void) { rpc_session[1].output_stream = furi_stream_buffer_alloc(1000, 1); rpc_session_set_send_bytes_callback(rpc_session[1].session, output_bytes_callback); - rpc_session[1].close_session_semaphore = furi_semaphore_alloc(1, 0); - rpc_session[1].terminate_semaphore = furi_semaphore_alloc(1, 0); + rpc_session[1].session_close_lock = api_lock_alloc_locked(); + rpc_session[1].session_terminate_lock = api_lock_alloc_locked(); rpc_session_set_close_callback(rpc_session[1].session, test_rpc_session_close_callback); rpc_session_set_terminated_callback( rpc_session[1].session, test_rpc_session_terminated_callback); @@ -121,36 +122,32 @@ static void test_rpc_setup_second_session(void) { } static void test_rpc_teardown(void) { - furi_check(rpc_session[0].close_session_semaphore); - furi_semaphore_acquire(rpc_session[0].terminate_semaphore, 0); + furi_check(rpc_session[0].session_close_lock); + api_lock_relock(rpc_session[0].session_terminate_lock); rpc_session_close(rpc_session[0].session); - furi_check( - furi_semaphore_acquire(rpc_session[0].terminate_semaphore, FuriWaitForever) == - FuriStatusOk); + api_lock_wait_unlock(rpc_session[0].session_terminate_lock); furi_record_close(RECORD_RPC); furi_stream_buffer_free(rpc_session[0].output_stream); - furi_semaphore_free(rpc_session[0].close_session_semaphore); - furi_semaphore_free(rpc_session[0].terminate_semaphore); + api_lock_free(rpc_session[0].session_close_lock); + api_lock_free(rpc_session[0].session_terminate_lock); ++command_id; rpc_session[0].output_stream = NULL; - rpc_session[0].close_session_semaphore = NULL; + rpc_session[0].session_close_lock = NULL; rpc = NULL; rpc_session[0].session = NULL; } static void test_rpc_teardown_second_session(void) { - furi_check(rpc_session[1].close_session_semaphore); - furi_semaphore_acquire(rpc_session[1].terminate_semaphore, 0); + furi_check(rpc_session[1].session_close_lock); + api_lock_relock(rpc_session[1].session_terminate_lock); rpc_session_close(rpc_session[1].session); - furi_check( - furi_semaphore_acquire(rpc_session[1].terminate_semaphore, FuriWaitForever) == - FuriStatusOk); + api_lock_wait_unlock(rpc_session[1].session_terminate_lock); furi_stream_buffer_free(rpc_session[1].output_stream); - furi_semaphore_free(rpc_session[1].close_session_semaphore); - furi_semaphore_free(rpc_session[1].terminate_semaphore); + api_lock_free(rpc_session[1].session_close_lock); + api_lock_free(rpc_session[1].session_terminate_lock); ++command_id; rpc_session[1].output_stream = NULL; - rpc_session[1].close_session_semaphore = NULL; + rpc_session[1].session_close_lock = NULL; rpc_session[1].session = NULL; } @@ -204,14 +201,14 @@ static void test_rpc_session_close_callback(void* context) { furi_check(context); RpcSessionContext* callbacks_context = context; - furi_check(furi_semaphore_release(callbacks_context->close_session_semaphore) == FuriStatusOk); + api_lock_unlock(callbacks_context->session_close_lock); } static void test_rpc_session_terminated_callback(void* context) { furi_check(context); RpcSessionContext* callbacks_context = context; - furi_check(furi_semaphore_release(callbacks_context->terminate_semaphore) == FuriStatusOk); + api_lock_unlock(callbacks_context->session_terminate_lock); } static void test_rpc_print_message_list(MsgList_t msg_list) { @@ -1645,7 +1642,7 @@ static void test_rpc_feed_rubbish_run( test_rpc_add_empty_to_list(expected, PB_CommandStatus_ERROR_DECODE, 0); - furi_check(furi_semaphore_acquire(rpc_session[0].close_session_semaphore, 0) != FuriStatusOk); + furi_check(api_lock_is_locked(rpc_session[0].session_close_lock)); test_rpc_encode_and_feed(input_before, 0); test_send_rubbish(rpc_session[0].session, pattern, pattern_size, size); test_rpc_encode_and_feed(input_after, 0); diff --git a/applications/debug/unit_tests/tests/subghz/subghz_test.c b/applications/debug/unit_tests/tests/subghz/subghz_test.c index 3e93ac4c3b..abbcbd2b08 100644 --- a/applications/debug/unit_tests/tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/tests/subghz/subghz_test.c @@ -663,6 +663,13 @@ MU_TEST(subghz_decoder_mastercode_test) { "Test decoder " SUBGHZ_PROTOCOL_MASTERCODE_NAME " error\r\n"); } +MU_TEST(subghz_decoder_dickert_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/dickert_raw.sub"), SUBGHZ_PROTOCOL_DICKERT_MAHS_NAME), + "Test decoder " SUBGHZ_PROTOCOL_DICKERT_MAHS_NAME " error\r\n"); +} + //test encoders MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -820,6 +827,12 @@ MU_TEST(subghz_encoder_mastercode_test) { "Test encoder " SUBGHZ_PROTOCOL_MASTERCODE_NAME " error\r\n"); } +MU_TEST(subghz_encoder_dickert_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/dickert_mahs.sub")), + "Test encoder " SUBGHZ_PROTOCOL_DICKERT_MAHS_NAME " error\r\n"); +} + MU_TEST(subghz_random_test) { mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); } @@ -871,6 +884,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_nice_one_test); MU_RUN_TEST(subghz_decoder_kinggates_stylo4k_test); MU_RUN_TEST(subghz_decoder_mastercode_test); + MU_RUN_TEST(subghz_decoder_dickert_test); MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_came_test); @@ -898,6 +912,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_holtek_ht12x_test); MU_RUN_TEST(subghz_encoder_dooya_test); MU_RUN_TEST(subghz_encoder_mastercode_test); + MU_RUN_TEST(subghz_encoder_dickert_test); MU_RUN_TEST(subghz_random_test); subghz_test_deinit(); diff --git a/applications/debug/unit_tests/unit_test_api_table_i.h b/applications/debug/unit_tests/unit_test_api_table_i.h index 1adec4db26..50524e5b7d 100644 --- a/applications/debug/unit_tests/unit_test_api_table_i.h +++ b/applications/debug/unit_tests/unit_test_api_table_i.h @@ -36,14 +36,10 @@ static constexpr auto unit_tests_api_table = sort(create_array_t( API_METHOD(furi_event_loop_alloc, FuriEventLoop*, (void)), API_METHOD(furi_event_loop_free, void, (FuriEventLoop*)), API_METHOD( - furi_event_loop_message_queue_subscribe, + furi_event_loop_subscribe_message_queue, void, - (FuriEventLoop*, - FuriMessageQueue*, - FuriEventLoopEvent, - FuriEventLoopMessageQueueCallback, - void*)), - API_METHOD(furi_event_loop_message_queue_unsubscribe, void, (FuriEventLoop*, FuriMessageQueue*)), + (FuriEventLoop*, FuriMessageQueue*, FuriEventLoopEvent, FuriEventLoopEventCallback, void*)), + API_METHOD(furi_event_loop_unsubscribe, void, (FuriEventLoop*, FuriEventLoopObject*)), API_METHOD(furi_event_loop_run, void, (FuriEventLoop*)), API_METHOD(furi_event_loop_stop, void, (FuriEventLoop*)), API_VARIABLE(PB_Main_msg, PB_Main_msg_t))); diff --git a/applications/debug/usb_test/usb_test.c b/applications/debug/usb_test/usb_test.c index ddec9d9b05..a71ac3c6e4 100644 --- a/applications/debug/usb_test/usb_test.c +++ b/applications/debug/usb_test/usb_test.c @@ -63,7 +63,6 @@ UsbTestApp* usb_test_app_alloc(void) { // View dispatcher app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); // Views diff --git a/applications/examples/example_ble_beacon/ble_beacon_app.c b/applications/examples/example_ble_beacon/ble_beacon_app.c index faa3feb915..16979543c8 100644 --- a/applications/examples/example_ble_beacon/ble_beacon_app.c +++ b/applications/examples/example_ble_beacon/ble_beacon_app.c @@ -75,7 +75,6 @@ static BleBeaconApp* ble_beacon_app_alloc(void) { view_dispatcher_set_tick_event_callback( app->view_dispatcher, ble_beacon_app_tick_event_callback, 100); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - view_dispatcher_enable_queue(app->view_dispatcher); app->submenu = submenu_alloc(); view_dispatcher_add_view( diff --git a/applications/examples/example_ble_beacon/example_ble_beacon_10px.png b/applications/examples/example_ble_beacon/example_ble_beacon_10px.png index 7060e893db..c6aff41893 100644 Binary files a/applications/examples/example_ble_beacon/example_ble_beacon_10px.png and b/applications/examples/example_ble_beacon/example_ble_beacon_10px.png differ diff --git a/applications/examples/example_ble_beacon/images/lighthouse_35x44.png b/applications/examples/example_ble_beacon/images/lighthouse_35x44.png index 4cf4d19c57..8ca6d664d0 100644 Binary files a/applications/examples/example_ble_beacon/images/lighthouse_35x44.png and b/applications/examples/example_ble_beacon/images/lighthouse_35x44.png differ diff --git a/applications/examples/example_event_loop/application.fam b/applications/examples/example_event_loop/application.fam new file mode 100644 index 0000000000..a37ffb1a04 --- /dev/null +++ b/applications/examples/example_event_loop/application.fam @@ -0,0 +1,36 @@ +App( + appid="example_event_loop_timer", + name="Example: Event Loop Timer", + apptype=FlipperAppType.EXTERNAL, + sources=["example_event_loop_timer.c"], + entry_point="example_event_loop_timer_app", + fap_category="Examples", +) + +App( + appid="example_event_loop_mutex", + name="Example: Event Loop Mutex", + apptype=FlipperAppType.EXTERNAL, + sources=["example_event_loop_mutex.c"], + entry_point="example_event_loop_mutex_app", + fap_category="Examples", +) + +App( + appid="example_event_loop_stream_buffer", + name="Example: Event Loop Stream Buffer", + apptype=FlipperAppType.EXTERNAL, + sources=["example_event_loop_stream_buffer.c"], + entry_point="example_event_loop_stream_buffer_app", + fap_category="Examples", +) + +App( + appid="example_event_loop_multi", + name="Example: Event Loop Multi", + apptype=FlipperAppType.EXTERNAL, + sources=["example_event_loop_multi.c"], + entry_point="example_event_loop_multi_app", + requires=["gui"], + fap_category="Examples", +) diff --git a/applications/examples/example_event_loop/example_event_loop_multi.c b/applications/examples/example_event_loop/example_event_loop_multi.c new file mode 100644 index 0000000000..ebfb009118 --- /dev/null +++ b/applications/examples/example_event_loop/example_event_loop_multi.c @@ -0,0 +1,342 @@ +/** + * @file example_event_loop_multi.c + * @brief Example application that demonstrates multiple primitives used with two FuriEventLoop instances. + * + * This application simulates a complex use case of having two concurrent event loops (each one executing in + * its own thread) using a stream buffer for communication and additional timers and message passing to handle + * the keypad input. Additionally, it shows how to use thread signals to stop an event loop in another thread. + * The GUI functionality is there only for the purpose of exclusive access to the input events. + * + * The application's functionality consists of the following: + * - Print keypad key names and types when pressed, + * - If the Back key is long-pressed, a countdown starts upon completion of which the app exits, + * - The countdown can be cancelled by long-pressing the Ok button, it also resets the counter, + * - Blocks of random data are periodically generated in a separate thread, + * - When ready, the main application thread gets notified and prints the data. + */ + +#include +#include +#include + +#include + +#define TAG "ExampleEventLoopMulti" + +#define COUNTDOWN_START_VALUE (5UL) +#define COUNTDOWN_INTERVAL_MS (1000UL) +#define WORKER_DATA_INTERVAL_MS (1500UL) + +#define INPUT_QUEUE_SIZE (8) +#define STREAM_BUFFER_SIZE (16) + +typedef struct { + FuriEventLoop* event_loop; + FuriEventLoopTimer* timer; + FuriStreamBuffer* stream_buffer; +} EventLoopMultiAppWorker; + +typedef struct { + Gui* gui; + ViewPort* view_port; + FuriThread* worker_thread; + FuriEventLoop* event_loop; + FuriMessageQueue* input_queue; + FuriEventLoopTimer* exit_timer; + FuriStreamBuffer* stream_buffer; + uint32_t exit_countdown_value; +} EventLoopMultiApp; + +/* + * Worker functions + */ + +// This function is executed each time the data is taken out of the stream buffer. It is used to restart the worker timer. +static bool + event_loop_multi_app_stream_buffer_worker_callback(FuriEventLoopObject* object, void* context) { + furi_assert(context); + EventLoopMultiAppWorker* worker = context; + + furi_assert(object == worker->stream_buffer); + + FURI_LOG_I(TAG, "Data was removed from buffer"); + // Restart the timer to generate another block of random data. + furi_event_loop_timer_start(worker->timer, WORKER_DATA_INTERVAL_MS); + + return true; +} + +// This function is executed when the worker timer expires. The timer will NOT restart automatically +// since it is of one-shot type. +static void event_loop_multi_app_worker_timer_callback(void* context) { + furi_assert(context); + EventLoopMultiAppWorker* worker = context; + + // Generate a block of random data. + uint8_t data[STREAM_BUFFER_SIZE]; + furi_hal_random_fill_buf(data, sizeof(data)); + // Put the generated data in the stream buffer. + // IMPORTANT: No waiting in the event handlers! + furi_check( + furi_stream_buffer_send(worker->stream_buffer, &data, sizeof(data), 0) == sizeof(data)); +} + +static EventLoopMultiAppWorker* + event_loop_multi_app_worker_alloc(FuriStreamBuffer* stream_buffer) { + EventLoopMultiAppWorker* worker = malloc(sizeof(EventLoopMultiAppWorker)); + // Create the worker event loop. + worker->event_loop = furi_event_loop_alloc(); + // Create the timer governing the data generation. + // It is of one-shot type, i.e. it will not restart automatically upon expiration. + worker->timer = furi_event_loop_timer_alloc( + worker->event_loop, + event_loop_multi_app_worker_timer_callback, + FuriEventLoopTimerTypeOnce, + worker); + + // Using the same stream buffer as the main thread (it was already created beforehand). + worker->stream_buffer = stream_buffer; + // Notify the worker event loop about data being taken out of the stream buffer. + furi_event_loop_subscribe_stream_buffer( + worker->event_loop, + worker->stream_buffer, + FuriEventLoopEventOut | FuriEventLoopEventFlagEdge, + event_loop_multi_app_stream_buffer_worker_callback, + worker); + + return worker; +} + +static void event_loop_multi_app_worker_free(EventLoopMultiAppWorker* worker) { + // IMPORTANT: The user code MUST unsubscribe from all events before deleting the event loop. + // Failure to do so will result in a crash. + furi_event_loop_unsubscribe(worker->event_loop, worker->stream_buffer); + // IMPORTANT: All timers MUST be deleted before deleting the associated event loop. + // Failure to do so will result in a crash. + furi_event_loop_timer_free(worker->timer); + // Now it is okay to delete the event loop. + furi_event_loop_free(worker->event_loop); + + free(worker); +} + +static void event_loop_multi_app_worker_run(EventLoopMultiAppWorker* worker) { + furi_event_loop_timer_start(worker->timer, WORKER_DATA_INTERVAL_MS); + furi_event_loop_run(worker->event_loop); +} + +// This function is the worker thread body and (obviously) is executed in the worker thread. +static int32_t event_loop_multi_app_worker_thread(void* context) { + furi_assert(context); + EventLoopMultiApp* app = context; + + // Because an event loop is used, it MUST be created in the thread it will be run in. + // Therefore, the worker creation and deletion is handled in the worker thread. + EventLoopMultiAppWorker* worker = event_loop_multi_app_worker_alloc(app->stream_buffer); + event_loop_multi_app_worker_run(worker); + event_loop_multi_app_worker_free(worker); + + return 0; +} + +/* + * Main application functions + */ + +// This function is executed in the GUI context each time an input event occurs (e.g. the user pressed a key) +static void event_loop_multi_app_input_callback(InputEvent* event, void* context) { + furi_assert(context); + EventLoopMultiApp* app = context; + // Pass the event to the the application's input queue + furi_check(furi_message_queue_put(app->input_queue, event, FuriWaitForever) == FuriStatusOk); +} + +// This function is executed each time new data is available in the stream buffer. +static bool + event_loop_multi_app_stream_buffer_callback(FuriEventLoopObject* object, void* context) { + furi_assert(context); + EventLoopMultiApp* app = context; + + furi_assert(object == app->stream_buffer); + // Get the data from the stream buffer + uint8_t data[STREAM_BUFFER_SIZE]; + // IMPORTANT: No waiting in the event handlers! + furi_check( + furi_stream_buffer_receive(app->stream_buffer, &data, sizeof(data), 0) == sizeof(data)); + + // Format the data for printing and print it to the debug output. + FuriString* tmp_str = furi_string_alloc(); + for(uint32_t i = 0; i < sizeof(data); ++i) { + furi_string_cat_printf(tmp_str, "%02X ", data[i]); + } + + FURI_LOG_I(TAG, "Received data: %s", furi_string_get_cstr(tmp_str)); + furi_string_free(tmp_str); + + return true; +} + +// This function is executed each time a new message is inserted in the input queue. +static bool event_loop_multi_app_input_queue_callback(FuriEventLoopObject* object, void* context) { + furi_assert(context); + EventLoopMultiApp* app = context; + + furi_assert(object == app->input_queue); + + InputEvent event; + // IMPORTANT: No waiting in the event handlers! + furi_check(furi_message_queue_get(app->input_queue, &event, 0) == FuriStatusOk); + + if(event.type == InputTypeLong) { + // The user has long-pressed the Back key, try starting the countdown. + if(event.key == InputKeyBack) { + if(!furi_event_loop_timer_is_running(app->exit_timer)) { + // Actually start the countdown + FURI_LOG_I(TAG, "Starting exit countdown!"); + furi_event_loop_timer_start(app->exit_timer, COUNTDOWN_INTERVAL_MS); + + } else { + // The countdown is already in progress, print a warning message + FURI_LOG_W(TAG, "Countdown has already been started"); + } + + // The user has long-pressed the Ok key, try stopping the countdown. + } else if(event.key == InputKeyOk) { + if(furi_event_loop_timer_is_running(app->exit_timer)) { + // Actually cancel the countdown + FURI_LOG_I(TAG, "Exit countdown cancelled!"); + app->exit_countdown_value = COUNTDOWN_START_VALUE; + furi_event_loop_timer_stop(app->exit_timer); + + } else { + // The countdown is not running, print a warning message + FURI_LOG_W(TAG, "Countdown has not been started yet"); + } + + } else { + // Not a Back or Ok key, just print its name. + FURI_LOG_I(TAG, "Long press: %s", input_get_key_name(event.key)); + } + + } else if(event.type == InputTypeShort) { + // Not a long press, just print the key's name. + FURI_LOG_I(TAG, "Short press: %s", input_get_key_name(event.key)); + } + + return true; +} + +// This function is executed each time the countdown timer expires. +static void event_loop_multi_app_exit_timer_callback(void* context) { + furi_assert(context); + EventLoopMultiApp* app = context; + + FURI_LOG_I(TAG, "Exiting in %lu ...", app->exit_countdown_value); + + // If the coundown value has reached 0, exit the application + if(app->exit_countdown_value == 0) { + FURI_LOG_I(TAG, "Exiting NOW!"); + + // Send a signal to the worker thread to exit. + // A signal handler that handles FuriSignalExit is already set by default. + furi_thread_signal(app->worker_thread, FuriSignalExit, NULL); + // Request the application event loop to stop. + furi_event_loop_stop(app->event_loop); + + // Otherwise just decrement it and wait for the next time the timer expires. + } else { + app->exit_countdown_value -= 1; + } +} + +static EventLoopMultiApp* event_loop_multi_app_alloc(void) { + EventLoopMultiApp* app = malloc(sizeof(EventLoopMultiApp)); + // Create event loop instances. + app->event_loop = furi_event_loop_alloc(); + + // Create a worker thread instance. The worker event loop will execute inside it. + app->worker_thread = furi_thread_alloc_ex( + "EventLoopMultiWorker", 1024, event_loop_multi_app_worker_thread, app); + // Create a message queue to receive the input events. + app->input_queue = furi_message_queue_alloc(INPUT_QUEUE_SIZE, sizeof(InputEvent)); + // Create a stream buffer to receive the generated data. + app->stream_buffer = furi_stream_buffer_alloc(STREAM_BUFFER_SIZE, STREAM_BUFFER_SIZE); + // Create a timer to run the countdown. + app->exit_timer = furi_event_loop_timer_alloc( + app->event_loop, + event_loop_multi_app_exit_timer_callback, + FuriEventLoopTimerTypePeriodic, + app); + + app->gui = furi_record_open(RECORD_GUI); + app->view_port = view_port_alloc(); + // Start the countdown from this value + app->exit_countdown_value = COUNTDOWN_START_VALUE; + // Gain exclusive access to the input events + view_port_input_callback_set(app->view_port, event_loop_multi_app_input_callback, app); + gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen); + // Notify the event loop about incoming messages in the queue + furi_event_loop_subscribe_message_queue( + app->event_loop, + app->input_queue, + FuriEventLoopEventIn, + event_loop_multi_app_input_queue_callback, + app); + // Notify the event loop about new data in the stream buffer + furi_event_loop_subscribe_stream_buffer( + app->event_loop, + app->stream_buffer, + FuriEventLoopEventIn | FuriEventLoopEventFlagEdge, + event_loop_multi_app_stream_buffer_callback, + app); + + return app; +} + +static void event_loop_multi_app_free(EventLoopMultiApp* app) { + gui_remove_view_port(app->gui, app->view_port); + furi_record_close(RECORD_GUI); + // IMPORTANT: The user code MUST unsubscribe from all events before deleting the event loop. + // Failure to do so will result in a crash. + furi_event_loop_unsubscribe(app->event_loop, app->input_queue); + furi_event_loop_unsubscribe(app->event_loop, app->stream_buffer); + // Delete all instances + view_port_free(app->view_port); + furi_message_queue_free(app->input_queue); + furi_stream_buffer_free(app->stream_buffer); + // IMPORTANT: All timers MUST be deleted before deleting the associated event loop. + // Failure to do so will result in a crash. + furi_event_loop_timer_free(app->exit_timer); + furi_thread_free(app->worker_thread); + furi_event_loop_free(app->event_loop); + + free(app); +} + +static void event_loop_multi_app_run(EventLoopMultiApp* app) { + FURI_LOG_I(TAG, "Press keys to see them printed here."); + FURI_LOG_I(TAG, "Long press \"Back\" to exit after %lu seconds.", COUNTDOWN_START_VALUE); + FURI_LOG_I(TAG, "Long press \"Ok\" to cancel the countdown."); + + // Start the worker thread + furi_thread_start(app->worker_thread); + // Run the application event loop. This call will block until the application is about to exit. + furi_event_loop_run(app->event_loop); + // Wait for the worker thread to finish. + furi_thread_join(app->worker_thread); +} + +/******************************************************************* + * vvv START HERE vvv + * + * The application's entry point - referenced in application.fam + *******************************************************************/ +int32_t example_event_loop_multi_app(void* arg) { + UNUSED(arg); + + EventLoopMultiApp* app = event_loop_multi_app_alloc(); + event_loop_multi_app_run(app); + event_loop_multi_app_free(app); + + return 0; +} diff --git a/applications/examples/example_event_loop/example_event_loop_mutex.c b/applications/examples/example_event_loop/example_event_loop_mutex.c new file mode 100644 index 0000000000..d043f3f899 --- /dev/null +++ b/applications/examples/example_event_loop/example_event_loop_mutex.c @@ -0,0 +1,140 @@ +/** + * @file example_event_loop_mutex.c + * @brief Example application that demonstrates the FuriEventLoop and FuriMutex integration. + * + * This application simulates a use case where a time-consuming blocking operation is executed + * in a separate thread and a mutex is being used for synchronization. The application runs 10 iterations + * of the above mentioned simulated work and prints the results to the debug output each time, then exits. + */ + +#include +#include + +#define TAG "ExampleEventLoopMutex" + +#define WORKER_ITERATION_COUNT (10) +// We are interested in IN events (for the mutex, that means that the mutex has been released), +// using edge trigger mode (reacting only to changes in mutex state) and +// employing one-shot mode to automatically unsubscribe before the event is processed. +#define MUTEX_EVENT_AND_FLAGS \ + (FuriEventLoopEventIn | FuriEventLoopEventFlagEdge | FuriEventLoopEventFlagOnce) + +typedef struct { + FuriEventLoop* event_loop; + FuriThread* worker_thread; + FuriMutex* worker_mutex; + uint8_t worker_result; +} EventLoopMutexApp; + +// This funciton is being run in a separate thread to simulate lenghty blocking operations +static int32_t event_loop_mutex_app_worker_thread(void* context) { + furi_assert(context); + EventLoopMutexApp* app = context; + + FURI_LOG_I(TAG, "Worker thread started"); + + // Run 10 iterations of simulated work + for(uint32_t i = 0; i < WORKER_ITERATION_COUNT; ++i) { + FURI_LOG_I(TAG, "Doing work ..."); + // Take the mutex so that no-one can access the worker_result variable + furi_check(furi_mutex_acquire(app->worker_mutex, FuriWaitForever) == FuriStatusOk); + // Simulate a blocking operation with a random delay between 900 and 1100 ms + const uint32_t work_time_ms = 900 + furi_hal_random_get() % 200; + furi_delay_ms(work_time_ms); + // Simulate a result with a random number between 0 and 255 + app->worker_result = furi_hal_random_get() % 0xFF; + + FURI_LOG_I(TAG, "Work done in %lu ms", work_time_ms); + // Release the mutex, which will notify the event loop that the result is ready + furi_check(furi_mutex_release(app->worker_mutex) == FuriStatusOk); + // Return control to the scheduler so that the event loop can take the mutex in its turn + furi_thread_yield(); + } + + FURI_LOG_I(TAG, "All work done, worker thread out!"); + // Request the event loop to stop + furi_event_loop_stop(app->event_loop); + + return 0; +} + +// This function is being run each time when the mutex gets released +static bool event_loop_mutex_app_event_callback(FuriEventLoopObject* object, void* context) { + furi_assert(context); + + EventLoopMutexApp* app = context; + furi_assert(object == app->worker_mutex); + + // Take the mutex so that no-one can access the worker_result variable + // IMPORTANT: the wait time MUST be 0, i.e. the event loop event callbacks + // must NOT ever block. If it is possible that the mutex will be taken by + // others, then the event callback code must take it into account. + furi_check(furi_mutex_acquire(app->worker_mutex, 0) == FuriStatusOk); + // Access the worker_result variable and print it. + FURI_LOG_I(TAG, "Result available! Value: %u", app->worker_result); + // Release the mutex, enabling the worker thread to continue when it's ready + furi_check(furi_mutex_release(app->worker_mutex) == FuriStatusOk); + // Subscribe for the mutex release events again, since we were unsubscribed automatically + // before processing the event. + furi_event_loop_subscribe_mutex( + app->event_loop, + app->worker_mutex, + MUTEX_EVENT_AND_FLAGS, + event_loop_mutex_app_event_callback, + app); + + return true; +} + +static EventLoopMutexApp* event_loop_mutex_app_alloc(void) { + EventLoopMutexApp* app = malloc(sizeof(EventLoopMutexApp)); + + // Create an event loop instance. + app->event_loop = furi_event_loop_alloc(); + // Create a worker thread instance. + app->worker_thread = furi_thread_alloc_ex( + "EventLoopMutexWorker", 1024, event_loop_mutex_app_worker_thread, app); + // Create a mutex instance. + app->worker_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + // Subscribe for the mutex release events. + // Note that since FuriEventLoopEventFlagOneShot is used, we will be automatically unsubscribed + // from events before entering the event processing callback. This is necessary in order to not + // trigger on events caused by releasing the mutex in the callback. + furi_event_loop_subscribe_mutex( + app->event_loop, + app->worker_mutex, + MUTEX_EVENT_AND_FLAGS, + event_loop_mutex_app_event_callback, + app); + + return app; +} + +static void event_loop_mutex_app_free(EventLoopMutexApp* app) { + // IMPORTANT: The user code MUST unsubscribe from all events before deleting the event loop. + // Failure to do so will result in a crash. + furi_event_loop_unsubscribe(app->event_loop, app->worker_mutex); + // Delete all instances + furi_thread_free(app->worker_thread); + furi_mutex_free(app->worker_mutex); + furi_event_loop_free(app->event_loop); + + free(app); +} + +static void event_loop_mutex_app_run(EventLoopMutexApp* app) { + furi_thread_start(app->worker_thread); + furi_event_loop_run(app->event_loop); + furi_thread_join(app->worker_thread); +} + +// The application's entry point - referenced in application.fam +int32_t example_event_loop_mutex_app(void* arg) { + UNUSED(arg); + + EventLoopMutexApp* app = event_loop_mutex_app_alloc(); + event_loop_mutex_app_run(app); + event_loop_mutex_app_free(app); + + return 0; +} diff --git a/applications/examples/example_event_loop/example_event_loop_stream_buffer.c b/applications/examples/example_event_loop/example_event_loop_stream_buffer.c new file mode 100644 index 0000000000..65dbd83cf5 --- /dev/null +++ b/applications/examples/example_event_loop/example_event_loop_stream_buffer.c @@ -0,0 +1,131 @@ +/** + * @file example_event_loop_stream_buffer.c + * @brief Example application that demonstrates the FuriEventLoop and FuriStreamBuffer integration. + * + * This application simulates a use case where some data data stream comes from a separate thread (or hardware) + * and a stream buffer is used to act as an intermediate buffer. The worker thread produces 10 iterations of 32 + * bytes of simulated data, and each time when the buffer is half-filled, the data is taken out of it and printed + * to the debug output. After completing all iterations, the application exits. + */ + +#include +#include + +#define TAG "ExampleEventLoopStreamBuffer" + +#define WORKER_ITERATION_COUNT (10) + +#define STREAM_BUFFER_SIZE (32) +#define STREAM_BUFFER_TRIG_LEVEL (STREAM_BUFFER_SIZE / 2) +#define STREAM_BUFFER_EVENT_AND_FLAGS (FuriEventLoopEventIn | FuriEventLoopEventFlagEdge) + +typedef struct { + FuriEventLoop* event_loop; + FuriThread* worker_thread; + FuriStreamBuffer* stream_buffer; +} EventLoopStreamBufferApp; + +// This funciton is being run in a separate thread to simulate data coming from a producer thread or some device. +static int32_t event_loop_stream_buffer_app_worker_thread(void* context) { + furi_assert(context); + EventLoopStreamBufferApp* app = context; + + FURI_LOG_I(TAG, "Worker thread started"); + + for(uint32_t i = 0; i < WORKER_ITERATION_COUNT; ++i) { + // Produce 32 bytes of simulated data. + for(uint32_t j = 0; j < STREAM_BUFFER_SIZE; ++j) { + // Simulate incoming data by generating a random byte. + uint8_t data = furi_hal_random_get() % 0xFF; + // Put the byte in the buffer. Depending on the use case, it may or may be not acceptable + // to wait for free space to become available. + furi_check( + furi_stream_buffer_send(app->stream_buffer, &data, 1, FuriWaitForever) == 1); + // Delay between 30 and 50 ms to slow down the output for clarity. + furi_delay_ms(30 + furi_hal_random_get() % 20); + } + } + + FURI_LOG_I(TAG, "All work done, worker thread out!"); + // Request the event loop to stop + furi_event_loop_stop(app->event_loop); + + return 0; +} + +// This function is being run each time when the number of bytes in the buffer is above its trigger level. +static bool + event_loop_stream_buffer_app_event_callback(FuriEventLoopObject* object, void* context) { + furi_assert(context); + EventLoopStreamBufferApp* app = context; + + furi_assert(object == app->stream_buffer); + + // Temporary buffer that can hold at most half of the stream buffer's capacity. + uint8_t data[STREAM_BUFFER_TRIG_LEVEL]; + // Receive the data. It is guaranteed that the amount of data in the buffer will be equal to + // or greater than the trigger level, therefore, no waiting delay is necessary. + furi_check( + furi_stream_buffer_receive(app->stream_buffer, data, sizeof(data), 0) == sizeof(data)); + + // Format the data for printing and print it to the debug output. + FuriString* tmp_str = furi_string_alloc(); + for(uint32_t i = 0; i < sizeof(data); ++i) { + furi_string_cat_printf(tmp_str, "%02X ", data[i]); + } + + FURI_LOG_I(TAG, "Received data: %s", furi_string_get_cstr(tmp_str)); + furi_string_free(tmp_str); + + return true; +} + +static EventLoopStreamBufferApp* event_loop_stream_buffer_app_alloc(void) { + EventLoopStreamBufferApp* app = malloc(sizeof(EventLoopStreamBufferApp)); + + // Create an event loop instance. + app->event_loop = furi_event_loop_alloc(); + // Create a worker thread instance. + app->worker_thread = furi_thread_alloc_ex( + "EventLoopStreamBufferWorker", 1024, event_loop_stream_buffer_app_worker_thread, app); + // Create a stream_buffer instance. + app->stream_buffer = furi_stream_buffer_alloc(STREAM_BUFFER_SIZE, STREAM_BUFFER_TRIG_LEVEL); + // Subscribe for the stream buffer IN events in edge triggered mode. + furi_event_loop_subscribe_stream_buffer( + app->event_loop, + app->stream_buffer, + STREAM_BUFFER_EVENT_AND_FLAGS, + event_loop_stream_buffer_app_event_callback, + app); + + return app; +} + +static void event_loop_stream_buffer_app_free(EventLoopStreamBufferApp* app) { + // IMPORTANT: The user code MUST unsubscribe from all events before deleting the event loop. + // Failure to do so will result in a crash. + furi_event_loop_unsubscribe(app->event_loop, app->stream_buffer); + // Delete all instances + furi_thread_free(app->worker_thread); + furi_stream_buffer_free(app->stream_buffer); + furi_event_loop_free(app->event_loop); + + free(app); +} + +static void event_loop_stream_buffer_app_run(EventLoopStreamBufferApp* app) { + furi_thread_start(app->worker_thread); + furi_event_loop_run(app->event_loop); + furi_thread_join(app->worker_thread); +} + +// The application's entry point - referenced in application.fam +int32_t example_event_loop_stream_buffer_app(void* arg) { + UNUSED(arg); + + EventLoopStreamBufferApp* app = event_loop_stream_buffer_app_alloc(); + event_loop_stream_buffer_app_run(app); + event_loop_stream_buffer_app_free(app); + + return 0; +} diff --git a/applications/examples/example_event_loop/example_event_loop_timer.c b/applications/examples/example_event_loop/example_event_loop_timer.c new file mode 100644 index 0000000000..e255f6b61b --- /dev/null +++ b/applications/examples/example_event_loop/example_event_loop_timer.c @@ -0,0 +1,87 @@ +/** + * @file example_event_loop_timer.c + * @brief Example application that demonstrates FuriEventLoop's software timer capability. + * + * This application prints a countdown from 10 to 0 to the debug output and then exits. + * Despite only one timer being used in this example for clarity, an event loop instance can have + * an arbitrary number of independent timers of any type (periodic or one-shot). + * + */ +#include + +#define TAG "ExampleEventLoopTimer" + +#define COUNTDOWN_START_VALUE (10) +#define COUNTDOWN_INTERVAL_MS (1000) + +typedef struct { + FuriEventLoop* event_loop; + FuriEventLoopTimer* timer; + uint32_t countdown_value; +} EventLoopTimerApp; + +// This function is called each time the timer expires (i.e. once per 1000 ms (1s) in this example) +static void event_loop_timer_callback(void* context) { + furi_assert(context); + EventLoopTimerApp* app = context; + + // Print the countdown value + FURI_LOG_I(TAG, "T-00:00:%02lu", app->countdown_value); + + if(app->countdown_value == 0) { + // If the countdown reached 0, print the final line and stop the event loop + FURI_LOG_I(TAG, "Blast off to adventure!"); + // After this call, the control will be returned back to event_loop_timers_app_run() + furi_event_loop_stop(app->event_loop); + + } else { + // Decrement the countdown value + app->countdown_value -= 1; + } +} + +static EventLoopTimerApp* event_loop_timer_app_alloc(void) { + EventLoopTimerApp* app = malloc(sizeof(EventLoopTimerApp)); + + // Create an event loop instance. + app->event_loop = furi_event_loop_alloc(); + // Create a software timer instance. + // The timer is bound to the event loop instance and will execute in its context. + // Here, the timer type is periodic, i.e. it will restart automatically after expiring. + app->timer = furi_event_loop_timer_alloc( + app->event_loop, event_loop_timer_callback, FuriEventLoopTimerTypePeriodic, app); + // The countdown value will be tracked in this variable. + app->countdown_value = COUNTDOWN_START_VALUE; + + return app; +} + +static void event_loop_timer_app_free(EventLoopTimerApp* app) { + // IMPORTANT: All event loop timers MUST be deleted BEFORE deleting the event loop itself. + // Failure to do so will result in a crash. + furi_event_loop_timer_free(app->timer); + // With all timers deleted, it's safe to delete the event loop. + furi_event_loop_free(app->event_loop); + free(app); +} + +static void event_loop_timer_app_run(EventLoopTimerApp* app) { + FURI_LOG_I(TAG, "All systems go! Prepare for countdown!"); + + // Timers can be started either before the event loop is run, or in any + // callback function called by a running event loop. + furi_event_loop_timer_start(app->timer, COUNTDOWN_INTERVAL_MS); + // This call will block until furi_event_loop_stop() is called. + furi_event_loop_run(app->event_loop); +} + +// The application's entry point - referenced in application.fam +int32_t example_event_loop_timer_app(void* arg) { + UNUSED(arg); + + EventLoopTimerApp* app = event_loop_timer_app_alloc(); + event_loop_timer_app_run(app); + event_loop_timer_app_free(app); + + return 0; +} diff --git a/applications/examples/example_images/images/dolphin_71x25.png b/applications/examples/example_images/images/dolphin_71x25.png index 6b3f8aa59b..26c21e2352 100644 Binary files a/applications/examples/example_images/images/dolphin_71x25.png and b/applications/examples/example_images/images/dolphin_71x25.png differ diff --git a/applications/examples/example_number_input/ReadMe.md b/applications/examples/example_number_input/ReadMe.md new file mode 100644 index 0000000000..9d5a0a9e5e --- /dev/null +++ b/applications/examples/example_number_input/ReadMe.md @@ -0,0 +1,7 @@ +# Number Input + +Simple keyboard that limits user inputs to a full number (integer). Useful to enforce correct entries without the need of intense validations after a user input. + +Definition of min/max values is required. Numbers are of type int32_t. If negative numbers are allowed withing min - max, an additional button is displayed to switch the sign between + and -. + +It is also possible to define a header text, shown in this example app with the 3 different input options. \ No newline at end of file diff --git a/applications/examples/example_number_input/application.fam b/applications/examples/example_number_input/application.fam new file mode 100644 index 0000000000..58cff44962 --- /dev/null +++ b/applications/examples/example_number_input/application.fam @@ -0,0 +1,10 @@ +App( + appid="example_number_input", + name="Example: Number Input", + apptype=FlipperAppType.EXTERNAL, + entry_point="example_number_input", + requires=["gui"], + stack_size=1 * 1024, + fap_icon="example_number_input_10px.png", + fap_category="Examples", +) diff --git a/applications/examples/example_number_input/example_number_input.c b/applications/examples/example_number_input/example_number_input.c new file mode 100644 index 0000000000..19d787ef5f --- /dev/null +++ b/applications/examples/example_number_input/example_number_input.c @@ -0,0 +1,79 @@ +#include "example_number_input.h" + +bool example_number_input_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + ExampleNumberInput* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool example_number_input_back_event_callback(void* context) { + furi_assert(context); + ExampleNumberInput* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static ExampleNumberInput* example_number_input_alloc() { + ExampleNumberInput* app = malloc(sizeof(ExampleNumberInput)); + app->gui = furi_record_open(RECORD_GUI); + + app->view_dispatcher = view_dispatcher_alloc(); + + app->scene_manager = scene_manager_alloc(&example_number_input_scene_handlers, app); + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, example_number_input_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, example_number_input_back_event_callback); + + app->number_input = number_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + ExampleNumberInputViewIdNumberInput, + number_input_get_view(app->number_input)); + + app->dialog_ex = dialog_ex_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + ExampleNumberInputViewIdShowNumber, + dialog_ex_get_view(app->dialog_ex)); + + app->current_number = 5; + app->min_value = INT32_MIN; + app->max_value = INT32_MAX; + + return app; +} + +static void example_number_input_free(ExampleNumberInput* app) { + furi_assert(app); + + view_dispatcher_remove_view(app->view_dispatcher, ExampleNumberInputViewIdShowNumber); + dialog_ex_free(app->dialog_ex); + + view_dispatcher_remove_view(app->view_dispatcher, ExampleNumberInputViewIdNumberInput); + number_input_free(app->number_input); + + scene_manager_free(app->scene_manager); + view_dispatcher_free(app->view_dispatcher); + + furi_record_close(RECORD_GUI); + app->gui = NULL; + + //Remove whatever is left + free(app); +} + +int32_t example_number_input(void* p) { + UNUSED(p); + ExampleNumberInput* app = example_number_input_alloc(); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + scene_manager_next_scene(app->scene_manager, ExampleNumberInputSceneShowNumber); + + view_dispatcher_run(app->view_dispatcher); + + example_number_input_free(app); + + return 0; +} diff --git a/applications/examples/example_number_input/example_number_input.h b/applications/examples/example_number_input/example_number_input.h new file mode 100644 index 0000000000..8d944e6fda --- /dev/null +++ b/applications/examples/example_number_input/example_number_input.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scenes/example_number_input_scene.h" + +typedef struct ExampleNumberInputShowNumber ExampleNumberInputShowNumber; + +typedef enum { + ExampleNumberInputViewIdShowNumber, + ExampleNumberInputViewIdNumberInput, +} ExampleNumberInputViewId; + +typedef struct { + Gui* gui; + SceneManager* scene_manager; + ViewDispatcher* view_dispatcher; + + NumberInput* number_input; + DialogEx* dialog_ex; + + int32_t current_number; + int32_t min_value; + int32_t max_value; +} ExampleNumberInput; diff --git a/applications/examples/example_number_input/example_number_input_10px.png b/applications/examples/example_number_input/example_number_input_10px.png new file mode 100644 index 0000000000..bdb494fcd0 Binary files /dev/null and b/applications/examples/example_number_input/example_number_input_10px.png differ diff --git a/applications/examples/example_number_input/scenes/example_number_input_scene.c b/applications/examples/example_number_input/scenes/example_number_input_scene.c new file mode 100644 index 0000000000..caf77fa8ce --- /dev/null +++ b/applications/examples/example_number_input/scenes/example_number_input_scene.c @@ -0,0 +1,30 @@ +#include "example_number_input_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const example_number_input_on_enter_handlers[])(void*) = { +#include "example_number_input_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const example_number_input_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "example_number_input_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const example_number_input_on_exit_handlers[])(void* context) = { +#include "example_number_input_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers example_number_input_scene_handlers = { + .on_enter_handlers = example_number_input_on_enter_handlers, + .on_event_handlers = example_number_input_on_event_handlers, + .on_exit_handlers = example_number_input_on_exit_handlers, + .scene_num = ExampleNumberInputSceneNum, +}; diff --git a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.h b/applications/examples/example_number_input/scenes/example_number_input_scene.h similarity index 61% rename from applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.h rename to applications/examples/example_number_input/scenes/example_number_input_scene.h index bdeb4a8433..49fcd256fb 100644 --- a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.h +++ b/applications/examples/example_number_input/scenes/example_number_input_scene.h @@ -3,27 +3,27 @@ #include // Generate scene id and total number -#define ADD_SCENE(prefix, name, id) StorageMoveToSd##id, +#define ADD_SCENE(prefix, name, id) ExampleNumberInputScene##id, typedef enum { -#include "storage_move_to_sd_scene_config.h" - StorageMoveToSdSceneNum, -} StorageMoveToSdScene; +#include "example_number_input_scene_config.h" + ExampleNumberInputSceneNum, +} ExampleNumberInputScene; #undef ADD_SCENE -extern const SceneManagerHandlers storage_move_to_sd_scene_handlers; +extern const SceneManagerHandlers example_number_input_scene_handlers; // Generate scene on_enter handlers declaration #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); -#include "storage_move_to_sd_scene_config.h" +#include "example_number_input_scene_config.h" #undef ADD_SCENE // Generate scene on_event handlers declaration #define ADD_SCENE(prefix, name, id) \ bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); -#include "storage_move_to_sd_scene_config.h" +#include "example_number_input_scene_config.h" #undef ADD_SCENE // Generate scene on_exit handlers declaration #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); -#include "storage_move_to_sd_scene_config.h" +#include "example_number_input_scene_config.h" #undef ADD_SCENE diff --git a/applications/examples/example_number_input/scenes/example_number_input_scene_config.h b/applications/examples/example_number_input/scenes/example_number_input_scene_config.h new file mode 100644 index 0000000000..71acbda528 --- /dev/null +++ b/applications/examples/example_number_input/scenes/example_number_input_scene_config.h @@ -0,0 +1,4 @@ +ADD_SCENE(example_number_input, input_number, InputNumber) +ADD_SCENE(example_number_input, show_number, ShowNumber) +ADD_SCENE(example_number_input, input_max, InputMax) +ADD_SCENE(example_number_input, input_min, InputMin) diff --git a/applications/examples/example_number_input/scenes/example_number_input_scene_input_max.c b/applications/examples/example_number_input/scenes/example_number_input_scene_input_max.c new file mode 100644 index 0000000000..7478f58a70 --- /dev/null +++ b/applications/examples/example_number_input/scenes/example_number_input_scene_input_max.c @@ -0,0 +1,39 @@ +#include "../example_number_input.h" + +void example_number_input_scene_input_max_callback(void* context, int32_t number) { + ExampleNumberInput* app = context; + app->max_value = number; + view_dispatcher_send_custom_event(app->view_dispatcher, 0); +} + +void example_number_input_scene_input_max_on_enter(void* context) { + furi_assert(context); + ExampleNumberInput* app = context; + NumberInput* number_input = app->number_input; + + number_input_set_header_text(number_input, "Enter the maximum value"); + number_input_set_result_callback( + number_input, + example_number_input_scene_input_max_callback, + context, + app->max_value, + app->min_value, + INT32_MAX); + + view_dispatcher_switch_to_view(app->view_dispatcher, ExampleNumberInputViewIdNumberInput); +} + +bool example_number_input_scene_input_max_on_event(void* context, SceneManagerEvent event) { + ExampleNumberInput* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_previous_scene(app->scene_manager); + return true; + } + return consumed; +} + +void example_number_input_scene_input_max_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/examples/example_number_input/scenes/example_number_input_scene_input_min.c b/applications/examples/example_number_input/scenes/example_number_input_scene_input_min.c new file mode 100644 index 0000000000..ad76562328 --- /dev/null +++ b/applications/examples/example_number_input/scenes/example_number_input_scene_input_min.c @@ -0,0 +1,39 @@ +#include "../example_number_input.h" + +void example_number_input_scene_input_min_callback(void* context, int32_t number) { + ExampleNumberInput* app = context; + app->min_value = number; + view_dispatcher_send_custom_event(app->view_dispatcher, 0); +} + +void example_number_input_scene_input_min_on_enter(void* context) { + furi_assert(context); + ExampleNumberInput* app = context; + NumberInput* number_input = app->number_input; + + number_input_set_header_text(number_input, "Enter the minimum value"); + number_input_set_result_callback( + number_input, + example_number_input_scene_input_min_callback, + context, + app->min_value, + INT32_MIN, + app->max_value); + + view_dispatcher_switch_to_view(app->view_dispatcher, ExampleNumberInputViewIdNumberInput); +} + +bool example_number_input_scene_input_min_on_event(void* context, SceneManagerEvent event) { + ExampleNumberInput* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_previous_scene(app->scene_manager); + return true; + } + return consumed; +} + +void example_number_input_scene_input_min_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/examples/example_number_input/scenes/example_number_input_scene_input_number.c b/applications/examples/example_number_input/scenes/example_number_input_scene_input_number.c new file mode 100644 index 0000000000..d9b1fd52f4 --- /dev/null +++ b/applications/examples/example_number_input/scenes/example_number_input_scene_input_number.c @@ -0,0 +1,42 @@ +#include "../example_number_input.h" + +void example_number_input_scene_input_number_callback(void* context, int32_t number) { + ExampleNumberInput* app = context; + app->current_number = number; + view_dispatcher_send_custom_event(app->view_dispatcher, 0); +} + +void example_number_input_scene_input_number_on_enter(void* context) { + furi_assert(context); + ExampleNumberInput* app = context; + NumberInput* number_input = app->number_input; + + char str[50]; + snprintf(str, sizeof(str), "Set Number (%ld - %ld)", app->min_value, app->max_value); + + number_input_set_header_text(number_input, str); + number_input_set_result_callback( + number_input, + example_number_input_scene_input_number_callback, + context, + app->current_number, + app->min_value, + app->max_value); + + view_dispatcher_switch_to_view(app->view_dispatcher, ExampleNumberInputViewIdNumberInput); +} + +bool example_number_input_scene_input_number_on_event(void* context, SceneManagerEvent event) { + ExampleNumberInput* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { //Back button pressed + scene_manager_previous_scene(app->scene_manager); + return true; + } + return consumed; +} + +void example_number_input_scene_input_number_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/examples/example_number_input/scenes/example_number_input_scene_show_number.c b/applications/examples/example_number_input/scenes/example_number_input_scene_show_number.c new file mode 100644 index 0000000000..2afdaf5c10 --- /dev/null +++ b/applications/examples/example_number_input/scenes/example_number_input_scene_show_number.c @@ -0,0 +1,66 @@ +#include "../example_number_input.h" + +static void + example_number_input_scene_confirm_dialog_callback(DialogExResult result, void* context) { + ExampleNumberInput* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, result); +} + +static void example_number_input_scene_update_view(void* context) { + ExampleNumberInput* app = context; + DialogEx* dialog_ex = app->dialog_ex; + + dialog_ex_set_header(dialog_ex, "The number is", 64, 0, AlignCenter, AlignTop); + + static char buffer[12]; //needs static for extended lifetime + + snprintf(buffer, sizeof(buffer), "%ld", app->current_number); + dialog_ex_set_text(dialog_ex, buffer, 64, 29, AlignCenter, AlignCenter); + + dialog_ex_set_left_button_text(dialog_ex, "Min"); + dialog_ex_set_right_button_text(dialog_ex, "Max"); + dialog_ex_set_center_button_text(dialog_ex, "Change"); + + dialog_ex_set_result_callback(dialog_ex, example_number_input_scene_confirm_dialog_callback); + dialog_ex_set_context(dialog_ex, app); +} + +void example_number_input_scene_show_number_on_enter(void* context) { + furi_assert(context); + ExampleNumberInput* app = context; + + example_number_input_scene_update_view(app); + + view_dispatcher_switch_to_view(app->view_dispatcher, ExampleNumberInputViewIdShowNumber); +} + +bool example_number_input_scene_show_number_on_event(void* context, SceneManagerEvent event) { + ExampleNumberInput* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + switch(event.event) { + case DialogExResultCenter: + scene_manager_next_scene(app->scene_manager, ExampleNumberInputSceneInputNumber); + consumed = true; + break; + case DialogExResultLeft: + scene_manager_next_scene(app->scene_manager, ExampleNumberInputSceneInputMin); + consumed = true; + break; + case DialogExResultRight: + scene_manager_next_scene(app->scene_manager, ExampleNumberInputSceneInputMax); + consumed = true; + break; + default: + break; + } + } + + return consumed; +} + +void example_number_input_scene_show_number_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/examples/example_thermo/example_thermo_10px.png b/applications/examples/example_thermo/example_thermo_10px.png index 3d527f306c..bc42d190c5 100644 Binary files a/applications/examples/example_thermo/example_thermo_10px.png and b/applications/examples/example_thermo/example_thermo_10px.png differ diff --git a/applications/examples/example_view_dispatcher/application.fam b/applications/examples/example_view_dispatcher/application.fam new file mode 100644 index 0000000000..f7b743bcf5 --- /dev/null +++ b/applications/examples/example_view_dispatcher/application.fam @@ -0,0 +1,8 @@ +App( + appid="example_view_dispatcher", + name="Example: ViewDispatcher", + apptype=FlipperAppType.EXTERNAL, + entry_point="example_view_dispatcher_app", + requires=["gui"], + fap_category="Examples", +) diff --git a/applications/examples/example_view_dispatcher/example_view_dispatcher.c b/applications/examples/example_view_dispatcher/example_view_dispatcher.c new file mode 100644 index 0000000000..71d29edfd9 --- /dev/null +++ b/applications/examples/example_view_dispatcher/example_view_dispatcher.c @@ -0,0 +1,173 @@ +/** + * @file example_view_dispatcher.c + * @brief Example application demonstrating the usage of the ViewDispatcher library. + * + * This application can display one of two views: either a Widget or a Submenu. + * Each view has its own way of switching to another one: + * + * - A center button in the Widget view. + * - A submenu item in the Submenu view + * + * Press either to switch to a different view. Press Back to exit the application. + * + */ + +#include +#include + +#include +#include + +// Enumeration of the view indexes. +typedef enum { + ViewIndexWidget, + ViewIndexSubmenu, + ViewIndexCount, +} ViewIndex; + +// Enumeration of submenu items. +typedef enum { + SubmenuIndexNothing, + SubmenuIndexSwitchView, +} SubmenuIndex; + +// Main application structure. +typedef struct { + ViewDispatcher* view_dispatcher; + Widget* widget; + Submenu* submenu; +} ExampleViewDispatcherApp; + +// This function is called when the user has pressed the Back key. +static bool example_view_dispatcher_app_navigation_callback(void* context) { + furi_assert(context); + ExampleViewDispatcherApp* app = context; + // Back means exit the application, which can be done by stopping the ViewDispatcher. + view_dispatcher_stop(app->view_dispatcher); + return true; +} + +// This function is called when there are custom events to process. +static bool example_view_dispatcher_app_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + ExampleViewDispatcherApp* app = context; + // The event numerical value can mean different things (the application is responsible to uphold its chosen convention) + // In this example, the only possible meaning is the view index to switch to. + furi_assert(event < ViewIndexCount); + // Switch to the requested view. + view_dispatcher_switch_to_view(app->view_dispatcher, event); + + return true; +} + +// This function is called when the user presses the "Switch View" button on the Widget view. +static void example_view_dispatcher_app_button_callback( + GuiButtonType button_type, + InputType input_type, + void* context) { + furi_assert(context); + ExampleViewDispatcherApp* app = context; + // Only request the view switch if the user short-presses the Center button. + if(button_type == GuiButtonTypeCenter && input_type == InputTypeShort) { + // Request switch to the Submenu view via the custom event queue. + view_dispatcher_send_custom_event(app->view_dispatcher, ViewIndexSubmenu); + } +} + +// This function is called when the user activates the "Switch View" submenu item. +static void example_view_dispatcher_app_submenu_callback(void* context, uint32_t index) { + furi_assert(context); + ExampleViewDispatcherApp* app = context; + // Only request the view switch if the user activates the "Switch View" item. + if(index == SubmenuIndexSwitchView) { + // Request switch to the Widget view via the custom event queue. + view_dispatcher_send_custom_event(app->view_dispatcher, ViewIndexWidget); + } +} + +// Application constructor function. +static ExampleViewDispatcherApp* example_view_dispatcher_app_alloc() { + ExampleViewDispatcherApp* app = malloc(sizeof(ExampleViewDispatcherApp)); + // Access the GUI API instance. + Gui* gui = furi_record_open(RECORD_GUI); + // Create and initialize the Widget view. + app->widget = widget_alloc(); + widget_add_string_multiline_element( + app->widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, "Press the Button below"); + widget_add_button_element( + app->widget, + GuiButtonTypeCenter, + "Switch View", + example_view_dispatcher_app_button_callback, + app); + // Create and initialize the Submenu view. + app->submenu = submenu_alloc(); + submenu_add_item(app->submenu, "Do Nothing", SubmenuIndexNothing, NULL, NULL); + submenu_add_item( + app->submenu, + "Switch View", + SubmenuIndexSwitchView, + example_view_dispatcher_app_submenu_callback, + app); + // Create the ViewDispatcher instance. + app->view_dispatcher = view_dispatcher_alloc(); + // Let the GUI know about this ViewDispatcher instance. + view_dispatcher_attach_to_gui(app->view_dispatcher, gui, ViewDispatcherTypeFullscreen); + // Register the views within the ViewDispatcher instance. This alone will not show any of them on the screen. + // Each view must have its own index to refer to it later (it is best done via an enumeration as shown here). + view_dispatcher_add_view(app->view_dispatcher, ViewIndexWidget, widget_get_view(app->widget)); + view_dispatcher_add_view( + app->view_dispatcher, ViewIndexSubmenu, submenu_get_view(app->submenu)); + // Set the custom event callback. It will be called each time a custom event is scheduled + // using the view_dispatcher_send_custom_callback() function. + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, example_view_dispatcher_app_custom_event_callback); + // Set the navigation, or back button callback. It will be called if the user pressed the Back button + // and the event was not handled in the currently displayed view. + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, example_view_dispatcher_app_navigation_callback); + // The context will be passed to the callbacks as a parameter, so we have access to our application object. + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + + return app; +} + +// Application destructor function. +static void example_view_dispatcher_app_free(ExampleViewDispatcherApp* app) { + // All views must be un-registered (removed) from a ViewDispatcher instance + // before deleting it. Failure to do so will result in a crash. + view_dispatcher_remove_view(app->view_dispatcher, ViewIndexWidget); + view_dispatcher_remove_view(app->view_dispatcher, ViewIndexSubmenu); + // Now it is safe to delete the ViewDispatcher instance. + view_dispatcher_free(app->view_dispatcher); + // Delete the views + widget_free(app->widget); + submenu_free(app->submenu); + // End access to hte the GUI API. + furi_record_close(RECORD_GUI); + // Free the remaining memory. + free(app); +} + +static void example_view_dispatcher_app_run(ExampleViewDispatcherApp* app) { + // Display the Widget view on the screen. + view_dispatcher_switch_to_view(app->view_dispatcher, ViewIndexWidget); + // This function will block until view_dispatcher_stop() is called. + // Internally, it uses a FuriEventLoop (see FuriEventLoop examples for more info on this). + view_dispatcher_run(app->view_dispatcher); +} + +/******************************************************************* + * vvv START HERE vvv + * + * The application's entry point - referenced in application.fam + *******************************************************************/ +int32_t example_view_dispatcher_app(void* arg) { + UNUSED(arg); + + ExampleViewDispatcherApp* app = example_view_dispatcher_app_alloc(); + example_view_dispatcher_app_run(app); + example_view_dispatcher_app_free(app); + + return 0; +} diff --git a/applications/examples/example_view_holder/application.fam b/applications/examples/example_view_holder/application.fam new file mode 100644 index 0000000000..19ad8d2ac4 --- /dev/null +++ b/applications/examples/example_view_holder/application.fam @@ -0,0 +1,8 @@ +App( + appid="example_view_holder", + name="Example: ViewHolder", + apptype=FlipperAppType.EXTERNAL, + entry_point="example_view_holder_app", + requires=["gui"], + fap_category="Examples", +) diff --git a/applications/examples/example_view_holder/example_view_holder.c b/applications/examples/example_view_holder/example_view_holder.c new file mode 100644 index 0000000000..24907dbc26 --- /dev/null +++ b/applications/examples/example_view_holder/example_view_holder.c @@ -0,0 +1,78 @@ +/** + * @file example_view_holder.c + * @brief Example application demonstrating the usage of the ViewHolder library. + * + * This application will display a text box with some scrollable text in it. + * Press the Back key to exit the application. + */ + +#include +#include +#include + +#include + +// This function will be called when the user presses the Back button. +static void example_view_holder_back_callback(void* context) { + FuriApiLock exit_lock = context; + // Unlock the exit lock, thus enabling the app to exit. + api_lock_unlock(exit_lock); +} + +int32_t example_view_holder_app(void* arg) { + UNUSED(arg); + + // Access the GUI API instance. + Gui* gui = furi_record_open(RECORD_GUI); + // Create a TextBox view. The Gui object only accepts + // ViewPort instances, so we will need to address that later. + TextBox* text_box = text_box_alloc(); + // Set some text so that the text box is not empty. + text_box_set_text( + text_box, + "ViewHolder is being used\n" + "to show this TextBox view.\n\n" + "Scroll down to see more.\n\n\n" + "Press \"Back\" to exit."); + + // Create a ViewHolder instance. It will serve as an adapter to convert + // between the View type provided by the TextBox view and the ViewPort type + // that the GUI can actually display. + ViewHolder* view_holder = view_holder_alloc(); + // Let the GUI know about this ViewHolder instance. + view_holder_attach_to_gui(view_holder, gui); + // Set the view that we want to display. + view_holder_set_view(view_holder, text_box_get_view(text_box)); + + // The part below is not really related to this example, but is necessary for it to function. + // We need to somehow stall the application thread so that the view stays on the screen (otherwise + // the app will just exit and won't display anything) and at the same time we need a way to quit out + // of the application. + + // In this example, a simple FuriApiLock instance is used. A real-world application is likely to have some + // kind of event handling loop here instead. (see the ViewDispatcher example or one of FuriEventLoop + // examples for that). + + // Create a pre-locked FuriApiLock instance. + FuriApiLock exit_lock = api_lock_alloc_locked(); + // Set a Back event callback for the ViewHolder instance. It will be called when the user + // presses the Back button. We pass the exit lock instance as the context to be able to access + // it inside the callback function. + view_holder_set_back_callback(view_holder, example_view_holder_back_callback, exit_lock); + + // This call will block the application thread from running until the exit lock gets unlocked somehow + // (the only way it can happen in this example is via the back callback). + api_lock_wait_unlock_and_free(exit_lock); + + // The back key has been pressed, which unlocked the exit lock. The application is about to exit. + + // The view must be removed from a ViewHolder instance before deleting it. + view_holder_set_view(view_holder, NULL); + // Delete everything to prevent memory leaks. + view_holder_free(view_holder); + text_box_free(text_box); + // End access to the GUI API. + furi_record_close(RECORD_GUI); + + return 0; +} diff --git a/applications/main/archive/archive.c b/applications/main/archive/archive.c index 2345d3f7d4..7c23ee3154 100644 --- a/applications/main/archive/archive.c +++ b/applications/main/archive/archive.c @@ -30,7 +30,6 @@ ArchiveApp* archive_alloc(void) { archive->view_dispatcher = view_dispatcher_alloc(); ViewDispatcher* view_dispatcher = archive->view_dispatcher; - view_dispatcher_enable_queue(view_dispatcher); view_dispatcher_set_event_callback_context(view_dispatcher, archive); view_dispatcher_set_custom_event_callback(view_dispatcher, archive_custom_event_callback); view_dispatcher_set_navigation_event_callback(view_dispatcher, archive_back_event_callback); diff --git a/applications/main/archive/helpers/archive_apps.c b/applications/main/archive/helpers/archive_apps.c index 43befc055b..7aca293649 100644 --- a/applications/main/archive/helpers/archive_apps.c +++ b/applications/main/archive/helpers/archive_apps.c @@ -30,8 +30,8 @@ bool archive_app_is_available(void* context, const char* path) { bool file_exists = false; Storage* storage = furi_record_open(RECORD_STORAGE); - if(storage_file_exists(storage, ANY_PATH("u2f/key.u2f"))) { - file_exists = storage_file_exists(storage, ANY_PATH("u2f/cnt.u2f")); + if(storage_file_exists(storage, EXT_PATH("u2f/key.u2f"))) { + file_exists = storage_file_exists(storage, EXT_PATH("u2f/cnt.u2f")); } furi_record_close(RECORD_STORAGE); @@ -68,8 +68,8 @@ void archive_app_delete_file(void* context, const char* path) { if(app == ArchiveAppTypeU2f) { Storage* fs_api = furi_record_open(RECORD_STORAGE); - res = (storage_common_remove(fs_api, ANY_PATH("u2f/key.u2f")) == FSE_OK); - res |= (storage_common_remove(fs_api, ANY_PATH("u2f/cnt.u2f")) == FSE_OK); + res = (storage_common_remove(fs_api, EXT_PATH("u2f/key.u2f")) == FSE_OK); + res |= (storage_common_remove(fs_api, EXT_PATH("u2f/cnt.u2f")) == FSE_OK); furi_record_close(RECORD_STORAGE); if(archive_is_favorite("/app:u2f/U2F Token")) { diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index bd9b007456..96518cd7af 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -450,16 +450,14 @@ void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) { } static bool archive_is_dir_exists(FuriString* path) { - if(furi_string_equal(path, STORAGE_ANY_PATH_PREFIX)) { - return true; - } bool state = false; FileInfo file_info; Storage* storage = furi_record_open(RECORD_STORAGE); - if(storage_common_stat(storage, furi_string_get_cstr(path), &file_info) == FSE_OK) { - if(file_info_is_dir(&file_info)) { - state = true; - } + + if(furi_string_equal(path, STORAGE_EXT_PATH_PREFIX)) { + state = storage_sd_status(storage) == FSE_OK; + } else if(storage_common_stat(storage, furi_string_get_cstr(path), &file_info) == FSE_OK) { + state = file_info_is_dir(&file_info); } furi_record_close(RECORD_STORAGE); return state; diff --git a/applications/main/archive/helpers/archive_browser.h b/applications/main/archive/helpers/archive_browser.h index 1e1cdc8818..bdfeba035c 100644 --- a/applications/main/archive/helpers/archive_browser.h +++ b/applications/main/archive/helpers/archive_browser.h @@ -9,17 +9,17 @@ static const char* tab_default_paths[] = { [ArchiveTabFavorites] = "/app:favorites", - [ArchiveTabIButton] = ANY_PATH("ibutton"), - [ArchiveTabNFC] = ANY_PATH("nfc"), - [ArchiveTabSubGhz] = ANY_PATH("subghz"), + [ArchiveTabIButton] = EXT_PATH("ibutton"), + [ArchiveTabNFC] = EXT_PATH("nfc"), + [ArchiveTabSubGhz] = EXT_PATH("subghz"), [ArchiveTabSubGhzRemote] = EXT_PATH("subghz_remote"), - [ArchiveTabLFRFID] = ANY_PATH("lfrfid"), - [ArchiveTabInfrared] = ANY_PATH("infrared"), - [ArchiveTabBadUsb] = ANY_PATH("badusb"), + [ArchiveTabLFRFID] = EXT_PATH("lfrfid"), + [ArchiveTabInfrared] = EXT_PATH("infrared"), + [ArchiveTabBadUsb] = EXT_PATH("badusb"), [ArchiveTabU2f] = "/app:u2f", - [ArchiveTabApplications] = ANY_PATH("apps"), + [ArchiveTabApplications] = EXT_PATH("apps"), [ArchiveTabInternal] = STORAGE_INT_PATH_PREFIX, - [ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX, + [ArchiveTabBrowser] = STORAGE_EXT_PATH_PREFIX, }; static const char* known_ext[] = { diff --git a/applications/main/archive/helpers/archive_favorites.h b/applications/main/archive/helpers/archive_favorites.h index 64ffcdd7bd..75070c44d5 100644 --- a/applications/main/archive/helpers/archive_favorites.h +++ b/applications/main/archive/helpers/archive_favorites.h @@ -2,8 +2,8 @@ #include -#define ARCHIVE_FAV_PATH ANY_PATH("favorites.txt") -#define ARCHIVE_FAV_TEMP_PATH ANY_PATH("favorites.tmp") +#define ARCHIVE_FAV_PATH EXT_PATH("favorites.txt") +#define ARCHIVE_FAV_TEMP_PATH EXT_PATH("favorites.tmp") uint16_t archive_favorites_count(void* context); bool archive_favorites_read(void* context); diff --git a/applications/main/archive/helpers/archive_files.c b/applications/main/archive/helpers/archive_files.c index 3684fe6430..868fa8a117 100644 --- a/applications/main/archive/helpers/archive_files.c +++ b/applications/main/archive/helpers/archive_files.c @@ -15,7 +15,7 @@ void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder } else { for(size_t i = 0; i < COUNT_OF(known_ext); i++) { if((known_ext[i][0] == '?') || (known_ext[i][0] == '*')) continue; - if(furi_string_end_with(file->path, known_ext[i])) { + if(furi_string_end_withi(file->path, known_ext[i])) { if((i == ArchiveFileTypeBadUsb) || (i == ArchiveFileTypeSubGhzRemote)) { if(furi_string_search( file->path, archive_get_default_path(ArchiveTabBadUsb)) == 0) { diff --git a/applications/main/bad_usb/bad_usb_app.c b/applications/main/bad_usb/bad_usb_app.c index 0f10d60d8f..2d2d4be86c 100644 --- a/applications/main/bad_usb/bad_usb_app.c +++ b/applications/main/bad_usb/bad_usb_app.c @@ -112,8 +112,6 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { app->dialogs = furi_record_open(RECORD_DIALOGS); app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); - app->scene_manager = scene_manager_alloc(&bad_usb_scene_handlers, app); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); diff --git a/applications/main/bad_usb/icon.png b/applications/main/bad_usb/icon.png index 037474aa3b..2b5a3bf973 100644 Binary files a/applications/main/bad_usb/icon.png and b/applications/main/bad_usb/icon.png differ diff --git a/applications/main/gpio/gpio_app.c b/applications/main/gpio/gpio_app.c index 217423ecc3..234cc793a8 100644 --- a/applications/main/gpio/gpio_app.c +++ b/applications/main/gpio/gpio_app.c @@ -32,7 +32,6 @@ GpioApp* gpio_app_alloc(void) { app->view_dispatcher = view_dispatcher_alloc(); app->scene_manager = scene_manager_alloc(&gpio_scene_handlers, app); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_set_custom_event_callback( diff --git a/applications/main/gpio/icon.png b/applications/main/gpio/icon.png index 4a6eccf058..7b54bb5cb3 100644 Binary files a/applications/main/gpio/icon.png and b/applications/main/gpio/icon.png differ diff --git a/applications/main/ibutton/ibutton.c b/applications/main/ibutton/ibutton.c index b6e8a20cf9..765d536125 100644 --- a/applications/main/ibutton/ibutton.c +++ b/applications/main/ibutton/ibutton.c @@ -85,7 +85,6 @@ iButton* ibutton_alloc(void) { ibutton->scene_manager = scene_manager_alloc(&ibutton_scene_handlers, ibutton); ibutton->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(ibutton->view_dispatcher); view_dispatcher_set_event_callback_context(ibutton->view_dispatcher, ibutton); view_dispatcher_set_custom_event_callback( ibutton->view_dispatcher, ibutton_custom_event_callback); diff --git a/applications/main/ibutton/ibutton_cli.c b/applications/main/ibutton/ibutton_cli.c index 12e237e8a7..dcac8f9632 100644 --- a/applications/main/ibutton/ibutton_cli.c +++ b/applications/main/ibutton/ibutton_cli.c @@ -143,7 +143,7 @@ void ibutton_cli_write(Cli* cli, FuriString* args) { } if(!(ibutton_protocols_get_features(protocols, ibutton_key_get_protocol_id(key)) & - iButtonProtocolFeatureWriteBlank)) { + iButtonProtocolFeatureWriteId)) { ibutton_cli_print_usage(); break; } @@ -152,7 +152,7 @@ void ibutton_cli_write(Cli* cli, FuriString* args) { ibutton_cli_print_key(protocols, key); printf("Press Ctrl+C to abort\r\n"); - ibutton_worker_write_blank_start(worker, key); + ibutton_worker_write_id_start(worker, key); while(true) { uint32_t flags = furi_event_flag_wait( write_context.event, EVENT_FLAG_IBUTTON_COMPLETE, FuriFlagWaitAny, 100); diff --git a/applications/main/ibutton/ibutton_i.h b/applications/main/ibutton/ibutton_i.h index d355a4ea5f..fc2324c635 100644 --- a/applications/main/ibutton/ibutton_i.h +++ b/applications/main/ibutton/ibutton_i.h @@ -28,7 +28,7 @@ #include "ibutton_custom_event.h" #include "scenes/ibutton_scene.h" -#define IBUTTON_APP_FOLDER ANY_PATH("ibutton") +#define IBUTTON_APP_FOLDER EXT_PATH("ibutton") #define IBUTTON_APP_FILENAME_PREFIX "iBtn" #define IBUTTON_APP_FILENAME_EXTENSION ".ibtn" @@ -36,7 +36,7 @@ typedef enum { iButtonWriteModeInvalid, - iButtonWriteModeBlank, + iButtonWriteModeId, iButtonWriteModeCopy, } iButtonWriteMode; diff --git a/applications/main/ibutton/icon.png b/applications/main/ibutton/icon.png index 2fdaf123a6..f73af065f4 100644 Binary files a/applications/main/ibutton/icon.png and b/applications/main/ibutton/icon.png differ diff --git a/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c b/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c index 890e0a2848..94ad4b69ee 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c +++ b/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c @@ -5,7 +5,7 @@ typedef enum { SubmenuIndexSave, SubmenuIndexEmulate, SubmenuIndexViewData, - SubmenuIndexWriteBlank, + SubmenuIndexWriteId, SubmenuIndexWriteCopy, } SubmenuIndex; @@ -30,11 +30,11 @@ void ibutton_scene_read_key_menu_on_enter(void* context) { ibutton_scene_read_key_menu_submenu_callback, ibutton); - if(features & iButtonProtocolFeatureWriteBlank) { + if(features & iButtonProtocolFeatureWriteId) { submenu_add_item( submenu, "Write ID", - SubmenuIndexWriteBlank, + SubmenuIndexWriteId, ibutton_scene_read_key_menu_submenu_callback, ibutton); } @@ -78,8 +78,8 @@ bool ibutton_scene_read_key_menu_on_event(void* context, SceneManagerEvent event dolphin_deed(DolphinDeedIbuttonEmulate); } else if(event.event == SubmenuIndexViewData) { scene_manager_next_scene(scene_manager, iButtonSceneViewData); - } else if(event.event == SubmenuIndexWriteBlank) { - ibutton->write_mode = iButtonWriteModeBlank; + } else if(event.event == SubmenuIndexWriteId) { + ibutton->write_mode = iButtonWriteModeId; scene_manager_next_scene(scene_manager, iButtonSceneWrite); } else if(event.event == SubmenuIndexWriteCopy) { ibutton->write_mode = iButtonWriteModeCopy; diff --git a/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c b/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c index 668b79ae3c..6727c5458c 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c +++ b/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c @@ -3,7 +3,7 @@ enum SubmenuIndex { SubmenuIndexEmulate, - SubmenuIndexWriteBlank, + SubmenuIndexWriteId, SubmenuIndexWriteCopy, SubmenuIndexEdit, SubmenuIndexRename, @@ -20,9 +20,9 @@ void ibutton_scene_saved_key_menu_on_enter(void* context) { submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, ibutton_submenu_callback, ibutton); - if(features & iButtonProtocolFeatureWriteBlank) { + if(features & iButtonProtocolFeatureWriteId) { submenu_add_item( - submenu, "Write ID", SubmenuIndexWriteBlank, ibutton_submenu_callback, ibutton); + submenu, "Write ID", SubmenuIndexWriteId, ibutton_submenu_callback, ibutton); } if(features & iButtonProtocolFeatureWriteCopy) { @@ -55,8 +55,8 @@ bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent even if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(scene_manager, iButtonSceneEmulate); dolphin_deed(DolphinDeedIbuttonEmulate); - } else if(event.event == SubmenuIndexWriteBlank) { - ibutton->write_mode = iButtonWriteModeBlank; + } else if(event.event == SubmenuIndexWriteId) { + ibutton->write_mode = iButtonWriteModeId; scene_manager_next_scene(scene_manager, iButtonSceneWrite); } else if(event.event == SubmenuIndexWriteCopy) { ibutton->write_mode = iButtonWriteModeCopy; diff --git a/applications/main/ibutton/scenes/ibutton_scene_write.c b/applications/main/ibutton/scenes/ibutton_scene_write.c index 0fc073fdae..4525eae7b8 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_write.c +++ b/applications/main/ibutton/scenes/ibutton_scene_write.c @@ -51,9 +51,9 @@ void ibutton_scene_write_on_enter(void* context) { ibutton_worker_write_set_callback(worker, ibutton_scene_write_callback, ibutton); - if(ibutton->write_mode == iButtonWriteModeBlank) { + if(ibutton->write_mode == iButtonWriteModeId) { furi_string_set(tmp, "Writing ID"); - ibutton_worker_write_blank_start(worker, key); + ibutton_worker_write_id_start(worker, key); } else if(ibutton->write_mode == iButtonWriteModeCopy) { furi_string_set(tmp, "Full Writing"); diff --git a/applications/main/infrared/icon.png b/applications/main/infrared/icon.png index 22c986180a..36c214f3b8 100644 Binary files a/applications/main/infrared/icon.png and b/applications/main/infrared/icon.png differ diff --git a/applications/main/infrared/infrared_app.c b/applications/main/infrared/infrared_app.c index d860aa3b23..db178fb42b 100644 --- a/applications/main/infrared/infrared_app.c +++ b/applications/main/infrared/infrared_app.c @@ -150,7 +150,6 @@ static InfraredApp* infrared_alloc(void) { infrared->gui = furi_record_open(RECORD_GUI); ViewDispatcher* view_dispatcher = infrared->view_dispatcher; - view_dispatcher_enable_queue(view_dispatcher); view_dispatcher_set_event_callback_context(view_dispatcher, infrared); view_dispatcher_set_custom_event_callback(view_dispatcher, infrared_custom_event_callback); view_dispatcher_set_navigation_event_callback(view_dispatcher, infrared_back_event_callback); diff --git a/applications/main/infrared/infrared_app_i.h b/applications/main/infrared/infrared_app_i.h index d353b2503b..75d4e230d2 100644 --- a/applications/main/infrared/infrared_app_i.h +++ b/applications/main/infrared/infrared_app_i.h @@ -46,7 +46,7 @@ #define INFRARED_MAX_BUTTON_NAME_LENGTH 22 #define INFRARED_MAX_REMOTE_NAME_LENGTH 22 -#define INFRARED_APP_FOLDER ANY_PATH("infrared") +#define INFRARED_APP_FOLDER EXT_PATH("infrared") #define INFRARED_APP_EXTENSION ".ir" #define INFRARED_DEFAULT_REMOTE_NAME "Remote" diff --git a/applications/main/lfrfid/icon.png b/applications/main/lfrfid/icon.png index ce01284a2c..fd3947ff36 100644 Binary files a/applications/main/lfrfid/icon.png and b/applications/main/lfrfid/icon.png differ diff --git a/applications/main/lfrfid/lfrfid.c b/applications/main/lfrfid/lfrfid.c index a405c0f853..b51a0da260 100644 --- a/applications/main/lfrfid/lfrfid.c +++ b/applications/main/lfrfid/lfrfid.c @@ -77,7 +77,6 @@ static LfRfid* lfrfid_alloc(void) { lfrfid->view_dispatcher = view_dispatcher_alloc(); lfrfid->scene_manager = scene_manager_alloc(&lfrfid_scene_handlers, lfrfid); - view_dispatcher_enable_queue(lfrfid->view_dispatcher); view_dispatcher_set_event_callback_context(lfrfid->view_dispatcher, lfrfid); view_dispatcher_set_custom_event_callback( lfrfid->view_dispatcher, lfrfid_debug_custom_event_callback); diff --git a/applications/main/lfrfid/lfrfid_i.h b/applications/main/lfrfid/lfrfid_i.h index f949e73e66..913b7358bd 100644 --- a/applications/main/lfrfid/lfrfid_i.h +++ b/applications/main/lfrfid/lfrfid_i.h @@ -38,7 +38,7 @@ #define LFRFID_KEY_NAME_SIZE 22 #define LFRFID_TEXT_STORE_SIZE 40 -#define LFRFID_APP_FOLDER ANY_PATH("lfrfid") +#define LFRFID_APP_FOLDER EXT_PATH("lfrfid") #define LFRFID_SD_FOLDER EXT_PATH("lfrfid") #define LFRFID_APP_FILENAME_PREFIX "RFID" #define LFRFID_APP_FILENAME_EXTENSION ".rfid" diff --git a/applications/main/nfc/helpers/mf_user_dict.c b/applications/main/nfc/helpers/mf_user_dict.c index 70b1114722..7f60d339e6 100644 --- a/applications/main/nfc/helpers/mf_user_dict.c +++ b/applications/main/nfc/helpers/mf_user_dict.c @@ -4,7 +4,7 @@ #include #include -#define NFC_APP_FOLDER ANY_PATH("nfc") +#define NFC_APP_FOLDER EXT_PATH("nfc") #define NFC_APP_MF_CLASSIC_DICT_USER_PATH (NFC_APP_FOLDER "/assets/mf_classic_dict_user.nfc") struct MfUserDict { diff --git a/applications/main/nfc/helpers/nfc_detected_protocols.c b/applications/main/nfc/helpers/nfc_detected_protocols.c new file mode 100644 index 0000000000..339d4ddc23 --- /dev/null +++ b/applications/main/nfc/helpers/nfc_detected_protocols.c @@ -0,0 +1,85 @@ +#include "nfc_detected_protocols.h" + +#include + +struct NfcDetectedProtocols { + uint32_t protocols_detected_num; + NfcProtocol protocols_detected[NfcProtocolNum]; + uint32_t selected_idx; +}; + +NfcDetectedProtocols* nfc_detected_protocols_alloc(void) { + NfcDetectedProtocols* instance = malloc(sizeof(NfcDetectedProtocols)); + + instance->protocols_detected_num = 0; + instance->selected_idx = 0; + + return instance; +} + +void nfc_detected_protocols_free(NfcDetectedProtocols* instance) { + furi_assert(instance); + + free(instance); +} + +void nfc_detected_protocols_reset(NfcDetectedProtocols* instance) { + furi_assert(instance); + + instance->protocols_detected_num = 0; + memset(instance->protocols_detected, 0, sizeof(instance->protocols_detected)); + instance->selected_idx = 0; +} + +void nfc_detected_protocols_select(NfcDetectedProtocols* instance, uint32_t idx) { + furi_assert(instance); + + instance->selected_idx = idx; +} + +void nfc_detected_protocols_set( + NfcDetectedProtocols* instance, + const NfcProtocol* types, + uint32_t count) { + furi_assert(instance); + furi_assert(types); + furi_assert(count < NfcProtocolNum); + + memcpy(instance->protocols_detected, types, count); + instance->protocols_detected_num = count; + instance->selected_idx = 0; +} + +uint32_t nfc_detected_protocols_get_num(NfcDetectedProtocols* instance) { + furi_assert(instance); + + return instance->protocols_detected_num; +} + +NfcProtocol nfc_detected_protocols_get_protocol(NfcDetectedProtocols* instance, uint32_t idx) { + furi_assert(instance); + furi_assert(idx < instance->protocols_detected_num); + + return instance->protocols_detected[idx]; +} + +void nfc_detected_protocols_fill_all_protocols(NfcDetectedProtocols* instance) { + furi_assert(instance); + + instance->protocols_detected_num = NfcProtocolNum; + for(uint32_t i = 0; i < NfcProtocolNum; i++) { + instance->protocols_detected[i] = i; + } +} + +NfcProtocol nfc_detected_protocols_get_selected(NfcDetectedProtocols* instance) { + furi_assert(instance); + + return instance->protocols_detected[instance->selected_idx]; +} + +uint32_t nfc_detected_protocols_get_selected_idx(NfcDetectedProtocols* instance) { + furi_assert(instance); + + return instance->selected_idx; +} diff --git a/applications/main/nfc/helpers/nfc_detected_protocols.h b/applications/main/nfc/helpers/nfc_detected_protocols.h new file mode 100644 index 0000000000..2ab46add39 --- /dev/null +++ b/applications/main/nfc/helpers/nfc_detected_protocols.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +typedef struct NfcDetectedProtocols NfcDetectedProtocols; + +NfcDetectedProtocols* nfc_detected_protocols_alloc(void); + +void nfc_detected_protocols_free(NfcDetectedProtocols* instance); + +void nfc_detected_protocols_reset(NfcDetectedProtocols* instance); + +void nfc_detected_protocols_select(NfcDetectedProtocols* instance, uint32_t idx); + +void nfc_detected_protocols_set( + NfcDetectedProtocols* instance, + const NfcProtocol* types, + uint32_t count); + +uint32_t nfc_detected_protocols_get_num(NfcDetectedProtocols* instance); + +NfcProtocol nfc_detected_protocols_get_protocol(NfcDetectedProtocols* instance, uint32_t idx); + +void nfc_detected_protocols_fill_all_protocols(NfcDetectedProtocols* instance); + +NfcProtocol nfc_detected_protocols_get_selected(NfcDetectedProtocols* instance); + +uint32_t nfc_detected_protocols_get_selected_idx(NfcDetectedProtocols* instance); diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index 063e0ece37..c56b553903 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -150,8 +150,7 @@ static void nfc_protocol_support_scene_read_on_enter(NfcApp* instance) { view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - const NfcProtocol protocol = - instance->protocols_detected[instance->protocols_detected_selected_idx]; + const NfcProtocol protocol = nfc_detected_protocols_get_selected(instance->detected_protocols); instance->poller = nfc_poller_alloc(instance->nfc, protocol); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); @@ -186,7 +185,7 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana consumed = true; } else { const NfcProtocol protocol = - instance->protocols_detected[instance->protocols_detected_selected_idx]; + nfc_detected_protocols_get_selected(instance->detected_protocols); consumed = nfc_protocol_support[protocol]->scene_read.on_event(instance, event); } } else if(event.event == NfcCustomEventPollerFailure) { @@ -199,7 +198,7 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana consumed = true; } else if(event.event == NfcCustomEventCardDetected) { const NfcProtocol protocol = - instance->protocols_detected[instance->protocols_detected_selected_idx]; + nfc_detected_protocols_get_selected(instance->detected_protocols); consumed = nfc_protocol_support[protocol]->scene_read.on_event(instance, event); } } else if(event.type == SceneManagerEventTypeBack) { diff --git a/applications/main/nfc/icon.png b/applications/main/nfc/icon.png index 6bc027111a..e998d291ee 100644 Binary files a/applications/main/nfc/icon.png and b/applications/main/nfc/icon.png differ diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index ce444982dd..9f855f9e9f 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -41,7 +41,6 @@ NfcApp* nfc_app_alloc(void) { instance->view_dispatcher = view_dispatcher_alloc(); instance->scene_manager = scene_manager_alloc(&nfc_scene_handlers, instance); - view_dispatcher_enable_queue(instance->view_dispatcher); view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance); view_dispatcher_set_custom_event_callback( instance->view_dispatcher, nfc_custom_event_callback); @@ -50,6 +49,7 @@ NfcApp* nfc_app_alloc(void) { instance->nfc = nfc_alloc(); + instance->detected_protocols = nfc_detected_protocols_alloc(); instance->felica_auth = felica_auth_alloc(); instance->mf_ul_auth = mf_ultralight_auth_alloc(); instance->slix_unlock = slix_unlock_alloc(); @@ -142,6 +142,7 @@ void nfc_app_free(NfcApp* instance) { nfc_free(instance->nfc); + nfc_detected_protocols_free(instance->detected_protocols); felica_auth_free(instance->felica_auth); mf_ultralight_auth_free(instance->mf_ul_auth); slix_unlock_free(instance->slix_unlock); @@ -433,23 +434,6 @@ void nfc_show_loading_popup(void* context, bool show) { } } -void nfc_app_set_detected_protocols(NfcApp* instance, const NfcProtocol* types, uint32_t count) { - furi_assert(instance); - furi_assert(types); - furi_assert(count < NfcProtocolNum); - - memcpy(instance->protocols_detected, types, count); - instance->protocols_detected_num = count; - instance->protocols_detected_selected_idx = 0; -} - -void nfc_app_reset_detected_protocols(NfcApp* instance) { - furi_assert(instance); - - instance->protocols_detected_selected_idx = 0; - instance->protocols_detected_num = 0; -} - void nfc_append_filename_string_when_present(NfcApp* instance, FuriString* string) { furi_assert(instance); furi_assert(string); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 9a9c81004d..1c174986ea 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -26,6 +26,7 @@ #include "views/dict_attack.h" #include +#include "helpers/nfc_detected_protocols.h" #include "helpers/nfc_custom_event.h" #include "helpers/mf_ultralight_auth.h" #include "helpers/mf_user_dict.h" @@ -66,7 +67,7 @@ #define NFC_TEXT_STORE_SIZE 128 #define NFC_BYTE_INPUT_STORE_SIZE 10 #define NFC_LOG_SIZE_MAX (1024) -#define NFC_APP_FOLDER ANY_PATH("nfc") +#define NFC_APP_FOLDER EXT_PATH("nfc") #define NFC_APP_EXTENSION ".nfc" #define NFC_APP_SHADOW_EXTENSION ".shd" #define NFC_APP_FILENAME_PREFIX "NFC" @@ -107,9 +108,7 @@ struct NfcApp { FuriString* text_box_store; uint8_t byte_input_store[NFC_BYTE_INPUT_STORE_SIZE]; - uint32_t protocols_detected_num; - NfcProtocol protocols_detected[NfcProtocolNum]; - uint32_t protocols_detected_selected_idx; + NfcDetectedProtocols* detected_protocols; RpcAppSystem* rpc_ctx; NfcRpcState rpc_state; @@ -194,8 +193,4 @@ bool nfc_save_file(NfcApp* instance, FuriString* path); void nfc_make_app_folder(NfcApp* instance); -void nfc_app_set_detected_protocols(NfcApp* instance, const NfcProtocol* types, uint32_t count); - -void nfc_app_reset_detected_protocols(NfcApp* instance); - void nfc_append_filename_string_when_present(NfcApp* instance, FuriString* string); diff --git a/applications/main/nfc/plugins/supported_cards/plantain.c b/applications/main/nfc/plugins/supported_cards/plantain.c index 11b60d6fa0..36f745697d 100644 --- a/applications/main/nfc/plugins/supported_cards/plantain.c +++ b/applications/main/nfc/plugins/supported_cards/plantain.c @@ -229,7 +229,7 @@ static bool plantain_parse(const NfcDevice* device, FuriString* parsed_data) { } furi_string_printf( - parsed_data, "\e#Plantain\nNo.: %llu?\nBalance:%lu\n", card_number, balance); + parsed_data, "\e#Plantain\nNo.: %lluX\nBalance: %lu\n", card_number, balance); parsed = true; } while(false); diff --git a/applications/main/nfc/plugins/supported_cards/two_cities.c b/applications/main/nfc/plugins/supported_cards/two_cities.c index 2f92030d95..dc87d3072f 100644 --- a/applications/main/nfc/plugins/supported_cards/two_cities.c +++ b/applications/main/nfc/plugins/supported_cards/two_cities.c @@ -157,7 +157,7 @@ static bool two_cities_parse(const NfcDevice* device, FuriString* parsed_data) { furi_string_printf( parsed_data, - "\e#Troika+Plantain\nPN: %llu?\nPB: %lu rur.\nTN: %lu\nTB: %u rur.\n", + "\e#Troika+Plantain\nPN: %lluX\nPB: %lu rur.\nTN: %lu\nTB: %u rur.\n", card_number, balance, troika_number, diff --git a/applications/main/nfc/scenes/nfc_scene_detect.c b/applications/main/nfc/scenes/nfc_scene_detect.c index 3ef153657d..7ef3f9d870 100644 --- a/applications/main/nfc/scenes/nfc_scene_detect.c +++ b/applications/main/nfc/scenes/nfc_scene_detect.c @@ -7,7 +7,8 @@ void nfc_scene_detect_scan_callback(NfcScannerEvent event, void* context) { NfcApp* instance = context; if(event.type == NfcScannerEventTypeDetected) { - nfc_app_set_detected_protocols(instance, event.data.protocols, event.data.protocol_num); + nfc_detected_protocols_set( + instance->detected_protocols, event.data.protocols, event.data.protocol_num); view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventWorkerExit); } } @@ -23,7 +24,7 @@ void nfc_scene_detect_on_enter(void* context) { popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - nfc_app_reset_detected_protocols(instance); + nfc_detected_protocols_reset(instance->detected_protocols); instance->scanner = nfc_scanner_alloc(instance->nfc); nfc_scanner_start(instance->scanner, nfc_scene_detect_scan_callback, instance); @@ -37,7 +38,7 @@ bool nfc_scene_detect_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventWorkerExit) { - if(instance->protocols_detected_num > 1) { + if(nfc_detected_protocols_get_num(instance->detected_protocols) > 1) { notification_message(instance->notifications, &sequence_single_vibro); scene_manager_next_scene(instance->scene_manager, NfcSceneSelectProtocol); } else { diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 4df8a62899..a0b6986d1e 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -57,7 +57,8 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultRight) { const NfcProtocol mfu_protocol[] = {NfcProtocolMfUltralight}; - nfc_app_set_detected_protocols(nfc, mfu_protocol, COUNT_OF(mfu_protocol)); + nfc_detected_protocols_set( + nfc->detected_protocols, mfu_protocol, COUNT_OF(mfu_protocol)); scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); dolphin_deed(DolphinDeedNfcRead); consumed = true; @@ -77,7 +78,8 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultCenter) { const NfcProtocol mfu_protocol[] = {NfcProtocolMfUltralight}; - nfc_app_set_detected_protocols(nfc, mfu_protocol, COUNT_OF(mfu_protocol)); + nfc_detected_protocols_set( + nfc->detected_protocols, mfu_protocol, COUNT_OF(mfu_protocol)); scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); dolphin_deed(DolphinDeedNfcRead); consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_select_protocol.c b/applications/main/nfc/scenes/nfc_scene_select_protocol.c index af644035e8..f2c92b6313 100644 --- a/applications/main/nfc/scenes/nfc_scene_select_protocol.c +++ b/applications/main/nfc/scenes/nfc_scene_select_protocol.c @@ -14,21 +14,19 @@ void nfc_scene_select_protocol_on_enter(void* context) { const char* prefix; if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneExtraActions)) { prefix = "Read"; - instance->protocols_detected_num = NfcProtocolNum; - for(uint32_t i = 0; i < NfcProtocolNum; i++) { - instance->protocols_detected[i] = i; - } + nfc_detected_protocols_fill_all_protocols(instance->detected_protocols); } else { prefix = "Read as"; submenu_set_header(submenu, "Multi-protocol card"); } - for(uint32_t i = 0; i < instance->protocols_detected_num; i++) { + for(uint32_t i = 0; i < nfc_detected_protocols_get_num(instance->detected_protocols); i++) { furi_string_printf( temp_str, "%s %s", prefix, - nfc_device_get_protocol_name(instance->protocols_detected[i])); + nfc_device_get_protocol_name( + nfc_detected_protocols_get_protocol(instance->detected_protocols, i))); furi_string_replace_str(temp_str, "Mifare", "MIFARE"); submenu_add_item( @@ -40,9 +38,8 @@ void nfc_scene_select_protocol_on_enter(void* context) { } furi_string_free(temp_str); - const uint32_t state = - scene_manager_get_scene_state(instance->scene_manager, NfcSceneSelectProtocol); - submenu_set_selected_item(submenu, state); + submenu_set_selected_item( + submenu, nfc_detected_protocols_get_selected_idx(instance->detected_protocols)); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewMenu); } @@ -52,10 +49,8 @@ bool nfc_scene_select_protocol_on_event(void* context, SceneManagerEvent event) bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - instance->protocols_detected_selected_idx = event.event; + nfc_detected_protocols_select(instance->detected_protocols, event.event); scene_manager_next_scene(instance->scene_manager, NfcSceneRead); - scene_manager_set_scene_state( - instance->scene_manager, NfcSceneSelectProtocol, event.event); consumed = true; } else if(event.type == SceneManagerEventTypeBack) { if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneDetect)) { diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index e8774b4aa5..53857b8495 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -25,7 +25,7 @@ void nfc_scene_start_on_enter(void* context) { nfc_device_clear(nfc->nfc_device); iso14443_3a_reset(nfc->iso14443_3a_edit_data); // Reset detected protocols list - nfc_app_reset_detected_protocols(nfc); + nfc_detected_protocols_reset(nfc->detected_protocols); submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc); submenu_add_item( diff --git a/applications/main/subghz/icon.png b/applications/main/subghz/icon.png index 5a25fdf4ef..70940ad779 100644 Binary files a/applications/main/subghz/icon.png and b/applications/main/subghz/icon.png differ diff --git a/applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c b/applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c index 2a0b5e498a..9e5289c548 100644 --- a/applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c +++ b/applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c @@ -69,8 +69,9 @@ bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent e return true; } else if(event.event == SubGhzCustomEventViewFreqAnalOkLong) { - // Don't need to save, we already saved on short event - //scene_manager_set_scene_state(subghz->scene_manager, SubGhzSceneStart, 10); + // Don't need to save, we already saved on short event (and on exit event too) + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); + scene_manager_set_scene_state(subghz->scene_manager, SubGhzSceneStart, 10); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver); return true; } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 01b46d2486..1a00634180 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -146,11 +146,11 @@ static void subghz_scene_add_to_history_callback( if(subghz_history_get_text_space_left(subghz->history, NULL)) { notification_message(subghz->notifications, &sequence_error); } + subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } subghz_receiver_reset(receiver); furi_string_free(item_name); furi_string_free(item_time); - subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } else { FURI_LOG_D(TAG, "%s protocol ignored", decoder_base->protocol->name); } diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 2f8a1f03f7..4675afaebf 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -59,7 +59,8 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { default: //if(SubGhzTxRxStartTxStateOk) result = true; subghz_blink_start(subghz); - state = SubGhzRpcStateTx; + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateTx); break; } } @@ -71,7 +72,8 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { subghz_blink_stop(subghz); result = true; } - state = SubGhzRpcStateIdle; + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle); rpc_system_app_confirm(subghz->rpc_ctx, result); } else if(event.event == SubGhzCustomEventSceneRpcLoad) { bool result = false; diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 7a5fad74c9..30480054ec 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -97,7 +97,6 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { // View Dispatcher subghz->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(subghz->view_dispatcher); subghz->scene_manager = scene_manager_alloc(&subghz_scene_handlers, subghz); view_dispatcher_set_event_callback_context(subghz->view_dispatcher, subghz); diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index 43bb25ab83..43ba9c6440 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -478,7 +478,7 @@ void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) { void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { UNUSED(context); FuriString* file_name = furi_string_alloc(); - furi_string_set(file_name, ANY_PATH("subghz/test.sub")); + furi_string_set(file_name, EXT_PATH("subghz/test.sub")); Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); @@ -592,7 +592,7 @@ void subghz_cli_command_tx_from_file(Cli* cli, FuriString* args, void* context) UNUSED(context); FuriString* file_name; file_name = furi_string_alloc(); - furi_string_set(file_name, ANY_PATH("subghz/test.sub")); + furi_string_set(file_name, EXT_PATH("subghz/test.sub")); uint32_t repeat = 10; uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT diff --git a/applications/main/subghz/views/subghz_frequency_analyzer.c b/applications/main/subghz/views/subghz_frequency_analyzer.c index 1bb2f044fe..fde3a1f613 100644 --- a/applications/main/subghz/views/subghz_frequency_analyzer.c +++ b/applications/main/subghz/views/subghz_frequency_analyzer.c @@ -1,7 +1,6 @@ #include "subghz_frequency_analyzer.h" #include -#include #include #include #include @@ -12,20 +11,79 @@ #define TAG "frequency_analyzer" -#define RSSI_MIN -97 -#define RSSI_MAX -60 -#define RSSI_SCALE 2.3 +#define RSSI_MIN (-97.0f) +#define RSSI_MAX (-60.0f) +#define RSSI_SCALE 2.3f #define TRIGGER_STEP 1 #define MAX_HISTORY 4 +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif static const uint32_t subghz_frequency_list[] = { - 300000000, 302757000, 303875000, 303900000, 304250000, 307000000, 307500000, 307800000, - 309000000, 310000000, 312000000, 312100000, 313000000, 313850000, 314000000, 314350000, - 314980000, 315000000, 318000000, 330000000, 345000000, 348000000, 350000000, 387000000, - 390000000, 418000000, 430000000, 431000000, 431500000, 433075000, 433220000, 433420000, - 433657070, 433889000, 433920000, 434075000, 434176948, 434390000, 434420000, 434775000, - 438900000, 440175000, 464000000, 779000000, 868350000, 868400000, 868800000, 868950000, - 906400000, 915000000, 925000000, 928000000}; + /* 300 - 348 */ + 300000000, + 302757000, + 303875000, + 303900000, + 304250000, + 307000000, + 307500000, + 307800000, + 309000000, + 310000000, + 312000000, + 312100000, + 312200000, + 313000000, + 313850000, + 314000000, + 314350000, + 314980000, + 315000000, + 318000000, + 330000000, + 345000000, + 348000000, + 350000000, + + /* 387 - 464 */ + 387000000, + 390000000, + 418000000, + 430000000, + 430500000, + 431000000, + 431500000, + 433075000, /* LPD433 first */ + 433220000, + 433420000, + 433657070, + 433889000, + 433920000, /* LPD433 mid */ + 434075000, + 434176948, + 434190000, + 434390000, + 434420000, + 434620000, + 434775000, /* LPD433 last channels */ + 438900000, + 440175000, + 464000000, + 467750000, + + /* 779 - 928 */ + 779000000, + 868350000, + 868400000, + 868800000, + 868950000, + 906400000, + 915000000, + 925000000, + 928000000, +}; typedef enum { SubGhzFrequencyAnalyzerStatusIDLE, @@ -80,7 +138,7 @@ void subghz_frequency_analyzer_draw_rssi( uint8_t x, uint8_t y) { // Current RSSI - if(rssi) { + if(!float_is_equal(rssi, 0.f)) { if(rssi > RSSI_MAX) { rssi = RSSI_MAX; } @@ -95,7 +153,7 @@ void subghz_frequency_analyzer_draw_rssi( } // Last RSSI - if(rssi_last) { + if(!float_is_equal(rssi_last, 0.f)) { if(rssi_last > RSSI_MAX) { rssi_last = RSSI_MAX; } @@ -108,7 +166,7 @@ void subghz_frequency_analyzer_draw_rssi( // Trigger cursor trigger = (trigger - RSSI_MIN) / RSSI_SCALE; - uint8_t tr_x = x + 2 * trigger; + uint8_t tr_x = (uint8_t)((float)x + (2 * trigger)); canvas_draw_dot(canvas, tr_x, y + 4); canvas_draw_line(canvas, tr_x - 1, y + 5, tr_x + 1, y + 5); @@ -118,7 +176,7 @@ void subghz_frequency_analyzer_draw_rssi( static void subghz_frequency_analyzer_history_frequency_draw( Canvas* canvas, SubGhzFrequencyAnalyzerModel* model) { - char buffer[64]; + char buffer[64] = {0}; const uint8_t x1 = 2; const uint8_t x2 = 66; const uint8_t y = 37; @@ -161,7 +219,7 @@ static void subghz_frequency_analyzer_history_frequency_draw( } void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel* model) { - char buffer[64]; + char buffer[64] = {0}; // Title canvas_set_color(canvas, ColorBlack); @@ -190,9 +248,7 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel canvas_draw_box(canvas, 4, 10, 121, 19); canvas_set_color(canvas, ColorWhite); } else { - // TODO: Disable this - //canvas_draw_box(canvas, 4, 11, 121, 19); - //canvas_set_color(canvas, ColorWhite); + canvas_set_color(canvas, ColorBlack); } canvas_draw_str(canvas, 8, 26, buffer); @@ -224,11 +280,14 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel uint32_t subghz_frequency_find_correct(uint32_t input) { uint32_t prev_freq = 0; - uint32_t current = 0; uint32_t result = 0; + uint32_t current; - for(size_t i = 0; i < sizeof(subghz_frequency_list); i++) { + for(size_t i = 0; i < ARRAY_SIZE(subghz_frequency_list) - 1; i++) { current = subghz_frequency_list[i]; + if(current == 0) { + continue; + } if(current == input) { result = current; break; @@ -249,47 +308,40 @@ uint32_t subghz_frequency_find_correct(uint32_t input) { bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { furi_assert(context); - SubGhzFrequencyAnalyzer* instance = context; + SubGhzFrequencyAnalyzer* instance = (SubGhzFrequencyAnalyzer*)context; bool need_redraw = false; - if(event->key == InputKeyBack) { - return false; + return need_redraw; } - if(((event->type == InputTypePress) || (event->type == InputTypeRepeat)) && - ((event->key == InputKeyLeft) || (event->key == InputKeyRight))) { + bool is_press_or_repeat = (event->type == InputTypePress) || (event->type == InputTypeRepeat); + if(is_press_or_repeat && (event->key == InputKeyLeft || event->key == InputKeyRight)) { // Trigger setup float trigger_level = subghz_frequency_analyzer_worker_get_trigger_level(instance->worker); - switch(event->key) { - case InputKeyLeft: + if(event->key == InputKeyLeft) { trigger_level -= TRIGGER_STEP; if(trigger_level < RSSI_MIN) { trigger_level = RSSI_MIN; } - break; - default: - case InputKeyRight: + } else { trigger_level += TRIGGER_STEP; if(trigger_level > RSSI_MAX) { trigger_level = RSSI_MAX; } - break; } subghz_frequency_analyzer_worker_set_trigger_level(instance->worker, trigger_level); FURI_LOG_D(TAG, "trigger = %.1f", (double)trigger_level); need_redraw = true; } else if(event->type == InputTypePress && event->key == InputKeyUp) { - if(instance->feedback_level == 0) { - instance->feedback_level = 2; + if(instance->feedback_level == SubGHzFrequencyAnalyzerFeedbackLevelAll) { + instance->feedback_level = SubGHzFrequencyAnalyzerFeedbackLevelMute; } else { instance->feedback_level--; } need_redraw = true; - } else if( - ((event->type == InputTypePress) || (event->type == InputTypeRepeat)) && - event->key == InputKeyDown) { + } else if(is_press_or_repeat && event->key == InputKeyDown) { instance->show_frame = instance->max_index > 0; if(instance->show_frame) { instance->selected_index = (instance->selected_index + 1) % instance->max_index; @@ -298,63 +350,32 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { } else if(event->key == InputKeyOk) { need_redraw = true; bool updated = false; - uint32_t frequency_to_save = 0; + uint32_t frequency_to_save; with_view_model( instance->view, SubGhzFrequencyAnalyzerModel * model, { frequency_to_save = model->frequency_to_save; + uint32_t prev_freq_to_save = model->frequency_to_save; + uint32_t frequency_candidate = 0; + if(model->show_frame && !model->signal) { - uint32_t prev_freq_to_save = model->frequency_to_save; - uint32_t frequency_candidate = model->history_frequency[model->selected_index]; - if(frequency_candidate == 0 || - // !furi_hal_subghz_is_frequency_valid(frequency_candidate) || - !subghz_txrx_radio_device_is_frequency_valid( - instance->txrx, frequency_candidate) || - prev_freq_to_save == frequency_candidate) { - frequency_candidate = 0; - } else { - frequency_candidate = subghz_frequency_find_correct(frequency_candidate); - } - if(frequency_candidate > 0 && - frequency_candidate != model->frequency_to_save) { - model->frequency_to_save = frequency_candidate; - updated = true; - } - } else if(model->show_frame && model->signal) { - uint32_t prev_freq_to_save = model->frequency_to_save; - uint32_t frequency_candidate = subghz_frequency_find_correct(model->frequency); - if(frequency_candidate == 0 || - // !furi_hal_subghz_is_frequency_valid(frequency_candidate) || - !subghz_txrx_radio_device_is_frequency_valid( - instance->txrx, frequency_candidate) || - prev_freq_to_save == frequency_candidate) { - frequency_candidate = 0; - } else { - frequency_candidate = subghz_frequency_find_correct(frequency_candidate); - } - if(frequency_candidate > 0 && - frequency_candidate != model->frequency_to_save) { - model->frequency_to_save = frequency_candidate; - updated = true; - } - } else if(!model->show_frame && model->signal) { - uint32_t prev_freq_to_save = model->frequency_to_save; - uint32_t frequency_candidate = subghz_frequency_find_correct(model->frequency); - if(frequency_candidate == 0 || - // !furi_hal_subghz_is_frequency_valid(frequency_candidate) || - !subghz_txrx_radio_device_is_frequency_valid( - instance->txrx, frequency_candidate) || - prev_freq_to_save == frequency_candidate) { - frequency_candidate = 0; - } else { - frequency_candidate = subghz_frequency_find_correct(frequency_candidate); - } - if(frequency_candidate > 0 && - frequency_candidate != model->frequency_to_save) { - model->frequency_to_save = frequency_candidate; - updated = true; - } + frequency_candidate = model->history_frequency[model->selected_index]; + } else if( + (model->show_frame && model->signal) || + (!model->show_frame && model->signal)) { + frequency_candidate = subghz_frequency_find_correct(model->frequency); + } + + frequency_candidate = frequency_candidate == 0 || + !subghz_txrx_radio_device_is_frequency_valid( + instance->txrx, frequency_candidate) || + prev_freq_to_save == frequency_candidate ? + 0 : + subghz_frequency_find_correct(frequency_candidate); + if(frequency_candidate > 0 && frequency_candidate != model->frequency_to_save) { + model->frequency_to_save = frequency_candidate; + updated = true; } }, true); @@ -363,7 +384,7 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { instance->callback(SubGhzCustomEventViewFreqAnalOkShort, instance->context); } - // First device receive short, then when user release button we get long + // First the device receives short, then when user release button we get long if(event->type == InputTypeLong && frequency_to_save > 0) { // Stop worker if(subghz_frequency_analyzer_worker_is_running(instance->worker)) { @@ -375,7 +396,6 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { } if(need_redraw) { - SubGhzFrequencyAnalyzer* instance = context; with_view_model( instance->view, SubGhzFrequencyAnalyzerModel * model, @@ -412,7 +432,7 @@ void subghz_frequency_analyzer_pair_callback( uint32_t frequency, float rssi, bool signal) { - SubGhzFrequencyAnalyzer* instance = context; + SubGhzFrequencyAnalyzer* instance = (SubGhzFrequencyAnalyzer*)context; if(float_is_equal(rssi, 0.f) && instance->locked) { if(instance->callback) { instance->callback(SubGhzCustomEventSceneAnalyzerUnlock, instance->context); @@ -477,7 +497,7 @@ void subghz_frequency_analyzer_pair_callback( }, false); instance->max_index = max_index; - } else if((rssi != 0.f) && (!instance->locked)) { + } else if(!float_is_equal(rssi, 0.f) && !instance->locked) { // There is some signal FURI_LOG_I(TAG, "rssi = %.2f, frequency = %ld Hz", (double)rssi, frequency); frequency = round_int(frequency, 3); // Round 299999990Hz to 300000000Hz @@ -490,11 +510,11 @@ void subghz_frequency_analyzer_pair_callback( } // Update values - if(rssi >= instance->rssi_last && (frequency != 0)) { + if(rssi >= instance->rssi_last && frequency != 0) { instance->rssi_last = rssi; } - instance->locked = (rssi != 0.f); + instance->locked = !float_is_equal(rssi, 0.f); with_view_model( instance->view, SubGhzFrequencyAnalyzerModel * model, @@ -514,7 +534,7 @@ void subghz_frequency_analyzer_pair_callback( void subghz_frequency_analyzer_enter(void* context) { furi_assert(context); - SubGhzFrequencyAnalyzer* instance = context; + SubGhzFrequencyAnalyzer* instance = (SubGhzFrequencyAnalyzer*)context; //Start worker instance->worker = subghz_frequency_analyzer_worker_alloc(instance->context); @@ -560,7 +580,7 @@ void subghz_frequency_analyzer_enter(void* context) { void subghz_frequency_analyzer_exit(void* context) { furi_assert(context); - SubGhzFrequencyAnalyzer* instance = context; + SubGhzFrequencyAnalyzer* instance = (SubGhzFrequencyAnalyzer*)context; // Stop worker if(subghz_frequency_analyzer_worker_is_running(instance->worker)) { @@ -574,7 +594,7 @@ void subghz_frequency_analyzer_exit(void* context) { SubGhzFrequencyAnalyzer* subghz_frequency_analyzer_alloc(SubGhzTxRx* txrx) { SubGhzFrequencyAnalyzer* instance = malloc(sizeof(SubGhzFrequencyAnalyzer)); - instance->feedback_level = 2; + instance->feedback_level = SubGHzFrequencyAnalyzerFeedbackLevelMute; // View allocation and configuration instance->view = view_alloc(); diff --git a/applications/main/subghz_remote b/applications/main/subghz_remote index 6ba386c09e..b631376798 160000 --- a/applications/main/subghz_remote +++ b/applications/main/subghz_remote @@ -1 +1 @@ -Subproject commit 6ba386c09e5650f3ea814faee021829f3332ee35 +Subproject commit b63137679870602ac5ba02cba4eb0f4b0efce6fa diff --git a/applications/main/u2f/icon.png b/applications/main/u2f/icon.png index fcd87a2ef5..6f46b0e783 100644 Binary files a/applications/main/u2f/icon.png and b/applications/main/u2f/icon.png differ diff --git a/applications/main/u2f/u2f.c b/applications/main/u2f/u2f.c index 6a37769a8b..0143eb245f 100644 --- a/applications/main/u2f/u2f.c +++ b/applications/main/u2f/u2f.c @@ -4,7 +4,6 @@ #include #include #include -#include // for lfs_tobe32 #include #include @@ -319,6 +318,10 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { return sizeof(U2fRegisterResp) + cert_len + signature_len + 2; } +static inline uint32_t u2f_to_big_endian(uint32_t a) { + return __builtin_bswap32(a); +} + static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { U2fAuthReq* req = (U2fAuthReq*)buf; U2fAuthResp* resp = (U2fAuthResp*)buf; @@ -348,7 +351,7 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { U2F->user_present = false; // The 4 byte counter is represented in big endian. Increment it before use - be_u2f_counter = lfs_tobe32(U2F->counter + 1); + be_u2f_counter = u2f_to_big_endian(U2F->counter + 1); // Generate hash { diff --git a/applications/main/u2f/u2f_app.c b/applications/main/u2f/u2f_app.c index 68966390a9..58af40e7bb 100644 --- a/applications/main/u2f/u2f_app.c +++ b/applications/main/u2f/u2f_app.c @@ -29,7 +29,6 @@ U2fApp* u2f_app_alloc(void) { app->view_dispatcher = view_dispatcher_alloc(); app->scene_manager = scene_manager_alloc(&u2f_scene_handlers, app); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_set_tick_event_callback( app->view_dispatcher, u2f_app_tick_event_callback, 500); diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c index 36e7446fb7..db058ce421 100644 --- a/applications/services/bt/bt_service/bt.c +++ b/applications/services/bt/bt_service/bt.c @@ -61,6 +61,21 @@ static void bt_pin_code_view_port_input_callback(InputEvent* event, void* contex } } +static void bt_storage_callback(const void* message, void* context) { + furi_assert(context); + Bt* bt = context; + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + const BtMessage msg = { + .type = BtMessageTypeReloadKeysSettings, + }; + + furi_check( + furi_message_queue_put(bt->message_queue, &msg, FuriWaitForever) == FuriStatusOk); + } +} + 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); @@ -143,8 +158,6 @@ Bt* bt_alloc(void) { // Init default maximum packet size bt->max_packet_size = BLE_PROFILE_SERIAL_PACKET_SIZE_MAX; bt->current_profile = NULL; - // Load settings - bt_settings_load(&bt->bt_settings); // Keys storage bt->keys_storage = bt_keys_storage_alloc(BT_KEYS_STORAGE_PATH); // Alloc queue @@ -396,6 +409,8 @@ void bt_close_rpc_connection(Bt* bt) { static void bt_change_profile(Bt* bt, BtMessage* message) { if(furi_hal_bt_is_gatt_gap_supported()) { + bt_settings_load(&bt->bt_settings); + bt_close_rpc_connection(bt); bt_keys_storage_load(bt->keys_storage); @@ -439,6 +454,87 @@ static void bt_close_connection(Bt* bt, BtMessage* message) { if(message->lock) api_lock_unlock(message->lock); } +static void bt_apply_settings(Bt* bt) { + if(bt->bt_settings.enabled) { + furi_hal_bt_start_advertising(); + } else { + furi_hal_bt_stop_advertising(); + } +} + +static void bt_load_keys(Bt* bt) { + if(!furi_hal_bt_is_gatt_gap_supported()) { + bt_show_warning(bt, "Unsupported radio stack"); + bt->status = BtStatusUnavailable; + return; + + } else if(bt_keys_storage_is_changed(bt->keys_storage)) { + FURI_LOG_I(TAG, "Loading new keys"); + + bt_close_rpc_connection(bt); + bt_keys_storage_load(bt->keys_storage); + + bt->current_profile = NULL; + + } else { + FURI_LOG_I(TAG, "Keys unchanged"); + } +} + +static void bt_start_application(Bt* bt) { + if(!bt->current_profile) { + bt->current_profile = + furi_hal_bt_change_app(ble_profile_serial, NULL, bt_on_gap_event_callback, bt); + + if(!bt->current_profile) { + FURI_LOG_E(TAG, "BLE App start failed"); + bt->status = BtStatusUnavailable; + } + } +} + +static void bt_load_settings(Bt* bt) { + bt_settings_load(&bt->bt_settings); + bt_apply_settings(bt); +} + +static void bt_handle_get_settings(Bt* bt, BtMessage* message) { + furi_assert(message->lock); + *message->data.settings = bt->bt_settings; + api_lock_unlock(message->lock); +} + +static void bt_handle_set_settings(Bt* bt, BtMessage* message) { + furi_assert(message->lock); + bt->bt_settings = *message->data.csettings; + + bt_apply_settings(bt); + bt_settings_save(&bt->bt_settings); + + api_lock_unlock(message->lock); +} + +static void bt_handle_reload_keys_settings(Bt* bt) { + bt_load_keys(bt); + bt_start_application(bt); + bt_load_settings(bt); +} + +static void bt_init_keys_settings(Bt* bt) { + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), bt_storage_callback, bt); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping settings"); + + // Just start the BLE serial application without loading the keys or settings + bt_start_application(bt); + return; + } + + bt_handle_reload_keys_settings(bt); +} + bool bt_remote_rssi(Bt* bt, uint8_t* rssi) { furi_assert(bt); @@ -465,35 +561,18 @@ int32_t bt_srv(void* p) { return 0; } - // Load keys - if(!bt_keys_storage_load(bt->keys_storage)) { - FURI_LOG_W(TAG, "Failed to load bonding keys"); - } - - // Start radio stack - if(!furi_hal_bt_start_radio_stack()) { - FURI_LOG_E(TAG, "Radio stack start failed"); - } + if(furi_hal_bt_start_radio_stack()) { + bt_init_keys_settings(bt); + furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt); - if(furi_hal_bt_is_gatt_gap_supported()) { - bt->current_profile = - furi_hal_bt_start_app(ble_profile_serial, NULL, bt_on_gap_event_callback, bt); - if(!bt->current_profile) { - FURI_LOG_E(TAG, "BLE App start failed"); - } else { - if(bt->bt_settings.enabled) { - furi_hal_bt_start_advertising(); - } - furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt); - } } else { - bt_show_warning(bt, "Unsupported radio stack"); - bt->status = BtStatusUnavailable; + FURI_LOG_E(TAG, "Radio stack start failed"); } furi_record_create(RECORD_BT, bt); BtMessage message; + while(1) { furi_check( furi_message_queue_get(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk); @@ -523,7 +602,14 @@ int32_t bt_srv(void* p) { bt_close_connection(bt, &message); } else if(message.type == BtMessageTypeForgetBondedDevices) { bt_keys_storage_delete(bt->keys_storage); + } else if(message.type == BtMessageTypeGetSettings) { + bt_handle_get_settings(bt, &message); + } else if(message.type == BtMessageTypeSetSettings) { + bt_handle_set_settings(bt, &message); + } else if(message.type == BtMessageTypeReloadKeysSettings) { + bt_handle_reload_keys_settings(bt); } } + return 0; } diff --git a/applications/services/bt/bt_service/bt_api.c b/applications/services/bt/bt_service/bt_api.c index f0e792d42e..39b9a099da 100644 --- a/applications/services/bt/bt_service/bt_api.c +++ b/applications/services/bt/bt_service/bt_api.c @@ -77,3 +77,39 @@ void bt_keys_storage_set_default_path(Bt* bt) { bt_keys_storage_set_file_path(bt->keys_storage, BT_KEYS_STORAGE_PATH); } + +/* + * Private API for the Settings app + */ + +void bt_get_settings(Bt* bt, BtSettings* settings) { + furi_assert(bt); + furi_assert(settings); + + BtMessage message = { + .lock = api_lock_alloc_locked(), + .type = BtMessageTypeGetSettings, + .data.settings = settings, + }; + + furi_check( + furi_message_queue_put(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk); + + api_lock_wait_unlock_and_free(message.lock); +} + +void bt_set_settings(Bt* bt, const BtSettings* settings) { + furi_assert(bt); + furi_assert(settings); + + BtMessage message = { + .lock = api_lock_alloc_locked(), + .type = BtMessageTypeSetSettings, + .data.csettings = settings, + }; + + furi_check( + furi_message_queue_put(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk); + + api_lock_wait_unlock_and_free(message.lock); +} diff --git a/applications/services/bt/bt_service/bt_i.h b/applications/services/bt/bt_service/bt_i.h index eb94283881..58a60e2751 100644 --- a/applications/services/bt/bt_service/bt_i.h +++ b/applications/services/bt/bt_service/bt_i.h @@ -32,6 +32,9 @@ typedef enum { BtMessageTypeSetProfile, BtMessageTypeDisconnect, BtMessageTypeForgetBondedDevices, + BtMessageTypeGetSettings, + BtMessageTypeSetSettings, + BtMessageTypeReloadKeysSettings, } BtMessageType; typedef struct { @@ -49,6 +52,8 @@ typedef union { } profile; FuriHalBleProfileParams profile_params; BtKeyStorageUpdateData key_storage_data; + BtSettings* settings; + const BtSettings* csettings; } BtMessageData; typedef struct { diff --git a/applications/services/bt/bt_service/bt_keys_storage.c b/applications/services/bt/bt_service/bt_keys_storage.c index 6392c2d677..57742e8e26 100644 --- a/applications/services/bt/bt_service/bt_keys_storage.c +++ b/applications/services/bt/bt_service/bt_keys_storage.c @@ -13,6 +13,7 @@ struct BtKeysStorage { uint8_t* nvm_sram_buff; uint16_t nvm_sram_buff_size; + uint16_t current_size; FuriString* file_path; }; @@ -66,44 +67,114 @@ void bt_keys_storage_set_ram_params(BtKeysStorage* instance, uint8_t* buff, uint instance->nvm_sram_buff_size = size; } -bool bt_keys_storage_load(BtKeysStorage* instance) { +static bool bt_keys_storage_file_exists(const char* file_path) { + Storage* storage = furi_record_open(RECORD_STORAGE); + FileInfo file_info; + const bool ret = storage_common_stat(storage, file_path, &file_info) == FSE_OK && + file_info.size != 0; + furi_record_close(RECORD_STORAGE); + return ret; +} + +static bool bt_keys_storage_validate_file(const char* file_path, size_t* payload_size) { + uint8_t magic, version; + size_t size; + + if(!saved_struct_get_metadata(file_path, &magic, &version, &size)) { + FURI_LOG_E(TAG, "Failed to get metadata"); + return false; + + } else if(magic != BT_KEYS_STORAGE_MAGIC || version != BT_KEYS_STORAGE_VERSION) { + FURI_LOG_E(TAG, "File version mismatch"); + return false; + } + + *payload_size = size; + return true; +} + +bool bt_keys_storage_is_changed(BtKeysStorage* instance) { furi_assert(instance); - bool loaded = false; + bool is_changed = false; + uint8_t* data_buffer = NULL; + do { - // Get payload size - uint8_t magic = 0, version = 0; - size_t payload_size = 0; - if(!saved_struct_get_metadata( - furi_string_get_cstr(instance->file_path), &magic, &version, &payload_size)) { - FURI_LOG_E(TAG, "Failed to read payload size"); + const char* file_path = furi_string_get_cstr(instance->file_path); + size_t payload_size; + + if(!bt_keys_storage_file_exists(file_path)) { + FURI_LOG_W(TAG, "Missing or empty file"); + break; + + } else if(!bt_keys_storage_validate_file(file_path, &payload_size)) { + FURI_LOG_E(TAG, "Invalid or corrupted file"); break; } - if(magic != BT_KEYS_STORAGE_MAGIC || version != BT_KEYS_STORAGE_VERSION) { - FURI_LOG_E(TAG, "Saved data version is mismatched"); + data_buffer = malloc(payload_size); + + const bool data_loaded = saved_struct_load( + file_path, data_buffer, payload_size, BT_KEYS_STORAGE_MAGIC, BT_KEYS_STORAGE_VERSION); + + if(!data_loaded) { + FURI_LOG_E(TAG, "Failed to load file"); break; + + } else if(payload_size == instance->current_size) { + furi_hal_bt_nvm_sram_sem_acquire(); + is_changed = memcmp(data_buffer, instance->nvm_sram_buff, payload_size); + furi_hal_bt_nvm_sram_sem_release(); + + } else { + FURI_LOG_D(TAG, "Size mismatch"); + is_changed = true; } + } while(false); - if(payload_size > instance->nvm_sram_buff_size) { - FURI_LOG_E(TAG, "Saved data doesn't fit ram buffer"); + if(data_buffer) { + free(data_buffer); + } + + return is_changed; +} + +bool bt_keys_storage_load(BtKeysStorage* instance) { + furi_assert(instance); + + bool loaded = false; + + do { + const char* file_path = furi_string_get_cstr(instance->file_path); + + // Get payload size + size_t payload_size; + if(!bt_keys_storage_validate_file(file_path, &payload_size)) { + FURI_LOG_E(TAG, "Invalid or corrupted file"); + break; + + } else if(payload_size > instance->nvm_sram_buff_size) { + FURI_LOG_E(TAG, "NVM RAM buffer overflow"); break; } // Load saved data to ram furi_hal_bt_nvm_sram_sem_acquire(); - bool data_loaded = saved_struct_load( - furi_string_get_cstr(instance->file_path), + const bool data_loaded = saved_struct_load( + file_path, instance->nvm_sram_buff, payload_size, BT_KEYS_STORAGE_MAGIC, BT_KEYS_STORAGE_VERSION); furi_hal_bt_nvm_sram_sem_release(); + if(!data_loaded) { - FURI_LOG_E(TAG, "Failed to load struct"); + FURI_LOG_E(TAG, "Failed to load file"); break; } + instance->current_size = payload_size; + loaded = true; } while(false); @@ -130,6 +201,8 @@ bool bt_keys_storage_update(BtKeysStorage* instance, uint8_t* start_addr, uint32 break; } + instance->current_size = new_size; + furi_hal_bt_nvm_sram_sem_acquire(); bool data_updated = saved_struct_save( furi_string_get_cstr(instance->file_path), @@ -138,10 +211,12 @@ bool bt_keys_storage_update(BtKeysStorage* instance, uint8_t* start_addr, uint32 BT_KEYS_STORAGE_MAGIC, BT_KEYS_STORAGE_VERSION); furi_hal_bt_nvm_sram_sem_release(); + if(!data_updated) { FURI_LOG_E(TAG, "Failed to update key storage"); break; } + updated = true; } while(false); diff --git a/applications/services/bt/bt_service/bt_keys_storage.h b/applications/services/bt/bt_service/bt_keys_storage.h index 587dd570dd..b7a127035d 100644 --- a/applications/services/bt/bt_service/bt_keys_storage.h +++ b/applications/services/bt/bt_service/bt_keys_storage.h @@ -17,6 +17,8 @@ void bt_keys_storage_set_file_path(BtKeysStorage* instance, const char* path); void bt_keys_storage_set_ram_params(BtKeysStorage* instance, uint8_t* buff, uint16_t size); +bool bt_keys_storage_is_changed(BtKeysStorage* instance); + bool bt_keys_storage_load(BtKeysStorage* instance); bool bt_keys_storage_update(BtKeysStorage* instance, uint8_t* start_addr, uint32_t size); diff --git a/applications/services/bt/bt_service/bt_settings_api_i.h b/applications/services/bt/bt_service/bt_settings_api_i.h new file mode 100644 index 0000000000..4412958931 --- /dev/null +++ b/applications/services/bt/bt_service/bt_settings_api_i.h @@ -0,0 +1,8 @@ +#pragma once + +#include "bt.h" +#include "../bt_settings.h" + +void bt_get_settings(Bt* bt, BtSettings* settings); + +void bt_set_settings(Bt* bt, const BtSettings* settings); diff --git a/applications/services/bt/bt_settings.c b/applications/services/bt/bt_settings.c index 3602cf4977..abdc97f7e7 100644 --- a/applications/services/bt/bt_settings.c +++ b/applications/services/bt/bt_settings.c @@ -1,23 +1,36 @@ #include "bt_settings.h" +#include "bt_settings_filename.h" #include -#include #include +#include + +#define TAG "BtSettings" #define BT_SETTINGS_PATH INT_PATH(BT_SETTINGS_FILE_NAME) #define BT_SETTINGS_VERSION (0) #define BT_SETTINGS_MAGIC (0x19) -bool bt_settings_load(BtSettings* bt_settings) { +void bt_settings_load(BtSettings* bt_settings) { furi_assert(bt_settings); - return saved_struct_load( + const bool success = saved_struct_load( BT_SETTINGS_PATH, bt_settings, sizeof(BtSettings), BT_SETTINGS_MAGIC, BT_SETTINGS_VERSION); + + if(!success) { + FURI_LOG_W(TAG, "Failed to load settings, using defaults"); + memset(bt_settings, 0, sizeof(BtSettings)); + bt_settings_save(bt_settings); + } } -bool bt_settings_save(const BtSettings* bt_settings) { +void bt_settings_save(const BtSettings* bt_settings) { furi_assert(bt_settings); - return saved_struct_save( + const bool success = saved_struct_save( BT_SETTINGS_PATH, bt_settings, sizeof(BtSettings), BT_SETTINGS_MAGIC, BT_SETTINGS_VERSION); + + if(!success) { + FURI_LOG_E(TAG, "Failed to save settings"); + } } diff --git a/applications/services/bt/bt_settings.h b/applications/services/bt/bt_settings.h index a4e76a12cc..c63220abb2 100644 --- a/applications/services/bt/bt_settings.h +++ b/applications/services/bt/bt_settings.h @@ -1,8 +1,5 @@ #pragma once -#include "bt_settings_filename.h" - -#include #include #ifdef __cplusplus @@ -13,9 +10,9 @@ typedef struct { bool enabled; } BtSettings; -bool bt_settings_load(BtSettings* bt_settings); +void bt_settings_load(BtSettings* bt_settings); -bool bt_settings_save(const BtSettings* bt_settings); +void bt_settings_save(const BtSettings* bt_settings); #ifdef __cplusplus } diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index 1604f4389d..8fe5643af6 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -270,7 +270,7 @@ void cli_command_sysctl_heap_track(Cli* cli, FuriString* args, void* context) { } else if(!furi_string_cmp(args, "main")) { furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackModeMain); printf("Heap tracking enabled for application main thread"); -#if FURI_DEBUG +#ifdef FURI_DEBUG } else if(!furi_string_cmp(args, "tree")) { furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackModeTree); printf("Heap tracking enabled for application main and child threads"); @@ -289,7 +289,7 @@ void cli_command_sysctl_print_usage(void) { printf("Cmd list:\r\n"); printf("\tdebug <0|1>\t - Enable or disable system debug\r\n"); -#if FURI_DEBUG +#ifdef FURI_DEBUG printf("\theap_track \t - Set heap allocation tracking mode\r\n"); #else printf("\theap_track \t - Set heap allocation tracking mode\r\n"); diff --git a/applications/services/desktop/animations/animation_manager.c b/applications/services/desktop/animations/animation_manager.c index 8e04e7894e..858efb9fe7 100644 --- a/applications/services/desktop/animations/animation_manager.c +++ b/applications/services/desktop/animations/animation_manager.c @@ -97,11 +97,14 @@ void animation_manager_set_interact_callback( void animation_manager_set_dummy_mode_state(AnimationManager* animation_manager, bool enabled) { furi_assert(animation_manager); - animation_manager->dummy_mode = enabled; - animation_manager_start_new_idle(animation_manager); + // Prevent change of animations if mode is the same + if(animation_manager->dummy_mode != enabled) { + animation_manager->dummy_mode = enabled; + animation_manager_start_new_idle(animation_manager); + } } -static void animation_manager_check_blocking_callback(const void* message, void* context) { +static void animation_manager_storage_callback(const void* message, void* context) { const StorageEvent* storage_event = message; switch(storage_event->type) { @@ -120,6 +123,22 @@ static void animation_manager_check_blocking_callback(const void* message, void* } } +static void animation_manager_dolphin_callback(const void* message, void* context) { + const DolphinPubsubEvent* dolphin_event = message; + + switch(*dolphin_event) { + case DolphinPubsubEventUpdate: + furi_assert(context); + AnimationManager* animation_manager = context; + if(animation_manager->check_blocking_callback) { + animation_manager->check_blocking_callback(animation_manager->context); + } + break; + default: + break; + } +} + static void animation_manager_timer_callback(void* context) { furi_assert(context); AnimationManager* animation_manager = context; @@ -297,12 +316,12 @@ AnimationManager* animation_manager_alloc(void) { Storage* storage = furi_record_open(RECORD_STORAGE); animation_manager->pubsub_subscription_storage = furi_pubsub_subscribe( - storage_get_pubsub(storage), animation_manager_check_blocking_callback, animation_manager); + storage_get_pubsub(storage), animation_manager_storage_callback, animation_manager); furi_record_close(RECORD_STORAGE); Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); animation_manager->pubsub_subscription_dolphin = furi_pubsub_subscribe( - dolphin_get_pubsub(dolphin), animation_manager_check_blocking_callback, animation_manager); + dolphin_get_pubsub(dolphin), animation_manager_dolphin_callback, animation_manager); furi_record_close(RECORD_DOLPHIN); animation_manager->blocking_shown_sd_ok = true; diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 53e2d29c84..e57e1eb00f 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -1,31 +1,24 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "desktop_i.h" + #include #include + +#include + #include +#include -#include "animations/animation_manager.h" -#include "desktop/scenes/desktop_scene.h" -#include "desktop/scenes/desktop_scene_i.h" -#include "desktop/views/desktop_view_locked.h" -#include "desktop/views/desktop_view_pin_input.h" -#include "desktop/views/desktop_view_pin_timeout.h" -#include "desktop_i.h" -#include "helpers/pin.h" -#include "helpers/slideshow_filename.h" +#include + +#include "scenes/desktop_scene.h" +#include "scenes/desktop_scene_locked.h" #define TAG "Desktop" static void desktop_auto_lock_arm(Desktop*); static void desktop_auto_lock_inhibit(Desktop*); static void desktop_start_auto_lock_timer(Desktop*); +static void desktop_apply_settings(Desktop*); static void desktop_loader_callback(const void* message, void* context) { furi_assert(context); @@ -42,6 +35,16 @@ static void desktop_loader_callback(const void* message, void* context) { } } +static void desktop_storage_callback(const void* message, void* context) { + furi_assert(context); + Desktop* desktop = context; + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalReloadSettings); + } +} + static void desktop_lock_icon_draw_callback(Canvas* canvas, void* context) { UNUSED(context); furi_assert(canvas); @@ -122,31 +125,39 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { furi_assert(context); Desktop* desktop = (Desktop*)context; - switch(event) { - case DesktopGlobalBeforeAppStarted: + if(event == DesktopGlobalBeforeAppStarted) { if(animation_manager_is_animation_loaded(desktop->animation_manager)) { animation_manager_unload_and_stall_animation(desktop->animation_manager); } + desktop_auto_lock_inhibit(desktop); + desktop->app_running = true; + furi_semaphore_release(desktop->animation_semaphore); - return true; - case DesktopGlobalAfterAppFinished: + + } else if(event == DesktopGlobalAfterAppFinished) { animation_manager_load_and_continue_animation(desktop->animation_manager); - DESKTOP_SETTINGS_LOAD(&desktop->settings); + desktop_auto_lock_arm(desktop); + desktop->app_running = false; - desktop_clock_reconfigure(desktop); - if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) { - desktop_auto_lock_arm(desktop); - } - return true; - case DesktopGlobalAutoLock: - if(!loader_is_locked(desktop->loader) && !desktop->locked) { + } else if(event == DesktopGlobalAutoLock) { + if(!desktop->app_running && !desktop->locked) { desktop_lock(desktop); } - return true; + + } else if(event == DesktopGlobalSaveSettings) { + desktop_settings_save(&desktop->settings); + desktop_apply_settings(desktop); + + } else if(event == DesktopGlobalReloadSettings) { + desktop_settings_load(&desktop->settings); + desktop_apply_settings(desktop); + + } else { + return scene_manager_handle_custom_event(desktop->scene_manager, event); } - return scene_manager_handle_custom_event(desktop->scene_manager, event); + return true; } static bool desktop_back_event_callback(void* context) { @@ -206,84 +217,45 @@ static void desktop_clock_timer_callback(void* context) { furi_assert(context); Desktop* desktop = context; - if(gui_active_view_port_count(desktop->gui, GuiLayerStatusBarLeft) < 6) { - desktop_clock_update(desktop); - - view_port_enabled_set(desktop->clock_viewport, true); - } else { - view_port_enabled_set(desktop->clock_viewport, false); - } -} - -void desktop_lock(Desktop* desktop) { - furi_assert(!desktop->locked); - - furi_hal_rtc_set_flag(FuriHalRtcFlagLock); + const bool clock_enabled = gui_active_view_port_count(desktop->gui, GuiLayerStatusBarLeft) < 6; - if(desktop->settings.pin_code.length) { - Cli* cli = furi_record_open(RECORD_CLI); - cli_session_close(cli); - furi_record_close(RECORD_CLI); + if(clock_enabled) { + desktop_clock_update(desktop); } - desktop_auto_lock_inhibit(desktop); - scene_manager_set_scene_state( - desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); - scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); - - DesktopStatus status = {.locked = true}; - furi_pubsub_publish(desktop->status_pubsub, &status); - - desktop->locked = true; + view_port_enabled_set(desktop->clock_viewport, clock_enabled); } -void desktop_unlock(Desktop* desktop) { - furi_assert(desktop->locked); - - view_port_enabled_set(desktop->lock_icon_viewport, false); - Gui* gui = furi_record_open(RECORD_GUI); - gui_set_lockdown(gui, false); - furi_record_close(RECORD_GUI); - desktop_view_locked_unlock(desktop->locked_view); - scene_manager_search_and_switch_to_previous_scene(desktop->scene_manager, DesktopSceneMain); - desktop_auto_lock_arm(desktop); - furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); - furi_hal_rtc_set_pin_fails(0); +static void desktop_apply_settings(Desktop* desktop) { + desktop->in_transition = true; - if(desktop->settings.pin_code.length) { - Cli* cli = furi_record_open(RECORD_CLI); - cli_session_open(cli, &cli_vcp); - furi_record_close(RECORD_CLI); - } + desktop_clock_reconfigure(desktop); - DesktopStatus status = {.locked = false}; - furi_pubsub_publish(desktop->status_pubsub, &status); + view_port_enabled_set(desktop->dummy_mode_icon_viewport, desktop->settings.dummy_mode); + desktop_main_set_dummy_mode_state(desktop->main_view, desktop->settings.dummy_mode); + animation_manager_set_dummy_mode_state( + desktop->animation_manager, desktop->settings.dummy_mode); - desktop->locked = false; -} + if(!desktop->app_running && !desktop->locked) { + desktop_auto_lock_arm(desktop); + } -void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled) { - desktop->in_transition = true; - view_port_enabled_set(desktop->dummy_mode_icon_viewport, enabled); - desktop_main_set_dummy_mode_state(desktop->main_view, enabled); - animation_manager_set_dummy_mode_state(desktop->animation_manager, enabled); - desktop->settings.dummy_mode = enabled; - DESKTOP_SETTINGS_SAVE(&desktop->settings); desktop->in_transition = false; } -void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled) { - desktop->in_transition = true; - if(enabled) { - furi_hal_rtc_set_flag(FuriHalRtcFlagStealthMode); - } else { - furi_hal_rtc_reset_flag(FuriHalRtcFlagStealthMode); +static void desktop_init_settings(Desktop* desktop) { + furi_pubsub_subscribe(storage_get_pubsub(desktop->storage), desktop_storage_callback, desktop); + + if(storage_sd_status(desktop->storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping settings"); + return; } - view_port_enabled_set(desktop->stealth_mode_icon_viewport, enabled); - desktop->in_transition = false; + + desktop_settings_load(&desktop->settings); + desktop_apply_settings(desktop); } -Desktop* desktop_alloc(void) { +static Desktop* desktop_alloc(void) { Desktop* desktop = malloc(sizeof(Desktop)); desktop->animation_semaphore = furi_semaphore_alloc(1, 0); @@ -293,7 +265,6 @@ Desktop* desktop_alloc(void) { desktop->view_dispatcher = view_dispatcher_alloc(); desktop->scene_manager = scene_manager_alloc(&desktop_scene_handlers, desktop); - view_dispatcher_enable_queue(desktop->view_dispatcher); view_dispatcher_attach_to_gui( desktop->view_dispatcher, desktop->gui, ViewDispatcherTypeDesktop); view_dispatcher_set_tick_event_callback( @@ -392,14 +363,13 @@ Desktop* desktop_alloc(void) { } gui_add_view_port(desktop->gui, desktop->stealth_mode_icon_viewport, GuiLayerStatusBarLeft); + // Unload animations before starting an application desktop->loader = furi_record_open(RECORD_LOADER); + furi_pubsub_subscribe(loader_get_pubsub(desktop->loader), desktop_loader_callback, desktop); + desktop->storage = furi_record_open(RECORD_STORAGE); desktop->notification = furi_record_open(RECORD_NOTIFICATION); - desktop->app_start_stop_subscription = furi_pubsub_subscribe( - loader_get_pubsub(desktop->loader), desktop_loader_callback, desktop); - desktop->input_events_pubsub = furi_record_open(RECORD_INPUT_EVENTS); - desktop->input_events_subscription = NULL; desktop->auto_lock_timer = furi_timer_alloc(desktop_auto_lock_timer_callback, FuriTimerTypeOnce, desktop); @@ -409,19 +379,95 @@ Desktop* desktop_alloc(void) { desktop->update_clock_timer = furi_timer_alloc(desktop_clock_timer_callback, FuriTimerTypePeriodic, desktop); + desktop->app_running = loader_is_locked(desktop->loader); + furi_record_create(RECORD_DESKTOP, desktop); return desktop; } -static bool desktop_check_file_flag(const char* flag_path) { - Storage* storage = furi_record_open(RECORD_STORAGE); - bool exists = storage_common_stat(storage, flag_path, NULL) == FSE_OK; - furi_record_close(RECORD_STORAGE); +/* + * Private API + */ - return exists; +void desktop_lock(Desktop* desktop) { + furi_assert(!desktop->locked); + + furi_hal_rtc_set_flag(FuriHalRtcFlagLock); + + if(desktop_pin_code_is_set()) { + Cli* cli = furi_record_open(RECORD_CLI); + cli_session_close(cli); + furi_record_close(RECORD_CLI); + } + + desktop_auto_lock_inhibit(desktop); + scene_manager_set_scene_state( + desktop->scene_manager, DesktopSceneLocked, DesktopSceneLockedStateFirstEnter); + scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); + + DesktopStatus status = {.locked = true}; + furi_pubsub_publish(desktop->status_pubsub, &status); + + desktop->locked = true; } +void desktop_unlock(Desktop* desktop) { + furi_assert(desktop->locked); + + view_port_enabled_set(desktop->lock_icon_viewport, false); + Gui* gui = furi_record_open(RECORD_GUI); + gui_set_lockdown(gui, false); + furi_record_close(RECORD_GUI); + desktop_view_locked_unlock(desktop->locked_view); + scene_manager_search_and_switch_to_previous_scene(desktop->scene_manager, DesktopSceneMain); + desktop_auto_lock_arm(desktop); + furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); + furi_hal_rtc_set_pin_fails(0); + + if(desktop_pin_code_is_set()) { + Cli* cli = furi_record_open(RECORD_CLI); + cli_session_open(cli, &cli_vcp); + furi_record_close(RECORD_CLI); + } + + DesktopStatus status = {.locked = false}; + furi_pubsub_publish(desktop->status_pubsub, &status); + + desktop->locked = false; +} + +void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled) { + desktop->in_transition = true; + + view_port_enabled_set(desktop->dummy_mode_icon_viewport, enabled); + desktop_main_set_dummy_mode_state(desktop->main_view, enabled); + animation_manager_set_dummy_mode_state(desktop->animation_manager, enabled); + desktop->settings.dummy_mode = enabled; + + desktop->in_transition = false; + + desktop_settings_save(&desktop->settings); +} + +void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled) { + desktop->in_transition = true; + + if(enabled) { + furi_hal_rtc_set_flag(FuriHalRtcFlagStealthMode); + } else { + furi_hal_rtc_reset_flag(FuriHalRtcFlagStealthMode); + } + + view_port_enabled_set(desktop->stealth_mode_icon_viewport, enabled); + + desktop->in_transition = false; +} + +/* + * Public API + */ + bool desktop_api_is_locked(Desktop* instance) { furi_assert(instance); return furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock); @@ -437,6 +483,30 @@ FuriPubSub* desktop_api_get_status_pubsub(Desktop* instance) { return instance->status_pubsub; } +void desktop_api_reload_settings(Desktop* instance) { + furi_assert(instance); + view_dispatcher_send_custom_event(instance->view_dispatcher, DesktopGlobalReloadSettings); +} + +void desktop_api_get_settings(Desktop* instance, DesktopSettings* settings) { + furi_assert(instance); + furi_assert(settings); + + *settings = instance->settings; +} + +void desktop_api_set_settings(Desktop* instance, const DesktopSettings* settings) { + furi_assert(instance); + furi_assert(settings); + + instance->settings = *settings; + view_dispatcher_send_custom_event(instance->view_dispatcher, DesktopGlobalSaveSettings); +} + +/* + * Application thread + */ + int32_t desktop_srv(void* p) { UNUSED(p); @@ -449,31 +519,15 @@ int32_t desktop_srv(void* p) { Desktop* desktop = desktop_alloc(); - bool loaded = DESKTOP_SETTINGS_LOAD(&desktop->settings); - if(!loaded) { - memset(&desktop->settings, 0, sizeof(desktop->settings)); - DESKTOP_SETTINGS_SAVE(&desktop->settings); - } - - view_port_enabled_set(desktop->dummy_mode_icon_viewport, desktop->settings.dummy_mode); - - desktop_clock_reconfigure(desktop); - - desktop_main_set_dummy_mode_state(desktop->main_view, desktop->settings.dummy_mode); - animation_manager_set_dummy_mode_state( - desktop->animation_manager, desktop->settings.dummy_mode); + desktop_init_settings(desktop); scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) { desktop_lock(desktop); - } else { - if(!loader_is_locked(desktop->loader)) { - desktop_auto_lock_arm(desktop); - } } - if(desktop_check_file_flag(SLIDESHOW_FS_PATH)) { + if(storage_file_exists(desktop->storage, SLIDESHOW_FS_PATH)) { scene_manager_next_scene(desktop->scene_manager, DesktopSceneSlideshow); } @@ -497,14 +551,12 @@ int32_t desktop_srv(void* p) { } // Special case: autostart application is already running - if(loader_is_locked(desktop->loader) && - animation_manager_is_animation_loaded(desktop->animation_manager)) { + if(desktop->app_running && animation_manager_is_animation_loaded(desktop->animation_manager)) { animation_manager_unload_and_stall_animation(desktop->animation_manager); } view_dispatcher_run(desktop->view_dispatcher); - furi_crash("That was unexpected"); - + // Should never get here (a service thread will crash automatically if it returns) return 0; } diff --git a/applications/services/desktop/desktop.h b/applications/services/desktop/desktop.h index 4eab24fcc5..e83bc3ee4d 100644 --- a/applications/services/desktop/desktop.h +++ b/applications/services/desktop/desktop.h @@ -2,16 +2,22 @@ #include -typedef struct Desktop Desktop; +#include "desktop_settings.h" #define RECORD_DESKTOP "desktop" -bool desktop_api_is_locked(Desktop* instance); - -void desktop_api_unlock(Desktop* instance); +typedef struct Desktop Desktop; typedef struct { bool locked; } DesktopStatus; +bool desktop_api_is_locked(Desktop* instance); + +void desktop_api_unlock(Desktop* instance); + FuriPubSub* desktop_api_get_status_pubsub(Desktop* instance); + +void desktop_api_get_settings(Desktop* instance, DesktopSettings* settings); + +void desktop_api_set_settings(Desktop* instance, const DesktopSettings* settings); diff --git a/applications/services/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h index 4bcbb6585a..1dc7c7d219 100644 --- a/applications/services/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -1,6 +1,8 @@ #pragma once #include "desktop.h" +#include "desktop_settings.h" + #include "animations/animation_manager.h" #include "views/desktop_view_pin_timeout.h" #include "views/desktop_view_pin_input.h" @@ -9,9 +11,7 @@ #include "views/desktop_view_lock_menu.h" #include "views/desktop_view_debug.h" #include "views/desktop_view_slideshow.h" -#include -#include #include #include #include @@ -42,9 +42,8 @@ typedef struct { } DesktopClock; struct Desktop { - // Scene FuriThread* scene_thread; - // GUI + Gui* gui; ViewDispatcher* view_dispatcher; SceneManager* scene_manager; @@ -56,42 +55,38 @@ struct Desktop { DesktopMainView* main_view; DesktopViewPinTimeout* pin_timeout_view; DesktopSlideshowView* slideshow_view; + DesktopViewPinInput* pin_input_view; ViewStack* main_view_stack; ViewStack* locked_view_stack; - DesktopSettings settings; - DesktopViewPinInput* pin_input_view; - ViewPort* lock_icon_viewport; ViewPort* dummy_mode_icon_viewport; ViewPort* clock_viewport; ViewPort* stealth_mode_icon_viewport; - AnimationManager* animation_manager; - Loader* loader; + Storage* storage; NotificationApp* notification; - FuriPubSubSubscription* app_start_stop_subscription; + FuriPubSub* status_pubsub; FuriPubSub* input_events_pubsub; FuriPubSubSubscription* input_events_subscription; + FuriTimer* auto_lock_timer; FuriTimer* update_clock_timer; - FuriPubSub* status_pubsub; + AnimationManager* animation_manager; + FuriSemaphore* animation_semaphore; DesktopClock clock; + DesktopSettings settings; - bool in_transition : 1; - bool locked : 1; - - FuriSemaphore* animation_semaphore; + bool in_transition; + bool app_running; + bool locked; }; -Desktop* desktop_alloc(void); - -void desktop_free(Desktop* desktop); void desktop_lock(Desktop* desktop); void desktop_unlock(Desktop* desktop); void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled); diff --git a/applications/services/desktop/desktop_settings.c b/applications/services/desktop/desktop_settings.c new file mode 100644 index 0000000000..828ec5f0d6 --- /dev/null +++ b/applications/services/desktop/desktop_settings.c @@ -0,0 +1,79 @@ +#include "desktop_settings.h" +#include "desktop_settings_filename.h" + +#include +#include + +#define TAG "DesktopSettings" + +#define DESKTOP_SETTINGS_VER_13 (13) +#define DESKTOP_SETTINGS_VER (14) + +#define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) +#define DESKTOP_SETTINGS_MAGIC (0x17) + +typedef struct { + uint8_t reserved[11]; + DesktopSettings settings; +} DesktopSettingsV13; + +// Actual size of DesktopSettings v13 +//static_assert(sizeof(DesktopSettingsV13) == 1234); + +void desktop_settings_load(DesktopSettings* settings) { + furi_assert(settings); + + bool success = false; + + do { + uint8_t version; + if(!saved_struct_get_metadata(DESKTOP_SETTINGS_PATH, NULL, &version, NULL)) break; + + if(version == DESKTOP_SETTINGS_VER) { + success = saved_struct_load( + DESKTOP_SETTINGS_PATH, + settings, + sizeof(DesktopSettings), + DESKTOP_SETTINGS_MAGIC, + DESKTOP_SETTINGS_VER); + + } else if(version == DESKTOP_SETTINGS_VER_13) { + DesktopSettingsV13* settings_v13 = malloc(sizeof(DesktopSettingsV13)); + + success = saved_struct_load( + DESKTOP_SETTINGS_PATH, + settings_v13, + sizeof(DesktopSettingsV13), + DESKTOP_SETTINGS_MAGIC, + DESKTOP_SETTINGS_VER_13); + + if(success) { + *settings = settings_v13->settings; + } + + free(settings_v13); + } + + } while(false); + + if(!success) { + FURI_LOG_W(TAG, "Failed to load file, using defaults"); + memset(settings, 0, sizeof(DesktopSettings)); + desktop_settings_save(settings); + } +} + +void desktop_settings_save(const DesktopSettings* settings) { + furi_assert(settings); + + const bool success = saved_struct_save( + DESKTOP_SETTINGS_PATH, + settings, + sizeof(DesktopSettings), + DESKTOP_SETTINGS_MAGIC, + DESKTOP_SETTINGS_VER); + + if(!success) { + FURI_LOG_E(TAG, "Failed to save file"); + } +} diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index 4c848117a2..ba5a78840e 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -1,40 +1,6 @@ #pragma once -#include "desktop_settings_filename.h" - -#include #include -#include -#include -#include - -#define DESKTOP_SETTINGS_VER (13) - -#define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) -#define DESKTOP_SETTINGS_MAGIC (0x17) -#define PIN_MAX_LENGTH 12 - -#define DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG "run_pin_setup" - -#define DESKTOP_SETTINGS_SAVE(x) \ - saved_struct_save( \ - DESKTOP_SETTINGS_PATH, \ - (x), \ - sizeof(DesktopSettings), \ - DESKTOP_SETTINGS_MAGIC, \ - DESKTOP_SETTINGS_VER) - -#define DESKTOP_SETTINGS_LOAD(x) \ - saved_struct_load( \ - DESKTOP_SETTINGS_PATH, \ - (x), \ - sizeof(DesktopSettings), \ - DESKTOP_SETTINGS_MAGIC, \ - DESKTOP_SETTINGS_VER) - -#define MAX_PIN_SIZE 10 -#define MIN_PIN_SIZE 4 -#define MAX_APP_LENGTH 128 #define DISPLAY_BATTERY_BAR 0 #define DISPLAY_BATTERY_PERCENT 1 @@ -44,7 +10,7 @@ #define DISPLAY_BATTERY_BAR_PERCENT 5 typedef enum { - FavoriteAppLeftShort = 0, + FavoriteAppLeftShort, FavoriteAppLeftLong, FavoriteAppRightShort, FavoriteAppRightLong, @@ -53,30 +19,24 @@ typedef enum { } FavoriteAppShortcut; typedef enum { - DummyAppLeft = 0, + DummyAppLeftShort, DummyAppLeftLong, - DummyAppRight, + DummyAppRightShort, DummyAppRightLong, DummyAppUpLong, - DummyAppDown, + DummyAppDownShort, DummyAppDownLong, - DummyAppOk, + DummyAppOkShort, DummyAppOkLong, DummyAppNumber, } DummyAppShortcut; typedef struct { - InputKey data[MAX_PIN_SIZE]; - uint8_t length; -} PinCode; - -typedef struct { - char name_or_path[MAX_APP_LENGTH]; + char name_or_path[128]; } FavoriteApp; typedef struct { - PinCode pin_code; uint32_t auto_lock_delay_ms; uint8_t displayBatteryPercentage; uint8_t dummy_mode; @@ -84,3 +44,6 @@ typedef struct { FavoriteApp favorite_apps[FavoriteAppNumber]; FavoriteApp dummy_apps[DummyAppNumber]; } DesktopSettings; + +void desktop_settings_load(DesktopSettings* settings); +void desktop_settings_save(const DesktopSettings* settings); diff --git a/applications/services/desktop/helpers/pin.c b/applications/services/desktop/helpers/pin.c deleted file mode 100644 index 0b1149d6c2..0000000000 --- a/applications/services/desktop/helpers/pin.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "pin.h" - -#include -#include -#include -#include -#include -#include - -static const NotificationSequence sequence_pin_fail = { - &message_display_backlight_on, - - &message_red_255, - &message_vibro_on, - &message_delay_100, - &message_vibro_off, - &message_red_0, - - &message_delay_250, - - &message_red_255, - &message_vibro_on, - &message_delay_100, - &message_vibro_off, - &message_red_0, - NULL, -}; - -static const uint8_t desktop_helpers_fails_timeout[] = { - 0, - 0, - 0, - 0, - 30, - 60, - 90, - 120, - 150, - 180, - /* +60 for every next fail */ -}; - -void desktop_pin_lock_error_notify(void) { - NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - notification_message(notification, &sequence_pin_fail); - furi_record_close(RECORD_NOTIFICATION); -} - -uint32_t desktop_pin_lock_get_fail_timeout(void) { - uint32_t pin_fails = furi_hal_rtc_get_pin_fails(); - uint32_t pin_timeout = 0; - uint32_t max_index = COUNT_OF(desktop_helpers_fails_timeout) - 1; - if(pin_fails <= max_index) { - pin_timeout = desktop_helpers_fails_timeout[pin_fails]; - } else { - pin_timeout = desktop_helpers_fails_timeout[max_index] + (pin_fails - max_index) * 60; - } - - return pin_timeout; -} - -bool desktop_pin_compare(const PinCode* pin_code1, const PinCode* pin_code2) { - furi_assert(pin_code1); - furi_assert(pin_code2); - bool result = false; - - if(pin_code1->length == pin_code2->length) { - result = !memcmp(pin_code1->data, pin_code2->data, pin_code1->length); - } - - return result; -} diff --git a/applications/services/desktop/helpers/pin.h b/applications/services/desktop/helpers/pin.h deleted file mode 100644 index 23d16b0aa4..0000000000 --- a/applications/services/desktop/helpers/pin.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include -#include -#include "../desktop.h" -#include - -void desktop_pin_lock_error_notify(void); - -uint32_t desktop_pin_lock_get_fail_timeout(void); - -bool desktop_pin_compare(const PinCode* pin_code1, const PinCode* pin_code2); diff --git a/applications/services/desktop/helpers/pin_code.c b/applications/services/desktop/helpers/pin_code.c new file mode 100644 index 0000000000..d1a37ed24c --- /dev/null +++ b/applications/services/desktop/helpers/pin_code.c @@ -0,0 +1,103 @@ +#include "pin_code.h" + +#include + +#include +#include + +#define DESKTOP_PIN_CODE_DIGIT_BIT_WIDTH (2) +#define DESKTOP_PIN_CODE_LENGTH_OFFSET (28) + +static const NotificationSequence sequence_pin_fail = { + &message_display_backlight_on, + + &message_red_255, + &message_vibro_on, + &message_delay_100, + &message_vibro_off, + &message_red_0, + + &message_delay_250, + + &message_red_255, + &message_vibro_on, + &message_delay_100, + &message_vibro_off, + &message_red_0, + NULL, +}; + +static const uint8_t desktop_helpers_fails_timeout[] = { + 0, + 0, + 0, + 0, + 30, + 60, + 90, + 120, + 150, + 180, + /* +60 for every next fail */ +}; + +static uint32_t desktop_pin_code_pack(const DesktopPinCode* pin_code) { + furi_check(pin_code); + furi_check(pin_code->length <= sizeof(pin_code->data)); + + uint32_t reg_value = 0; + + for(uint8_t i = 0; i < pin_code->length; ++i) { + furi_check(pin_code->data[i] < (1 << DESKTOP_PIN_CODE_DIGIT_BIT_WIDTH)); + reg_value |= (uint32_t)pin_code->data[i] << (i * DESKTOP_PIN_CODE_DIGIT_BIT_WIDTH); + } + + reg_value |= (uint32_t)pin_code->length << DESKTOP_PIN_CODE_LENGTH_OFFSET; + + return reg_value; +} + +bool desktop_pin_code_is_set(void) { + return furi_hal_rtc_get_pin_value() >> DESKTOP_PIN_CODE_LENGTH_OFFSET; +} + +void desktop_pin_code_set(const DesktopPinCode* pin_code) { + furi_hal_rtc_set_pin_value(desktop_pin_code_pack(pin_code)); +} + +void desktop_pin_code_reset(void) { + furi_hal_rtc_set_pin_value(0); +} + +bool desktop_pin_code_check(const DesktopPinCode* pin_code) { + return furi_hal_rtc_get_pin_value() == desktop_pin_code_pack(pin_code); +} + +bool desktop_pin_code_is_equal(const DesktopPinCode* pin_code1, const DesktopPinCode* pin_code2) { + furi_check(pin_code1); + furi_check(pin_code1->length <= sizeof(pin_code1->data)); + furi_check(pin_code2); + furi_check(pin_code2->length <= sizeof(pin_code2->data)); + + return pin_code1->length == pin_code2->length && + memcmp(pin_code1->data, pin_code2->data, pin_code1->length) == 0; +} + +void desktop_pin_lock_error_notify(void) { + NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); + notification_message(notification, &sequence_pin_fail); + furi_record_close(RECORD_NOTIFICATION); +} + +uint32_t desktop_pin_lock_get_fail_timeout(void) { + uint32_t pin_fails = furi_hal_rtc_get_pin_fails(); + uint32_t pin_timeout = 0; + uint32_t max_index = COUNT_OF(desktop_helpers_fails_timeout) - 1; + if(pin_fails <= max_index) { + pin_timeout = desktop_helpers_fails_timeout[pin_fails]; + } else { + pin_timeout = desktop_helpers_fails_timeout[max_index] + (pin_fails - max_index) * 60; + } + + return pin_timeout; +} diff --git a/applications/services/desktop/helpers/pin_code.h b/applications/services/desktop/helpers/pin_code.h new file mode 100644 index 0000000000..848c915b6c --- /dev/null +++ b/applications/services/desktop/helpers/pin_code.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +#define DESKTOP_PIN_CODE_MAX_LEN (10) + +typedef struct { + uint8_t data[DESKTOP_PIN_CODE_MAX_LEN]; + uint8_t length; +} DesktopPinCode; + +bool desktop_pin_code_is_set(void); + +void desktop_pin_code_set(const DesktopPinCode* pin_code); + +void desktop_pin_code_reset(void); + +bool desktop_pin_code_check(const DesktopPinCode* pin_code); + +bool desktop_pin_code_is_equal(const DesktopPinCode* pin_code1, const DesktopPinCode* pin_code2); + +void desktop_pin_lock_error_notify(void); + +uint32_t desktop_pin_lock_get_fail_timeout(void); diff --git a/applications/services/desktop/scenes/desktop_scene_i.h b/applications/services/desktop/scenes/desktop_scene_i.h deleted file mode 100644 index f481733aca..0000000000 --- a/applications/services/desktop/scenes/desktop_scene_i.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -#define SCENE_LOCKED_FIRST_ENTER 0 -#define SCENE_LOCKED_REPEAT_ENTER 1 diff --git a/applications/services/desktop/scenes/desktop_scene_lock_menu.c b/applications/services/desktop/scenes/desktop_scene_lock_menu.c index 5951a8e4e3..5ca95c4c59 100644 --- a/applications/services/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/services/desktop/scenes/desktop_scene_lock_menu.c @@ -20,7 +20,6 @@ void desktop_scene_lock_menu_callback(DesktopEvent event, void* context) { void desktop_scene_lock_menu_on_enter(void* context) { Desktop* desktop = (Desktop*)context; - DESKTOP_SETTINGS_LOAD(&desktop->settings); scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop); desktop_lock_menu_set_dummy_mode_state(desktop->lock_menu, desktop->settings.dummy_mode); @@ -38,11 +37,8 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeTick) { bool check_pin_changed = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLockMenu); - if(check_pin_changed) { - DESKTOP_SETTINGS_LOAD(&desktop->settings); - if(desktop->settings.pin_code.length > 0) { - scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); - } + if(check_pin_changed && desktop_pin_code_is_set()) { + scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); } } else if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { diff --git a/applications/services/desktop/scenes/desktop_scene_locked.c b/applications/services/desktop/scenes/desktop_scene_locked.c index 846b2b5412..e7eeebca6d 100644 --- a/applications/services/desktop/scenes/desktop_scene_locked.c +++ b/applications/services/desktop/scenes/desktop_scene_locked.c @@ -6,12 +6,12 @@ #include "../desktop.h" #include "../desktop_i.h" -#include "../helpers/pin.h" +#include "../helpers/pin_code.h" #include "../animations/animation_manager.h" #include "../views/desktop_events.h" #include "../views/desktop_view_locked.h" #include "desktop_scene.h" -#include "desktop_scene_i.h" +#include "desktop_scene_locked.h" #define WRONG_PIN_HEADER_TIMEOUT 3000 #define INPUT_PIN_VIEW_TIMEOUT 15000 @@ -42,15 +42,13 @@ void desktop_scene_locked_on_enter(void* context) { bool switch_to_timeout_scene = false; uint32_t state = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLocked); - if(state == SCENE_LOCKED_FIRST_ENTER) { - bool pin_locked = desktop->settings.pin_code.length > 0; + if(state == DesktopSceneLockedStateFirstEnter) { view_port_enabled_set(desktop->lock_icon_viewport, true); Gui* gui = furi_record_open(RECORD_GUI); gui_set_lockdown(gui, true); furi_record_close(RECORD_GUI); - if(pin_locked) { - DESKTOP_SETTINGS_LOAD(&desktop->settings); + if(desktop_pin_code_is_set()) { desktop_view_locked_lock(desktop->locked_view, true); uint32_t pin_timeout = desktop_pin_lock_get_fail_timeout(); if(pin_timeout > 0) { @@ -65,7 +63,7 @@ void desktop_scene_locked_on_enter(void* context) { desktop_view_locked_close_doors(desktop->locked_view); } scene_manager_set_scene_state( - desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_REPEAT_ENTER); + desktop->scene_manager, DesktopSceneLocked, DesktopSceneLockedStateRepeatEnter); } if(switch_to_timeout_scene) { diff --git a/applications/services/desktop/scenes/desktop_scene_locked.h b/applications/services/desktop/scenes/desktop_scene_locked.h new file mode 100644 index 0000000000..7d5b6b7bcd --- /dev/null +++ b/applications/services/desktop/scenes/desktop_scene_locked.h @@ -0,0 +1,6 @@ +#pragma once + +typedef enum { + DesktopSceneLockedStateFirstEnter, + DesktopSceneLockedStateRepeatEnter, +} DesktopSceneLockedState; diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 5cc2033c3d..4fdcc34006 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -155,25 +155,21 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { } case DesktopMainEventOpenFavoriteLeftShort: - DESKTOP_SETTINGS_LOAD(&desktop->settings); desktop_scene_main_start_favorite( desktop, &desktop->settings.favorite_apps[FavoriteAppLeftShort]); consumed = true; break; case DesktopMainEventOpenFavoriteLeftLong: - DESKTOP_SETTINGS_LOAD(&desktop->settings); desktop_scene_main_start_favorite( desktop, &desktop->settings.favorite_apps[FavoriteAppLeftLong]); consumed = true; break; case DesktopMainEventOpenFavoriteRightShort: - DESKTOP_SETTINGS_LOAD(&desktop->settings); desktop_scene_main_start_favorite( desktop, &desktop->settings.favorite_apps[FavoriteAppRightShort]); consumed = true; break; case DesktopMainEventOpenFavoriteRightLong: - DESKTOP_SETTINGS_LOAD(&desktop->settings); desktop_scene_main_start_favorite( desktop, &desktop->settings.favorite_apps[FavoriteAppRightLong]); consumed = true; @@ -189,13 +185,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { break; case DesktopAnimationEventInteractAnimation: if(!animation_manager_interact_process(desktop->animation_manager)) { - DESKTOP_SETTINGS_LOAD(&desktop->settings); if(!desktop->settings.dummy_mode) { desktop_scene_main_open_app_or_profile( desktop, &desktop->settings.favorite_apps[FavoriteAppRightShort]); } else { desktop_scene_main_open_app_or_profile( - desktop, &desktop->settings.dummy_apps[DummyAppRight]); + desktop, &desktop->settings.dummy_apps[DummyAppRightShort]); } } consumed = true; @@ -203,15 +198,15 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { case DesktopDummyEventOpenLeft: desktop_scene_main_open_app_or_profile( - desktop, &desktop->settings.dummy_apps[DummyAppLeft]); + desktop, &desktop->settings.dummy_apps[DummyAppLeftShort]); break; case DesktopDummyEventOpenDown: desktop_scene_main_open_app_or_profile( - desktop, &desktop->settings.dummy_apps[DummyAppDown]); + desktop, &desktop->settings.dummy_apps[DummyAppDownShort]); break; case DesktopDummyEventOpenOk: desktop_scene_main_open_app_or_profile( - desktop, &desktop->settings.dummy_apps[DummyAppOk]); + desktop, &desktop->settings.dummy_apps[DummyAppOkShort]); break; case DesktopDummyEventOpenUpLong: if(!desktop_scene_main_check_none( diff --git a/applications/services/desktop/scenes/desktop_scene_pin_input.c b/applications/services/desktop/scenes/desktop_scene_pin_input.c index 6f5bfe8cb3..449dd97f1a 100644 --- a/applications/services/desktop/scenes/desktop_scene_pin_input.c +++ b/applications/services/desktop/scenes/desktop_scene_pin_input.c @@ -10,7 +10,7 @@ #include "../desktop_i.h" #include "../views/desktop_events.h" #include "../views/desktop_view_pin_input.h" -#include "../helpers/pin.h" +#include "../helpers/pin_code.h" #include "desktop_scene.h" #define WRONG_PIN_HEADER_TIMEOUT 3000 @@ -49,10 +49,12 @@ static void desktop_scene_pin_input_back_callback(void* context) { view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinInputEventBack); } -static void desktop_scene_pin_input_done_callback(const PinCode* pin_code, void* context) { +static void desktop_scene_pin_input_done_callback(const DesktopPinCode* pin_code, void* context) { Desktop* desktop = (Desktop*)context; - if(desktop_pin_compare(&desktop->settings.pin_code, pin_code)) { + + if(desktop_pin_code_check(pin_code)) { view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinInputEventUnlocked); + } else { uint32_t pin_fails = furi_hal_rtc_get_pin_fails(); furi_hal_rtc_set_pin_fails(pin_fails + 1); diff --git a/applications/services/desktop/scenes/desktop_scene_slideshow.c b/applications/services/desktop/scenes/desktop_scene_slideshow.c index 012aff7519..7599241164 100644 --- a/applications/services/desktop/scenes/desktop_scene_slideshow.c +++ b/applications/services/desktop/scenes/desktop_scene_slideshow.c @@ -45,9 +45,6 @@ bool desktop_scene_slideshow_on_event(void* context, SceneManagerEvent event) { } void desktop_scene_slideshow_on_exit(void* context) { - UNUSED(context); - - Storage* storage = furi_record_open(RECORD_STORAGE); - storage_common_remove(storage, SLIDESHOW_FS_PATH); - furi_record_close(RECORD_STORAGE); + Desktop* desktop = context; + storage_common_remove(desktop->storage, SLIDESHOW_FS_PATH); } diff --git a/applications/services/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h index c22b19acc7..ba91a30ccd 100644 --- a/applications/services/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -60,4 +60,6 @@ typedef enum { DesktopGlobalAfterAppFinished, DesktopGlobalAutoLock, DesktopGlobalApiUnlock, + DesktopGlobalSaveSettings, + DesktopGlobalReloadSettings, } DesktopEvent; diff --git a/applications/services/desktop/views/desktop_view_locked.c b/applications/services/desktop/views/desktop_view_locked.c index 74b020f45f..2fb89b27e4 100644 --- a/applications/services/desktop/views/desktop_view_locked.c +++ b/applications/services/desktop/views/desktop_view_locked.c @@ -1,12 +1,11 @@ -#include -#include #include + #include #include #include + #include -#include #include "../desktop_i.h" #include "desktop_view_locked.h" diff --git a/applications/services/desktop/views/desktop_view_pin_input.c b/applications/services/desktop/views/desktop_view_pin_input.c index 965b5cceb7..c89a143c87 100644 --- a/applications/services/desktop/views/desktop_view_pin_input.c +++ b/applications/services/desktop/views/desktop_view_pin_input.c @@ -6,7 +6,6 @@ #include #include "desktop_view_pin_input.h" -#include #define NO_ACTIVITY_TIMEOUT 15000 @@ -14,6 +13,9 @@ #define DEFAULT_PIN_X 64 #define DEFAULT_PIN_Y 32 +#define MIN_PIN_LENGTH 4 +#define MAX_PIN_LENGTH DESKTOP_PIN_CODE_MAX_LEN + struct DesktopViewPinInput { View* view; DesktopViewPinInputCallback back_callback; @@ -24,7 +26,7 @@ struct DesktopViewPinInput { }; typedef struct { - PinCode pin; + DesktopPinCode pin; bool pin_hidden; bool locked_input; uint8_t pin_x; @@ -50,7 +52,7 @@ static bool desktop_view_pin_input_input(InputEvent* event, void* context) { bool call_back_callback = false; bool call_done_callback = false; - PinCode pin_code = {0}; + DesktopPinCode pin_code = {0}; if(event->type == InputTypeShort) { switch(event->key) { @@ -59,13 +61,13 @@ static bool desktop_view_pin_input_input(InputEvent* event, void* context) { case InputKeyDown: case InputKeyUp: if(!model->locked_input) { - if(model->pin.length < MAX_PIN_SIZE) { + if(model->pin.length < MAX_PIN_LENGTH) { model->pin.data[model->pin.length++] = event->key; } } break; case InputKeyOk: - if(model->pin.length >= MIN_PIN_SIZE) { + if(model->pin.length >= MIN_PIN_LENGTH) { call_done_callback = true; pin_code = model->pin; } @@ -102,7 +104,7 @@ static void desktop_view_pin_input_draw_cells(Canvas* canvas, DesktopViewPinInpu furi_assert(model); uint8_t draw_pin_size = MAX(4, model->pin.length + 1); - if(model->locked_input || (model->pin.length == MAX_PIN_SIZE)) { + if(model->locked_input || (model->pin.length == MAX_PIN_LENGTH)) { draw_pin_size = model->pin.length; } @@ -155,7 +157,7 @@ static void desktop_view_pin_input_draw(Canvas* canvas, void* context) { canvas_draw_str(canvas, 16, 60, "= clear"); } - if(model->button_label && ((model->pin.length >= MIN_PIN_SIZE) || model->locked_input)) { + if(model->button_label && ((model->pin.length >= MIN_PIN_LENGTH) || model->locked_input)) { elements_button_center(canvas, model->button_label); } @@ -247,7 +249,7 @@ void desktop_view_pin_input_unlock_input(DesktopViewPinInput* pin_input) { view_commit_model(pin_input->view, true); } -void desktop_view_pin_input_set_pin(DesktopViewPinInput* pin_input, const PinCode* pin) { +void desktop_view_pin_input_set_pin(DesktopViewPinInput* pin_input, const DesktopPinCode* pin) { furi_assert(pin_input); furi_assert(pin); diff --git a/applications/services/desktop/views/desktop_view_pin_input.h b/applications/services/desktop/views/desktop_view_pin_input.h index c430aff9ff..4605b6ff15 100644 --- a/applications/services/desktop/views/desktop_view_pin_input.h +++ b/applications/services/desktop/views/desktop_view_pin_input.h @@ -1,16 +1,17 @@ #pragma once #include -#include + +#include "../helpers/pin_code.h" typedef void (*DesktopViewPinInputCallback)(void*); -typedef void (*DesktopViewPinInputDoneCallback)(const PinCode* pin_code, void*); +typedef void (*DesktopViewPinInputDoneCallback)(const DesktopPinCode* pin_code, void*); typedef struct DesktopViewPinInput DesktopViewPinInput; DesktopViewPinInput* desktop_view_pin_input_alloc(void); void desktop_view_pin_input_free(DesktopViewPinInput*); -void desktop_view_pin_input_set_pin(DesktopViewPinInput* pin_input, const PinCode* pin); +void desktop_view_pin_input_set_pin(DesktopViewPinInput* pin_input, const DesktopPinCode* pin_code); void desktop_view_pin_input_reset_pin(DesktopViewPinInput* pin_input); void desktop_view_pin_input_hide_pin(DesktopViewPinInput* pin_input, bool pin_hidden); void desktop_view_pin_input_set_label_button(DesktopViewPinInput* pin_input, const char* label); diff --git a/applications/services/desktop/views/desktop_view_pin_timeout.c b/applications/services/desktop/views/desktop_view_pin_timeout.c index 2811ba7d25..d7e5507a75 100644 --- a/applications/services/desktop/views/desktop_view_pin_timeout.c +++ b/applications/services/desktop/views/desktop_view_pin_timeout.c @@ -1,9 +1,5 @@ - #include -#include -#include -#include -#include + #include #include diff --git a/applications/services/dialogs/dialogs_module_file_browser.c b/applications/services/dialogs/dialogs_module_file_browser.c index b1558f1e95..12a7439e60 100644 --- a/applications/services/dialogs/dialogs_module_file_browser.c +++ b/applications/services/dialogs/dialogs_module_file_browser.c @@ -49,12 +49,11 @@ bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrow file_browser_start(file_browser, data->preselected_filename); view_holder_set_view(view_holder, file_browser_get_view(file_browser)); - view_holder_start(view_holder); api_lock_wait_unlock(file_browser_context->lock); ret = file_browser_context->result; - view_holder_stop(view_holder); + view_holder_set_view(view_holder, NULL); view_holder_free(view_holder); file_browser_stop(file_browser); file_browser_free(file_browser); diff --git a/applications/services/dialogs/dialogs_module_message.c b/applications/services/dialogs/dialogs_module_message.c index a71f403c54..9dc9ff9cb9 100644 --- a/applications/services/dialogs/dialogs_module_message.c +++ b/applications/services/dialogs/dialogs_module_message.c @@ -88,12 +88,11 @@ DialogMessageButton dialogs_app_process_module_message(const DialogsAppMessageDa dialog_ex_set_right_button_text(dialog_ex, message->right_button_text); view_holder_set_view(view_holder, dialog_ex_get_view(dialog_ex)); - view_holder_start(view_holder); api_lock_wait_unlock(message_context->lock); ret = message_context->result; - view_holder_stop(view_holder); + view_holder_set_view(view_holder, NULL); view_holder_free(view_holder); dialog_ex_free(dialog_ex); api_lock_free(message_context->lock); diff --git a/applications/services/dolphin/dolphin.c b/applications/services/dolphin/dolphin.c index 95982f1af8..501e37c3c8 100644 --- a/applications/services/dolphin/dolphin.c +++ b/applications/services/dolphin/dolphin.c @@ -1,6 +1,7 @@ #include "dolphin_i.h" #include +#include #define TAG "Dolphin" @@ -191,8 +192,8 @@ static void dolphin_update_clear_limits_timer_period(void* context) { FURI_LOG_D(TAG, "Daily limits reset in %lu ms", time_to_clear_limits); } -static bool dolphin_process_event(FuriMessageQueue* queue, void* context) { - UNUSED(queue); +static bool dolphin_process_event(FuriEventLoopObject* object, void* context) { + UNUSED(object); Dolphin* dolphin = context; DolphinEvent event; @@ -203,8 +204,8 @@ static bool dolphin_process_event(FuriMessageQueue* queue, void* context) { if(event.type == DolphinEventTypeDeed) { dolphin_state_on_deed(dolphin->state, event.deed); - DolphinPubsubEvent event = DolphinPubsubEventUpdate; - furi_pubsub_publish(dolphin->pubsub, &event); + DolphinPubsubEvent pubsub_event = DolphinPubsubEventUpdate; + furi_pubsub_publish(dolphin->pubsub, &pubsub_event); furi_event_loop_timer_start(dolphin->butthurt_timer, BUTTHURT_INCREASE_PERIOD_TICKS); furi_event_loop_timer_start(dolphin->flush_timer, FLUSH_TIMEOUT_TICKS); @@ -223,6 +224,10 @@ static bool dolphin_process_event(FuriMessageQueue* queue, void* context) { dolphin_state_increase_level(dolphin->state); furi_event_loop_timer_start(dolphin->flush_timer, FLUSH_TIMEOUT_TICKS); + } else if(event.type == DolphinEventTypeReloadState) { + dolphin_state_load(dolphin->state); + furi_event_loop_timer_start(dolphin->butthurt_timer, BUTTHURT_INCREASE_PERIOD_TICKS); + } else { furi_crash(); } @@ -232,6 +237,32 @@ static bool dolphin_process_event(FuriMessageQueue* queue, void* context) { return true; } +static void dolphin_storage_callback(const void* message, void* context) { + furi_assert(context); + Dolphin* dolphin = context; + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + DolphinEvent event = { + .type = DolphinEventTypeReloadState, + }; + + dolphin_event_send_async(dolphin, &event); + } +} + +static void dolphin_init_state(Dolphin* dolphin) { + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), dolphin_storage_callback, dolphin); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping state"); + return; + } + + dolphin_state_load(dolphin->state); +} + // Application thread int32_t dolphin_srv(void* p) { @@ -247,9 +278,9 @@ int32_t dolphin_srv(void* p) { Dolphin* dolphin = dolphin_alloc(); furi_record_create(RECORD_DOLPHIN, dolphin); - dolphin_state_load(dolphin->state); + dolphin_init_state(dolphin); - furi_event_loop_message_queue_subscribe( + furi_event_loop_subscribe_message_queue( dolphin->event_loop, dolphin->event_queue, FuriEventLoopEventIn, diff --git a/applications/services/dolphin/dolphin_i.h b/applications/services/dolphin/dolphin_i.h index d4add808ad..6a6b3dfd81 100644 --- a/applications/services/dolphin/dolphin_i.h +++ b/applications/services/dolphin/dolphin_i.h @@ -12,6 +12,7 @@ typedef enum { DolphinEventTypeStats, DolphinEventTypeFlush, DolphinEventTypeLevel, + DolphinEventTypeReloadState, } DolphinEventType; typedef struct { diff --git a/applications/services/dolphin/helpers/dolphin_state.c b/applications/services/dolphin/helpers/dolphin_state.c index 5216b961dc..5cbc511458 100644 --- a/applications/services/dolphin/helpers/dolphin_state.c +++ b/applications/services/dolphin/helpers/dolphin_state.c @@ -1,11 +1,10 @@ #include "dolphin_state.h" -#include "dolphin/helpers/dolphin_deed.h" #include "dolphin_state_filename.h" -#include -#include #include #include + +#include #include #define TAG "DolphinState" @@ -26,29 +25,28 @@ void dolphin_state_free(DolphinState* dolphin_state) { free(dolphin_state); } -bool dolphin_state_save(DolphinState* dolphin_state) { +void dolphin_state_save(DolphinState* dolphin_state) { if(!dolphin_state->dirty) { - return true; + return; } - bool result = saved_struct_save( + bool success = saved_struct_save( DOLPHIN_STATE_PATH, &dolphin_state->data, sizeof(DolphinStoreData), DOLPHIN_STATE_HEADER_MAGIC, DOLPHIN_STATE_HEADER_VERSION); - if(result) { + if(success) { FURI_LOG_I(TAG, "State saved"); dolphin_state->dirty = false; + } else { FURI_LOG_E(TAG, "Failed to save state"); } - - return result; } -bool dolphin_state_load(DolphinState* dolphin_state) { +void dolphin_state_load(DolphinState* dolphin_state) { bool success = saved_struct_load( DOLPHIN_STATE_PATH, &dolphin_state->data, @@ -64,12 +62,12 @@ bool dolphin_state_load(DolphinState* dolphin_state) { } if(!success) { - FURI_LOG_W(TAG, "Reset dolphin-state"); - memset(dolphin_state, 0, sizeof(*dolphin_state)); + FURI_LOG_W(TAG, "Reset Dolphin state"); + memset(dolphin_state, 0, sizeof(DolphinState)); + dolphin_state->dirty = true; + dolphin_state_save(dolphin_state); } - - return success; } uint64_t dolphin_state_timestamp(void) { diff --git a/applications/services/dolphin/helpers/dolphin_state.h b/applications/services/dolphin/helpers/dolphin_state.h index a8d8406bef..bdbd98d473 100644 --- a/applications/services/dolphin/helpers/dolphin_state.h +++ b/applications/services/dolphin/helpers/dolphin_state.h @@ -1,9 +1,9 @@ #pragma once -#include "dolphin_deed.h" #include #include -#include + +#include "dolphin_deed.h" typedef struct DolphinState DolphinState; typedef struct { @@ -25,9 +25,9 @@ DolphinState* dolphin_state_alloc(void); void dolphin_state_free(DolphinState* dolphin_state); -bool dolphin_state_save(DolphinState* dolphin_state); +void dolphin_state_save(DolphinState* dolphin_state); -bool dolphin_state_load(DolphinState* dolphin_state); +void dolphin_state_load(DolphinState* dolphin_state); void dolphin_state_clear_limits(DolphinState* dolphin_state); diff --git a/applications/services/expansion/expansion.c b/applications/services/expansion/expansion.c index 9b0b31cf71..219bf06414 100644 --- a/applications/services/expansion/expansion.c +++ b/applications/services/expansion/expansion.c @@ -1,9 +1,9 @@ #include "expansion.h" -#include "expansion_i.h" #include #include +#include #include #include "expansion_worker.h" @@ -18,24 +18,19 @@ typedef enum { ExpansionStateDisabled, ExpansionStateEnabled, ExpansionStateRunning, - ExpansionStateConnectionEstablished, } ExpansionState; typedef enum { ExpansionMessageTypeEnable, ExpansionMessageTypeDisable, ExpansionMessageTypeSetListenSerial, + ExpansionMessageTypeReloadSettings, ExpansionMessageTypeModuleConnected, ExpansionMessageTypeModuleDisconnected, - ExpansionMessageTypeConnectionEstablished, - ExpansionMessageTypeIsConnected, } ExpansionMessageType; typedef union { - union { - FuriHalSerialId serial_id; - bool* is_connected; - }; + FuriHalSerialId serial_id; } ExpansionMessageData; typedef struct { @@ -50,8 +45,6 @@ struct Expansion { FuriHalSerialId serial_id; ExpansionWorker* worker; ExpansionState state; - - ExpansionSettings settings; }; static const char* const expansion_uart_names[] = { @@ -74,21 +67,13 @@ static void expansion_detect_callback(void* context) { UNUSED(status); } -static void expansion_worker_callback(void* context, ExpansionWorkerCallbackReason reason) { +static void expansion_worker_callback(void* context) { furi_assert(context); Expansion* instance = context; - ExpansionMessage message; - switch(reason) { - case ExpansionWorkerCallbackReasonExit: - message.type = ExpansionMessageTypeModuleDisconnected; - message.api_lock = NULL; // Not locking the API here to avoid a deadlock - break; - - case ExpansionWorkerCallbackReasonConnected: - message.type = ExpansionMessageTypeConnectionEstablished; - message.api_lock = api_lock_alloc_locked(); - break; + ExpansionMessage message = { + .type = ExpansionMessageTypeModuleDisconnected, + .api_lock = NULL, // Not locking the API here to avoid a deadlock }; const FuriStatus status = furi_message_queue_put(instance->queue, &message, FuriWaitForever); @@ -103,9 +88,12 @@ static void return; } - if(instance->settings.uart_index < FuriHalSerialIdMax) { + ExpansionSettings settings; + expansion_settings_load(&settings); + + if(settings.uart_index < FuriHalSerialIdMax) { instance->state = ExpansionStateEnabled; - instance->serial_id = instance->settings.uart_index; + instance->serial_id = settings.uart_index; furi_hal_serial_control_set_expansion_callback( instance->serial_id, expansion_detect_callback, instance); @@ -116,12 +104,9 @@ static void static void expansion_control_handler_disable(Expansion* instance, const ExpansionMessageData* data) { UNUSED(data); - if(instance->state == ExpansionStateDisabled) { return; - } else if( - instance->state == ExpansionStateRunning || - instance->state == ExpansionStateConnectionEstablished) { + } else if(instance->state == ExpansionStateRunning) { expansion_worker_stop(instance->worker); expansion_worker_free(instance->worker); } else { @@ -136,10 +121,10 @@ static void static void expansion_control_handler_set_listen_serial( Expansion* instance, const ExpansionMessageData* data) { - furi_check(data->serial_id < FuriHalSerialIdMax); + if(instance->state != ExpansionStateDisabled && instance->serial_id == data->serial_id) { + return; - if(instance->state == ExpansionStateRunning || - instance->state == ExpansionStateConnectionEstablished) { + } else if(instance->state == ExpansionStateRunning) { expansion_worker_stop(instance->worker); expansion_worker_free(instance->worker); @@ -156,6 +141,26 @@ static void expansion_control_handler_set_listen_serial( FURI_LOG_D(TAG, "Listen serial changed to %s", expansion_uart_names[instance->serial_id]); } +static void expansion_control_handler_reload_settings( + Expansion* instance, + const ExpansionMessageData* data) { + UNUSED(data); + + ExpansionSettings settings; + expansion_settings_load(&settings); + + if(settings.uart_index < FuriHalSerialIdMax) { + const ExpansionMessageData data = { + .serial_id = settings.uart_index, + }; + + expansion_control_handler_set_listen_serial(instance, &data); + + } else { + expansion_control_handler_disable(instance, NULL); + } +} + static void expansion_control_handler_module_connected( Expansion* instance, const ExpansionMessageData* data) { @@ -177,8 +182,7 @@ static void expansion_control_handler_module_disconnected( Expansion* instance, const ExpansionMessageData* data) { UNUSED(data); - if(instance->state != ExpansionStateRunning && - instance->state != ExpansionStateConnectionEstablished) { + if(instance->state != ExpansionStateRunning) { return; } @@ -188,33 +192,15 @@ static void expansion_control_handler_module_disconnected( instance->serial_id, expansion_detect_callback, instance); } -static void expansion_control_handler_connection_established( - Expansion* instance, - const ExpansionMessageData* data) { - UNUSED(data); - if(instance->state != ExpansionStateRunning && - instance->state != ExpansionStateConnectionEstablished) { - return; - } - - instance->state = ExpansionStateConnectionEstablished; -} - -static void - expansion_control_handler_is_connected(Expansion* instance, const ExpansionMessageData* data) { - *data->is_connected = instance->state == ExpansionStateConnectionEstablished; -} - typedef void (*ExpansionControlHandler)(Expansion*, const ExpansionMessageData*); static const ExpansionControlHandler expansion_control_handlers[] = { [ExpansionMessageTypeEnable] = expansion_control_handler_enable, [ExpansionMessageTypeDisable] = expansion_control_handler_disable, [ExpansionMessageTypeSetListenSerial] = expansion_control_handler_set_listen_serial, + [ExpansionMessageTypeReloadSettings] = expansion_control_handler_reload_settings, [ExpansionMessageTypeModuleConnected] = expansion_control_handler_module_connected, [ExpansionMessageTypeModuleDisconnected] = expansion_control_handler_module_disconnected, - [ExpansionMessageTypeConnectionEstablished] = expansion_control_handler_connection_established, - [ExpansionMessageTypeIsConnected] = expansion_control_handler_is_connected, }; static int32_t expansion_control(void* context) { @@ -249,6 +235,22 @@ static Expansion* expansion_alloc(void) { return instance; } +static void expansion_storage_callback(const void* message, void* context) { + furi_assert(context); + + const StorageEvent* event = message; + Expansion* instance = context; + + if(event->type == StorageEventTypeCardMount) { + ExpansionMessage em = { + .type = ExpansionMessageTypeReloadSettings, + .api_lock = NULL, + }; + + furi_check(furi_message_queue_put(instance->queue, &em, FuriWaitForever) == FuriStatusOk); + } +} + void expansion_on_system_start(void* arg) { UNUSED(arg); @@ -256,7 +258,14 @@ void expansion_on_system_start(void* arg) { furi_record_create(RECORD_EXPANSION, instance); furi_thread_start(instance->thread); - expansion_settings_load(&instance->settings); + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), expansion_storage_callback, instance); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping settings"); + return; + } + expansion_enable(instance); } @@ -286,22 +295,6 @@ void expansion_disable(Expansion* instance) { api_lock_wait_unlock_and_free(message.api_lock); } -bool expansion_is_connected(Expansion* instance) { - furi_check(instance); - bool is_connected; - - ExpansionMessage message = { - .type = ExpansionMessageTypeIsConnected, - .data.is_connected = &is_connected, - .api_lock = api_lock_alloc_locked(), - }; - - furi_message_queue_put(instance->queue, &message, FuriWaitForever); - api_lock_wait_unlock_and_free(message.api_lock); - - return is_connected; -} - void expansion_set_listen_serial(Expansion* instance, FuriHalSerialId serial_id) { furi_check(instance); furi_check(serial_id < FuriHalSerialIdMax); @@ -315,7 +308,3 @@ void expansion_set_listen_serial(Expansion* instance, FuriHalSerialId serial_id) furi_message_queue_put(instance->queue, &message, FuriWaitForever); api_lock_wait_unlock_and_free(message.api_lock); } - -ExpansionSettings* expansion_get_settings(Expansion* instance) { - return &instance->settings; -} diff --git a/applications/services/expansion/expansion.h b/applications/services/expansion/expansion.h index 1b0879b1ec..e169b3c15d 100644 --- a/applications/services/expansion/expansion.h +++ b/applications/services/expansion/expansion.h @@ -50,15 +50,6 @@ void expansion_enable(Expansion* instance); */ void expansion_disable(Expansion* instance); -/** - * @brief Check if an expansion module is connected. - * - * @param[in,out] instance pointer to the Expansion instance. - * - * @returns true if the module is connected and initialized, false otherwise. - */ -bool expansion_is_connected(Expansion* instance); - /** * @brief Enable support for expansion modules on designated serial port. * diff --git a/applications/services/expansion/expansion_i.h b/applications/services/expansion/expansion_i.h deleted file mode 100644 index 13a4962521..0000000000 --- a/applications/services/expansion/expansion_i.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include "expansion_settings.h" -#include "expansion.h" - -ExpansionSettings* expansion_get_settings(Expansion* instance); diff --git a/applications/services/expansion/expansion_settings.c b/applications/services/expansion/expansion_settings.c index c00b8fe247..274ac74304 100644 --- a/applications/services/expansion/expansion_settings.c +++ b/applications/services/expansion/expansion_settings.c @@ -2,33 +2,43 @@ #include #include -#include #include "expansion_settings_filename.h" +#define TAG "ExpansionSettings" + #define EXPANSION_SETTINGS_PATH INT_PATH(EXPANSION_SETTINGS_FILE_NAME) #define EXPANSION_SETTINGS_VERSION (0) #define EXPANSION_SETTINGS_MAGIC (0xEA) -bool expansion_settings_load(ExpansionSettings* settings) { +void expansion_settings_load(ExpansionSettings* settings) { furi_assert(settings); - if(!saved_struct_load( - EXPANSION_SETTINGS_PATH, - settings, - sizeof(ExpansionSettings), - EXPANSION_SETTINGS_MAGIC, - EXPANSION_SETTINGS_VERSION)) { - settings->uart_index = FuriHalSerialIdMax; + + const bool success = saved_struct_load( + EXPANSION_SETTINGS_PATH, + settings, + sizeof(ExpansionSettings), + EXPANSION_SETTINGS_MAGIC, + EXPANSION_SETTINGS_VERSION); + + if(!success) { + FURI_LOG_W(TAG, "Failed to load file, using defaults"); + memset(settings, 0, sizeof(ExpansionSettings)); + expansion_settings_save(settings); } - return true; } -bool expansion_settings_save(const ExpansionSettings* settings) { +void expansion_settings_save(const ExpansionSettings* settings) { furi_assert(settings); - return saved_struct_save( + + const bool success = saved_struct_save( EXPANSION_SETTINGS_PATH, settings, sizeof(ExpansionSettings), EXPANSION_SETTINGS_MAGIC, EXPANSION_SETTINGS_VERSION); + + if(!success) { + FURI_LOG_E(TAG, "Failed to save file"); + } } diff --git a/applications/services/expansion/expansion_settings.h b/applications/services/expansion/expansion_settings.h index 38e9f8d025..4594918e33 100644 --- a/applications/services/expansion/expansion_settings.h +++ b/applications/services/expansion/expansion_settings.h @@ -25,18 +25,16 @@ typedef struct { /** * @brief Load expansion module support settings from file. * - * @param[out] settings pointer to an ExpansionSettings instance to load settings into. - * @returns true if the settings were successfully loaded, false otherwise. + * @param[in,out] settings pointer to an ExpansionSettings instance to load settings into. */ -bool expansion_settings_load(ExpansionSettings* settings); +void expansion_settings_load(ExpansionSettings* settings); /** * @brief Save expansion module support settings to file. * * @param[in] settings pointer to an ExpansionSettings instance to save settings from. - * @returns true if the settings were successfully saved, false otherwise. */ -bool expansion_settings_save(const ExpansionSettings* settings); +void expansion_settings_save(const ExpansionSettings* settings); #ifdef __cplusplus } diff --git a/applications/services/expansion/expansion_worker.c b/applications/services/expansion/expansion_worker.c index edc1d09cce..449d02cffc 100644 --- a/applications/services/expansion/expansion_worker.c +++ b/applications/services/expansion/expansion_worker.c @@ -223,7 +223,6 @@ static bool expansion_worker_handle_state_handshake( if(furi_hal_serial_is_baud_rate_supported(instance->serial_handle, baud_rate)) { instance->state = ExpansionWorkerStateConnected; - instance->callback(instance->cb_context, ExpansionWorkerCallbackReasonConnected); // Send response at previous baud rate if(!expansion_worker_send_status_response(instance, ExpansionFrameErrorNone)) break; furi_hal_serial_set_br(instance->serial_handle, baud_rate); @@ -352,7 +351,7 @@ static int32_t expansion_worker(void* context) { // Do not invoke worker callback on user-requested exit if((instance->exit_reason != ExpansionWorkerExitReasonUser) && (instance->callback != NULL)) { - instance->callback(instance->cb_context, ExpansionWorkerCallbackReasonExit); + instance->callback(instance->cb_context); } return 0; diff --git a/applications/services/expansion/expansion_worker.h b/applications/services/expansion/expansion_worker.h index faab2887f3..761f79c1d9 100644 --- a/applications/services/expansion/expansion_worker.h +++ b/applications/services/expansion/expansion_worker.h @@ -17,20 +17,14 @@ */ typedef struct ExpansionWorker ExpansionWorker; -typedef enum { - ExpansionWorkerCallbackReasonExit, - ExpansionWorkerCallbackReasonConnected, -} ExpansionWorkerCallbackReason; - /** * @brief Worker callback type. * * @see expansion_worker_set_callback() * * @param[in,out] context pointer to a user-defined object. - * @param[in] reason reason for the callback. */ -typedef void (*ExpansionWorkerCallback)(void* context, ExpansionWorkerCallbackReason reason); +typedef void (*ExpansionWorkerCallback)(void* context); /** * @brief Create an expansion worker instance. diff --git a/applications/services/gui/application.fam b/applications/services/gui/application.fam index b7dd18baa1..b24f5bbb6a 100644 --- a/applications/services/gui/application.fam +++ b/applications/services/gui/application.fam @@ -19,6 +19,7 @@ App( "view_holder.h", "modules/button_menu.h", "modules/byte_input.h", + "modules/number_input.h", "modules/popup.h", "modules/text_input.h", "modules/widget.h", diff --git a/applications/services/gui/modules/file_browser_worker.c b/applications/services/gui/modules/file_browser_worker.c index 7092e15da8..78a438ebbb 100644 --- a/applications/services/gui/modules/file_browser_worker.c +++ b/applications/services/gui/modules/file_browser_worker.c @@ -15,7 +15,7 @@ #define TAG "BrowserWorker" #define ASSETS_DIR "assets" -#define BROWSER_ROOT STORAGE_ANY_PATH_PREFIX +#define BROWSER_ROOT STORAGE_EXT_PATH_PREFIX #define FILE_NAME_LEN_MAX 256 #define LONG_LOAD_THRESHOLD 100 @@ -134,7 +134,7 @@ static bool browser_filter_by_name(BrowserWorker* browser, FuriString* name, boo if((furi_string_empty(ext)) || (furi_string_cmp_str(ext, "*") == 0)) { return true; } - if(furi_string_end_with(name, ext)) { + if(furi_string_end_withi(name, ext)) { return true; } } diff --git a/applications/services/gui/modules/number_input.c b/applications/services/gui/modules/number_input.c new file mode 100644 index 0000000000..317f22f547 --- /dev/null +++ b/applications/services/gui/modules/number_input.c @@ -0,0 +1,449 @@ +#include "number_input.h" + +#include +#include +#include + +struct NumberInput { + View* view; +}; + +typedef struct { + const char text; + const size_t x; + const size_t y; +} NumberInputKey; + +typedef struct { + FuriString* header; + FuriString* text_buffer; + + int32_t current_number; + int32_t max_value; + int32_t min_value; + + NumberInputCallback callback; + void* callback_context; + + size_t selected_row; + size_t selected_column; +} NumberInputModel; + +static const size_t keyboard_origin_x = 7; +static const size_t keyboard_origin_y = 31; +static const size_t keyboard_row_count = 2; +static const char enter_symbol = '\r'; +static const char backspace_symbol = '\b'; +static const char sign_symbol = '-'; + +static const NumberInputKey keyboard_keys_row_1[] = { + {'0', 0, 12}, + {'1', 11, 12}, + {'2', 22, 12}, + {'3', 33, 12}, + {'4', 44, 12}, + {backspace_symbol, 103, 4}, +}; + +static const NumberInputKey keyboard_keys_row_2[] = { + {'5', 0, 26}, + {'6', 11, 26}, + {'7', 22, 26}, + {'8', 33, 26}, + {'9', 44, 26}, + {sign_symbol, 55, 17}, + {enter_symbol, 95, 17}, +}; + +static size_t number_input_get_row_size(size_t row_index) { + size_t row_size = 0; + + switch(row_index + 1) { + case 1: + row_size = COUNT_OF(keyboard_keys_row_1); + break; + case 2: + row_size = COUNT_OF(keyboard_keys_row_2); + break; + default: + furi_crash(); + } + + return row_size; +} + +static const NumberInputKey* number_input_get_row(size_t row_index) { + const NumberInputKey* row = NULL; + + switch(row_index + 1) { + case 1: + row = keyboard_keys_row_1; + break; + case 2: + row = keyboard_keys_row_2; + break; + default: + furi_crash(); + } + + return row; +} + +static void number_input_draw_input(Canvas* canvas, NumberInputModel* model) { + const size_t text_x = 8; + const size_t text_y = 25; + + elements_slightly_rounded_frame(canvas, 4, 14, 120, 15); + + canvas_draw_str(canvas, text_x, text_y, furi_string_get_cstr(model->text_buffer)); +} + +static bool number_input_use_sign(NumberInputModel* model) { + //only show sign button if allowed number range needs it + if(model->min_value < 0 && model->max_value >= 0) { + return true; + } + return false; +} + +static void number_input_backspace_cb(NumberInputModel* model) { + size_t text_length = furi_string_utf8_length(model->text_buffer); + if(text_length < 1 || (text_length < 2 && model->current_number <= 0)) { + return; + } + furi_string_set_strn( + model->text_buffer, furi_string_get_cstr(model->text_buffer), text_length - 1); + model->current_number = strtol(furi_string_get_cstr(model->text_buffer), NULL, 10); +} + +static void number_input_handle_up(NumberInputModel* model) { + if(model->selected_row > 0) { + model->selected_row--; + if(model->selected_column > number_input_get_row_size(model->selected_row) - 1) { + model->selected_column = number_input_get_row_size(model->selected_row) - 1; + } + } +} + +static void number_input_handle_down(NumberInputModel* model) { + if(model->selected_row < keyboard_row_count - 1) { + if(model->selected_column >= number_input_get_row_size(model->selected_row) - 1) { + model->selected_column = number_input_get_row_size(model->selected_row + 1) - 1; + } + model->selected_row += 1; + } + const NumberInputKey* keys = number_input_get_row(model->selected_row); + if(keys[model->selected_column].text == sign_symbol && !number_input_use_sign(model)) { + model->selected_column--; + } +} + +static void number_input_handle_left(NumberInputModel* model) { + if(model->selected_column > 0) { + model->selected_column--; + } else { + model->selected_column = number_input_get_row_size(model->selected_row) - 1; + } + const NumberInputKey* keys = number_input_get_row(model->selected_row); + if(keys[model->selected_column].text == sign_symbol && !number_input_use_sign(model)) { + model->selected_column--; + } +} + +static void number_input_handle_right(NumberInputModel* model) { + if(model->selected_column < number_input_get_row_size(model->selected_row) - 1) { + model->selected_column++; + } else { + model->selected_column = 0; + } + const NumberInputKey* keys = number_input_get_row(model->selected_row); + if(keys[model->selected_column].text == sign_symbol && !number_input_use_sign(model)) { + model->selected_column++; + } +} + +static bool is_number_too_large(NumberInputModel* model) { + int64_t value = strtoll(furi_string_get_cstr(model->text_buffer), NULL, 10); + if(value > (int64_t)model->max_value) { + return true; + } + return false; +} + +static bool is_number_too_small(NumberInputModel* model) { + int64_t value = strtoll(furi_string_get_cstr(model->text_buffer), NULL, 10); + if(value < (int64_t)model->min_value) { + return true; + } + return false; +} + +static void number_input_sign(NumberInputModel* model) { + int32_t number = strtol(furi_string_get_cstr(model->text_buffer), NULL, 10); + if(number == 0 && furi_string_cmp_str(model->text_buffer, "-") != 0) { + furi_string_set_str(model->text_buffer, "-"); + return; + } + number = number * -1; + furi_string_printf(model->text_buffer, "%ld", number); + if(is_number_too_large(model) || is_number_too_small(model)) { + furi_string_printf(model->text_buffer, "%ld", model->current_number); + return; + } + model->current_number = strtol(furi_string_get_cstr(model->text_buffer), NULL, 10); + if(model->current_number == 0) { + furi_string_set_str(model->text_buffer, ""); //show empty if 0, better for usability + } +} + +static void number_input_add_digit(NumberInputModel* model, char* newChar) { + furi_string_cat_str(model->text_buffer, newChar); + if((model->max_value >= 0 && is_number_too_large(model)) || + (model->min_value < 0 && is_number_too_small(model))) { + //you still need to be able to type invalid numbers in some cases to reach valid numbers on later keypress + furi_string_printf(model->text_buffer, "%ld", model->current_number); + return; + } + model->current_number = strtol(furi_string_get_cstr(model->text_buffer), NULL, 10); + if(model->current_number == 0) { + furi_string_set(model->text_buffer, "0"); + } +} + +static void number_input_handle_ok(NumberInputModel* model) { + char selected = number_input_get_row(model->selected_row)[model->selected_column].text; + char temp_str[2] = {selected, '\0'}; + if(selected == enter_symbol) { + if(is_number_too_large(model) || is_number_too_small(model)) { + return; //Do nothing if number outside allowed range + } + model->current_number = strtol(furi_string_get_cstr(model->text_buffer), NULL, 10); + model->callback(model->callback_context, model->current_number); + } else if(selected == backspace_symbol) { + number_input_backspace_cb(model); + } else if(selected == sign_symbol) { + number_input_sign(model); + } else { + number_input_add_digit(model, temp_str); + } +} + +static void number_input_view_draw_callback(Canvas* canvas, void* _model) { + NumberInputModel* model = _model; + + number_input_draw_input(canvas, model); + + if(!furi_string_empty(model->header)) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 2, 9, furi_string_get_cstr(model->header)); + } + canvas_set_font(canvas, FontKeyboard); + // Draw keyboard + for(size_t row = 0; row < keyboard_row_count; row++) { + const size_t column_count = number_input_get_row_size(row); + const NumberInputKey* keys = number_input_get_row(row); + + for(size_t column = 0; column < column_count; column++) { + if(keys[column].text == sign_symbol && !number_input_use_sign(model)) { + continue; + } + + if(keys[column].text == enter_symbol) { + if(is_number_too_small(model) || is_number_too_large(model)) { + //in some cases you need to be able to type a number smaller/larger than the limits (expl. min = 50, clear all and editor must allow to type 9 and later 0 for 90) + if(model->selected_row == row && model->selected_column == column) { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeySaveBlockedSelected_24x11); + } else { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeySaveBlocked_24x11); + } + } else { + if(model->selected_row == row && model->selected_column == column) { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeySaveSelected_24x11); + } else { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeySave_24x11); + } + } + } else if(keys[column].text == backspace_symbol) { + if(model->selected_row == row && model->selected_column == column) { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeyBackspaceSelected_16x9); + } else { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeyBackspace_16x9); + } + } else if(keys[column].text == sign_symbol) { + if(model->selected_row == row && model->selected_column == column) { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeySignSelected_21x11); + } else { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeySign_21x11); + } + } else { + if(model->selected_row == row && model->selected_column == column) { + canvas_draw_box( + canvas, + keyboard_origin_x + keys[column].x - 3, + keyboard_origin_y + keys[column].y - 10, + 11, + 13); + canvas_set_color(canvas, ColorWhite); + } + + canvas_draw_glyph( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + keys[column].text); + canvas_set_color(canvas, ColorBlack); + } + } + } +} + +static bool number_input_view_input_callback(InputEvent* event, void* context) { + furi_assert(context); + NumberInput* number_input = context; + + bool consumed = false; + + // Fetch the model + NumberInputModel* model = view_get_model(number_input->view); + + if(event->type == InputTypeShort || event->type == InputTypeLong || + event->type == InputTypeRepeat) { + consumed = true; + switch(event->key) { + case InputKeyLeft: + number_input_handle_left(model); + break; + case InputKeyRight: + number_input_handle_right(model); + break; + case InputKeyUp: + number_input_handle_up(model); + break; + case InputKeyDown: + number_input_handle_down(model); + break; + case InputKeyOk: + number_input_handle_ok(model); + break; + default: + consumed = false; + break; + } + } + + // commit view + view_commit_model(number_input->view, consumed); + + return consumed; +} + +NumberInput* number_input_alloc(void) { + NumberInput* number_input = malloc(sizeof(NumberInput)); + number_input->view = view_alloc(); + view_set_context(number_input->view, number_input); + view_allocate_model(number_input->view, ViewModelTypeLocking, sizeof(NumberInputModel)); + view_set_draw_callback(number_input->view, number_input_view_draw_callback); + view_set_input_callback(number_input->view, number_input_view_input_callback); + + with_view_model( + number_input->view, + NumberInputModel * model, + { + model->header = furi_string_alloc(); + model->text_buffer = furi_string_alloc(); + }, + true); + + return number_input; +} + +void number_input_free(NumberInput* number_input) { + furi_check(number_input); + with_view_model( + number_input->view, + NumberInputModel * model, + { + furi_string_free(model->header); + furi_string_free(model->text_buffer); + }, + true); + view_free(number_input->view); + free(number_input); +} + +View* number_input_get_view(NumberInput* number_input) { + furi_check(number_input); + return number_input->view; +} + +void number_input_set_result_callback( + NumberInput* number_input, + NumberInputCallback callback, + void* callback_context, + int32_t current_number, + int32_t min_value, + int32_t max_value) { + furi_check(number_input); + + if(current_number != 0) { + current_number = CLAMP(current_number, max_value, min_value); + } + + with_view_model( + number_input->view, + NumberInputModel * model, + { + model->callback = callback; + model->callback_context = callback_context; + model->current_number = current_number; + if(current_number != 0) { + furi_string_printf(model->text_buffer, "%ld", current_number); + } else { + furi_string_set(model->text_buffer, ""); + } + model->min_value = min_value; + model->max_value = max_value; + }, + true); +} + +void number_input_set_header_text(NumberInput* number_input, const char* text) { + furi_check(number_input); + with_view_model( + number_input->view, + NumberInputModel * model, + { furi_string_set(model->header, text); }, + true); +} diff --git a/applications/services/gui/modules/number_input.h b/applications/services/gui/modules/number_input.h new file mode 100644 index 0000000000..80e631e9bd --- /dev/null +++ b/applications/services/gui/modules/number_input.h @@ -0,0 +1,69 @@ +/** + * @file number_input.h + * GUI: Integer string keyboard view module API + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Number input anonymous structure */ +typedef struct NumberInput NumberInput; + +/** Callback to be called on save button press */ +typedef void (*NumberInputCallback)(void* context, int32_t number); + +/** Allocate and initialize Number input. + * + * This Number input is used to enter Numbers (Integers). + * + * @return NumberInput instance pointer + */ +NumberInput* number_input_alloc(void); + +/** Deinitialize and free byte input + * + * @param number_input Number input instance + */ +void number_input_free(NumberInput* number_input); + +/** Get byte input view + * + * @param number_input byte input instance + * + * @return View instance that can be used for embedding + */ +View* number_input_get_view(NumberInput* number_input); + +/** Set byte input result callback + * + * @param number_input byte input instance + * @param input_callback input callback fn + * @param callback_context callback context + * @param[in] current_number The current number + * @param min_value Min number value + * @param max_value Max number value + */ + +void number_input_set_result_callback( + NumberInput* number_input, + NumberInputCallback input_callback, + void* callback_context, + int32_t current_number, + int32_t min_value, + int32_t max_value); + +/** Set byte input header text + * + * @param number_input byte input instance + * @param text text to be shown + */ +void number_input_set_header_text(NumberInput* number_input, const char* text); + +#ifdef __cplusplus +} +#endif diff --git a/applications/services/gui/view_dispatcher.c b/applications/services/gui/view_dispatcher.c index b4c534932f..63878fc190 100644 --- a/applications/services/gui/view_dispatcher.c +++ b/applications/services/gui/view_dispatcher.c @@ -2,6 +2,8 @@ #define TAG "ViewDispatcher" +#define VIEW_DISPATCHER_QUEUE_LEN (16U) + ViewDispatcher* view_dispatcher_alloc(void) { ViewDispatcher* view_dispatcher = malloc(sizeof(ViewDispatcher)); @@ -14,6 +16,26 @@ ViewDispatcher* view_dispatcher_alloc(void) { ViewDict_init(view_dispatcher->views); + view_dispatcher->event_loop = furi_event_loop_alloc(); + + view_dispatcher->input_queue = + furi_message_queue_alloc(VIEW_DISPATCHER_QUEUE_LEN, sizeof(InputEvent)); + furi_event_loop_subscribe_message_queue( + view_dispatcher->event_loop, + view_dispatcher->input_queue, + FuriEventLoopEventIn, + view_dispatcher_run_input_callback, + view_dispatcher); + + view_dispatcher->event_queue = + furi_message_queue_alloc(VIEW_DISPATCHER_QUEUE_LEN, sizeof(uint32_t)); + furi_event_loop_subscribe_message_queue( + view_dispatcher->event_loop, + view_dispatcher->event_queue, + FuriEventLoopEventIn, + view_dispatcher_run_event_callback, + view_dispatcher); + return view_dispatcher; } @@ -29,44 +51,19 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher) { // Free ViewPort view_port_free(view_dispatcher->view_port); // Free internal queue - if(view_dispatcher->input_queue) { - furi_event_loop_message_queue_unsubscribe( - view_dispatcher->event_loop, view_dispatcher->input_queue); - furi_message_queue_free(view_dispatcher->input_queue); - } - if(view_dispatcher->event_queue) { - furi_event_loop_message_queue_unsubscribe( - view_dispatcher->event_loop, view_dispatcher->event_queue); - furi_message_queue_free(view_dispatcher->event_queue); - } - if(view_dispatcher->event_loop) { - furi_event_loop_free(view_dispatcher->event_loop); - } + furi_event_loop_unsubscribe(view_dispatcher->event_loop, view_dispatcher->input_queue); + furi_event_loop_unsubscribe(view_dispatcher->event_loop, view_dispatcher->event_queue); + + furi_message_queue_free(view_dispatcher->input_queue); + furi_message_queue_free(view_dispatcher->event_queue); + + furi_event_loop_free(view_dispatcher->event_loop); // Free dispatcher free(view_dispatcher); } void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher) { - furi_check(view_dispatcher); - furi_check(view_dispatcher->event_loop == NULL); - - view_dispatcher->event_loop = furi_event_loop_alloc(); - - view_dispatcher->input_queue = furi_message_queue_alloc(16, sizeof(InputEvent)); - furi_event_loop_message_queue_subscribe( - view_dispatcher->event_loop, - view_dispatcher->input_queue, - FuriEventLoopEventIn, - view_dispatcher_run_input_callback, - view_dispatcher); - - view_dispatcher->event_queue = furi_message_queue_alloc(16, sizeof(uint32_t)); - furi_event_loop_message_queue_subscribe( - view_dispatcher->event_loop, - view_dispatcher->event_queue, - FuriEventLoopEventIn, - view_dispatcher_run_event_callback, - view_dispatcher); + UNUSED(view_dispatcher); } void view_dispatcher_set_navigation_event_callback( @@ -99,14 +96,12 @@ void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, FuriEventLoop* view_dispatcher_get_event_loop(ViewDispatcher* view_dispatcher) { furi_check(view_dispatcher); - furi_check(view_dispatcher->event_loop); return view_dispatcher->event_loop; } void view_dispatcher_run(ViewDispatcher* view_dispatcher) { furi_check(view_dispatcher); - furi_check(view_dispatcher->event_loop); uint32_t tick_period = view_dispatcher->tick_period == 0 ? FuriWaitForever : view_dispatcher->tick_period; @@ -134,7 +129,6 @@ void view_dispatcher_run(ViewDispatcher* view_dispatcher) { void view_dispatcher_stop(ViewDispatcher* view_dispatcher) { furi_check(view_dispatcher); - furi_check(view_dispatcher->event_loop); furi_event_loop_stop(view_dispatcher->event_loop); } @@ -242,13 +236,9 @@ void view_dispatcher_draw_callback(Canvas* canvas, void* context) { void view_dispatcher_input_callback(InputEvent* event, void* context) { ViewDispatcher* view_dispatcher = context; - if(view_dispatcher->input_queue) { - furi_check( - furi_message_queue_put(view_dispatcher->input_queue, event, FuriWaitForever) == - FuriStatusOk); - } else { - view_dispatcher_handle_input(view_dispatcher, event); - } + furi_check( + furi_message_queue_put(view_dispatcher->input_queue, event, FuriWaitForever) == + FuriStatusOk); } void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* event) { @@ -328,7 +318,6 @@ void view_dispatcher_handle_custom_event(ViewDispatcher* view_dispatcher, uint32 void view_dispatcher_send_custom_event(ViewDispatcher* view_dispatcher, uint32_t event) { furi_check(view_dispatcher); - furi_check(view_dispatcher->event_loop); furi_check( furi_message_queue_put(view_dispatcher->event_queue, &event, FuriWaitForever) == @@ -364,9 +353,7 @@ void view_dispatcher_set_current_view(ViewDispatcher* view_dispatcher, View* vie view_port_update(view_dispatcher->view_port); } else { view_port_enabled_set(view_dispatcher->view_port, false); - if(view_dispatcher->event_loop) { - view_dispatcher_stop(view_dispatcher); - } + view_dispatcher_stop(view_dispatcher); } } @@ -381,10 +368,10 @@ void view_dispatcher_update(View* view, void* context) { } } -bool view_dispatcher_run_event_callback(FuriMessageQueue* queue, void* context) { +bool view_dispatcher_run_event_callback(FuriEventLoopObject* object, void* context) { furi_assert(context); ViewDispatcher* instance = context; - furi_assert(instance->event_queue == queue); + furi_assert(instance->event_queue == object); uint32_t event; furi_check(furi_message_queue_get(instance->event_queue, &event, 0) == FuriStatusOk); @@ -393,10 +380,10 @@ bool view_dispatcher_run_event_callback(FuriMessageQueue* queue, void* context) return true; } -bool view_dispatcher_run_input_callback(FuriMessageQueue* queue, void* context) { +bool view_dispatcher_run_input_callback(FuriEventLoopObject* object, void* context) { furi_assert(context); ViewDispatcher* instance = context; - furi_assert(instance->input_queue == queue); + furi_assert(instance->input_queue == object); InputEvent input; furi_check(furi_message_queue_get(instance->input_queue, &input, 0) == FuriStatusOk); diff --git a/applications/services/gui/view_dispatcher.h b/applications/services/gui/view_dispatcher.h index 905c60975b..9fbf897918 100644 --- a/applications/services/gui/view_dispatcher.h +++ b/applications/services/gui/view_dispatcher.h @@ -2,6 +2,14 @@ * @file view_dispatcher.h * @brief GUI: ViewDispatcher API * + * ViewDispatcher is used to connect several Views to a Gui instance, switch between them and handle various events. + * This is useful in applications featuring an advanced graphical user interface. + * + * Internally, ViewDispatcher employs a FuriEventLoop instance together with two separate + * message queues for input and custom event handling. See FuriEventLoop for more information. + * + * If no multi-view or complex event handling capabilities are required, consider using ViewHolder instead. + * * @warning Views added to a ViewDispatcher MUST NOT be in a ViewStack at the same time. */ @@ -40,6 +48,9 @@ typedef void (*ViewDispatcherTickEventCallback)(void* context); ViewDispatcher* view_dispatcher_alloc(void); /** Free ViewDispatcher instance + * + * @warning All added views MUST be removed using view_dispatcher_remove_view() + * before calling this function. * * @param view_dispatcher pointer to ViewDispatcher */ @@ -47,12 +58,13 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher); /** Enable queue support * - * Allocates event_loop, input and event message queues. Must be used with - * `view_dispatcher_run` + * @deprecated Do NOT use in new code and remove all calls to it from existing code. + * The queue support is now always enabled during construction. If no queue support + * is required, consider using ViewHolder instead. * * @param view_dispatcher ViewDispatcher instance */ -void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher); +FURI_DEPRECATED void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher); /** Send custom event * @@ -103,11 +115,11 @@ void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, /** Get event_loop instance * - * event_loop instance is allocated on `view_dispatcher_enable_queue` and used - * in view_dispatcher_run. + * Use the return value to connect additional supported primitives (message queues, timers, etc) + * to this ViewDispatcher instance's event loop. * - * You can add your objects into event_loop instance, but don't run the loop on - * your side as it will cause issues with input processing on dispatcher stop. + * @warning Do NOT call furi_event_loop_run() on the returned instance, it is done internally + * in the view_dispatcher_run() call. * * @param view_dispatcher ViewDispatcher instance * @@ -117,15 +129,14 @@ FuriEventLoop* view_dispatcher_get_event_loop(ViewDispatcher* view_dispatcher); /** Run ViewDispatcher * - * Use only after queue enabled + * This function will start the event loop and block until view_dispatcher_stop() is called + * or the current thread receives a FuriSignalExit signal. * * @param view_dispatcher ViewDispatcher instance */ void view_dispatcher_run(ViewDispatcher* view_dispatcher); /** Stop ViewDispatcher - * - * Use only after queue enabled * * @param view_dispatcher ViewDispatcher instance */ diff --git a/applications/services/gui/view_dispatcher_i.h b/applications/services/gui/view_dispatcher_i.h index 46a4ac7fa7..c6c8dc665c 100644 --- a/applications/services/gui/view_dispatcher_i.h +++ b/applications/services/gui/view_dispatcher_i.h @@ -56,7 +56,7 @@ void view_dispatcher_set_current_view(ViewDispatcher* view_dispatcher, View* vie void view_dispatcher_update(View* view, void* context); /** ViewDispatcher run event loop event callback */ -bool view_dispatcher_run_event_callback(FuriMessageQueue* queue, void* context); +bool view_dispatcher_run_event_callback(FuriEventLoopObject* object, void* context); /** ViewDispatcher run event loop input callback */ -bool view_dispatcher_run_input_callback(FuriMessageQueue* queue, void* context); +bool view_dispatcher_run_input_callback(FuriEventLoopObject* object, void* context); diff --git a/applications/services/gui/view_holder.c b/applications/services/gui/view_holder.c index ca2f9b04e1..7d8b5e17c3 100644 --- a/applications/services/gui/view_holder.c +++ b/applications/services/gui/view_holder.c @@ -32,7 +32,8 @@ ViewHolder* view_holder_alloc(void) { } void view_holder_free(ViewHolder* view_holder) { - furi_assert(view_holder); + furi_check(view_holder); + furi_check(view_holder->view == NULL); if(view_holder->gui) { gui_remove_view_port(view_holder->gui, view_holder->view_port); @@ -48,12 +49,14 @@ void view_holder_free(ViewHolder* view_holder) { } void view_holder_set_view(ViewHolder* view_holder, View* view) { - furi_assert(view_holder); + furi_check(view_holder); + if(view_holder->view) { - if(view_holder->view->exit_callback) { - view_holder->view->exit_callback(view_holder->view->context); + while(view_holder->ongoing_input) { + furi_delay_tick(1); } + view_exit(view_holder->view); view_set_update_callback(view_holder->view, NULL); view_set_update_callback_context(view_holder->view, NULL); } @@ -61,12 +64,23 @@ void view_holder_set_view(ViewHolder* view_holder, View* view) { view_holder->view = view; if(view_holder->view) { + const ViewPortOrientation orientation = (ViewPortOrientation)view->orientation; + furi_assert(orientation < ViewPortOrientationMAX); + if(view_port_get_orientation(view_holder->view_port) != orientation) { + view_port_set_orientation(view_holder->view_port, orientation); + // we just rotated input keys, now it's time to sacrifice some input + view_holder->ongoing_input = 0; + } + view_set_update_callback(view_holder->view, view_holder_update); view_set_update_callback_context(view_holder->view, view_holder); - if(view_holder->view->enter_callback) { - view_holder->view->enter_callback(view_holder->view->context); - } + view_enter(view_holder->view); + view_port_enabled_set(view_holder->view_port, true); + view_port_update(view_holder->view_port); + + } else { + view_port_enabled_set(view_holder->view_port, false); } } @@ -74,7 +88,7 @@ void view_holder_set_free_callback( ViewHolder* view_holder, FreeCallback free_callback, void* free_context) { - furi_assert(view_holder); + furi_check(view_holder); view_holder->free_callback = free_callback; view_holder->free_context = free_context; } @@ -87,31 +101,22 @@ void view_holder_set_back_callback( ViewHolder* view_holder, BackCallback back_callback, void* back_context) { - furi_assert(view_holder); + furi_check(view_holder); view_holder->back_callback = back_callback; view_holder->back_context = back_context; } void view_holder_attach_to_gui(ViewHolder* view_holder, Gui* gui) { - furi_assert(gui); - furi_assert(view_holder); - view_holder->gui = gui; + furi_check(view_holder); + furi_check(view_holder->gui == NULL); + furi_check(gui); gui_add_view_port(gui, view_holder->view_port, GuiLayerFullscreen); -} - -void view_holder_start(ViewHolder* view_holder) { - view_port_enabled_set(view_holder->view_port, true); -} - -void view_holder_stop(ViewHolder* view_holder) { - while(view_holder->ongoing_input) - furi_delay_tick(1); - view_port_enabled_set(view_holder->view_port, false); + view_holder->gui = gui; } void view_holder_update(View* view, void* context) { - furi_assert(view); - furi_assert(context); + furi_check(view); + furi_check(context); ViewHolder* view_holder = context; if(view == view_holder->view) { @@ -119,6 +124,18 @@ void view_holder_update(View* view, void* context) { } } +void view_holder_send_to_front(ViewHolder* view_holder) { + furi_check(view_holder); + furi_check(view_holder->gui); + gui_view_port_send_to_front(view_holder->gui, view_holder->view_port); +} + +void view_holder_send_to_back(ViewHolder* view_holder) { + furi_check(view_holder); + furi_check(view_holder->gui); + gui_view_port_send_to_back(view_holder->gui, view_holder->view_port); +} + static void view_holder_draw_callback(Canvas* canvas, void* context) { ViewHolder* view_holder = context; if(view_holder->view) { diff --git a/applications/services/gui/view_holder.h b/applications/services/gui/view_holder.h index 90ce82b377..78dbfda0ec 100644 --- a/applications/services/gui/view_holder.h +++ b/applications/services/gui/view_holder.h @@ -2,7 +2,10 @@ * @file view_holder.h * @brief GUI: ViewHolder API * - * @warning View added to a ViewHolder MUST NOT be in a ViewStack at the same time. + * ViewHolder is used to connect a single View to a Gui instance. This is useful in smaller applications + * with a simple user interface. If advanced view switching capabilites are required, consider using ViewDispatcher instead. + * + * @warning Views added to a ViewHolder MUST NOT be in a ViewStack at the same time. */ #pragma once @@ -22,7 +25,8 @@ typedef void (*FreeCallback)(void* free_context); /** * @brief Back callback type - * @warning comes from GUI thread + * + * @warning Will be called from the GUI thread */ typedef void (*BackCallback)(void* back_context); @@ -34,12 +38,17 @@ ViewHolder* view_holder_alloc(void); /** * @brief Free ViewHolder and call Free callback + * + * @warning The current view must be unset prior to freeing a ViewHolder instance. + * * @param view_holder pointer to ViewHolder */ void view_holder_free(ViewHolder* view_holder); /** * @brief Set view for ViewHolder + * + * Pass NULL as the view parameter to unset the current view. * * @param view_holder ViewHolder instance * @param view View instance @@ -59,13 +68,25 @@ void view_holder_set_free_callback( void* free_context); /** - * @brief Free callback context getter. Useful if your Free callback is a module destructor, so you can get an instance of the module using this method. + * @brief Free callback context getter. + * + * Useful if your Free callback is a module destructor, so you can get an instance of the module using this method. * * @param view_holder ViewHolder instance * @return void* free callback context */ void* view_holder_get_free_context(ViewHolder* view_holder); +/** + * @brief Set the back key callback. + * + * The callback function will be called if the user has pressed the Back key + * and the current view did not handle this event. + * + * @param view_holder ViewHolder instance + * @param back_callback pointer to the callback function + * @param back_context pointer to a user-specific object, can be NULL + */ void view_holder_set_back_callback( ViewHolder* view_holder, BackCallback back_callback, @@ -80,25 +101,26 @@ void view_holder_set_back_callback( void view_holder_attach_to_gui(ViewHolder* view_holder, Gui* gui); /** - * @brief Enable view processing - * - * @param view_holder + * @brief View Update Handler + * + * @param view View Instance + * @param context ViewHolder instance */ -void view_holder_start(ViewHolder* view_holder); +void view_holder_update(View* view, void* context); /** - * @brief Disable view processing - * - * @param view_holder + * @brief Send ViewPort of this ViewHolder instance to front + * + * @param view_holder ViewHolder instance */ -void view_holder_stop(ViewHolder* view_holder); +void view_holder_send_to_front(ViewHolder* view_holder); -/** View Update Handler +/** + * @brief Send ViewPort of this ViewHolder instance to back * - * @param view View Instance - * @param context ViewHolder instance + * @param view_holder ViewHolder instance */ -void view_holder_update(View* view, void* context); +void view_holder_send_to_back(ViewHolder* view_holder); #ifdef __cplusplus } diff --git a/applications/services/loader/loader_applications.c b/applications/services/loader/loader_applications.c index 232e5314e9..5399ba26fc 100644 --- a/applications/services/loader/loader_applications.c +++ b/applications/services/loader/loader_applications.c @@ -61,7 +61,6 @@ static LoaderApplicationsApp* loader_applications_app_alloc(void) { app->loading = loading_alloc(); view_holder_attach_to_gui(app->view_holder, app->gui); - view_holder_set_view(app->view_holder, loading_get_view(app->loading)); return app; } //-V773 @@ -149,7 +148,7 @@ static int32_t loader_applications_thread(void* p) { LoaderApplicationsApp* app = loader_applications_app_alloc(); // start loading animation - view_holder_start(app->view_holder); + view_holder_set_view(app->view_holder, loading_get_view(app->loading)); while(loader_applications_select_app(app)) { if(!furi_string_end_with(app->file_path, ".js")) { @@ -161,7 +160,7 @@ static int32_t loader_applications_thread(void* p) { } // stop loading animation - view_holder_stop(app->view_holder); + view_holder_set_view(app->view_holder, NULL); loader_applications_app_free(app); diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c index 0ee3cada2d..ad4a4c7d59 100644 --- a/applications/services/loader/loader_menu.c +++ b/applications/services/loader/loader_menu.c @@ -160,8 +160,6 @@ static LoaderMenuApp* loader_menu_app_alloc(LoaderMenu* loader_menu) { view_set_context(settings_view, app->settings_menu); view_set_previous_callback(settings_view, loader_menu_switch_to_primary); view_dispatcher_add_view(app->view_dispatcher, LoaderMenuViewSettings, settings_view); - - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_switch_to_view(app->view_dispatcher, LoaderMenuViewPrimary); return app; diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index d4c5b91c8c..35d2fe675a 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -438,7 +438,7 @@ static bool notification_load_settings(NotificationApp* app) { File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); const size_t settings_size = sizeof(NotificationSettings); - FURI_LOG_I(TAG, "loading settings from \"%s\"", NOTIFICATION_SETTINGS_PATH); + FURI_LOG_I(TAG, "Loading \"%s\"", NOTIFICATION_SETTINGS_PATH); bool fs_result = storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING); @@ -451,8 +451,6 @@ static bool notification_load_settings(NotificationApp* app) { } if(fs_result) { - FURI_LOG_I(TAG, "load success"); - if(settings.version != NOTIFICATION_SETTINGS_VERSION) { FURI_LOG_E( TAG, "version(%d != %d) mismatch", settings.version, NOTIFICATION_SETTINGS_VERSION); @@ -462,7 +460,7 @@ static bool notification_load_settings(NotificationApp* app) { furi_kernel_unlock(); } } else { - FURI_LOG_E(TAG, "load failed, %s", storage_file_get_error_desc(file)); + FURI_LOG_E(TAG, "Load failed, %s", storage_file_get_error_desc(file)); } storage_file_close(file); @@ -477,7 +475,7 @@ static bool notification_save_settings(NotificationApp* app) { File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); const size_t settings_size = sizeof(NotificationSettings); - FURI_LOG_I(TAG, "saving settings to \"%s\"", NOTIFICATION_SETTINGS_PATH); + FURI_LOG_I(TAG, "Saving \"%s\"", NOTIFICATION_SETTINGS_PATH); furi_kernel_lock(); memcpy(&settings, &app->settings, settings_size); @@ -495,9 +493,8 @@ static bool notification_save_settings(NotificationApp* app) { } if(fs_result) { - FURI_LOG_I(TAG, "save success"); } else { - FURI_LOG_E(TAG, "save failed, %s", storage_file_get_error_desc(file)); + FURI_LOG_E(TAG, "Save failed, %s", storage_file_get_error_desc(file)); } storage_file_close(file); @@ -556,14 +553,46 @@ static NotificationApp* notification_app_alloc(void) { return app; } +static void notification_storage_callback(const void* message, void* context) { + furi_assert(context); + NotificationApp* app = context; + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + NotificationAppMessage m = { + .type = LoadSettingsMessage, + }; + + furi_check(furi_message_queue_put(app->queue, &m, FuriWaitForever) == FuriStatusOk); + } +} + +static void notification_apply_settings(NotificationApp* app) { + if(!notification_load_settings(app)) { + notification_save_settings(app); + } + + notification_apply_lcd_contrast(app); +} + +static void notification_init_settings(NotificationApp* app) { + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), notification_storage_callback, app); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping settings"); + return; + } + + notification_apply_settings(app); +} + // App int32_t notification_srv(void* p) { UNUSED(p); NotificationApp* app = notification_app_alloc(); - if(!notification_load_settings(app)) { - notification_save_settings(app); - } + notification_init_settings(app); notification_vibro_off(); notification_sound_off(); @@ -571,7 +600,6 @@ int32_t notification_srv(void* p) { notification_apply_internal_led_layer(&app->led[0], 0x00); notification_apply_internal_led_layer(&app->led[1], 0x00); notification_apply_internal_led_layer(&app->led[2], 0x00); - notification_apply_lcd_contrast(app); furi_record_create(RECORD_NOTIFICATION, app); @@ -589,6 +617,9 @@ int32_t notification_srv(void* p) { case SaveSettingsMessage: notification_save_settings(app); break; + case LoadSettingsMessage: + notification_load_settings(app); + break; } if(message.back_event != NULL) { diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 434773f2e5..e195465741 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -11,6 +11,7 @@ typedef enum { NotificationLayerMessage, InternalLayerMessage, SaveSettingsMessage, + LoadSettingsMessage, } NotificationAppMessageType; typedef struct { diff --git a/applications/services/power/power_cli.c b/applications/services/power/power_cli.c index 6e1e34e67e..93d0f232ac 100644 --- a/applications/services/power/power_cli.c +++ b/applications/services/power/power_cli.c @@ -17,13 +17,15 @@ void power_cli_off(Cli* cli, FuriString* args) { void power_cli_reboot(Cli* cli, FuriString* args) { UNUSED(cli); UNUSED(args); - power_reboot(PowerBootModeNormal); + Power* power = furi_record_open(RECORD_POWER); + power_reboot(power, PowerBootModeNormal); } void power_cli_reboot2dfu(Cli* cli, FuriString* args) { UNUSED(cli); UNUSED(args); - power_reboot(PowerBootModeDfu); + Power* power = furi_record_open(RECORD_POWER); + power_reboot(power, PowerBootModeDfu); } void power_cli_5v(Cli* cli, FuriString* args) { diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index 636a2bc983..2773e9fe80 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -4,10 +4,18 @@ #include #include -#define POWER_OFF_TIMEOUT 90 -#define TAG "Power" +#include +#include -void power_draw_battery_callback(Canvas* canvas, void* context) { +#define TAG "Power" + +#define POWER_OFF_TIMEOUT_S (90U) +#define POWER_POLL_PERIOD_MS (1000UL) + +#define POWER_VBUS_LOW_THRESHOLD (4.0f) +#define POWER_HEALTH_LOW_THRESHOLD (70U) + +static void power_draw_battery_callback(Canvas* canvas, void* context) { furi_assert(context); Power* power = context; canvas_draw_icon(canvas, 0, 0, &I_Battery_26x8); @@ -219,6 +227,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { } canvas_set_bitmap_mode(canvas, 0); } + } else { canvas_draw_box(canvas, 8, 3, 8, 2); } @@ -228,99 +237,61 @@ static ViewPort* power_battery_view_port_alloc(Power* power) { ViewPort* battery_view_port = view_port_alloc(); view_port_set_width(battery_view_port, icon_get_width(&I_Battery_26x8)); view_port_draw_callback_set(battery_view_port, power_draw_battery_callback, power); - gui_add_view_port(power->gui, battery_view_port, GuiLayerStatusBarRight); return battery_view_port; } -Power* power_alloc(void) { - Power* power = malloc(sizeof(Power)); - - // Records - power->notification = furi_record_open(RECORD_NOTIFICATION); - power->gui = furi_record_open(RECORD_GUI); - - // Pubsub - power->event_pubsub = furi_pubsub_alloc(); - - // State initialization - power->state = PowerStateNotCharging; - power->battery_low = false; - power->power_off_timeout = POWER_OFF_TIMEOUT; - power->api_mtx = furi_mutex_alloc(FuriMutexTypeNormal); - - // Gui - power->view_dispatcher = view_dispatcher_alloc(); - power->power_off = power_off_alloc(); - view_dispatcher_add_view( - power->view_dispatcher, PowerViewOff, power_off_get_view(power->power_off)); - power->power_unplug_usb = power_unplug_usb_alloc(); - view_dispatcher_add_view( - power->view_dispatcher, - PowerViewUnplugUsb, - power_unplug_usb_get_view(power->power_unplug_usb)); - view_dispatcher_attach_to_gui( - power->view_dispatcher, power->gui, ViewDispatcherTypeFullscreen); - - // Battery view port - power->battery_view_port = power_battery_view_port_alloc(power); - power->show_low_bat_level_message = true; - - return power; +static bool power_update_info(Power* power) { + const PowerInfo info = { + .is_charging = furi_hal_power_is_charging(), + .gauge_is_ok = furi_hal_power_gauge_is_ok(), + .is_shutdown_requested = furi_hal_power_is_shutdown_requested(), + .charge = furi_hal_power_get_pct(), + .health = furi_hal_power_get_bat_health_pct(), + .capacity_remaining = furi_hal_power_get_battery_remaining_capacity(), + .capacity_full = furi_hal_power_get_battery_full_capacity(), + .current_charger = furi_hal_power_get_battery_current(FuriHalPowerICCharger), + .current_gauge = furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge), + .voltage_battery_charge_limit = furi_hal_power_get_battery_charge_voltage_limit(), + .voltage_charger = furi_hal_power_get_battery_voltage(FuriHalPowerICCharger), + .voltage_gauge = furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge), + .voltage_vbus = furi_hal_power_get_usb_voltage(), + .temperature_charger = furi_hal_power_get_battery_temperature(FuriHalPowerICCharger), + .temperature_gauge = furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge), + }; + + const bool need_refresh = (power->info.charge != info.charge) || + (power->info.is_charging != info.is_charging); + power->info = info; + return need_refresh; } static void power_check_charging_state(Power* power) { + NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); + if(furi_hal_power_is_charging()) { if((power->info.charge == 100) || (furi_hal_power_is_charging_done())) { if(power->state != PowerStateCharged) { - notification_internal_message(power->notification, &sequence_charged); + notification_internal_message(notification, &sequence_charged); power->state = PowerStateCharged; power->event.type = PowerEventTypeFullyCharged; furi_pubsub_publish(power->event_pubsub, &power->event); } - } else { - if(power->state != PowerStateCharging) { - notification_internal_message(power->notification, &sequence_charging); - power->state = PowerStateCharging; - power->event.type = PowerEventTypeStartCharging; - furi_pubsub_publish(power->event_pubsub, &power->event); - } - } - } else { - if(power->state != PowerStateNotCharging) { - notification_internal_message(power->notification, &sequence_not_charging); - power->state = PowerStateNotCharging; - power->event.type = PowerEventTypeStopCharging; + + } else if(power->state != PowerStateCharging) { + notification_internal_message(notification, &sequence_charging); + power->state = PowerStateCharging; + power->event.type = PowerEventTypeStartCharging; furi_pubsub_publish(power->event_pubsub, &power->event); } - } -} -static bool power_update_info(Power* power) { - PowerInfo info; - - info.is_charging = furi_hal_power_is_charging(); - info.gauge_is_ok = furi_hal_power_gauge_is_ok(); - info.is_shutdown_requested = furi_hal_power_is_shutdown_requested(); - info.charge = furi_hal_power_get_pct(); - info.health = furi_hal_power_get_bat_health_pct(); - info.capacity_remaining = furi_hal_power_get_battery_remaining_capacity(); - info.capacity_full = furi_hal_power_get_battery_full_capacity(); - info.current_charger = furi_hal_power_get_battery_current(FuriHalPowerICCharger); - info.current_gauge = furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge); - info.voltage_battery_charge_limit = furi_hal_power_get_battery_charge_voltage_limit(); - info.voltage_charger = furi_hal_power_get_battery_voltage(FuriHalPowerICCharger); - info.voltage_gauge = furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge); - info.voltage_vbus = furi_hal_power_get_usb_voltage(); - info.temperature_charger = furi_hal_power_get_battery_temperature(FuriHalPowerICCharger); - info.temperature_gauge = furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge); - - furi_mutex_acquire(power->api_mtx, FuriWaitForever); - bool need_refresh = power->info.charge != info.charge; - need_refresh |= power->info.is_charging != info.is_charging; - power->info = info; - furi_mutex_release(power->api_mtx); + } else if(power->state != PowerStateNotCharging) { + notification_internal_message(notification, &sequence_not_charging); + power->state = PowerStateNotCharging; + power->event.type = PowerEventTypeStopCharging; + furi_pubsub_publish(power->event_pubsub, &power->event); + } - return need_refresh; + furi_record_close(RECORD_NOTIFICATION); } static void power_check_low_battery(Power* power) { @@ -329,40 +300,41 @@ static void power_check_low_battery(Power* power) { } // Check battery charge and vbus voltage - if((power->info.is_shutdown_requested) && (power->info.voltage_vbus < 4.0f) && - power->show_low_bat_level_message) { + if((power->info.is_shutdown_requested) && + (power->info.voltage_vbus < POWER_VBUS_LOW_THRESHOLD) && power->show_battery_low_warning) { if(!power->battery_low) { - view_dispatcher_send_to_front(power->view_dispatcher); - view_dispatcher_switch_to_view(power->view_dispatcher, PowerViewOff); + view_holder_send_to_front(power->view_holder); + view_holder_set_view(power->view_holder, power_off_get_view(power->view_power_off)); } power->battery_low = true; } else { if(power->battery_low) { - view_dispatcher_switch_to_view(power->view_dispatcher, VIEW_NONE); - power->power_off_timeout = POWER_OFF_TIMEOUT; + // view_dispatcher_switch_to_view(power->view_dispatcher, VIEW_NONE); + view_holder_set_view(power->view_holder, NULL); + power->power_off_timeout = POWER_OFF_TIMEOUT_S; } power->battery_low = false; } // If battery low, update view and switch off power after timeout if(power->battery_low) { - PowerOffResponse response = power_off_get_response(power->power_off); + PowerOffResponse response = power_off_get_response(power->view_power_off); if(response == PowerOffResponseDefault) { if(power->power_off_timeout) { - power_off_set_time_left(power->power_off, power->power_off_timeout--); + power_off_set_time_left(power->view_power_off, power->power_off_timeout--); } else { power_off(power); } } else if(response == PowerOffResponseOk) { power_off(power); } else if(response == PowerOffResponseHide) { - view_dispatcher_switch_to_view(power->view_dispatcher, VIEW_NONE); + view_holder_set_view(power->view_holder, NULL); if(power->power_off_timeout) { - power_off_set_time_left(power->power_off, power->power_off_timeout--); + power_off_set_time_left(power->view_power_off, power->power_off_timeout--); } else { power_off(power); } } else if(response == PowerOffResponseCancel) { - view_dispatcher_switch_to_view(power->view_dispatcher, VIEW_NONE); + view_holder_set_view(power->view_holder, NULL); } } } @@ -378,62 +350,148 @@ static void power_check_battery_level_change(Power* power) { void power_trigger_ui_update(Power* power) { DesktopSettings* settings = malloc(sizeof(DesktopSettings)); - bool is_loaded = DESKTOP_SETTINGS_LOAD(settings); - if(is_loaded) { - power->displayBatteryPercentage = settings->displayBatteryPercentage; - } else { - power->displayBatteryPercentage = DISPLAY_BATTERY_BAR; - } + desktop_settings_load(settings); + power->displayBatteryPercentage = settings->displayBatteryPercentage; free(settings); view_port_update(power->battery_view_port); } -int32_t power_srv(void* p) { - UNUSED(p); +static void power_handle_shutdown(Power* power) { + furi_hal_power_off(); + // Notify user if USB is plugged + view_holder_send_to_front(power->view_holder); + view_holder_set_view( + power->view_holder, power_unplug_usb_get_view(power->view_power_unplug_usb)); + furi_delay_ms(100); + furi_halt("Disconnect USB for safe shutdown"); +} - if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { - FURI_LOG_W(TAG, "Skipping start in special boot mode"); +static void power_handle_reboot(PowerBootMode mode) { + if(mode == PowerBootModeNormal) { + update_operation_disarm(); + } else if(mode == PowerBootModeDfu) { + furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeDfu); + } else if(mode == PowerBootModeUpdateStart) { + furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePreUpdate); + } else { + furi_crash(); + } - furi_thread_suspend(furi_thread_get_current_id()); - return 0; + furi_hal_power_reset(); +} + +static bool power_message_callback(FuriEventLoopObject* object, void* context) { + furi_assert(context); + Power* power = context; + + furi_assert(object == power->message_queue); + + PowerMessage msg; + furi_check(furi_message_queue_get(power->message_queue, &msg, 0) == FuriStatusOk); + + switch(msg.type) { + case PowerMessageTypeShutdown: + power_handle_shutdown(power); + break; + case PowerMessageTypeReboot: + power_handle_reboot(msg.boot_mode); + break; + case PowerMessageTypeGetInfo: + *msg.power_info = power->info; + break; + case PowerMessageTypeIsBatteryHealthy: + *msg.bool_param = power->info.health > POWER_HEALTH_LOW_THRESHOLD; + break; + case PowerMessageTypeShowBatteryLowWarning: + power->show_battery_low_warning = *msg.bool_param; + break; + default: + furi_crash(); } - Power* power = power_alloc(); - power_update_info(power); - furi_record_create(RECORD_POWER, power); + if(msg.lock) { + api_lock_unlock(msg.lock); + } + return true; +} + +static void power_tick_callback(void* context) { + furi_assert(context); + Power* power = context; + + // Update data from gauge and charger + const bool need_refresh = power_update_info(power); + // Check low battery level + power_check_low_battery(power); + // Check and notify about charging state + power_check_charging_state(power); + // Check and notify about battery level change + power_check_battery_level_change(power); + // Update battery view port + if(need_refresh) { + view_port_update(power->battery_view_port); + } + // Check OTG status and disable it in case of fault + if(furi_hal_power_is_otg_enabled()) { + furi_hal_power_check_otg_status(); + } +} + +static Power* power_alloc(void) { + Power* power = malloc(sizeof(Power)); + // Pubsub + power->event_pubsub = furi_pubsub_alloc(); + // State initialization + power->power_off_timeout = POWER_OFF_TIMEOUT_S; + power->show_battery_low_warning = true; + + // Load UI settings DesktopSettings* settings = malloc(sizeof(DesktopSettings)); - DESKTOP_SETTINGS_LOAD(settings); + desktop_settings_load(settings); power->displayBatteryPercentage = settings->displayBatteryPercentage; free(settings); + // Gui + Gui* gui = furi_record_open(RECORD_GUI); - while(1) { - // Update data from gauge and charger - bool need_refresh = power_update_info(power); - - // Check low battery level - power_check_low_battery(power); + power->view_holder = view_holder_alloc(); + power->view_power_off = power_off_alloc(); + power->view_power_unplug_usb = power_unplug_usb_alloc(); - // Check and notify about charging state - power_check_charging_state(power); + view_holder_attach_to_gui(power->view_holder, gui); + // Battery view port + power->battery_view_port = power_battery_view_port_alloc(power); + gui_add_view_port(gui, power->battery_view_port, GuiLayerStatusBarRight); + // Event loop + power->event_loop = furi_event_loop_alloc(); + power->message_queue = furi_message_queue_alloc(4, sizeof(PowerMessage)); + + furi_event_loop_subscribe_message_queue( + power->event_loop, + power->message_queue, + FuriEventLoopEventIn, + power_message_callback, + power); + furi_event_loop_tick_set(power->event_loop, 1000, power_tick_callback, power); - // Check and notify about battery level change - power_check_battery_level_change(power); + return power; +} - // Update battery view port - if(need_refresh) { - view_port_update(power->battery_view_port); - } +int32_t power_srv(void* p) { + UNUSED(p); - // Check OTG status and disable it in case of fault - if(furi_hal_power_is_otg_enabled()) { - furi_hal_power_check_otg_status(); - } + if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { + FURI_LOG_W(TAG, "Skipping start in special boot mode"); - furi_delay_ms(1000); + furi_thread_suspend(furi_thread_get_current_id()); + return 0; } - furi_crash("That was unexpected"); + Power* power = power_alloc(); + power_update_info(power); + + furi_record_create(RECORD_POWER, power); + furi_event_loop_run(power->event_loop); return 0; } diff --git a/applications/services/power/power_service/power.h b/applications/services/power/power_service/power.h index e43651ea28..34d58353a2 100644 --- a/applications/services/power/power_service/power.h +++ b/applications/services/power/power_service/power.h @@ -1,9 +1,10 @@ #pragma once #include -#include #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -65,7 +66,7 @@ void power_off(Power* power); * * @param mode PowerBootMode */ -void power_reboot(PowerBootMode mode); +void power_reboot(Power* power, PowerBootMode mode); /** Get power info * diff --git a/applications/services/power/power_service/power_api.c b/applications/services/power/power_service/power_api.c index 1bb482bf52..6f7515f5e4 100644 --- a/applications/services/power/power_service/power_api.c +++ b/applications/services/power/power_service/power_api.c @@ -1,41 +1,39 @@ #include "power_i.h" -#include -#include -#include - void power_off(Power* power) { furi_check(power); - furi_hal_power_off(); - // Notify user if USB is plugged - view_dispatcher_send_to_front(power->view_dispatcher); - view_dispatcher_switch_to_view(power->view_dispatcher, PowerViewUnplugUsb); - furi_delay_ms(100); - furi_halt("Disconnect USB for safe shutdown"); + PowerMessage msg = { + .type = PowerMessageTypeShutdown, + }; + + furi_check( + furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk); } -void power_reboot(PowerBootMode mode) { - if(mode == PowerBootModeNormal) { - update_operation_disarm(); - } else if(mode == PowerBootModeDfu) { - furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeDfu); - } else if(mode == PowerBootModeUpdateStart) { - furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePreUpdate); - } else { - furi_crash(); - } - - furi_hal_power_reset(); +void power_reboot(Power* power, PowerBootMode mode) { + PowerMessage msg = { + .type = PowerMessageTypeReboot, + .boot_mode = mode, + }; + + furi_check( + furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk); } void power_get_info(Power* power, PowerInfo* info) { furi_check(power); furi_check(info); - furi_mutex_acquire(power->api_mtx, FuriWaitForever); - memcpy(info, &power->info, sizeof(power->info)); - furi_mutex_release(power->api_mtx); + PowerMessage msg = { + .type = PowerMessageTypeGetInfo, + .power_info = info, + .lock = api_lock_alloc_locked(), + }; + + furi_check( + furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk); + api_lock_wait_unlock_and_free(msg.lock); } FuriPubSub* power_get_pubsub(Power* power) { @@ -45,16 +43,30 @@ FuriPubSub* power_get_pubsub(Power* power) { bool power_is_battery_healthy(Power* power) { furi_check(power); - bool is_healthy = false; - furi_mutex_acquire(power->api_mtx, FuriWaitForever); - is_healthy = power->info.health > POWER_BATTERY_HEALTHY_LEVEL; - furi_mutex_release(power->api_mtx); - return is_healthy; + + bool ret = false; + + PowerMessage msg = { + .type = PowerMessageTypeIsBatteryHealthy, + .lock = api_lock_alloc_locked(), + .bool_param = &ret, + }; + + furi_check( + furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk); + api_lock_wait_unlock_and_free(msg.lock); + + return ret; } void power_enable_low_battery_level_notification(Power* power, bool enable) { furi_check(power); - furi_mutex_acquire(power->api_mtx, FuriWaitForever); - power->show_low_bat_level_message = enable; - furi_mutex_release(power->api_mtx); + + PowerMessage msg = { + .type = PowerMessageTypeShowBatteryLowWarning, + .bool_param = &enable, + }; + + furi_check( + furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk); } diff --git a/applications/services/power/power_service/power_i.h b/applications/services/power/power_service/power_i.h index a09a6f072f..d75071f8f6 100644 --- a/applications/services/power/power_service/power_i.h +++ b/applications/services/power/power_service/power_i.h @@ -2,19 +2,15 @@ #include "power.h" -#include -#include #include +#include + +#include #include -#include #include "views/power_off.h" #include "views/power_unplug_usb.h" -#include - -#define POWER_BATTERY_HEALTHY_LEVEL 70 - typedef enum { PowerStateNotCharging, PowerStateCharging, @@ -22,29 +18,45 @@ typedef enum { } PowerState; struct Power { - ViewDispatcher* view_dispatcher; - PowerOff* power_off; - PowerUnplugUsb* power_unplug_usb; + ViewHolder* view_holder; + FuriPubSub* event_pubsub; + FuriEventLoop* event_loop; + FuriMessageQueue* message_queue; ViewPort* battery_view_port; - Gui* gui; - NotificationApp* notification; - FuriPubSub* event_pubsub; - PowerEvent event; + PowerOff* view_power_off; + PowerUnplugUsb* view_power_unplug_usb; + PowerEvent event; PowerState state; PowerInfo info; bool battery_low; - bool show_low_bat_level_message; + bool show_battery_low_warning; uint8_t displayBatteryPercentage; uint8_t battery_level; uint8_t power_off_timeout; - - FuriMutex* api_mtx; }; typedef enum { PowerViewOff, PowerViewUnplugUsb, } PowerView; + +typedef enum { + PowerMessageTypeShutdown, + PowerMessageTypeReboot, + PowerMessageTypeGetInfo, + PowerMessageTypeIsBatteryHealthy, + PowerMessageTypeShowBatteryLowWarning, +} PowerMessageType; + +typedef struct { + PowerMessageType type; + union { + PowerBootMode boot_mode; + PowerInfo* power_info; + bool* bool_param; + }; + FuriApiLock lock; +} PowerMessage; diff --git a/applications/services/power/power_service/views/power_off.c b/applications/services/power/power_service/views/power_off.c index 4da374b31a..dbc233dde5 100644 --- a/applications/services/power/power_service/views/power_off.c +++ b/applications/services/power/power_service/views/power_off.c @@ -33,7 +33,7 @@ static void power_off_draw_callback(Canvas* canvas, void* _model) { elements_button_center(canvas, "OK"); elements_button_right(canvas, "Hide"); } else { - snprintf(buff, sizeof(buff), "Charge me!\nDont't forget!"); + snprintf(buff, sizeof(buff), "Charge me!\nDon't forget!"); elements_multiline_text_aligned(canvas, 70, 23, AlignLeft, AlignTop, buff); canvas_draw_str_aligned(canvas, 64, 60, AlignCenter, AlignBottom, "Hold a second..."); diff --git a/applications/services/region/application.fam b/applications/services/region/application.fam new file mode 100644 index 0000000000..a4cdc94ea5 --- /dev/null +++ b/applications/services/region/application.fam @@ -0,0 +1,10 @@ +App( + appid="region", + name="RegionSrv", + apptype=FlipperAppType.STARTUP, + targets=["f7"], + entry_point="region_on_system_start", + cdefines=["SRV_REGION"], + requires=["storage"], + order=170, +) diff --git a/applications/services/region/region.c b/applications/services/region/region.c new file mode 100644 index 0000000000..dffcc6b2d5 --- /dev/null +++ b/applications/services/region/region.c @@ -0,0 +1,147 @@ +#include + +#include +#include + +#include +#include + +#define TAG "RegionSrv" + +#define SUBGHZ_REGION_FILENAME INT_PATH(".region_data") + +static bool region_istream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { + File* file = istream->state; + size_t ret = storage_file_read(file, buf, count); + return count == ret; +} + +static bool region_istream_decode_band(pb_istream_t* stream, const pb_field_t* field, void** arg) { + UNUSED(field); + + FuriHalRegion* region = *arg; + + PB_Region_Band band = {0}; + if(!pb_decode(stream, PB_Region_Band_fields, &band)) { + FURI_LOG_E(TAG, "PB Region band decode error: %s", PB_GET_ERROR(stream)); + return false; + } + + region->bands_count += 1; + region = realloc( //-V701 + region, + sizeof(FuriHalRegion) + sizeof(FuriHalRegionBand) * region->bands_count); + size_t pos = region->bands_count - 1; + region->bands[pos].start = band.start; + region->bands[pos].end = band.end; + region->bands[pos].power_limit = band.power_limit; + region->bands[pos].duty_cycle = band.duty_cycle; + *arg = region; + + FURI_LOG_I( + TAG, + "Add allowed band: start %luHz, stop %luHz, power_limit %ddBm, duty_cycle %u%%", + band.start, + band.end, + band.power_limit, + band.duty_cycle); + return true; +} + +static int32_t region_load_file(void* context) { + UNUSED(context); + + Storage* storage = furi_record_open(RECORD_STORAGE); + File* file = storage_file_alloc(storage); + + PB_Region pb_region = {0}; + pb_region.bands.funcs.decode = region_istream_decode_band; + + do { + FileInfo fileinfo = {0}; + + if(storage_common_stat(storage, SUBGHZ_REGION_FILENAME, &fileinfo) != FSE_OK || + fileinfo.size == 0) { + FURI_LOG_W(TAG, "Region file missing or empty"); + break; + + } else if(!storage_file_open(file, SUBGHZ_REGION_FILENAME, FSAM_READ, FSOM_OPEN_EXISTING)) { + FURI_LOG_E(TAG, "Failed to open region file"); + break; + } + + pb_istream_t istream = { + .callback = region_istream_read, + .state = file, + .errmsg = NULL, + .bytes_left = fileinfo.size, + }; + + pb_region.bands.arg = malloc(sizeof(FuriHalRegion)); + + if(!pb_decode(&istream, PB_Region_fields, &pb_region)) { + FURI_LOG_E(TAG, "Failed to decode region file"); + free(pb_region.bands.arg); + break; + } + + FuriHalRegion* region = pb_region.bands.arg; + + memcpy( + region->country_code, + pb_region.country_code->bytes, + MIN(pb_region.country_code->size, sizeof(region->country_code) - 1)); + + furi_hal_region_set(region); + + FURI_LOG_I(TAG, "Dynamic region set: %s", region->country_code); + } while(0); + + pb_release(PB_Region_fields, &pb_region); + storage_file_free(file); + furi_record_close(RECORD_STORAGE); + + return 0; +} + +static void region_loader_pending_callback(void* context, uint32_t arg) { + UNUSED(arg); + + FuriThread* loader = context; + furi_thread_join(loader); + furi_thread_free(loader); +} + +static void region_loader_state_callback(FuriThreadState state, void* context) { + UNUSED(context); + + if(state == FuriThreadStateStopped) { + furi_timer_pending_callback(region_loader_pending_callback, furi_thread_get_current(), 0); + } +} + +static void region_storage_callback(const void* message, void* context) { + UNUSED(context); + const StorageEvent* event = message; + + if(event->type == StorageEventTypeCardMount) { + FuriThread* loader = furi_thread_alloc_ex(NULL, 2048, region_load_file, NULL); + furi_thread_set_state_callback(loader, region_loader_state_callback); + furi_thread_start(loader); + } +} + +int32_t region_on_system_start(void* p) { + UNUSED(p); + + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_pubsub_subscribe(storage_get_pubsub(storage), region_storage_callback, NULL); + + if(storage_sd_status(storage) != FSE_OK) { + FURI_LOG_D(TAG, "SD Card not ready, skipping dynamic region"); + return 0; + } + + region_load_file(NULL); + return 0; +} diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index c2aa3e27c3..d5cef52f0a 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -228,7 +228,7 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { } } -#if SRV_RPC_DEBUG +#ifdef SRV_RPC_DEBUG rpc_debug_print_data("INPUT", buf, bytes_received); #endif @@ -268,7 +268,7 @@ static int32_t rpc_session_worker(void* context) { bool message_decode_failed = false; if(pb_decode_ex(&istream, &PB_Main_msg, session->decoded_message, PB_DECODE_DELIMITED)) { -#if SRV_RPC_DEBUG +#ifdef SRV_RPC_DEBUG FURI_LOG_I(TAG, "INPUT:"); rpc_debug_print_message(session->decoded_message); #endif @@ -452,7 +452,7 @@ void rpc_send(RpcSession* session, PB_Main* message) { pb_ostream_t ostream = PB_OSTREAM_SIZING; -#if SRV_RPC_DEBUG +#ifdef SRV_RPC_DEBUG FURI_LOG_I(TAG, "OUTPUT:"); rpc_debug_print_message(message); #endif @@ -465,7 +465,7 @@ void rpc_send(RpcSession* session, PB_Main* message) { pb_encode_ex(&ostream, &PB_Main_msg, message, PB_ENCODE_DELIMITED); -#if SRV_RPC_DEBUG +#ifdef SRV_RPC_DEBUG rpc_debug_print_data("OUTPUT", buffer, ostream.bytes_written); #endif diff --git a/applications/services/rpc/rpc_system.c b/applications/services/rpc/rpc_system.c index 0b9fd33f95..1cc0f90eb2 100644 --- a/applications/services/rpc/rpc_system.c +++ b/applications/services/rpc/rpc_system.c @@ -54,18 +54,21 @@ static void rpc_system_system_reboot_process(const PB_Main* request, void* conte RpcSession* session = (RpcSession*)context; furi_assert(session); + Power* power = furi_record_open(RECORD_POWER); const int mode = request->content.system_reboot_request.mode; if(mode == PB_System_RebootRequest_RebootMode_OS) { - power_reboot(PowerBootModeNormal); + power_reboot(power, PowerBootModeNormal); } else if(mode == PB_System_RebootRequest_RebootMode_DFU) { - power_reboot(PowerBootModeDfu); + power_reboot(power, PowerBootModeDfu); } else if(mode == PB_System_RebootRequest_RebootMode_UPDATE) { - power_reboot(PowerBootModeUpdateStart); + power_reboot(power, PowerBootModeUpdateStart); } else { rpc_send_and_release_empty( session, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS); } + + furi_record_close(RECORD_POWER); } static void rpc_system_system_device_info_callback( @@ -181,9 +184,9 @@ static void rpc_system_system_factory_reset_process(const PB_Main* request, void furi_hal_rtc_reset_registers(); furi_hal_rtc_set_flag(FuriHalRtcFlagStorageFormatInternal); - power_reboot(PowerBootModeNormal); - (void)session; + Power* power = furi_record_open(RECORD_POWER); + power_reboot(power, PowerBootModeNormal); } static void diff --git a/applications/services/storage/storage.c b/applications/services/storage/storage.c index 21f8789cec..bfe2a08b21 100644 --- a/applications/services/storage/storage.c +++ b/applications/services/storage/storage.c @@ -3,7 +3,6 @@ #include "storage_message.h" #include "storage_processing.h" #include "storage/storage_glue.h" -#include "storages/storage_int.h" #include "storages/storage_ext.h" #include @@ -42,9 +41,6 @@ Storage* storage_app_alloc(void) { storage_data_timestamp(&app->storage[i]); } -#ifndef FURI_RAM_EXEC - storage_int_init(&app->storage[ST_INT]); -#endif storage_ext_init(&app->storage[ST_EXT]); // sd icon gui @@ -106,6 +102,11 @@ int32_t storage_srv(void* p) { Storage* app = storage_app_alloc(); furi_record_create(RECORD_STORAGE, app); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStorageFormatInternal)) { + FURI_LOG_W(TAG, "Format Internal not supported, clearing flag"); + furi_hal_rtc_reset_flag(FuriHalRtcFlagStorageFormatInternal); + } + StorageMessage message; while(1) { if(furi_message_queue_get(app->message_queue, &message, STORAGE_TICK) == FuriStatusOk) { diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index a4dffe6330..6dbeb0d36b 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -506,7 +506,7 @@ FS_Error storage_sd_status(Storage* storage); /******************* Internal LFS Functions *******************/ -typedef void (*Storage_name_converter)(FuriString*); +typedef void (*StorageNameConverter)(FuriString*); /** * @brief Back up the internal storage contents to a *.tar archive. @@ -526,7 +526,7 @@ FS_Error storage_int_backup(Storage* storage, const char* dstname); * @return FSE_OK if the storage was successfully restored, any other error code on failure. */ FS_Error - storage_int_restore(Storage* storage, const char* dstname, Storage_name_converter converter); + storage_int_restore(Storage* storage, const char* dstname, StorageNameConverter converter); /***************** Simplified Functions ******************/ diff --git a/applications/services/storage/storage_cli.c b/applications/services/storage/storage_cli.c index 918e796ce3..a18b289408 100644 --- a/applications/services/storage/storage_cli.c +++ b/applications/services/storage/storage_cli.c @@ -33,7 +33,7 @@ static void storage_cli_info(Cli* cli, FuriString* path, FuriString* args) { storage_cli_print_error(error); } else { printf( - "Label: %s\r\nType: LittleFS\r\n%luKiB total\r\n%luKiB free\r\n", + "Label: %s\r\nType: Virtual\r\n%luKiB total\r\n%luKiB free\r\n", furi_hal_version_get_name_ptr() ? furi_hal_version_get_name_ptr() : "Unknown", (uint32_t)(total_space / 1024), (uint32_t)(free_space / 1024)); @@ -675,9 +675,12 @@ static void storage_cli_factory_reset(Cli* cli, FuriString* args, void* context) char c = cli_getc(cli); if(c == 'y' || c == 'Y') { printf("Data will be wiped after reboot.\r\n"); + furi_hal_rtc_reset_registers(); furi_hal_rtc_set_flag(FuriHalRtcFlagStorageFormatInternal); - power_reboot(PowerBootModeNormal); + + Power* power = furi_record_open(RECORD_POWER); + power_reboot(power, PowerBootModeNormal); } else { printf("Safe choice.\r\n"); } diff --git a/applications/services/storage/storage_internal_api.c b/applications/services/storage/storage_internal_api.c index 4cbce7546e..defab966ce 100644 --- a/applications/services/storage/storage_internal_api.c +++ b/applications/services/storage/storage_internal_api.c @@ -14,7 +14,7 @@ FS_Error storage_int_backup(Storage* storage, const char* dstname) { } FS_Error - storage_int_restore(Storage* storage, const char* srcname, Storage_name_converter converter) { + storage_int_restore(Storage* storage, const char* srcname, StorageNameConverter converter) { furi_check(storage); TarArchive* archive = tar_archive_alloc(storage); diff --git a/applications/services/storage/storage_internal_dirname_i.h b/applications/services/storage/storage_internal_dirname_i.h new file mode 100644 index 0000000000..889bdc4976 --- /dev/null +++ b/applications/services/storage/storage_internal_dirname_i.h @@ -0,0 +1,3 @@ +#pragma once + +#define STORAGE_INTERNAL_DIR_NAME ".int" diff --git a/applications/services/storage/storage_processing.c b/applications/services/storage/storage_processing.c index 9e96765b62..8d86dd3851 100644 --- a/applications/services/storage/storage_processing.c +++ b/applications/services/storage/storage_processing.c @@ -1,7 +1,11 @@ -#include "storage_processing.h" #include #include +#include "storage_processing.h" +#include "storage_internal_dirname_i.h" + +#define TAG "Storage" + #define STORAGE_PATH_PREFIX_LEN 4u _Static_assert( sizeof(STORAGE_ANY_PATH_PREFIX) == STORAGE_PATH_PREFIX_LEN + 1, @@ -60,36 +64,27 @@ static StorageType storage_get_type_by_path(FuriString* path) { return type; } -static void storage_path_change_to_real_storage(FuriString* path, StorageType real_storage) { - if(furi_string_search(path, STORAGE_ANY_PATH_PREFIX) == 0) { - switch(real_storage) { - case ST_EXT: - furi_string_replace_at( - path, 0, strlen(STORAGE_EXT_PATH_PREFIX), STORAGE_EXT_PATH_PREFIX); - break; - case ST_INT: - furi_string_replace_at( - path, 0, strlen(STORAGE_INT_PATH_PREFIX), STORAGE_INT_PATH_PREFIX); - break; - default: - break; - } - } -} static FS_Error storage_get_data(Storage* app, FuriString* path, StorageData** storage) { StorageType type = storage_get_type_by_path(path); if(storage_type_is_valid(type)) { + // Any storage phase-out: redirect "/any" to "/ext" if(type == ST_ANY) { - type = ST_INT; - if(storage_data_status(&app->storage[ST_EXT]) == StorageStatusOK) { - type = ST_EXT; - } - storage_path_change_to_real_storage(path, type); + FURI_LOG_W( + TAG, + STORAGE_ANY_PATH_PREFIX " is deprecated, use " STORAGE_EXT_PATH_PREFIX " instead"); + furi_string_replace_at( + path, 0, strlen(STORAGE_EXT_PATH_PREFIX), STORAGE_EXT_PATH_PREFIX); + type = ST_EXT; + } + + furi_assert(type == ST_EXT); + + if(storage_data_status(&app->storage[type]) != StorageStatusOK) { + return FSE_NOT_READY; } - furi_assert(type == ST_EXT || type == ST_INT); *storage = &app->storage[type]; return FSE_OK; @@ -559,6 +554,16 @@ void storage_process_alias( furi_string_get_cstr(apps_assets_path_with_appsid)); furi_string_free(apps_assets_path_with_appsid); + + } else if(furi_string_start_with(path, STORAGE_INT_PATH_PREFIX)) { + furi_string_replace_at( + path, 0, strlen(STORAGE_INT_PATH_PREFIX), EXT_PATH(STORAGE_INTERNAL_DIR_NAME)); + + FuriString* int_on_ext_path = furi_string_alloc_set(EXT_PATH(STORAGE_INTERNAL_DIR_NAME)); + if(storage_process_common_stat(app, int_on_ext_path, NULL) != FSE_OK) { + storage_process_common_mkdir(app, int_on_ext_path); + } + furi_string_free(int_on_ext_path); } } diff --git a/applications/services/storage/storages/storage_ext.c b/applications/services/storage/storages/storage_ext.c index 93e06f6632..a945f1cd51 100644 --- a/applications/services/storage/storages/storage_ext.c +++ b/applications/services/storage/storages/storage_ext.c @@ -1,10 +1,13 @@ -#include "fatfs.h" -#include "../filesystem_api_internal.h" -#include "storage_ext.h" +#include #include -#include "sd_notify.h" #include +#include "sd_notify.h" +#include "storage_ext.h" + +#include "../filesystem_api_internal.h" +#include "../storage_internal_dirname_i.h" + typedef FIL SDFile; typedef DIR SDDir; typedef FILINFO SDFileInfo; @@ -93,6 +96,64 @@ static bool sd_mount_card_internal(StorageData* storage, bool notify) { return result; } +static bool sd_remove_recursive(const char* path) { + SDDir* current_dir = malloc(sizeof(DIR)); + SDFileInfo* file_info = malloc(sizeof(FILINFO)); + FuriString* current_path = furi_string_alloc_set(path); + + bool go_deeper = false; + SDError status; + + while(true) { + status = f_opendir(current_dir, furi_string_get_cstr(current_path)); + if(status != FR_OK) break; + + while(true) { + status = f_readdir(current_dir, file_info); + if(status != FR_OK || !strlen(file_info->fname)) break; + + if(file_info->fattrib & AM_DIR) { + furi_string_cat_printf(current_path, "/%s", file_info->fname); + go_deeper = true; + break; + + } else { + FuriString* file_path = furi_string_alloc_printf( + "%s/%s", furi_string_get_cstr(current_path), file_info->fname); + status = f_unlink(furi_string_get_cstr(file_path)); + furi_string_free(file_path); + + if(status != FR_OK) break; + } + } + + status = f_closedir(current_dir); + if(status != FR_OK) break; + + if(go_deeper) { + go_deeper = false; + continue; + } + + status = f_unlink(furi_string_get_cstr(current_path)); + if(status != FR_OK) break; + + if(!furi_string_equal(current_path, path)) { + size_t last_char_pos = furi_string_search_rchar(current_path, '/'); + furi_assert(last_char_pos != FURI_STRING_FAILURE); + furi_string_left(current_path, last_char_pos); + } else { + break; + } + } + + free(current_dir); + free(file_info); + furi_string_free(current_path); + + return status == FR_OK; +} + FS_Error sd_unmount_card(StorageData* storage) { SDData* sd_data = storage->data; SDError error; @@ -112,21 +173,32 @@ FS_Error sd_mount_card(StorageData* storage, bool notify) { if(storage->status != StorageStatusOK) { FURI_LOG_E(TAG, "sd init error: %s", storage_data_status_text(storage)); - if(notify) { - NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - sd_notify_error(notification); - furi_record_close(RECORD_NOTIFICATION); - } error = FSE_INTERNAL; + } else { FURI_LOG_I(TAG, "card mounted"); - if(notify) { - NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - sd_notify_success(notification); - furi_record_close(RECORD_NOTIFICATION); - } +#ifndef FURI_RAM_EXEC + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStorageFormatInternal)) { + FURI_LOG_I(TAG, "deleting internal storage directory"); + error = sd_remove_recursive(STORAGE_INTERNAL_DIR_NAME) ? FSE_OK : FSE_INTERNAL; + } else { + error = FSE_OK; + } +#else + UNUSED(sd_remove_recursive); error = FSE_OK; +#endif + } + + if(notify) { + NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); + if(error != FSE_OK) { + sd_notify_error(notification); + } else { + sd_notify_success(notification); + } + furi_record_close(RECORD_NOTIFICATION); } return error; @@ -654,4 +726,8 @@ void storage_ext_init(StorageData* storage) { // do not notify on first launch, notifications app is waiting for our thread to read settings storage_ext_tick_internal(storage, false); +#ifndef FURI_RAM_EXEC + // always reset the flag to prevent accidental wipe on SD card insertion + furi_hal_rtc_reset_flag(FuriHalRtcFlagStorageFormatInternal); +#endif } diff --git a/applications/services/storage/storages/storage_int.c b/applications/services/storage/storages/storage_int.c deleted file mode 100644 index 324ce63286..0000000000 --- a/applications/services/storage/storages/storage_int.c +++ /dev/null @@ -1,744 +0,0 @@ -#include "storage_int.h" -#include -#include -#include - -#define TAG "StorageInt" - -#define STORAGE_PATH STORAGE_INT_PATH_PREFIX -#define LFS_CLEAN_FINGERPRINT 0 - -/* When less than LFS_RESERVED_PAGES_COUNT are left free, creation & - * modification of non-dot files is restricted */ -#define LFS_RESERVED_PAGES_COUNT 3 - -typedef struct { - const size_t start_address; - const size_t start_page; - struct lfs_config config; - lfs_t lfs; -} LFSData; - -typedef struct { - void* data; - bool open; -} LFSHandle; - -static LFSHandle* lfs_handle_alloc_file(void) { - LFSHandle* handle = malloc(sizeof(LFSHandle)); - handle->data = malloc(sizeof(lfs_file_t)); - return handle; -} - -static LFSHandle* lfs_handle_alloc_dir(void) { - LFSHandle* handle = malloc(sizeof(LFSHandle)); - handle->data = malloc(sizeof(lfs_dir_t)); - return handle; -} - -/* INTERNALS */ - -static lfs_dir_t* lfs_handle_get_dir(LFSHandle* handle) { - return handle->data; -} - -static lfs_file_t* lfs_handle_get_file(LFSHandle* handle) { - return handle->data; -} - -static void lfs_handle_free(LFSHandle* handle) { - free(handle->data); - free(handle); -} - -static void lfs_handle_set_open(LFSHandle* handle) { - handle->open = true; -} - -static bool lfs_handle_is_open(LFSHandle* handle) { - return handle->open; -} - -static lfs_t* lfs_get_from_storage(StorageData* storage) { - return &((LFSData*)storage->data)->lfs; -} - -static LFSData* lfs_data_get_from_storage(StorageData* storage) { - return (LFSData*)storage->data; -} - -static int storage_int_device_read( - const struct lfs_config* c, - lfs_block_t block, - lfs_off_t off, - void* buffer, - lfs_size_t size) { - LFSData* lfs_data = c->context; - size_t address = lfs_data->start_address + block * c->block_size + off; - - FURI_LOG_T( - TAG, - "Device read: block %lu, off %lu, buffer: %p, size %lu, translated address: %p", - block, - off, - buffer, - size, - (void*)address); - - memcpy(buffer, (void*)address, size); - - return 0; -} - -static int storage_int_device_prog( - const struct lfs_config* c, - lfs_block_t block, - lfs_off_t off, - const void* buffer, - lfs_size_t size) { - LFSData* lfs_data = c->context; - size_t address = lfs_data->start_address + block * c->block_size + off; - - FURI_LOG_T( - TAG, - "Device prog: block %lu, off %lu, buffer: %p, size %lu, translated address: %p", - block, - off, - buffer, - size, - (void*)address); - - int ret = 0; - while(size > 0) { - furi_hal_flash_write_dword(address, *(uint64_t*)buffer); - address += c->prog_size; - buffer += c->prog_size; - size -= c->prog_size; - } - - return ret; -} - -static int storage_int_device_erase(const struct lfs_config* c, lfs_block_t block) { - LFSData* lfs_data = c->context; - size_t page = lfs_data->start_page + block; - - FURI_LOG_D(TAG, "Device erase: page %lu, translated page: %zx", block, page); - - furi_hal_flash_erase(page); - return 0; -} - -static int storage_int_device_sync(const struct lfs_config* c) { - UNUSED(c); - FURI_LOG_D(TAG, "Device sync: skipping"); - return 0; -} - -static LFSData* storage_int_lfs_data_alloc(void) { - LFSData* lfs_data = malloc(sizeof(LFSData)); - - // Internal storage start address - *(size_t*)(&lfs_data->start_address) = furi_hal_flash_get_free_page_start_address(); - *(size_t*)(&lfs_data->start_page) = - (lfs_data->start_address - furi_hal_flash_get_base()) / furi_hal_flash_get_page_size(); - - // LFS configuration - // Glue and context - lfs_data->config.context = lfs_data; - lfs_data->config.read = storage_int_device_read; - lfs_data->config.prog = storage_int_device_prog; - lfs_data->config.erase = storage_int_device_erase; - lfs_data->config.sync = storage_int_device_sync; - - // Block device description - lfs_data->config.read_size = furi_hal_flash_get_read_block_size(); - lfs_data->config.prog_size = furi_hal_flash_get_write_block_size(); - lfs_data->config.block_size = furi_hal_flash_get_page_size(); - lfs_data->config.block_count = furi_hal_flash_get_free_page_count(); - lfs_data->config.block_cycles = furi_hal_flash_get_cycles_count(); - lfs_data->config.cache_size = 16; - lfs_data->config.lookahead_size = 16; - - return lfs_data; -} - -// Returns true if fingerprint was invalid and LFS reformatting is needed -static bool storage_int_check_and_set_fingerprint(LFSData* lfs_data) { - bool value = false; - - uint32_t os_fingerprint = 0; - os_fingerprint |= ((lfs_data->start_page & 0xFF) << 0); - os_fingerprint |= ((lfs_data->config.block_count & 0xFF) << 8); - os_fingerprint |= ((LFS_DISK_VERSION_MAJOR & 0xFFFF) << 16); - - uint32_t rtc_fingerprint = furi_hal_rtc_get_register(FuriHalRtcRegisterLfsFingerprint); - if(rtc_fingerprint == LFS_CLEAN_FINGERPRINT) { - FURI_LOG_I(TAG, "Storing LFS fingerprint in RTC"); - furi_hal_rtc_set_register(FuriHalRtcRegisterLfsFingerprint, os_fingerprint); - } else if(rtc_fingerprint != os_fingerprint) { - FURI_LOG_E(TAG, "LFS fingerprint mismatch"); - furi_hal_rtc_set_register(FuriHalRtcRegisterLfsFingerprint, os_fingerprint); - value = true; - } - - return value; -} - -static void storage_int_lfs_mount(LFSData* lfs_data, StorageData* storage) { - int err; - lfs_t* lfs = &lfs_data->lfs; - - bool was_fingerprint_outdated = storage_int_check_and_set_fingerprint(lfs_data); - bool need_format = furi_hal_rtc_is_flag_set(FuriHalRtcFlagStorageFormatInternal) || - was_fingerprint_outdated; - - if(need_format) { - // Format storage - err = lfs_format(lfs, &lfs_data->config); - if(err == 0) { - FURI_LOG_I(TAG, "Factory reset: Format successful, trying to mount"); - furi_hal_rtc_reset_flag(FuriHalRtcFlagStorageFormatInternal); - err = lfs_mount(lfs, &lfs_data->config); - if(err == 0) { - FURI_LOG_I(TAG, "Factory reset: Mounted"); - storage->status = StorageStatusOK; - } else { - FURI_LOG_E(TAG, "Factory reset: Mount after format failed"); - storage->status = StorageStatusNotMounted; - } - } else { - FURI_LOG_E(TAG, "Factory reset: Format failed"); - storage->status = StorageStatusNoFS; - } - } else { - // Normal - err = lfs_mount(lfs, &lfs_data->config); - if(err == 0) { - FURI_LOG_I(TAG, "Mounted"); - storage->status = StorageStatusOK; - } else { - FURI_LOG_E(TAG, "Mount failed, formatting"); - err = lfs_format(lfs, &lfs_data->config); - if(err == 0) { - FURI_LOG_I(TAG, "Format successful, trying to mount"); - err = lfs_mount(lfs, &lfs_data->config); - if(err == 0) { - FURI_LOG_I(TAG, "Mounted"); - storage->status = StorageStatusOK; - } else { - FURI_LOG_E(TAG, "Mount after format failed"); - storage->status = StorageStatusNotMounted; - } - } else { - FURI_LOG_E(TAG, "Format failed"); - storage->status = StorageStatusNoFS; - } - } - } -} - -/****************** Common Functions ******************/ - -static FS_Error storage_int_parse_error(int error) { - FS_Error result; - - if(error >= LFS_ERR_OK) { - result = FSE_OK; - } else { - switch(error) { - case LFS_ERR_NOENT: - result = FSE_NOT_EXIST; - break; - case LFS_ERR_EXIST: - result = FSE_EXIST; - break; - case LFS_ERR_NOTEMPTY: - result = FSE_DENIED; - break; - case LFS_ERR_INVAL: - case LFS_ERR_NOATTR: - result = FSE_INVALID_PARAMETER; - break; - case LFS_ERR_BADF: - case LFS_ERR_ISDIR: - case LFS_ERR_NOTDIR: - case LFS_ERR_NAMETOOLONG: - result = FSE_INVALID_NAME; - break; - case LFS_ERR_IO: - case LFS_ERR_FBIG: - case LFS_ERR_NOSPC: - case LFS_ERR_NOMEM: - case LFS_ERR_CORRUPT: - default: - result = FSE_INTERNAL; - } - } - - return result; -} - -/* Returns false if less than reserved space is left free */ -static bool storage_int_check_for_free_space(StorageData* storage) { - LFSData* lfs_data = lfs_data_get_from_storage(storage); - - lfs_ssize_t result = lfs_fs_size(lfs_get_from_storage(storage)); - if(result >= 0) { - lfs_size_t free_space = - (lfs_data->config.block_count - result) * lfs_data->config.block_size; - - return free_space > LFS_RESERVED_PAGES_COUNT * furi_hal_flash_get_page_size(); - } - - return false; -} -/******************* File Functions *******************/ - -static bool storage_int_file_open( - void* ctx, - File* file, - const char* path, - FS_AccessMode access_mode, - FS_OpenMode open_mode) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - - bool enough_free_space = storage_int_check_for_free_space(storage); - - int flags = 0; - - if(access_mode & FSAM_READ) flags |= LFS_O_RDONLY; - if(access_mode & FSAM_WRITE) flags |= LFS_O_WRONLY; - - if(open_mode & FSOM_OPEN_EXISTING) flags |= 0; - if(open_mode & FSOM_OPEN_ALWAYS) flags |= LFS_O_CREAT; - if(open_mode & FSOM_OPEN_APPEND) flags |= LFS_O_CREAT | LFS_O_APPEND; - if(open_mode & FSOM_CREATE_NEW) flags |= LFS_O_CREAT | LFS_O_EXCL; - if(open_mode & FSOM_CREATE_ALWAYS) flags |= LFS_O_CREAT | LFS_O_TRUNC; - - LFSHandle* handle = lfs_handle_alloc_file(); - storage_set_storage_file_data(file, handle, storage); - - if(!enough_free_space) { - FuriString* filename; - filename = furi_string_alloc(); - path_extract_basename(path, filename); - bool is_dot_file = - (!furi_string_empty(filename) && (furi_string_get_char(filename, 0) == '.')); - furi_string_free(filename); - - /* Restrict write & creation access to all non-dot files */ - if(!is_dot_file && (flags & (LFS_O_CREAT | LFS_O_WRONLY))) { - file->internal_error_id = LFS_ERR_NOSPC; - file->error_id = FSE_DENIED; - FURI_LOG_W(TAG, "Denied access to '%s': no free space", path); - return false; - } - } - - file->internal_error_id = lfs_file_open(lfs, lfs_handle_get_file(handle), path, flags); - - if(file->internal_error_id >= LFS_ERR_OK) { - lfs_handle_set_open(handle); - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - - return file->error_id == FSE_OK; -} - -static bool storage_int_file_close(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_file_close(lfs, lfs_handle_get_file(handle)); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - lfs_handle_free(handle); - return file->error_id == FSE_OK; -} - -static uint16_t - storage_int_file_read(void* ctx, File* file, void* buff, uint16_t const bytes_to_read) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - uint16_t bytes_read = 0; - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = - lfs_file_read(lfs, lfs_handle_get_file(handle), buff, bytes_to_read); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - - if(file->error_id == FSE_OK) { - bytes_read = file->internal_error_id; - file->internal_error_id = 0; - } - return bytes_read; -} - -static uint16_t - storage_int_file_write(void* ctx, File* file, const void* buff, uint16_t const bytes_to_write) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - uint16_t bytes_written = 0; - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = - lfs_file_write(lfs, lfs_handle_get_file(handle), buff, bytes_to_write); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - - if(file->error_id == FSE_OK) { - bytes_written = file->internal_error_id; - file->internal_error_id = 0; - } - return bytes_written; -} - -static bool - storage_int_file_seek(void* ctx, File* file, const uint32_t offset, const bool from_start) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - if(from_start) { - file->internal_error_id = - lfs_file_seek(lfs, lfs_handle_get_file(handle), offset, LFS_SEEK_SET); - } else { - file->internal_error_id = - lfs_file_seek(lfs, lfs_handle_get_file(handle), offset, LFS_SEEK_CUR); - } - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - return file->error_id == FSE_OK; -} - -static uint64_t storage_int_file_tell(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_file_tell(lfs, lfs_handle_get_file(handle)); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - - int32_t position = 0; - if(file->error_id == FSE_OK) { - position = file->internal_error_id; - file->internal_error_id = 0; - } - - return position; -} - -static bool storage_int_file_truncate(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_file_tell(lfs, lfs_handle_get_file(handle)); - file->error_id = storage_int_parse_error(file->internal_error_id); - - if(file->error_id == FSE_OK) { - uint32_t position = file->internal_error_id; - file->internal_error_id = - lfs_file_truncate(lfs, lfs_handle_get_file(handle), position); - file->error_id = storage_int_parse_error(file->internal_error_id); - } - } else { - file->internal_error_id = LFS_ERR_BADF; - file->error_id = storage_int_parse_error(file->internal_error_id); - } - - return file->error_id == FSE_OK; -} - -static bool storage_int_file_sync(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_file_sync(lfs, lfs_handle_get_file(handle)); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - return file->error_id == FSE_OK; -} - -static uint64_t storage_int_file_size(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_file_size(lfs, lfs_handle_get_file(handle)); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - - uint32_t size = 0; - if(file->error_id == FSE_OK) { - size = file->internal_error_id; - file->internal_error_id = 0; - } - - return size; -} - -static bool storage_int_file_eof(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - bool eof = true; - - if(lfs_handle_is_open(handle)) { - int32_t position = lfs_file_tell(lfs, lfs_handle_get_file(handle)); - int32_t size = lfs_file_size(lfs, lfs_handle_get_file(handle)); - - if(position < 0) { - file->internal_error_id = position; - } else if(size < 0) { - file->internal_error_id = size; - } else { - file->internal_error_id = LFS_ERR_OK; - eof = (position >= size); - } - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - return eof; -} - -/******************* Dir Functions *******************/ - -static bool storage_int_dir_open(void* ctx, File* file, const char* path) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - - LFSHandle* handle = lfs_handle_alloc_dir(); - storage_set_storage_file_data(file, handle, storage); - - file->internal_error_id = lfs_dir_open(lfs, lfs_handle_get_dir(handle), path); - if(file->internal_error_id >= LFS_ERR_OK) { - lfs_handle_set_open(handle); - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - return file->error_id == FSE_OK; -} - -static bool storage_int_dir_close(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_dir_close(lfs, lfs_handle_get_dir(handle)); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - lfs_handle_free(handle); - return file->error_id == FSE_OK; -} - -static bool storage_int_dir_read( - void* ctx, - File* file, - FileInfo* fileinfo, - char* name, - const uint16_t name_length) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - struct lfs_info _fileinfo; - - // LFS returns virtual directories "." and "..", so we read until we get something meaningful or an empty string - do { - file->internal_error_id = lfs_dir_read(lfs, lfs_handle_get_dir(handle), &_fileinfo); - file->error_id = storage_int_parse_error(file->internal_error_id); - } while(strcmp(_fileinfo.name, ".") == 0 || strcmp(_fileinfo.name, "..") == 0); - - if(fileinfo != NULL) { - fileinfo->size = _fileinfo.size; - fileinfo->flags = 0; - if(_fileinfo.type & LFS_TYPE_DIR) fileinfo->flags |= FSF_DIRECTORY; - } - - if(name != NULL) { - snprintf(name, name_length, "%s", _fileinfo.name); - } - - // set FSE_NOT_EXIST error on end of directory - if(file->internal_error_id == 0) { - file->error_id = FSE_NOT_EXIST; - } - } else { - file->internal_error_id = LFS_ERR_BADF; - file->error_id = storage_int_parse_error(file->internal_error_id); - } - - return file->error_id == FSE_OK; -} - -static bool storage_int_dir_rewind(void* ctx, File* file) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - LFSHandle* handle = storage_get_storage_file_data(file, storage); - - if(lfs_handle_is_open(handle)) { - file->internal_error_id = lfs_dir_rewind(lfs, lfs_handle_get_dir(handle)); - } else { - file->internal_error_id = LFS_ERR_BADF; - } - - file->error_id = storage_int_parse_error(file->internal_error_id); - return file->error_id == FSE_OK; -} - -/******************* Common FS Functions *******************/ - -static FS_Error storage_int_common_stat(void* ctx, const char* path, FileInfo* fileinfo) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - struct lfs_info _fileinfo; - int result = lfs_stat(lfs, path, &_fileinfo); - - if(fileinfo != NULL) { - fileinfo->size = _fileinfo.size; - fileinfo->flags = 0; - if(_fileinfo.type & LFS_TYPE_DIR) fileinfo->flags |= FSF_DIRECTORY; - } - - return storage_int_parse_error(result); -} - -static FS_Error storage_int_common_remove(void* ctx, const char* path) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - int result = lfs_remove(lfs, path); - return storage_int_parse_error(result); -} - -static FS_Error storage_int_common_mkdir(void* ctx, const char* path) { - StorageData* storage = ctx; - lfs_t* lfs = lfs_get_from_storage(storage); - int result = lfs_mkdir(lfs, path); - return storage_int_parse_error(result); -} - -static FS_Error storage_int_common_fs_info( - void* ctx, - const char* fs_path, - uint64_t* total_space, - uint64_t* free_space) { - UNUSED(fs_path); - StorageData* storage = ctx; - - lfs_t* lfs = lfs_get_from_storage(storage); - LFSData* lfs_data = lfs_data_get_from_storage(storage); - - if(total_space) { - *total_space = lfs_data->config.block_size * lfs_data->config.block_count; - } - - lfs_ssize_t result = lfs_fs_size(lfs); - if(free_space && (result >= 0)) { - *free_space = (lfs_data->config.block_count - result) * lfs_data->config.block_size; - } - - return storage_int_parse_error(result); -} - -static bool storage_int_common_equivalent_path(const char* path1, const char* path2) { - return strcmp(path1, path2) == 0; -} - -/******************* Init Storage *******************/ -static const FS_Api fs_api = { - .file = - { - .open = storage_int_file_open, - .close = storage_int_file_close, - .read = storage_int_file_read, - .write = storage_int_file_write, - .seek = storage_int_file_seek, - .tell = storage_int_file_tell, - .truncate = storage_int_file_truncate, - .size = storage_int_file_size, - .sync = storage_int_file_sync, - .eof = storage_int_file_eof, - }, - .dir = - { - .open = storage_int_dir_open, - .close = storage_int_dir_close, - .read = storage_int_dir_read, - .rewind = storage_int_dir_rewind, - }, - .common = - { - .stat = storage_int_common_stat, - .mkdir = storage_int_common_mkdir, - .remove = storage_int_common_remove, - .fs_info = storage_int_common_fs_info, - .equivalent_path = storage_int_common_equivalent_path, - }, -}; - -void storage_int_init(StorageData* storage) { - FURI_LOG_I(TAG, "Starting"); - LFSData* lfs_data = storage_int_lfs_data_alloc(); - FURI_LOG_I( - TAG, - "Config: start %p, read %lu, write %lu, page size: %lu, page count: %lu, cycles: %ld", - (void*)lfs_data->start_address, - lfs_data->config.read_size, - lfs_data->config.prog_size, - lfs_data->config.block_size, - lfs_data->config.block_count, - lfs_data->config.block_cycles); - - storage_int_lfs_mount(lfs_data, storage); - - storage->data = lfs_data; - storage->api.tick = NULL; - storage->fs_api = &fs_api; -} diff --git a/applications/services/storage/storages/storage_int.h b/applications/services/storage/storages/storage_int.h deleted file mode 100644 index 456d72408f..0000000000 --- a/applications/services/storage/storages/storage_int.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include -#include "../storage_glue.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void storage_int_init(StorageData* storage); - -#ifdef __cplusplus -} -#endif diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index a4c2e5b9ef..d9fbca87ad 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -1,9 +1,12 @@ #include -#include + #include -#include +#include #include + +#include #include + #include #include #include @@ -202,18 +205,15 @@ int32_t about_settings_app(void* p) { DialogMessage* message = dialog_message_alloc(); Gui* gui = furi_record_open(RECORD_GUI); - ViewDispatcher* view_dispatcher = view_dispatcher_alloc(); + ViewHolder* view_holder = view_holder_alloc(); EmptyScreen* empty_screen = empty_screen_alloc(); - const uint32_t empty_screen_index = 0; size_t screen_index = 0; DialogMessageButton screen_result; // draw empty screen to prevent menu flickering - view_dispatcher_add_view( - view_dispatcher, empty_screen_index, empty_screen_get_view(empty_screen)); - view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); - view_dispatcher_switch_to_view(view_dispatcher, empty_screen_index); + view_holder_attach_to_gui(view_holder, gui); + view_holder_set_view(view_holder, empty_screen_get_view(empty_screen)); while(1) { if(screen_index >= COUNT_OF(about_screens) - 1) { @@ -244,8 +244,8 @@ int32_t about_settings_app(void* p) { dialog_message_free(message); furi_record_close(RECORD_DIALOGS); - view_dispatcher_remove_view(view_dispatcher, empty_screen_index); - view_dispatcher_free(view_dispatcher); + view_holder_set_view(view_holder, NULL); + view_holder_free(view_holder); empty_screen_free(empty_screen); furi_record_close(RECORD_GUI); diff --git a/applications/settings/bt_settings_app/bt_settings_app.c b/applications/settings/bt_settings_app/bt_settings_app.c index d86c9df647..174d0bcbb2 100644 --- a/applications/settings/bt_settings_app/bt_settings_app.c +++ b/applications/settings/bt_settings_app/bt_settings_app.c @@ -15,15 +15,12 @@ static bool bt_settings_back_event_callback(void* context) { BtSettingsApp* bt_settings_app_alloc(void) { BtSettingsApp* app = malloc(sizeof(BtSettingsApp)); - // Load settings - bt_settings_load(&app->settings); app->gui = furi_record_open(RECORD_GUI); app->bt = furi_record_open(RECORD_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); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_set_custom_event_callback( @@ -48,6 +45,8 @@ BtSettingsApp* bt_settings_app_alloc(void) { view_dispatcher_add_view( app->view_dispatcher, BtSettingsAppViewPopup, popup_get_view(app->popup)); + bt_get_settings(app->bt, &app->settings); + // Set first scene scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneStart); return app; @@ -55,6 +54,7 @@ BtSettingsApp* bt_settings_app_alloc(void) { void bt_settings_app_free(BtSettingsApp* app) { furi_assert(app); + bt_set_settings(app->bt, &app->settings); // Gui modules view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewVarItemList); variable_item_list_free(app->var_item_list); @@ -79,7 +79,6 @@ extern int32_t bt_settings_app(void* p) { UNUSED(p); BtSettingsApp* app = bt_settings_app_alloc(); view_dispatcher_run(app->view_dispatcher); - bt_settings_save(&app->settings); bt_settings_app_free(app); return 0; } diff --git a/applications/settings/bt_settings_app/bt_settings_app.h b/applications/settings/bt_settings_app/bt_settings_app.h index b79e369511..5255945ff5 100644 --- a/applications/settings/bt_settings_app/bt_settings_app.h +++ b/applications/settings/bt_settings_app/bt_settings_app.h @@ -1,18 +1,21 @@ #pragma once #include -#include + #include #include #include #include -#include #include #include #include -#include +#include +#include + +#include + #include "scenes/bt_settings_scene.h" enum BtSettingsCustomEvent { diff --git a/applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c b/applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c index 1d72a9e6fa..a76740bd1e 100644 --- a/applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c +++ b/applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c @@ -70,18 +70,17 @@ bool bt_settings_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == BtSettingOn) { - furi_hal_bt_start_advertising(); app->settings.enabled = true; consumed = true; } else if(event.event == BtSettingOff) { app->settings.enabled = false; - furi_hal_bt_stop_advertising(); consumed = true; } else if(event.event == BtSettingsCustomEventForgetDevices) { scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneForgetDevConfirm); consumed = true; } } + return consumed; } diff --git a/applications/settings/desktop_settings/desktop_settings_app.c b/applications/settings/desktop_settings/desktop_settings_app.c index 35ee2a3f1f..30d80514ac 100644 --- a/applications/settings/desktop_settings/desktop_settings_app.c +++ b/applications/settings/desktop_settings/desktop_settings_app.c @@ -5,9 +5,14 @@ #include #include +#include +#include + +#include +#include + #include "desktop_settings_app.h" #include "scenes/desktop_settings_scene.h" -#include static bool desktop_settings_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -28,7 +33,6 @@ DesktopSettingsApp* desktop_settings_app_alloc(void) { app->dialogs = furi_record_open(RECORD_DIALOGS); app->view_dispatcher = view_dispatcher_alloc(); app->scene_manager = scene_manager_alloc(&desktop_settings_scene_handlers, app); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_set_custom_event_callback( @@ -126,23 +130,26 @@ void desktop_settings_app_free(DesktopSettingsApp* app) { free(app); if(temp_save_name) { - power_reboot(PowerBootModeNormal); + Power* power = furi_record_open(RECORD_POWER); + power_reboot(power, PowerBootModeNormal); } } extern int32_t desktop_settings_app(void* p) { + UNUSED(p); + DesktopSettingsApp* app = desktop_settings_app_alloc(); - DESKTOP_SETTINGS_LOAD(&app->settings); + Desktop* desktop = furi_record_open(RECORD_DESKTOP); - if(p && (strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG) == 0)) { - scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto); - } else { - scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart); - } + desktop_api_get_settings(desktop, &app->settings); + + scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart); view_dispatcher_run(app->view_dispatcher); - DESKTOP_SETTINGS_SAVE(&app->settings); + desktop_api_set_settings(desktop, &app->settings); + furi_record_close(RECORD_DESKTOP); + desktop_settings_app_free(app); return 0; diff --git a/applications/settings/desktop_settings/desktop_settings_app.h b/applications/settings/desktop_settings/desktop_settings_app.h index 48adb9cfb0..2ce57c1186 100644 --- a/applications/settings/desktop_settings/desktop_settings_app.h +++ b/applications/settings/desktop_settings/desktop_settings_app.h @@ -15,6 +15,8 @@ #include "views/desktop_settings_view_pin_setup_howto.h" #include "views/desktop_settings_view_pin_setup_howto2.h" +#include + typedef enum { DesktopSettingsAppViewMenu, DesktopSettingsAppViewVarItemList, @@ -40,7 +42,7 @@ typedef struct { DesktopSettingsViewPinSetupHowto* pin_setup_howto_view; DesktopSettingsViewPinSetupHowto2* pin_setup_howto2_view; - PinCode pincode_buffer; + DesktopPinCode pincode_buffer; bool pincode_buffer_filled; bool save_name; diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c index ee6af0bd9c..ec970a3155 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -194,19 +194,25 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e strncpy( curr_favorite_app->name_or_path, furi_string_get_cstr(temp_path), - MAX_APP_LENGTH); + sizeof(curr_favorite_app->name_or_path)); consumed = true; } } else { size_t app_index = event.event - MAIN_LIST_APPLICATION_OFFSET; const char* name = favorite_fap_get_app_name(app_index); - if(name) strncpy(curr_favorite_app->name_or_path, name, MAX_APP_LENGTH); + if(name) + strncpy( + curr_favorite_app->name_or_path, + name, + sizeof(curr_favorite_app->name_or_path)); consumed = true; } if(consumed) { scene_manager_previous_scene(app->scene_manager); }; consumed = true; + + desktop_settings_save(&app->settings); } furi_string_free(temp_path); @@ -215,6 +221,5 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e void desktop_settings_scene_favorite_on_exit(void* context) { DesktopSettingsApp* app = context; - DESKTOP_SETTINGS_SAVE(&app->settings); submenu_reset(app->submenu); } diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c index 5af25cd614..1e64165314 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "../desktop_settings_app.h" #include #include @@ -12,13 +12,14 @@ #define SCENE_EVENT_PINS_EQUAL (1U) #define SCENE_EVENT_PINS_DIFFERENT (2U) -static void pin_auth_done_callback(const PinCode* pin_code, void* context) { +static void pin_auth_done_callback(const DesktopPinCode* pin_code, void* context) { furi_assert(pin_code); furi_assert(context); - DesktopSettingsApp* app = context; + DesktopSettingsApp* app = context; app->pincode_buffer = *pin_code; - if(desktop_pin_compare(&app->settings.pin_code, pin_code)) { + + if(desktop_pin_code_check(pin_code)) { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_EQUAL); } else { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_DIFFERENT); @@ -31,10 +32,9 @@ static void pin_auth_back_callback(void* context) { } void desktop_settings_scene_pin_auth_on_enter(void* context) { - DesktopSettingsApp* app = context; + furi_assert(desktop_pin_code_is_set()); - DESKTOP_SETTINGS_LOAD(&app->settings); - furi_assert(app->settings.pin_code.length > 0); + DesktopSettingsApp* app = context; desktop_view_pin_input_set_context(app->pin_input_view, app); desktop_view_pin_input_set_back_callback(app->pin_input_view, pin_auth_back_callback); diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c index f31a968944..abcce66da7 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c @@ -17,9 +17,8 @@ static void pin_disable_back_callback(void* context) { void desktop_settings_scene_pin_disable_on_enter(void* context) { furi_assert(context); DesktopSettingsApp* app = context; - app->settings.pin_code.length = 0; - memset(app->settings.pin_code.data, '0', sizeof(app->settings.pin_code.data)); - DESKTOP_SETTINGS_SAVE(&app->settings); + + desktop_pin_code_reset(); popup_set_context(app->popup, app); popup_set_callback(app->popup, pin_disable_back_callback); diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c index 1ba3c1b2da..711683c3fe 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c @@ -6,7 +6,7 @@ #include #include "desktop_settings_scene.h" #include "desktop_settings_scene_i.h" -#include +#include #include "../desktop_settings_app.h" #define SCENE_EVENT_EXIT (0U) @@ -17,7 +17,7 @@ static void pin_error_back_callback(void* context) { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT); } -static void pin_error_done_callback(const PinCode* pin_code, void* context) { +static void pin_error_done_callback(const DesktopPinCode* pin_code, void* context) { UNUSED(pin_code); furi_assert(context); DesktopSettingsApp* app = context; diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_menu.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_menu.c index 7375edd3f4..e0c66cb288 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_menu.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_menu.c @@ -19,7 +19,7 @@ void desktop_settings_scene_pin_menu_on_enter(void* context) { Submenu* submenu = app->submenu; submenu_reset(submenu); - if(!app->settings.pin_code.length) { + if(!desktop_pin_code_is_set()) { submenu_add_item( submenu, "Set PIN", diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c index 93012330aa..08f5fcb3fc 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup.c @@ -7,14 +7,14 @@ #include #include "desktop_settings_scene.h" #include "desktop_settings_scene_i.h" -#include +#include #define SCENE_EVENT_EXIT (0U) #define SCENE_EVENT_1ST_PIN_ENTERED (1U) #define SCENE_EVENT_PINS_EQUAL (2U) #define SCENE_EVENT_PINS_DIFFERENT (3U) -static void pin_setup_done_callback(const PinCode* pin_code, void* context) { +static void pin_setup_done_callback(const DesktopPinCode* pin_code, void* context) { furi_assert(pin_code); furi_assert(context); DesktopSettingsApp* app = context; @@ -25,7 +25,7 @@ static void pin_setup_done_callback(const PinCode* pin_code, void* context) { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_1ST_PIN_ENTERED); } else { app->pincode_buffer_filled = false; - if(desktop_pin_compare(&app->pincode_buffer, pin_code)) { + if(desktop_pin_code_is_equal(&app->pincode_buffer, pin_code)) { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_EQUAL); } else { view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_DIFFERENT); diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c index 170e6bca56..aa3d2214e5 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c @@ -11,7 +11,7 @@ #define SCENE_EVENT_DONE (0U) -static void pin_setup_done_callback(const PinCode* pin_code, void* context) { +static void pin_setup_done_callback(const DesktopPinCode* pin_code, void* context) { furi_assert(pin_code); furi_assert(context); DesktopSettingsApp* app = context; @@ -22,8 +22,8 @@ static void pin_setup_done_callback(const PinCode* pin_code, void* context) { void desktop_settings_scene_pin_setup_done_on_enter(void* context) { DesktopSettingsApp* app = context; - app->settings.pin_code = app->pincode_buffer; - DESKTOP_SETTINGS_SAVE(&app->settings); + desktop_pin_code_set(&app->pincode_buffer); + NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); notification_message(notification, &sequence_single_vibro); notification_message(notification, &sequence_blink_green_10); @@ -32,7 +32,7 @@ void desktop_settings_scene_pin_setup_done_on_enter(void* context) { desktop_view_pin_input_set_context(app->pin_input_view, app); desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL); desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_setup_done_callback); - desktop_view_pin_input_set_pin(app->pin_input_view, &app->settings.pin_code); + desktop_view_pin_input_set_pin(app->pin_input_view, &app->pincode_buffer); desktop_view_pin_input_set_label_button(app->pin_input_view, "Done"); desktop_view_pin_input_set_label_primary(app->pin_input_view, 29, 8, "PIN Activated!"); desktop_view_pin_input_set_label_secondary( diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index 52e7769599..fec783a35d 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -215,7 +215,7 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even scene_manager_set_scene_state( app->scene_manager, DesktopSettingsAppSceneFavorite, - SCENE_STATE_SET_DUMMY_APP | DummyAppLeft); + SCENE_STATE_SET_DUMMY_APP | DummyAppLeftShort); scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite); break; case DesktopSettingsDummyLeftLong: @@ -229,7 +229,7 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even scene_manager_set_scene_state( app->scene_manager, DesktopSettingsAppSceneFavorite, - SCENE_STATE_SET_DUMMY_APP | DummyAppRight); + SCENE_STATE_SET_DUMMY_APP | DummyAppRightShort); scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite); break; case DesktopSettingsDummyRightLong: @@ -250,7 +250,7 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even scene_manager_set_scene_state( app->scene_manager, DesktopSettingsAppSceneFavorite, - SCENE_STATE_SET_DUMMY_APP | DummyAppDown); + SCENE_STATE_SET_DUMMY_APP | DummyAppDownShort); scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite); break; case DesktopSettingsDummyDownLong: @@ -264,7 +264,7 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even scene_manager_set_scene_state( app->scene_manager, DesktopSettingsAppSceneFavorite, - SCENE_STATE_SET_DUMMY_APP | DummyAppOk); + SCENE_STATE_SET_DUMMY_APP | DummyAppOkShort); scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite); break; case DesktopSettingsDummyOkLong: @@ -286,7 +286,7 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even void desktop_settings_scene_start_on_exit(void* context) { DesktopSettingsApp* app = context; variable_item_list_reset(app->variable_item_list); - DESKTOP_SETTINGS_SAVE(&app->settings); + desktop_settings_save(&app->settings); // Trigger UI update in case we changed battery layout Power* power = furi_record_open(RECORD_POWER); diff --git a/applications/settings/expansion_settings_app/expansion_settings_app.c b/applications/settings/expansion_settings_app/expansion_settings_app.c index fe0e3ca2c0..639f7f23d5 100644 --- a/applications/settings/expansion_settings_app/expansion_settings_app.c +++ b/applications/settings/expansion_settings_app/expansion_settings_app.c @@ -10,7 +10,7 @@ static void expansion_settings_app_uart_changed(VariableItem* item) { ExpansionSettingsApp* app = variable_item_get_context(item); const uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, expansion_uart_text[index]); - app->settings->uart_index = index; + app->settings.uart_index = index; if(index < FuriHalSerialIdMax) { expansion_set_listen_serial(app->expansion, index); @@ -27,12 +27,12 @@ static uint32_t expansion_settings_app_exit(void* context) { static ExpansionSettingsApp* expansion_settings_app_alloc(void) { ExpansionSettingsApp* app = malloc(sizeof(ExpansionSettingsApp)); + expansion_settings_load(&app->settings); + app->gui = furi_record_open(RECORD_GUI); app->expansion = furi_record_open(RECORD_EXPANSION); - app->settings = expansion_get_settings(app->expansion); app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); @@ -48,7 +48,7 @@ static ExpansionSettingsApp* expansion_settings_app_alloc(void) { COUNT_OF(expansion_uart_text), expansion_settings_app_uart_changed, app); - value_index = app->settings->uart_index; + value_index = app->settings.uart_index; variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, expansion_uart_text[value_index]); @@ -67,7 +67,7 @@ static ExpansionSettingsApp* expansion_settings_app_alloc(void) { static void expansion_settings_app_free(ExpansionSettingsApp* app) { furi_assert(app); - expansion_settings_save(app->settings); + expansion_settings_save(&app->settings); view_dispatcher_remove_view(app->view_dispatcher, ExpansionSettingsViewVarItemList); variable_item_list_free(app->var_item_list); diff --git a/applications/settings/expansion_settings_app/expansion_settings_app.h b/applications/settings/expansion_settings_app/expansion_settings_app.h index a404f9c1a5..a43bf853fc 100644 --- a/applications/settings/expansion_settings_app/expansion_settings_app.h +++ b/applications/settings/expansion_settings_app/expansion_settings_app.h @@ -8,7 +8,6 @@ #include #include -#include #include typedef struct { @@ -16,7 +15,7 @@ typedef struct { ViewDispatcher* view_dispatcher; VariableItemList* var_item_list; Expansion* expansion; - ExpansionSettings* settings; + ExpansionSettings settings; } ExpansionSettingsApp; typedef enum { diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 7576dcf3c2..2462b32bde 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -242,7 +242,6 @@ static NotificationAppSettings* alloc_settings(void) { } app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); view_dispatcher_add_view(app->view_dispatcher, 0, view); view_dispatcher_switch_to_view(app->view_dispatcher, 0); diff --git a/applications/settings/power_settings_app/power_settings_app.c b/applications/settings/power_settings_app/power_settings_app.c index d2eaec0a5a..57df1344f3 100644 --- a/applications/settings/power_settings_app/power_settings_app.c +++ b/applications/settings/power_settings_app/power_settings_app.c @@ -28,7 +28,6 @@ PowerSettingsApp* power_settings_app_alloc(uint32_t first_scene) { // View dispatcher app->view_dispatcher = view_dispatcher_alloc(); app->scene_manager = scene_manager_alloc(&power_settings_scene_handlers, app); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_set_custom_event_callback( app->view_dispatcher, power_settings_custom_event_callback); diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_reboot_confirm.c b/applications/settings/power_settings_app/scenes/power_settings_scene_reboot_confirm.c index 62e06de927..25e7b2bc42 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_reboot_confirm.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_reboot_confirm.c @@ -49,10 +49,12 @@ bool power_settings_scene_reboot_confirm_on_event(void* context, SceneManagerEve if(event.event == DialogExResultLeft) { scene_manager_previous_scene(app->scene_manager); } else if(event.event == DialogExResultRight) { + Power* power = furi_record_open(RECORD_POWER); + if(reboot_type == RebootTypeDFU) { - power_reboot(PowerBootModeDfu); + power_reboot(power, PowerBootModeDfu); } else { - power_reboot(PowerBootModeNormal); + power_reboot(power, PowerBootModeNormal); } } consumed = true; diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c b/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c index 2d977176a0..0f8e1aa965 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_factory_reset.c @@ -65,7 +65,9 @@ bool storage_settings_scene_factory_reset_on_event(void* context, SceneManagerEv } else { furi_hal_rtc_reset_registers(); furi_hal_rtc_set_flag(FuriHalRtcFlagStorageFormatInternal); - power_reboot(PowerBootModeNormal); + + Power* power = furi_record_open(RECORD_POWER); + power_reboot(power, PowerBootModeNormal); } consumed = true; diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c b/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c index b7620b6e82..5a367afcec 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_internal_info.c @@ -27,7 +27,7 @@ void storage_settings_scene_internal_info_on_enter(void* context) { } else { furi_string_printf( app->text_string, - "Name: %s\nType: LittleFS\nTotal: %lu KiB\nFree: %lu KiB", + "Name: %s\nType: Virtual\nTotal: %lu KiB\nFree: %lu KiB", furi_hal_version_get_name_ptr() ? furi_hal_version_get_name_ptr() : "Unknown", (uint32_t)(total_space / 1024), (uint32_t)(free_space / 1024)); diff --git a/applications/settings/storage_settings/storage_settings.c b/applications/settings/storage_settings/storage_settings.c index 0508e8e0fa..3546328904 100644 --- a/applications/settings/storage_settings/storage_settings.c +++ b/applications/settings/storage_settings/storage_settings.c @@ -23,7 +23,6 @@ static StorageSettings* storage_settings_alloc(void) { app->scene_manager = scene_manager_alloc(&storage_settings_scene_handlers, app); app->text_string = furi_string_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_set_custom_event_callback( diff --git a/applications/settings/system/system_settings.c b/applications/settings/system/system_settings.c index 29fe0cd481..1c2654c5e5 100644 --- a/applications/settings/system/system_settings.c +++ b/applications/settings/system/system_settings.c @@ -92,7 +92,7 @@ static void debug_changed(VariableItem* item) { const char* const heap_trace_mode_text[] = { "None", "Main", -#if FURI_DEBUG +#ifdef FURI_DEBUG "Tree", "All", #endif @@ -101,7 +101,7 @@ const char* const heap_trace_mode_text[] = { const uint32_t heap_trace_mode_value[] = { FuriHalRtcHeapTrackModeNone, FuriHalRtcHeapTrackModeMain, -#if FURI_DEBUG +#ifdef FURI_DEBUG FuriHalRtcHeapTrackModeTree, FuriHalRtcHeapTrackModeAll, #endif @@ -220,7 +220,6 @@ SystemSettings* system_settings_alloc(void) { app->gui = furi_record_open(RECORD_GUI); app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); diff --git a/applications/system/application.fam b/applications/system/application.fam index 095ca1ab2c..c5f81defa6 100644 --- a/applications/system/application.fam +++ b/applications/system/application.fam @@ -4,7 +4,6 @@ App( apptype=FlipperAppType.METAPACKAGE, provides=[ "updater_app", - "storage_move_to_sd", "js_app", "js_app_start", # "archive", diff --git a/applications/system/hid_app/assets/Alt_17x10.png b/applications/system/hid_app/assets/Alt_17x10.png index 78529ca07d..54c4557bad 100644 Binary files a/applications/system/hid_app/assets/Alt_17x10.png and b/applications/system/hid_app/assets/Alt_17x10.png differ diff --git a/applications/system/hid_app/assets/Alt_active_17x9.png b/applications/system/hid_app/assets/Alt_active_17x9.png old mode 100755 new mode 100644 index 46a21a2e85..bd1adf606d Binary files a/applications/system/hid_app/assets/Alt_active_17x9.png and b/applications/system/hid_app/assets/Alt_active_17x9.png differ diff --git a/applications/system/hid_app/assets/Arr_dwn_7x9.png b/applications/system/hid_app/assets/Arr_dwn_7x9.png index d4034efc43..dc97d3abcd 100644 Binary files a/applications/system/hid_app/assets/Arr_dwn_7x9.png and b/applications/system/hid_app/assets/Arr_dwn_7x9.png differ diff --git a/applications/system/hid_app/assets/Arr_up_7x9.png b/applications/system/hid_app/assets/Arr_up_7x9.png index 28b4236a29..4e199c7d05 100644 Binary files a/applications/system/hid_app/assets/Arr_up_7x9.png and b/applications/system/hid_app/assets/Arr_up_7x9.png differ diff --git a/applications/system/hid_app/assets/Ble_connected_15x15.png b/applications/system/hid_app/assets/Ble_connected_15x15.png index 64dab9b530..1301399da9 100644 Binary files a/applications/system/hid_app/assets/Ble_connected_15x15.png and b/applications/system/hid_app/assets/Ble_connected_15x15.png differ diff --git a/applications/system/hid_app/assets/Ble_disconnected_15x15.png b/applications/system/hid_app/assets/Ble_disconnected_15x15.png index bd54646d89..f926ce2128 100644 Binary files a/applications/system/hid_app/assets/Ble_disconnected_15x15.png and b/applications/system/hid_app/assets/Ble_disconnected_15x15.png differ diff --git a/applications/system/hid_app/assets/ButtonDown_7x4.png b/applications/system/hid_app/assets/ButtonDown_7x4.png index 2954bb6a67..0cda838e05 100644 Binary files a/applications/system/hid_app/assets/ButtonDown_7x4.png and b/applications/system/hid_app/assets/ButtonDown_7x4.png differ diff --git a/applications/system/hid_app/assets/ButtonF10_5x8.png b/applications/system/hid_app/assets/ButtonF10_5x8.png index d1a7a04f06..a817cce367 100644 Binary files a/applications/system/hid_app/assets/ButtonF10_5x8.png and b/applications/system/hid_app/assets/ButtonF10_5x8.png differ diff --git a/applications/system/hid_app/assets/ButtonF11_5x8.png b/applications/system/hid_app/assets/ButtonF11_5x8.png index 7e177358e8..9ebe40150a 100644 Binary files a/applications/system/hid_app/assets/ButtonF11_5x8.png and b/applications/system/hid_app/assets/ButtonF11_5x8.png differ diff --git a/applications/system/hid_app/assets/ButtonF12_5x8.png b/applications/system/hid_app/assets/ButtonF12_5x8.png index 50d2a7dc63..a50b16ca31 100644 Binary files a/applications/system/hid_app/assets/ButtonF12_5x8.png and b/applications/system/hid_app/assets/ButtonF12_5x8.png differ diff --git a/applications/system/hid_app/assets/ButtonF1_5x8.png b/applications/system/hid_app/assets/ButtonF1_5x8.png index 7394d27105..53a30974ba 100644 Binary files a/applications/system/hid_app/assets/ButtonF1_5x8.png and b/applications/system/hid_app/assets/ButtonF1_5x8.png differ diff --git a/applications/system/hid_app/assets/ButtonF2_5x8.png b/applications/system/hid_app/assets/ButtonF2_5x8.png index 9d922a3858..df28654a5e 100644 Binary files a/applications/system/hid_app/assets/ButtonF2_5x8.png and b/applications/system/hid_app/assets/ButtonF2_5x8.png differ diff --git a/applications/system/hid_app/assets/ButtonF3_5x8.png b/applications/system/hid_app/assets/ButtonF3_5x8.png index 95c2dd4f41..a36cd56b9c 100644 Binary files a/applications/system/hid_app/assets/ButtonF3_5x8.png and b/applications/system/hid_app/assets/ButtonF3_5x8.png differ diff --git a/applications/system/hid_app/assets/ButtonF4_5x8.png b/applications/system/hid_app/assets/ButtonF4_5x8.png index 602466f4b6..535195859d 100644 Binary files a/applications/system/hid_app/assets/ButtonF4_5x8.png and b/applications/system/hid_app/assets/ButtonF4_5x8.png differ diff --git a/applications/system/hid_app/assets/ButtonF5_5x8.png b/applications/system/hid_app/assets/ButtonF5_5x8.png index d73b540527..918017f5a7 100644 Binary files a/applications/system/hid_app/assets/ButtonF5_5x8.png and b/applications/system/hid_app/assets/ButtonF5_5x8.png differ diff --git a/applications/system/hid_app/assets/ButtonF6_5x8.png b/applications/system/hid_app/assets/ButtonF6_5x8.png index c50748257a..1009799a56 100644 Binary files a/applications/system/hid_app/assets/ButtonF6_5x8.png and b/applications/system/hid_app/assets/ButtonF6_5x8.png differ diff --git a/applications/system/hid_app/assets/ButtonF7_5x8.png b/applications/system/hid_app/assets/ButtonF7_5x8.png index 396c98f510..a6c44ddd8e 100644 Binary files a/applications/system/hid_app/assets/ButtonF7_5x8.png and b/applications/system/hid_app/assets/ButtonF7_5x8.png differ diff --git a/applications/system/hid_app/assets/ButtonF8_5x8.png b/applications/system/hid_app/assets/ButtonF8_5x8.png index 6304d7fb88..a789a0f364 100644 Binary files a/applications/system/hid_app/assets/ButtonF8_5x8.png and b/applications/system/hid_app/assets/ButtonF8_5x8.png differ diff --git a/applications/system/hid_app/assets/ButtonF9_5x8.png b/applications/system/hid_app/assets/ButtonF9_5x8.png index 148e69580f..222b2e151d 100644 Binary files a/applications/system/hid_app/assets/ButtonF9_5x8.png and b/applications/system/hid_app/assets/ButtonF9_5x8.png differ diff --git a/applications/system/hid_app/assets/ButtonLeft_4x7.png b/applications/system/hid_app/assets/ButtonLeft_4x7.png index 0b4655d432..7c43f3b04d 100644 Binary files a/applications/system/hid_app/assets/ButtonLeft_4x7.png and b/applications/system/hid_app/assets/ButtonLeft_4x7.png differ diff --git a/applications/system/hid_app/assets/ButtonRight_4x7.png b/applications/system/hid_app/assets/ButtonRight_4x7.png index 8e1c74c1c0..31de21c0e2 100644 Binary files a/applications/system/hid_app/assets/ButtonRight_4x7.png and b/applications/system/hid_app/assets/ButtonRight_4x7.png differ diff --git a/applications/system/hid_app/assets/ButtonUp_7x4.png b/applications/system/hid_app/assets/ButtonUp_7x4.png index 1be79328b4..48d0f9f018 100644 Binary files a/applications/system/hid_app/assets/ButtonUp_7x4.png and b/applications/system/hid_app/assets/ButtonUp_7x4.png differ diff --git a/applications/system/hid_app/assets/Button_18x18.png b/applications/system/hid_app/assets/Button_18x18.png index 30a5b4fab2..2334dd8be0 100644 Binary files a/applications/system/hid_app/assets/Button_18x18.png and b/applications/system/hid_app/assets/Button_18x18.png differ diff --git a/applications/system/hid_app/assets/Cmd_17x10.png b/applications/system/hid_app/assets/Cmd_17x10.png index b29da07b71..68b3be6068 100644 Binary files a/applications/system/hid_app/assets/Cmd_17x10.png and b/applications/system/hid_app/assets/Cmd_17x10.png differ diff --git a/applications/system/hid_app/assets/Cmd_active_17x9.png b/applications/system/hid_app/assets/Cmd_active_17x9.png old mode 100755 new mode 100644 index 9d31b4eb3e..9f9cdea996 Binary files a/applications/system/hid_app/assets/Cmd_active_17x9.png and b/applications/system/hid_app/assets/Cmd_active_17x9.png differ diff --git a/applications/system/hid_app/assets/Ctrl_17x10.png b/applications/system/hid_app/assets/Ctrl_17x10.png index 05be3292eb..c70dd2c16a 100644 Binary files a/applications/system/hid_app/assets/Ctrl_17x10.png and b/applications/system/hid_app/assets/Ctrl_17x10.png differ diff --git a/applications/system/hid_app/assets/Ctrl_active_17x9.png b/applications/system/hid_app/assets/Ctrl_active_17x9.png old mode 100755 new mode 100644 index 6fade6dd77..c16df04ee4 Binary files a/applications/system/hid_app/assets/Ctrl_active_17x9.png and b/applications/system/hid_app/assets/Ctrl_active_17x9.png differ diff --git a/applications/system/hid_app/assets/Del_17x10.png b/applications/system/hid_app/assets/Del_17x10.png index 95cbf7d5bd..3fd55e92f2 100644 Binary files a/applications/system/hid_app/assets/Del_17x10.png and b/applications/system/hid_app/assets/Del_17x10.png differ diff --git a/applications/system/hid_app/assets/DolphinDone_80x58.png b/applications/system/hid_app/assets/DolphinDone_80x58.png index 594d62d529..881aaa8d2a 100644 Binary files a/applications/system/hid_app/assets/DolphinDone_80x58.png and b/applications/system/hid_app/assets/DolphinDone_80x58.png differ diff --git a/applications/system/hid_app/assets/Enter_11x7.png b/applications/system/hid_app/assets/Enter_11x7.png old mode 100755 new mode 100644 index d41b8feffb..1b07df2cfa Binary files a/applications/system/hid_app/assets/Enter_11x7.png and b/applications/system/hid_app/assets/Enter_11x7.png differ diff --git a/applications/system/hid_app/assets/Esc_17x10.png b/applications/system/hid_app/assets/Esc_17x10.png index 83a6f225fc..bd7e3cb963 100644 Binary files a/applications/system/hid_app/assets/Esc_17x10.png and b/applications/system/hid_app/assets/Esc_17x10.png differ diff --git a/applications/system/hid_app/assets/Ok_btn_9x9.png b/applications/system/hid_app/assets/Ok_btn_9x9.png index 9a1539da20..ceff4e8a88 100644 Binary files a/applications/system/hid_app/assets/Ok_btn_9x9.png and b/applications/system/hid_app/assets/Ok_btn_9x9.png differ diff --git a/applications/system/hid_app/assets/Pin_arrow_down_7x9.png b/applications/system/hid_app/assets/Pin_arrow_down_7x9.png index 9687397afa..dc97d3abcd 100644 Binary files a/applications/system/hid_app/assets/Pin_arrow_down_7x9.png and b/applications/system/hid_app/assets/Pin_arrow_down_7x9.png differ diff --git a/applications/system/hid_app/assets/Pin_arrow_left_9x7.png b/applications/system/hid_app/assets/Pin_arrow_left_9x7.png index fb4ded78fd..9b6ccb51f5 100644 Binary files a/applications/system/hid_app/assets/Pin_arrow_left_9x7.png and b/applications/system/hid_app/assets/Pin_arrow_left_9x7.png differ diff --git a/applications/system/hid_app/assets/Pin_arrow_right_9x7.png b/applications/system/hid_app/assets/Pin_arrow_right_9x7.png index 97648d1761..b79bca2e3e 100644 Binary files a/applications/system/hid_app/assets/Pin_arrow_right_9x7.png and b/applications/system/hid_app/assets/Pin_arrow_right_9x7.png differ diff --git a/applications/system/hid_app/assets/Pin_arrow_up_7x9.png b/applications/system/hid_app/assets/Pin_arrow_up_7x9.png index a91a6fd5e9..4e199c7d05 100644 Binary files a/applications/system/hid_app/assets/Pin_arrow_up_7x9.png and b/applications/system/hid_app/assets/Pin_arrow_up_7x9.png differ diff --git a/applications/system/hid_app/assets/Pin_back_arrow_10x8.png b/applications/system/hid_app/assets/Pin_back_arrow_10x8.png index 3bafabd144..64b25db5af 100644 Binary files a/applications/system/hid_app/assets/Pin_back_arrow_10x8.png and b/applications/system/hid_app/assets/Pin_back_arrow_10x8.png differ diff --git a/applications/system/hid_app/assets/Pressed_Button_13x13.png b/applications/system/hid_app/assets/Pressed_Button_13x13.png index 823926b842..d0e2c3a373 100644 Binary files a/applications/system/hid_app/assets/Pressed_Button_13x13.png and b/applications/system/hid_app/assets/Pressed_Button_13x13.png differ diff --git a/applications/system/hid_app/assets/Return_10x7.png b/applications/system/hid_app/assets/Return_10x7.png index ffa1e9acaf..ebf0a77777 100644 Binary files a/applications/system/hid_app/assets/Return_10x7.png and b/applications/system/hid_app/assets/Return_10x7.png differ diff --git a/applications/system/hid_app/assets/Shift_active_7x9.png b/applications/system/hid_app/assets/Shift_active_7x9.png index 1ec9ce11e8..1dbb762f95 100644 Binary files a/applications/system/hid_app/assets/Shift_active_7x9.png and b/applications/system/hid_app/assets/Shift_active_7x9.png differ diff --git a/applications/system/hid_app/assets/Shift_inactive_7x9.png b/applications/system/hid_app/assets/Shift_inactive_7x9.png index 1cd97076ed..696e7e9eed 100644 Binary files a/applications/system/hid_app/assets/Shift_inactive_7x9.png and b/applications/system/hid_app/assets/Shift_inactive_7x9.png differ diff --git a/applications/system/hid_app/assets/Space_60x18.png b/applications/system/hid_app/assets/Space_60x18.png index e29f50ae92..7d2116ad52 100644 Binary files a/applications/system/hid_app/assets/Space_60x18.png and b/applications/system/hid_app/assets/Space_60x18.png differ diff --git a/applications/system/hid_app/assets/Space_65x18.png b/applications/system/hid_app/assets/Space_65x18.png index b60ae50970..eb417f6746 100644 Binary files a/applications/system/hid_app/assets/Space_65x18.png and b/applications/system/hid_app/assets/Space_65x18.png differ diff --git a/applications/system/hid_app/assets/Tab_17x10.png b/applications/system/hid_app/assets/Tab_17x10.png index 4d8471483e..0be2d938c8 100644 Binary files a/applications/system/hid_app/assets/Tab_17x10.png and b/applications/system/hid_app/assets/Tab_17x10.png differ diff --git a/applications/system/hid_app/assets/Tab_19x12.png b/applications/system/hid_app/assets/Tab_19x12.png old mode 100755 new mode 100644 index 4dbde3babf..6748d1f497 Binary files a/applications/system/hid_app/assets/Tab_19x12.png and b/applications/system/hid_app/assets/Tab_19x12.png differ diff --git a/applications/system/hid_app/assets/Voldwn_6x6.png b/applications/system/hid_app/assets/Voldwn_6x6.png index d7a82a2df8..d6d7e286a3 100644 Binary files a/applications/system/hid_app/assets/Voldwn_6x6.png and b/applications/system/hid_app/assets/Voldwn_6x6.png differ diff --git a/applications/system/hid_app/assets/Volup_8x6.png b/applications/system/hid_app/assets/Volup_8x6.png index 4b7ec66d65..66477bc7b5 100644 Binary files a/applications/system/hid_app/assets/Volup_8x6.png and b/applications/system/hid_app/assets/Volup_8x6.png differ diff --git a/applications/system/hid_app/assets/apostrophe_button_9x11.png b/applications/system/hid_app/assets/apostrophe_button_9x11.png index 0f54f0e2b1..a4b2cab8ed 100644 Binary files a/applications/system/hid_app/assets/apostrophe_button_9x11.png and b/applications/system/hid_app/assets/apostrophe_button_9x11.png differ diff --git a/applications/system/hid_app/assets/backslash_button_9x11.png b/applications/system/hid_app/assets/backslash_button_9x11.png old mode 100755 new mode 100644 index 6cac74a57a..e579e113ec Binary files a/applications/system/hid_app/assets/backslash_button_9x11.png and b/applications/system/hid_app/assets/backslash_button_9x11.png differ diff --git a/applications/system/hid_app/assets/backspace_19x11.png b/applications/system/hid_app/assets/backspace_19x11.png old mode 100755 new mode 100644 index caf92807b5..80e91c3c21 Binary files a/applications/system/hid_app/assets/backspace_19x11.png and b/applications/system/hid_app/assets/backspace_19x11.png differ diff --git a/applications/system/hid_app/assets/backspace_hovered_9x11.png b/applications/system/hid_app/assets/backspace_hovered_9x11.png old mode 100755 new mode 100644 index 17cb1b7403..a4acbf0db8 Binary files a/applications/system/hid_app/assets/backspace_hovered_9x11.png and b/applications/system/hid_app/assets/backspace_hovered_9x11.png differ diff --git a/applications/system/hid_app/assets/backtick_button_9x11.png b/applications/system/hid_app/assets/backtick_button_9x11.png old mode 100755 new mode 100644 index 1e5955a03a..0d2b8942c4 Binary files a/applications/system/hid_app/assets/backtick_button_9x11.png and b/applications/system/hid_app/assets/backtick_button_9x11.png differ diff --git a/applications/system/hid_app/assets/brace_left_button_9x11.png b/applications/system/hid_app/assets/brace_left_button_9x11.png old mode 100755 new mode 100644 index a61db48f36..56eb690434 Binary files a/applications/system/hid_app/assets/brace_left_button_9x11.png and b/applications/system/hid_app/assets/brace_left_button_9x11.png differ diff --git a/applications/system/hid_app/assets/brace_right_button_9x11.png b/applications/system/hid_app/assets/brace_right_button_9x11.png old mode 100755 new mode 100644 index bf6b927f19..8df2c19ce8 Binary files a/applications/system/hid_app/assets/brace_right_button_9x11.png and b/applications/system/hid_app/assets/brace_right_button_9x11.png differ diff --git a/applications/system/hid_app/assets/equals_button_9x11.png b/applications/system/hid_app/assets/equals_button_9x11.png old mode 100755 new mode 100644 index 8fe8afe34d..4d3232af24 Binary files a/applications/system/hid_app/assets/equals_button_9x11.png and b/applications/system/hid_app/assets/equals_button_9x11.png differ diff --git a/applications/system/hid_app/assets/hash_button_9x11.png b/applications/system/hid_app/assets/hash_button_9x11.png old mode 100755 new mode 100644 index bddc7aacea..0a3974f643 Binary files a/applications/system/hid_app/assets/hash_button_9x11.png and b/applications/system/hid_app/assets/hash_button_9x11.png differ diff --git a/applications/system/hid_app/assets/percent_button_9x11.png b/applications/system/hid_app/assets/percent_button_9x11.png old mode 100755 new mode 100644 index ce12dcbf1e..72190605bc Binary files a/applications/system/hid_app/assets/percent_button_9x11.png and b/applications/system/hid_app/assets/percent_button_9x11.png differ diff --git a/applications/system/hid_app/assets/quote_button_9x11.png b/applications/system/hid_app/assets/quote_button_9x11.png old mode 100755 new mode 100644 index e96d29ddcd..9fabcd26cd Binary files a/applications/system/hid_app/assets/quote_button_9x11.png and b/applications/system/hid_app/assets/quote_button_9x11.png differ diff --git a/applications/system/hid_app/assets/slash_button_9x11.png b/applications/system/hid_app/assets/slash_button_9x11.png old mode 100755 new mode 100644 index 60871320ff..b877b9106d Binary files a/applications/system/hid_app/assets/slash_button_9x11.png and b/applications/system/hid_app/assets/slash_button_9x11.png differ diff --git a/applications/system/hid_app/assets/sq_bracket_left_button_9x11.png b/applications/system/hid_app/assets/sq_bracket_left_button_9x11.png old mode 100755 new mode 100644 index 0983db1296..ea50cd657c Binary files a/applications/system/hid_app/assets/sq_bracket_left_button_9x11.png and b/applications/system/hid_app/assets/sq_bracket_left_button_9x11.png differ diff --git a/applications/system/hid_app/assets/sq_bracket_right_button_9x11.png b/applications/system/hid_app/assets/sq_bracket_right_button_9x11.png old mode 100755 new mode 100644 index 48f9c77e4d..bd18bbfad6 Binary files a/applications/system/hid_app/assets/sq_bracket_right_button_9x11.png and b/applications/system/hid_app/assets/sq_bracket_right_button_9x11.png differ diff --git a/applications/system/hid_app/assets/underscore_button_9x11.png b/applications/system/hid_app/assets/underscore_button_9x11.png old mode 100755 new mode 100644 index eb000cba55..7ab5cdbab5 Binary files a/applications/system/hid_app/assets/underscore_button_9x11.png and b/applications/system/hid_app/assets/underscore_button_9x11.png differ diff --git a/applications/system/hid_app/hid.c b/applications/system/hid_app/hid.c index 586d198a9b..e297e07387 100644 --- a/applications/system/hid_app/hid.c +++ b/applications/system/hid_app/hid.c @@ -72,7 +72,6 @@ Hid* hid_alloc() { // View dispatcher app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_set_custom_event_callback(app->view_dispatcher, hid_custom_event_callback); view_dispatcher_set_navigation_event_callback(app->view_dispatcher, hid_back_event_callback); diff --git a/applications/system/hid_app/hid_ble_10px.png b/applications/system/hid_app/hid_ble_10px.png index d4d30afe04..27355f8dba 100644 Binary files a/applications/system/hid_app/hid_ble_10px.png and b/applications/system/hid_app/hid_ble_10px.png differ diff --git a/applications/system/js_app/icon.png b/applications/system/js_app/icon.png index 77ac76337e..48210a0497 100644 Binary files a/applications/system/js_app/icon.png and b/applications/system/js_app/icon.png differ diff --git a/applications/system/js_app/js_app.c b/applications/system/js_app/js_app.c index 24cb545891..20c4ce7336 100644 --- a/applications/system/js_app/js_app.c +++ b/applications/system/js_app/js_app.c @@ -69,7 +69,6 @@ static JsApp* js_app_alloc(void) { app->loading = loading_alloc(); app->gui = furi_record_open("gui"); - view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); view_dispatcher_add_view( app->view_dispatcher, JsAppViewLoading, loading_get_view(app->loading)); diff --git a/applications/system/js_app/modules/js_keyboard.c b/applications/system/js_app/modules/js_keyboard.c index 65373db785..53f48d01de 100644 --- a/applications/system/js_app/modules/js_keyboard.c +++ b/applications/system/js_app/modules/js_keyboard.c @@ -92,10 +92,9 @@ static void js_keyboard_text(struct mjs* mjs) { view_holder_set_back_callback(keyboard->view_holder, keyboard_exit, keyboard); view_holder_set_view(keyboard->view_holder, text_input_get_view(keyboard->text_input)); - view_holder_start(keyboard->view_holder); api_lock_wait_unlock(keyboard->lock); - view_holder_stop(keyboard->view_holder); + view_holder_set_view(keyboard->view_holder, NULL); view_holder_free(keyboard->view_holder); furi_record_close(RECORD_GUI); @@ -148,10 +147,9 @@ static void js_keyboard_byte(struct mjs* mjs) { view_holder_set_back_callback(keyboard->view_holder, keyboard_exit, keyboard); view_holder_set_view(keyboard->view_holder, byte_input_get_view(keyboard->byte_input)); - view_holder_start(keyboard->view_holder); api_lock_wait_unlock(keyboard->lock); - view_holder_stop(keyboard->view_holder); + view_holder_set_view(keyboard->view_holder, NULL); view_holder_free(keyboard->view_holder); furi_record_close(RECORD_GUI); diff --git a/applications/system/js_app/modules/js_submenu.c b/applications/system/js_app/modules/js_submenu.c index 058b32fd09..5ab9bef77c 100644 --- a/applications/system/js_app/modules/js_submenu.c +++ b/applications/system/js_app/modules/js_submenu.c @@ -97,10 +97,9 @@ static void js_submenu_show(struct mjs* mjs) { view_holder_set_back_callback(submenu->view_holder, submenu_exit, submenu); view_holder_set_view(submenu->view_holder, submenu_get_view(submenu->submenu)); - view_holder_start(submenu->view_holder); api_lock_wait_unlock(submenu->lock); - view_holder_stop(submenu->view_holder); + view_holder_set_view(submenu->view_holder, NULL); view_holder_free(submenu->view_holder); furi_record_close(RECORD_GUI); api_lock_free(submenu->lock); diff --git a/applications/system/js_app/modules/js_textbox.c b/applications/system/js_app/modules/js_textbox.c index 33798b2965..b90dbc153a 100644 --- a/applications/system/js_app/modules/js_textbox.c +++ b/applications/system/js_app/modules/js_textbox.c @@ -125,7 +125,7 @@ static void js_textbox_is_open(struct mjs* mjs) { static void textbox_callback(void* context, uint32_t arg) { UNUSED(arg); JsTextboxInst* textbox = context; - view_holder_stop(textbox->view_holder); + view_holder_set_view(textbox->view_holder, NULL); textbox->is_shown = false; } @@ -145,7 +145,7 @@ static void js_textbox_show(struct mjs* mjs) { return; } - view_holder_start(textbox->view_holder); + view_holder_set_view(textbox->view_holder, text_box_get_view(textbox->text_box)); textbox->is_shown = true; mjs_return(mjs, MJS_UNDEFINED); @@ -155,7 +155,7 @@ static void js_textbox_close(struct mjs* mjs) { JsTextboxInst* textbox = get_this_ctx(mjs); if(!check_arg_count(mjs, 0)) return; - view_holder_stop(textbox->view_holder); + view_holder_set_view(textbox->view_holder, NULL); textbox->is_shown = false; mjs_return(mjs, MJS_UNDEFINED); @@ -180,7 +180,6 @@ static void* js_textbox_create(struct mjs* mjs, mjs_val_t* object) { textbox->view_holder = view_holder_alloc(); view_holder_attach_to_gui(textbox->view_holder, gui); view_holder_set_back_callback(textbox->view_holder, textbox_exit, textbox); - view_holder_set_view(textbox->view_holder, text_box_get_view(textbox->text_box)); *object = textbox_obj; return textbox; @@ -189,7 +188,7 @@ static void* js_textbox_create(struct mjs* mjs, mjs_val_t* object) { static void js_textbox_destroy(void* inst) { JsTextboxInst* textbox = inst; - view_holder_stop(textbox->view_holder); + view_holder_set_view(textbox->view_holder, NULL); view_holder_free(textbox->view_holder); textbox->view_holder = NULL; diff --git a/applications/system/js_app/modules/js_widget.c b/applications/system/js_app/modules/js_widget.c index 0d6aeb1dba..6c8e79b2ec 100644 --- a/applications/system/js_app/modules/js_widget.c +++ b/applications/system/js_app/modules/js_widget.c @@ -759,7 +759,7 @@ static void js_widget_is_open(struct mjs* mjs) { static void widget_callback(void* context, uint32_t arg) { UNUSED(arg); JsWidgetInst* widget = context; - view_holder_stop(widget->view_holder); + view_holder_set_view(widget->view_holder, NULL); widget->is_shown = false; } @@ -779,7 +779,7 @@ static void js_widget_show(struct mjs* mjs) { return; } - view_holder_start(widget->view_holder); + view_holder_set_view(widget->view_holder, widget->view); widget->is_shown = true; mjs_return(mjs, MJS_UNDEFINED); @@ -789,7 +789,7 @@ static void js_widget_close(struct mjs* mjs) { JsWidgetInst* widget = get_this_ctx(mjs); if(!check_arg_count(mjs, 0)) return; - view_holder_stop(widget->view_holder); + view_holder_set_view(widget->view_holder, NULL); widget->is_shown = false; mjs_return(mjs, MJS_UNDEFINED); @@ -874,7 +874,7 @@ static void* js_widget_create(struct mjs* mjs, mjs_val_t* object) { static void js_widget_destroy(void* inst) { JsWidgetInst* widget = inst; - view_holder_stop(widget->view_holder); + view_holder_set_view(widget->view_holder, NULL); view_holder_free(widget->view_holder); widget->view_holder = NULL; diff --git a/applications/system/snake_game/snake_10px.png b/applications/system/snake_game/snake_10px.png index 52d9fa7e0e..3ace2de40d 100644 Binary files a/applications/system/snake_game/snake_10px.png and b/applications/system/snake_game/snake_10px.png differ diff --git a/applications/system/storage_move_to_sd/application.fam b/applications/system/storage_move_to_sd/application.fam deleted file mode 100644 index de47de0551..0000000000 --- a/applications/system/storage_move_to_sd/application.fam +++ /dev/null @@ -1,18 +0,0 @@ -App( - appid="storage_move_to_sd", - name="StorageMoveToSd", - apptype=FlipperAppType.SYSTEM, - entry_point="storage_move_to_sd_app", - requires=["gui", "storage"], - provides=["storage_move_to_sd_start"], - stack_size=2 * 1024, - order=30, -) - -App( - appid="storage_move_to_sd_start", - apptype=FlipperAppType.STARTUP, - entry_point="storage_move_to_sd_start", - requires=["storage"], - order=120, -) diff --git a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.c b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.c deleted file mode 100644 index 011bf47df9..0000000000 --- a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "storage_move_to_sd_scene.h" - -// Generate scene on_enter handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, -void (*const storage_move_to_sd_on_enter_handlers[])(void*) = { -#include "storage_move_to_sd_scene_config.h" -}; -#undef ADD_SCENE - -// Generate scene on_event handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, -bool (*const storage_move_to_sd_on_event_handlers[])(void* context, SceneManagerEvent event) = { -#include "storage_move_to_sd_scene_config.h" -}; -#undef ADD_SCENE - -// Generate scene on_exit handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, -void (*const storage_move_to_sd_on_exit_handlers[])(void* context) = { -#include "storage_move_to_sd_scene_config.h" -}; -#undef ADD_SCENE - -// Initialize scene handlers configuration structure -const SceneManagerHandlers storage_move_to_sd_scene_handlers = { - .on_enter_handlers = storage_move_to_sd_on_enter_handlers, - .on_event_handlers = storage_move_to_sd_on_event_handlers, - .on_exit_handlers = storage_move_to_sd_on_exit_handlers, - .scene_num = StorageMoveToSdSceneNum, -}; diff --git a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_config.h b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_config.h deleted file mode 100644 index 1d7b2d25b8..0000000000 --- a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_config.h +++ /dev/null @@ -1,2 +0,0 @@ -ADD_SCENE(storage_move_to_sd, confirm, Confirm) -ADD_SCENE(storage_move_to_sd, progress, Progress) diff --git a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c deleted file mode 100644 index 08c9e2d7fc..0000000000 --- a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "../storage_move_to_sd.h" -#include -#include -#include - -static void storage_move_to_sd_scene_confirm_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - StorageMoveToSd* app = context; - furi_assert(app); - if(type == InputTypeShort) { - if(result == GuiButtonTypeRight) { - view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventConfirm); - } else if(result == GuiButtonTypeLeft) { - view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit); - } - } -} - -void storage_move_to_sd_scene_confirm_on_enter(void* context) { - StorageMoveToSd* app = context; - - widget_add_button_element( - app->widget, - GuiButtonTypeLeft, - "Cancel", - storage_move_to_sd_scene_confirm_widget_callback, - app); - widget_add_button_element( - app->widget, - GuiButtonTypeRight, - "Confirm", - storage_move_to_sd_scene_confirm_widget_callback, - app); - - widget_add_string_element( - app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "SD card inserted"); - widget_add_string_multiline_element( - app->widget, - 64, - 32, - AlignCenter, - AlignCenter, - FontSecondary, - "Move data from\ninternal storage to SD card?"); - - view_dispatcher_switch_to_view(app->view_dispatcher, StorageMoveToSdViewWidget); -} - -bool storage_move_to_sd_scene_confirm_on_event(void* context, SceneManagerEvent event) { - StorageMoveToSd* app = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == MoveToSdCustomEventConfirm) { - scene_manager_next_scene(app->scene_manager, StorageMoveToSdProgress); - consumed = true; - } else if(event.event == MoveToSdCustomEventExit) { - view_dispatcher_stop(app->view_dispatcher); - } - } - - return consumed; -} - -void storage_move_to_sd_scene_confirm_on_exit(void* context) { - StorageMoveToSd* app = context; - widget_reset(app->widget); -} diff --git a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_progress.c b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_progress.c deleted file mode 100644 index 7aa951bd83..0000000000 --- a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_progress.c +++ /dev/null @@ -1,31 +0,0 @@ -#include "../storage_move_to_sd.h" - -void storage_move_to_sd_scene_progress_on_enter(void* context) { - StorageMoveToSd* app = context; - - widget_add_string_element( - app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "Moving..."); - - view_dispatcher_switch_to_view(app->view_dispatcher, StorageMoveToSdViewWidget); - - storage_move_to_sd_perform(); - view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit); -} - -bool storage_move_to_sd_scene_progress_on_event(void* context, SceneManagerEvent event) { - StorageMoveToSd* app = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - view_dispatcher_stop(app->view_dispatcher); - } else if(event.type == SceneManagerEventTypeBack) { - consumed = true; - } - - return consumed; -} - -void storage_move_to_sd_scene_progress_on_exit(void* context) { - StorageMoveToSd* app = context; - widget_reset(app->widget); -} diff --git a/applications/system/storage_move_to_sd/storage_move_to_sd.c b/applications/system/storage_move_to_sd/storage_move_to_sd.c deleted file mode 100644 index 44e73c6895..0000000000 --- a/applications/system/storage_move_to_sd/storage_move_to_sd.c +++ /dev/null @@ -1,203 +0,0 @@ -#include "storage_move_to_sd.h" - -#include -#include -#include -#include -#include -#include - -#define TAG "MoveToSd" - -#define MOVE_SRC STORAGE_INT_PATH_PREFIX -#define MOVE_DST STORAGE_EXT_PATH_PREFIX - -static bool storage_move_to_sd_check_entry(const char* name, FileInfo* fileinfo, void* ctx) { - UNUSED(ctx); - if(file_info_is_dir(fileinfo)) { - return true; - } - - return name && (*name != '.'); -} - -static void storage_move_to_sd_remove_region() { - if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) return; - Storage* storage = furi_record_open(RECORD_STORAGE); - - if(storage_common_exists(storage, INT_PATH(".region_data"))) { - storage_common_remove(storage, INT_PATH(".region_data")); - } - - furi_record_close(RECORD_STORAGE); -} - -bool storage_move_to_sd_perform(void) { - Storage* storage = furi_record_open(RECORD_STORAGE); - - DirWalk* dir_walk = dir_walk_alloc(storage); - dir_walk_set_recursive(dir_walk, false); - dir_walk_set_filter_cb(dir_walk, storage_move_to_sd_check_entry, NULL); - - FuriString *path_src, *path_dst; - - path_dst = furi_string_alloc(); - path_src = furi_string_alloc(); - - if(dir_walk_open(dir_walk, STORAGE_INT_PATH_PREFIX)) { - while(dir_walk_read(dir_walk, path_src, NULL) == DirWalkOK) { - furi_string_set(path_dst, path_src); - furi_string_replace_at( - path_dst, 0, strlen(STORAGE_INT_PATH_PREFIX), STORAGE_EXT_PATH_PREFIX); - - storage_common_merge( - storage, furi_string_get_cstr(path_src), furi_string_get_cstr(path_dst)); - storage_simply_remove_recursive(storage, furi_string_get_cstr(path_src)); - } - } - - dir_walk_free(dir_walk); - furi_string_free(path_dst); - furi_string_free(path_src); - - furi_record_close(RECORD_STORAGE); - - return false; -} - -static bool storage_move_to_sd_check(void) { - Storage* storage = furi_record_open(RECORD_STORAGE); - - bool should_migrate = false; - - DirWalk* dir_walk = dir_walk_alloc(storage); - dir_walk_set_recursive(dir_walk, false); - dir_walk_set_filter_cb(dir_walk, storage_move_to_sd_check_entry, NULL); - - FuriString* name; - name = furi_string_alloc(); - - if(dir_walk_open(dir_walk, STORAGE_INT_PATH_PREFIX)) { - // if at least 1 entry is present, we should migrate - should_migrate = (dir_walk_read(dir_walk, name, NULL) == DirWalkOK); - } - - dir_walk_free(dir_walk); - furi_string_free(name); - - furi_record_close(RECORD_STORAGE); - - return should_migrate; -} - -static bool storage_move_to_sd_custom_event_callback(void* context, uint32_t event) { - furi_assert(context); - StorageMoveToSd* app = context; - return scene_manager_handle_custom_event(app->scene_manager, event); -} - -static bool storage_move_to_sd_back_event_callback(void* context) { - furi_assert(context); - StorageMoveToSd* app = context; - return scene_manager_handle_back_event(app->scene_manager); -} - -static void storage_move_to_sd_unmount_callback(const void* message, void* context) { - StorageMoveToSd* app = context; - furi_assert(app); - const StorageEvent* storage_event = message; - - if((storage_event->type == StorageEventTypeCardUnmount) || - (storage_event->type == StorageEventTypeCardMountError)) { - view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit); - } -} - -static StorageMoveToSd* storage_move_to_sd_alloc(void) { - StorageMoveToSd* app = malloc(sizeof(StorageMoveToSd)); - - app->gui = furi_record_open(RECORD_GUI); - app->notifications = furi_record_open(RECORD_NOTIFICATION); - - app->view_dispatcher = view_dispatcher_alloc(); - app->scene_manager = scene_manager_alloc(&storage_move_to_sd_scene_handlers, app); - - view_dispatcher_enable_queue(app->view_dispatcher); - view_dispatcher_set_event_callback_context(app->view_dispatcher, app); - - view_dispatcher_set_custom_event_callback( - app->view_dispatcher, storage_move_to_sd_custom_event_callback); - view_dispatcher_set_navigation_event_callback( - app->view_dispatcher, storage_move_to_sd_back_event_callback); - - view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - - app->widget = widget_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, StorageMoveToSdViewWidget, widget_get_view(app->widget)); - - scene_manager_next_scene(app->scene_manager, StorageMoveToSdConfirm); - - Storage* storage = furi_record_open(RECORD_STORAGE); - app->sub = furi_pubsub_subscribe( - storage_get_pubsub(storage), storage_move_to_sd_unmount_callback, app); - furi_record_close(RECORD_STORAGE); - - return app; -} - -static void storage_move_to_sd_free(StorageMoveToSd* app) { - Storage* storage = furi_record_open(RECORD_STORAGE); - furi_pubsub_unsubscribe(storage_get_pubsub(storage), app->sub); - furi_record_close(RECORD_STORAGE); - furi_record_close(RECORD_NOTIFICATION); - - view_dispatcher_remove_view(app->view_dispatcher, StorageMoveToSdViewWidget); - widget_free(app->widget); - view_dispatcher_free(app->view_dispatcher); - scene_manager_free(app->scene_manager); - - furi_record_close(RECORD_GUI); - - free(app); -} - -int32_t storage_move_to_sd_app(void* p) { - UNUSED(p); - - if(storage_move_to_sd_check()) { - StorageMoveToSd* app = storage_move_to_sd_alloc(); - notification_message(app->notifications, &sequence_display_backlight_on); - view_dispatcher_run(app->view_dispatcher); - storage_move_to_sd_free(app); - } else { - FURI_LOG_I(TAG, "Nothing to move"); - } - - // Remove unused region file from int memory - storage_move_to_sd_remove_region(); - - return 0; -} - -static void storage_move_to_sd_mount_callback(const void* message, void* context) { - UNUSED(context); - - const StorageEvent* storage_event = message; - - if(storage_event->type == StorageEventTypeCardMount) { - Loader* loader = furi_record_open(RECORD_LOADER); - loader_start(loader, "StorageMoveToSd", NULL, NULL); - furi_record_close(RECORD_LOADER); - } -} - -int32_t storage_move_to_sd_start(void* p) { - UNUSED(p); - Storage* storage = furi_record_open(RECORD_STORAGE); - - furi_pubsub_subscribe(storage_get_pubsub(storage), storage_move_to_sd_mount_callback, NULL); - - furi_record_close(RECORD_STORAGE); - return 0; -} diff --git a/applications/system/storage_move_to_sd/storage_move_to_sd.h b/applications/system/storage_move_to_sd/storage_move_to_sd.h deleted file mode 100644 index 135f3e9b0b..0000000000 --- a/applications/system/storage_move_to_sd/storage_move_to_sd.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "scenes/storage_move_to_sd_scene.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - MoveToSdCustomEventExit, - MoveToSdCustomEventConfirm, -} MoveToSdCustomEvent; - -typedef struct { - // records - Gui* gui; - Widget* widget; - NotificationApp* notifications; - - // view management - SceneManager* scene_manager; - ViewDispatcher* view_dispatcher; - - FuriPubSubSubscription* sub; - -} StorageMoveToSd; - -typedef enum { - StorageMoveToSdViewWidget, -} StorageMoveToSdView; - -bool storage_move_to_sd_perform(void); - -#ifdef __cplusplus -} -#endif diff --git a/applications/system/updater/updater.c b/applications/system/updater/updater.c index 4c7fd29e9c..15d7dd3a94 100644 --- a/applications/system/updater/updater.c +++ b/applications/system/updater/updater.c @@ -47,8 +47,6 @@ Updater* updater_alloc(const char* arg) { updater->view_dispatcher = view_dispatcher_alloc(); updater->scene_manager = scene_manager_alloc(&updater_scene_handlers, updater); - view_dispatcher_enable_queue(updater->view_dispatcher); - view_dispatcher_set_event_callback_context(updater->view_dispatcher, updater); view_dispatcher_set_custom_event_callback( updater->view_dispatcher, updater_custom_event_callback); diff --git a/applications/system/updater/util/update_task.c b/applications/system/updater/util/update_task.c index 0eae0eaf52..8f051ff77a 100644 --- a/applications/system/updater/util/update_task.c +++ b/applications/system/updater/util/update_task.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #define TAG "UpdWorker" diff --git a/applications/system/updater/util/update_task_worker_flasher.c b/applications/system/updater/util/update_task_worker_flasher.c index 848cc54942..e7e1bbbedc 100644 --- a/applications/system/updater/util/update_task_worker_flasher.c +++ b/applications/system/updater/util/update_task_worker_flasher.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/assets/dolphin/blocking/L0_NewMail_128x51/frame_0.png b/assets/dolphin/blocking/L0_NewMail_128x51/frame_0.png index 5f7f5fa425..d948c55bdd 100644 Binary files a/assets/dolphin/blocking/L0_NewMail_128x51/frame_0.png and b/assets/dolphin/blocking/L0_NewMail_128x51/frame_0.png differ diff --git a/assets/dolphin/blocking/L0_NewMail_128x51/frame_1.png b/assets/dolphin/blocking/L0_NewMail_128x51/frame_1.png index db9bf227b0..5730f18898 100644 Binary files a/assets/dolphin/blocking/L0_NewMail_128x51/frame_1.png and b/assets/dolphin/blocking/L0_NewMail_128x51/frame_1.png differ diff --git a/assets/dolphin/blocking/L0_NewMail_128x51/frame_2.png b/assets/dolphin/blocking/L0_NewMail_128x51/frame_2.png index 5394851f55..aa1061b94c 100644 Binary files a/assets/dolphin/blocking/L0_NewMail_128x51/frame_2.png and b/assets/dolphin/blocking/L0_NewMail_128x51/frame_2.png differ diff --git a/assets/dolphin/blocking/L0_NewMail_128x51/frame_3.png b/assets/dolphin/blocking/L0_NewMail_128x51/frame_3.png index d16966fb40..cdcdda356e 100644 Binary files a/assets/dolphin/blocking/L0_NewMail_128x51/frame_3.png and b/assets/dolphin/blocking/L0_NewMail_128x51/frame_3.png differ diff --git a/assets/dolphin/blocking/L0_NoDb_128x51/frame_0.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_0.png index 759007623a..ee52444d89 100644 Binary files a/assets/dolphin/blocking/L0_NoDb_128x51/frame_0.png and b/assets/dolphin/blocking/L0_NoDb_128x51/frame_0.png differ diff --git a/assets/dolphin/blocking/L0_NoDb_128x51/frame_1.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_1.png index c9810b61e3..a654758995 100644 Binary files a/assets/dolphin/blocking/L0_NoDb_128x51/frame_1.png and b/assets/dolphin/blocking/L0_NoDb_128x51/frame_1.png differ diff --git a/assets/dolphin/blocking/L0_NoDb_128x51/frame_2.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_2.png index e4d381b0ae..4469a5cad7 100644 Binary files a/assets/dolphin/blocking/L0_NoDb_128x51/frame_2.png and b/assets/dolphin/blocking/L0_NoDb_128x51/frame_2.png differ diff --git a/assets/dolphin/blocking/L0_NoDb_128x51/frame_3.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_3.png index b48aef9783..c7668019d4 100644 Binary files a/assets/dolphin/blocking/L0_NoDb_128x51/frame_3.png and b/assets/dolphin/blocking/L0_NoDb_128x51/frame_3.png differ diff --git a/assets/dolphin/blocking/L0_SdBad_128x51/frame_0.png b/assets/dolphin/blocking/L0_SdBad_128x51/frame_0.png index f9a7e073a6..6b6ddb123f 100644 Binary files a/assets/dolphin/blocking/L0_SdBad_128x51/frame_0.png and b/assets/dolphin/blocking/L0_SdBad_128x51/frame_0.png differ diff --git a/assets/dolphin/blocking/L0_SdBad_128x51/frame_1.png b/assets/dolphin/blocking/L0_SdBad_128x51/frame_1.png index 147561f0a4..dffda30108 100644 Binary files a/assets/dolphin/blocking/L0_SdBad_128x51/frame_1.png and b/assets/dolphin/blocking/L0_SdBad_128x51/frame_1.png differ diff --git a/assets/dolphin/blocking/L0_SdOk_128x51/frame_0.png b/assets/dolphin/blocking/L0_SdOk_128x51/frame_0.png index 6ebbc11110..89af52e697 100644 Binary files a/assets/dolphin/blocking/L0_SdOk_128x51/frame_0.png and b/assets/dolphin/blocking/L0_SdOk_128x51/frame_0.png differ diff --git a/assets/dolphin/blocking/L0_SdOk_128x51/frame_1.png b/assets/dolphin/blocking/L0_SdOk_128x51/frame_1.png index 5f7a5d2a50..7417b7ed90 100644 Binary files a/assets/dolphin/blocking/L0_SdOk_128x51/frame_1.png and b/assets/dolphin/blocking/L0_SdOk_128x51/frame_1.png differ diff --git a/assets/dolphin/blocking/L0_SdOk_128x51/frame_2.png b/assets/dolphin/blocking/L0_SdOk_128x51/frame_2.png index a3450ae05d..3e7d95af36 100644 Binary files a/assets/dolphin/blocking/L0_SdOk_128x51/frame_2.png and b/assets/dolphin/blocking/L0_SdOk_128x51/frame_2.png differ diff --git a/assets/dolphin/blocking/L0_SdOk_128x51/frame_3.png b/assets/dolphin/blocking/L0_SdOk_128x51/frame_3.png index 1e52f15137..78dc1e8092 100644 Binary files a/assets/dolphin/blocking/L0_SdOk_128x51/frame_3.png and b/assets/dolphin/blocking/L0_SdOk_128x51/frame_3.png differ diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_0.png b/assets/dolphin/blocking/L0_Url_128x51/frame_0.png index 387c85ea2e..e95d7c3a41 100644 Binary files a/assets/dolphin/blocking/L0_Url_128x51/frame_0.png and b/assets/dolphin/blocking/L0_Url_128x51/frame_0.png differ diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_1.png b/assets/dolphin/blocking/L0_Url_128x51/frame_1.png index 9975ca3f04..d614498e6a 100644 Binary files a/assets/dolphin/blocking/L0_Url_128x51/frame_1.png and b/assets/dolphin/blocking/L0_Url_128x51/frame_1.png differ diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_2.png b/assets/dolphin/blocking/L0_Url_128x51/frame_2.png index 84241c3f16..e1e676d9d3 100644 Binary files a/assets/dolphin/blocking/L0_Url_128x51/frame_2.png and b/assets/dolphin/blocking/L0_Url_128x51/frame_2.png differ diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_3.png b/assets/dolphin/blocking/L0_Url_128x51/frame_3.png index c44b171bfa..928c1a78d3 100644 Binary files a/assets/dolphin/blocking/L0_Url_128x51/frame_3.png and b/assets/dolphin/blocking/L0_Url_128x51/frame_3.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_0.png b/assets/dolphin/external/L1_Akira_128x64/frame_0.png old mode 100755 new mode 100644 index 36c1bbd499..bef9d522da Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_0.png and b/assets/dolphin/external/L1_Akira_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_1.png b/assets/dolphin/external/L1_Akira_128x64/frame_1.png old mode 100755 new mode 100644 index 1950347a63..4d476beed4 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_1.png and b/assets/dolphin/external/L1_Akira_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_10.png b/assets/dolphin/external/L1_Akira_128x64/frame_10.png old mode 100755 new mode 100644 index 65a0154d49..ca01a68d11 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_10.png and b/assets/dolphin/external/L1_Akira_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_11.png b/assets/dolphin/external/L1_Akira_128x64/frame_11.png old mode 100755 new mode 100644 index f7c0864314..f767fe332b Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_11.png and b/assets/dolphin/external/L1_Akira_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_12.png b/assets/dolphin/external/L1_Akira_128x64/frame_12.png old mode 100755 new mode 100644 index e3bfd179d9..701b70c439 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_12.png and b/assets/dolphin/external/L1_Akira_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_13.png b/assets/dolphin/external/L1_Akira_128x64/frame_13.png old mode 100755 new mode 100644 index 0094ab5ae4..01d8b8c9a5 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_13.png and b/assets/dolphin/external/L1_Akira_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_14.png b/assets/dolphin/external/L1_Akira_128x64/frame_14.png old mode 100755 new mode 100644 index b36fd051fc..18da66c105 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_14.png and b/assets/dolphin/external/L1_Akira_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_15.png b/assets/dolphin/external/L1_Akira_128x64/frame_15.png old mode 100755 new mode 100644 index 33607328a0..529ae406e4 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_15.png and b/assets/dolphin/external/L1_Akira_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_16.png b/assets/dolphin/external/L1_Akira_128x64/frame_16.png old mode 100755 new mode 100644 index e115834eff..d7c0152123 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_16.png and b/assets/dolphin/external/L1_Akira_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_17.png b/assets/dolphin/external/L1_Akira_128x64/frame_17.png old mode 100755 new mode 100644 index 8e5fa20d8d..95068c50f0 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_17.png and b/assets/dolphin/external/L1_Akira_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_18.png b/assets/dolphin/external/L1_Akira_128x64/frame_18.png old mode 100755 new mode 100644 index 6a658e0e22..87069ea8e1 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_18.png and b/assets/dolphin/external/L1_Akira_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_19.png b/assets/dolphin/external/L1_Akira_128x64/frame_19.png old mode 100755 new mode 100644 index cba72f16f7..48e6070965 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_19.png and b/assets/dolphin/external/L1_Akira_128x64/frame_19.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_2.png b/assets/dolphin/external/L1_Akira_128x64/frame_2.png old mode 100755 new mode 100644 index 9f4cc1fb9e..72febfa30e Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_2.png and b/assets/dolphin/external/L1_Akira_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_20.png b/assets/dolphin/external/L1_Akira_128x64/frame_20.png old mode 100755 new mode 100644 index 457fa7a00e..4b4c5b14c6 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_20.png and b/assets/dolphin/external/L1_Akira_128x64/frame_20.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_21.png b/assets/dolphin/external/L1_Akira_128x64/frame_21.png old mode 100755 new mode 100644 index 727511100d..ec6168e31c Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_21.png and b/assets/dolphin/external/L1_Akira_128x64/frame_21.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_22.png b/assets/dolphin/external/L1_Akira_128x64/frame_22.png old mode 100755 new mode 100644 index 213e05771f..c90432ebe6 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_22.png and b/assets/dolphin/external/L1_Akira_128x64/frame_22.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_23.png b/assets/dolphin/external/L1_Akira_128x64/frame_23.png old mode 100755 new mode 100644 index 5d3571db86..b49348856e Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_23.png and b/assets/dolphin/external/L1_Akira_128x64/frame_23.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_24.png b/assets/dolphin/external/L1_Akira_128x64/frame_24.png old mode 100755 new mode 100644 index e54d47e29f..b5ea1a21ca Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_24.png and b/assets/dolphin/external/L1_Akira_128x64/frame_24.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_25.png b/assets/dolphin/external/L1_Akira_128x64/frame_25.png old mode 100755 new mode 100644 index 26c944d16e..9da0a4cc6a Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_25.png and b/assets/dolphin/external/L1_Akira_128x64/frame_25.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_26.png b/assets/dolphin/external/L1_Akira_128x64/frame_26.png old mode 100755 new mode 100644 index 2972318cda..e7838e39f3 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_26.png and b/assets/dolphin/external/L1_Akira_128x64/frame_26.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_27.png b/assets/dolphin/external/L1_Akira_128x64/frame_27.png old mode 100755 new mode 100644 index 397face78d..b1ae3ee6c2 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_27.png and b/assets/dolphin/external/L1_Akira_128x64/frame_27.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_28.png b/assets/dolphin/external/L1_Akira_128x64/frame_28.png old mode 100755 new mode 100644 index 6ca246f57c..3b12a422df Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_28.png and b/assets/dolphin/external/L1_Akira_128x64/frame_28.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_29.png b/assets/dolphin/external/L1_Akira_128x64/frame_29.png old mode 100755 new mode 100644 index 8bcc83a1db..b4a35158e3 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_29.png and b/assets/dolphin/external/L1_Akira_128x64/frame_29.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_3.png b/assets/dolphin/external/L1_Akira_128x64/frame_3.png old mode 100755 new mode 100644 index 7a1d2b36e8..9afce23c9b Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_3.png and b/assets/dolphin/external/L1_Akira_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_30.png b/assets/dolphin/external/L1_Akira_128x64/frame_30.png old mode 100755 new mode 100644 index 9f477f8d7f..8702554973 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_30.png and b/assets/dolphin/external/L1_Akira_128x64/frame_30.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_31.png b/assets/dolphin/external/L1_Akira_128x64/frame_31.png old mode 100755 new mode 100644 index 4f2deb5c58..68249a4d52 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_31.png and b/assets/dolphin/external/L1_Akira_128x64/frame_31.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_32.png b/assets/dolphin/external/L1_Akira_128x64/frame_32.png old mode 100755 new mode 100644 index 4f59f99555..5eb2b770bf Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_32.png and b/assets/dolphin/external/L1_Akira_128x64/frame_32.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_33.png b/assets/dolphin/external/L1_Akira_128x64/frame_33.png old mode 100755 new mode 100644 index 1adf3d3512..795b88fb40 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_33.png and b/assets/dolphin/external/L1_Akira_128x64/frame_33.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_34.png b/assets/dolphin/external/L1_Akira_128x64/frame_34.png old mode 100755 new mode 100644 index 5ffc55f75f..cd9673d565 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_34.png and b/assets/dolphin/external/L1_Akira_128x64/frame_34.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_35.png b/assets/dolphin/external/L1_Akira_128x64/frame_35.png old mode 100755 new mode 100644 index 9a101f0aa3..7a2154c4b9 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_35.png and b/assets/dolphin/external/L1_Akira_128x64/frame_35.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_4.png b/assets/dolphin/external/L1_Akira_128x64/frame_4.png old mode 100755 new mode 100644 index ea42d75d60..55f3b66a68 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_4.png and b/assets/dolphin/external/L1_Akira_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_5.png b/assets/dolphin/external/L1_Akira_128x64/frame_5.png old mode 100755 new mode 100644 index c347d30353..6b56666772 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_5.png and b/assets/dolphin/external/L1_Akira_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_6.png b/assets/dolphin/external/L1_Akira_128x64/frame_6.png old mode 100755 new mode 100644 index 07a7c70c02..f16295ffdb Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_6.png and b/assets/dolphin/external/L1_Akira_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_7.png b/assets/dolphin/external/L1_Akira_128x64/frame_7.png old mode 100755 new mode 100644 index 275f2a3577..e28db78328 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_7.png and b/assets/dolphin/external/L1_Akira_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_8.png b/assets/dolphin/external/L1_Akira_128x64/frame_8.png old mode 100755 new mode 100644 index 1feb3e8751..e44453afac Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_8.png and b/assets/dolphin/external/L1_Akira_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L1_Akira_128x64/frame_9.png b/assets/dolphin/external/L1_Akira_128x64/frame_9.png old mode 100755 new mode 100644 index e0ba8250fc..aed5833f38 Binary files a/assets/dolphin/external/L1_Akira_128x64/frame_9.png and b/assets/dolphin/external/L1_Akira_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L1_Boxing_128x64/frame_0.png b/assets/dolphin/external/L1_Boxing_128x64/frame_0.png index b6b2c75b8f..59d3ef3fab 100644 Binary files a/assets/dolphin/external/L1_Boxing_128x64/frame_0.png and b/assets/dolphin/external/L1_Boxing_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Boxing_128x64/frame_1.png b/assets/dolphin/external/L1_Boxing_128x64/frame_1.png index 347d71cc20..ecbd274190 100644 Binary files a/assets/dolphin/external/L1_Boxing_128x64/frame_1.png and b/assets/dolphin/external/L1_Boxing_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Boxing_128x64/frame_2.png b/assets/dolphin/external/L1_Boxing_128x64/frame_2.png index 51a7fd2365..7c5f0b6cc1 100644 Binary files a/assets/dolphin/external/L1_Boxing_128x64/frame_2.png and b/assets/dolphin/external/L1_Boxing_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Boxing_128x64/frame_3.png b/assets/dolphin/external/L1_Boxing_128x64/frame_3.png index 7004e10c30..aee654cc8f 100644 Binary files a/assets/dolphin/external/L1_Boxing_128x64/frame_3.png and b/assets/dolphin/external/L1_Boxing_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Boxing_128x64/frame_4.png b/assets/dolphin/external/L1_Boxing_128x64/frame_4.png index 556cb8948d..eef11402bf 100644 Binary files a/assets/dolphin/external/L1_Boxing_128x64/frame_4.png and b/assets/dolphin/external/L1_Boxing_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_Boxing_128x64/frame_5.png b/assets/dolphin/external/L1_Boxing_128x64/frame_5.png index fd61703404..cf2299b284 100644 Binary files a/assets/dolphin/external/L1_Boxing_128x64/frame_5.png and b/assets/dolphin/external/L1_Boxing_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_Boxing_128x64/frame_6.png b/assets/dolphin/external/L1_Boxing_128x64/frame_6.png index 34839517ca..853d85fb71 100644 Binary files a/assets/dolphin/external/L1_Boxing_128x64/frame_6.png and b/assets/dolphin/external/L1_Boxing_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_Cry_128x64/frame_0.png b/assets/dolphin/external/L1_Cry_128x64/frame_0.png index b2636f005f..58ceddd8fd 100644 Binary files a/assets/dolphin/external/L1_Cry_128x64/frame_0.png and b/assets/dolphin/external/L1_Cry_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Cry_128x64/frame_1.png b/assets/dolphin/external/L1_Cry_128x64/frame_1.png index e73499e945..df0abf137f 100644 Binary files a/assets/dolphin/external/L1_Cry_128x64/frame_1.png and b/assets/dolphin/external/L1_Cry_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Cry_128x64/frame_2.png b/assets/dolphin/external/L1_Cry_128x64/frame_2.png index 16005a990f..17b991809a 100644 Binary files a/assets/dolphin/external/L1_Cry_128x64/frame_2.png and b/assets/dolphin/external/L1_Cry_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Cry_128x64/frame_3.png b/assets/dolphin/external/L1_Cry_128x64/frame_3.png index 02e833dec8..e0c975beaf 100644 Binary files a/assets/dolphin/external/L1_Cry_128x64/frame_3.png and b/assets/dolphin/external/L1_Cry_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Cry_128x64/frame_4.png b/assets/dolphin/external/L1_Cry_128x64/frame_4.png index 3f7dff4db6..4e2e802402 100644 Binary files a/assets/dolphin/external/L1_Cry_128x64/frame_4.png and b/assets/dolphin/external/L1_Cry_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_Cry_128x64/frame_5.png b/assets/dolphin/external/L1_Cry_128x64/frame_5.png index 3851067874..0a32853970 100644 Binary files a/assets/dolphin/external/L1_Cry_128x64/frame_5.png and b/assets/dolphin/external/L1_Cry_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_Cry_128x64/frame_6.png b/assets/dolphin/external/L1_Cry_128x64/frame_6.png index 7871674dbb..4bc351b8d5 100644 Binary files a/assets/dolphin/external/L1_Cry_128x64/frame_6.png and b/assets/dolphin/external/L1_Cry_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_Cry_128x64/frame_7.png b/assets/dolphin/external/L1_Cry_128x64/frame_7.png index 5865e91e11..f1f78883f5 100644 Binary files a/assets/dolphin/external/L1_Cry_128x64/frame_7.png and b/assets/dolphin/external/L1_Cry_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_0.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_0.png index 396ec251af..120855f61b 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_0.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_1.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_1.png index 2a497f85a5..a9346b8dad 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_1.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_10.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_10.png index d33f1e4165..d4ab0e356c 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_10.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_11.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_11.png index e5ee82f701..2d98d57ab2 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_11.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_12.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_12.png index f3059dde73..95d09d14be 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_12.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_13.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_13.png index 5d1ff45be8..c385a5ec45 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_13.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_14.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_14.png index d46f62e897..25b4ec5653 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_14.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_15.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_15.png index ec11dbd035..d9ef6edbbe 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_15.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_16.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_16.png index 720e95f9e0..d682438268 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_16.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_17.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_17.png index 7debe764fd..1a94e80b61 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_17.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_18.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_18.png index d3674a02b4..54615c6138 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_18.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_2.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_2.png index ba44351579..ca7cb9dbcd 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_2.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_3.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_3.png index c0ee416231..5a18e3cbe6 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_3.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_4.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_4.png index ecda812749..909c6106c7 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_4.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_5.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_5.png index e8662b2eb6..582e2b19fc 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_5.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_6.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_6.png index 29cadd14eb..d1e4f0af49 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_6.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_7.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_7.png index 18e793b585..120855f61b 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_7.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_8.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_8.png index 34b2e40012..521a8ec43e 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_8.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L1_Furippa1_128x64/frame_9.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_9.png index d192f2e344..77d0198d0b 100644 Binary files a/assets/dolphin/external/L1_Furippa1_128x64/frame_9.png and b/assets/dolphin/external/L1_Furippa1_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_0.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_0.png index 8b8dc80bce..ed6f4a71f5 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_0.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_1.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_1.png index 956de61707..f2dba5e872 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_1.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_10.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_10.png index 93fdaa0767..bd6291f994 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_10.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_11.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_11.png index a4e194825e..e4a6d1639d 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_11.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_12.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_12.png index 9cbcbd070e..fc62957e28 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_12.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_13.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_13.png index a745cdb03f..ef2875aefc 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_13.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_14.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_14.png index 768f471ec1..e56f7c6c46 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_14.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_15.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_15.png index 2f50fb8c94..1bb46d54a1 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_15.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_16.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_16.png index fc7b76696c..76ebd1f395 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_16.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_17.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_17.png index 013e2008a2..7a63396382 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_17.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_18.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_18.png index 795120e772..172ee4d9cb 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_18.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_19.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_19.png index 52061a5a26..afd4c496fe 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_19.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_19.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_2.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_2.png index 10afed391e..5f3fe28047 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_2.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_20.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_20.png index 52f87f3a88..287800454c 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_20.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_20.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_21.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_21.png index 9696e0b5cc..50ef42181f 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_21.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_21.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_22.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_22.png index d23ee492b0..ebab212e25 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_22.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_22.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_23.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_23.png index 9d368900c9..55d2e56952 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_23.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_23.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_24.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_24.png index daf0788ad7..df78c0887b 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_24.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_24.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_25.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_25.png index b40333654f..9d71ca41b9 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_25.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_25.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_26.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_26.png index 9d499f23d2..ea66720dd5 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_26.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_26.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_27.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_27.png index 0291dfb583..0ee0b2135b 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_27.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_27.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_28.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_28.png index 54a889d815..02b31050b1 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_28.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_28.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_29.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_29.png index ba79b3b88f..c00255748b 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_29.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_29.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_3.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_3.png index bedf366c6c..9cac278976 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_3.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_30.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_30.png index 0731760dff..8d9176c4c2 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_30.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_30.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_31.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_31.png index 898efdc4b8..d73a655832 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_31.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_31.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_32.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_32.png index 39f5db8a01..c97abe79bd 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_32.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_32.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_33.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_33.png index bee4cff087..20299c04dd 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_33.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_33.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_34.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_34.png index 969b91193d..bf89e9d7bb 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_34.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_34.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_35.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_35.png index a72cf1823e..40440a0e12 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_35.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_35.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_36.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_36.png index 9a13e7c67d..627a02ef2e 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_36.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_36.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_37.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_37.png index da3ee77f30..7cb901f41b 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_37.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_37.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_38.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_38.png index 93da7f4f94..6b46de6098 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_38.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_38.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_39.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_39.png index 7510931b44..a2946bff32 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_39.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_39.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_4.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_4.png index f99454b164..314e716ed5 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_4.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_40.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_40.png index a17a14044a..5cb229d26a 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_40.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_40.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_41.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_41.png index f763540c91..048d4dfeb4 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_41.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_41.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_42.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_42.png index 97a829e9b7..6ec37e4a60 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_42.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_42.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_43.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_43.png index 7eadf75185..efb7389dfe 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_43.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_43.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_44.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_44.png index 5241195d32..80a09122dc 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_44.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_44.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_45.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_45.png index 2a3ea8e23a..232a5c63a1 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_45.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_45.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_46.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_46.png index f4b263b199..3d2b6a87b6 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_46.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_46.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_47.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_47.png index 1563ff39b2..90a5aa5d61 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_47.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_47.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_5.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_5.png index 394bb53df4..934c098b3c 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_5.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_6.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_6.png index 3f84ad47e3..54ad31fb49 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_6.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_7.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_7.png index 8ea650ad07..1488511859 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_7.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_8.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_8.png index 2c8cf3f5d7..542ff45cbf 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_8.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_9.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_9.png index caf6a90ef6..cf612c74ef 100644 Binary files a/assets/dolphin/external/L1_Kaiju_128x64/frame_9.png and b/assets/dolphin/external/L1_Kaiju_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L1_Laptop_128x51/frame_0.png b/assets/dolphin/external/L1_Laptop_128x51/frame_0.png index a42e97fc44..cd0f0bfb48 100644 Binary files a/assets/dolphin/external/L1_Laptop_128x51/frame_0.png and b/assets/dolphin/external/L1_Laptop_128x51/frame_0.png differ diff --git a/assets/dolphin/external/L1_Laptop_128x51/frame_1.png b/assets/dolphin/external/L1_Laptop_128x51/frame_1.png index 90152d2b3c..3b326e5846 100644 Binary files a/assets/dolphin/external/L1_Laptop_128x51/frame_1.png and b/assets/dolphin/external/L1_Laptop_128x51/frame_1.png differ diff --git a/assets/dolphin/external/L1_Laptop_128x51/frame_2.png b/assets/dolphin/external/L1_Laptop_128x51/frame_2.png index 93df45f84d..d8a2623b44 100644 Binary files a/assets/dolphin/external/L1_Laptop_128x51/frame_2.png and b/assets/dolphin/external/L1_Laptop_128x51/frame_2.png differ diff --git a/assets/dolphin/external/L1_Laptop_128x51/frame_3.png b/assets/dolphin/external/L1_Laptop_128x51/frame_3.png index a86b5e744b..d4ab7525c6 100644 Binary files a/assets/dolphin/external/L1_Laptop_128x51/frame_3.png and b/assets/dolphin/external/L1_Laptop_128x51/frame_3.png differ diff --git a/assets/dolphin/external/L1_Laptop_128x51/frame_4.png b/assets/dolphin/external/L1_Laptop_128x51/frame_4.png index 8ca6f6319e..ef5fc0e7f4 100644 Binary files a/assets/dolphin/external/L1_Laptop_128x51/frame_4.png and b/assets/dolphin/external/L1_Laptop_128x51/frame_4.png differ diff --git a/assets/dolphin/external/L1_Laptop_128x51/frame_5.png b/assets/dolphin/external/L1_Laptop_128x51/frame_5.png index ef1a75b90e..0f0528f50a 100644 Binary files a/assets/dolphin/external/L1_Laptop_128x51/frame_5.png and b/assets/dolphin/external/L1_Laptop_128x51/frame_5.png differ diff --git a/assets/dolphin/external/L1_Laptop_128x51/frame_6.png b/assets/dolphin/external/L1_Laptop_128x51/frame_6.png index 7e148697b1..1c06ae08f2 100644 Binary files a/assets/dolphin/external/L1_Laptop_128x51/frame_6.png and b/assets/dolphin/external/L1_Laptop_128x51/frame_6.png differ diff --git a/assets/dolphin/external/L1_Laptop_128x51/frame_7.png b/assets/dolphin/external/L1_Laptop_128x51/frame_7.png index ca19b669fd..24a9b853a6 100644 Binary files a/assets/dolphin/external/L1_Laptop_128x51/frame_7.png and b/assets/dolphin/external/L1_Laptop_128x51/frame_7.png differ diff --git a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_0.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_0.png index c7751a1d4b..011570b2c3 100644 Binary files a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_0.png and b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_1.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_1.png index 20b3a71045..6ee8edd662 100644 Binary files a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_1.png and b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_10.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_10.png index ef2ed21d6e..c25a72534a 100644 Binary files a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_10.png and b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_11.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_11.png index 0d2610a11d..420ee0ef59 100644 Binary files a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_11.png and b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_12.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_12.png index 1edc934806..fef1b5d50a 100644 Binary files a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_12.png and b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_2.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_2.png index 5752d80e6f..64103f1dba 100644 Binary files a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_2.png and b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_3.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_3.png index f62078f842..a05fdf8253 100644 Binary files a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_3.png and b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_4.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_4.png index 021e058220..569fc7779a 100644 Binary files a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_4.png and b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_5.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_5.png index d7e88112a8..d8ab4235c1 100644 Binary files a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_5.png and b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_6.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_6.png index 142ebbca02..c927e79284 100644 Binary files a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_6.png and b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_7.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_7.png index 26af849480..898ecd842b 100644 Binary files a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_7.png and b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_8.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_8.png index d307e7a27c..da93d6f148 100644 Binary files a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_8.png and b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_9.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_9.png index 0d28a86156..edf48b0f0d 100644 Binary files a/assets/dolphin/external/L1_Leaving_sad_128x64/frame_9.png and b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_0.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_0.png index 04aa17ac07..c1046f9e11 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_0.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_1.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_1.png index d93b1f588d..24c08c043c 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_1.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_10.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_10.png index 47185499d7..324adab8c2 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_10.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_11.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_11.png index d90fd3d5bc..5cbb23ec58 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_11.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_12.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_12.png index 15ded26725..e9562ab71f 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_12.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_13.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_13.png index 13ee0450e2..449235a1ed 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_13.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_2.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_2.png index 32c0a1b9b5..c94fbaf161 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_2.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_3.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_3.png index 93593594e9..eb23cfe0cd 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_3.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_4.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_4.png index d6ca9b82d4..1db181127a 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_4.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_5.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_5.png index 0421d8f6fe..107d827799 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_5.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_6.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_6.png index 17930e0758..6c2fa6ecb7 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_6.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_7.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_7.png index d4115d240c..fb13a48b0a 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_7.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_8.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_8.png index 570c8b0c4c..9cf7366e4b 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_8.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L1_Mad_fist_128x64/frame_9.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_9.png index 2b6b6e57cb..27e3dc369b 100644 Binary files a/assets/dolphin/external/L1_Mad_fist_128x64/frame_9.png and b/assets/dolphin/external/L1_Mad_fist_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_0.png b/assets/dolphin/external/L1_Mods_128x64/frame_0.png index 220908495a..e185204eec 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_0.png and b/assets/dolphin/external/L1_Mods_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_1.png b/assets/dolphin/external/L1_Mods_128x64/frame_1.png index 9123906fbb..69bff228bf 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_1.png and b/assets/dolphin/external/L1_Mods_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_10.png b/assets/dolphin/external/L1_Mods_128x64/frame_10.png index e90ad5e90d..d09cc03a0e 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_10.png and b/assets/dolphin/external/L1_Mods_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_11.png b/assets/dolphin/external/L1_Mods_128x64/frame_11.png index 031c0ad81a..78ca6798f2 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_11.png and b/assets/dolphin/external/L1_Mods_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_12.png b/assets/dolphin/external/L1_Mods_128x64/frame_12.png index 856e068fd0..bfe678880a 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_12.png and b/assets/dolphin/external/L1_Mods_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_13.png b/assets/dolphin/external/L1_Mods_128x64/frame_13.png index a0366b2cfb..ad29e872d4 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_13.png and b/assets/dolphin/external/L1_Mods_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_14.png b/assets/dolphin/external/L1_Mods_128x64/frame_14.png index 24fd557abd..94ef0e6807 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_14.png and b/assets/dolphin/external/L1_Mods_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_15.png b/assets/dolphin/external/L1_Mods_128x64/frame_15.png index 3bf1d3ed2b..5f3e54d956 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_15.png and b/assets/dolphin/external/L1_Mods_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_16.png b/assets/dolphin/external/L1_Mods_128x64/frame_16.png index f0b44898fb..7bd404a93e 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_16.png and b/assets/dolphin/external/L1_Mods_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_17.png b/assets/dolphin/external/L1_Mods_128x64/frame_17.png index c98c70c912..f10d328f9d 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_17.png and b/assets/dolphin/external/L1_Mods_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_18.png b/assets/dolphin/external/L1_Mods_128x64/frame_18.png index 4f7b7ae82e..05cdb7be82 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_18.png and b/assets/dolphin/external/L1_Mods_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_19.png b/assets/dolphin/external/L1_Mods_128x64/frame_19.png index b3ad6700ce..c7e290ff92 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_19.png and b/assets/dolphin/external/L1_Mods_128x64/frame_19.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_2.png b/assets/dolphin/external/L1_Mods_128x64/frame_2.png index c4aac4b916..bba9f165e4 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_2.png and b/assets/dolphin/external/L1_Mods_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_20.png b/assets/dolphin/external/L1_Mods_128x64/frame_20.png index ea2eae4d7c..76f9007922 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_20.png and b/assets/dolphin/external/L1_Mods_128x64/frame_20.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_21.png b/assets/dolphin/external/L1_Mods_128x64/frame_21.png index 00a7a6e99c..a0c56bb318 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_21.png and b/assets/dolphin/external/L1_Mods_128x64/frame_21.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_22.png b/assets/dolphin/external/L1_Mods_128x64/frame_22.png index 137d5ddf6e..bd8464e4e2 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_22.png and b/assets/dolphin/external/L1_Mods_128x64/frame_22.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_23.png b/assets/dolphin/external/L1_Mods_128x64/frame_23.png index 89690fc038..4074e09830 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_23.png and b/assets/dolphin/external/L1_Mods_128x64/frame_23.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_24.png b/assets/dolphin/external/L1_Mods_128x64/frame_24.png index 53d7b07a5e..2aa0c42e0f 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_24.png and b/assets/dolphin/external/L1_Mods_128x64/frame_24.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_25.png b/assets/dolphin/external/L1_Mods_128x64/frame_25.png index 2838804e56..776f1a73df 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_25.png and b/assets/dolphin/external/L1_Mods_128x64/frame_25.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_26.png b/assets/dolphin/external/L1_Mods_128x64/frame_26.png index 2af49cf177..4df95f3759 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_26.png and b/assets/dolphin/external/L1_Mods_128x64/frame_26.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_27.png b/assets/dolphin/external/L1_Mods_128x64/frame_27.png index 7dc44d061e..3ee650af3d 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_27.png and b/assets/dolphin/external/L1_Mods_128x64/frame_27.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_28.png b/assets/dolphin/external/L1_Mods_128x64/frame_28.png index 87df75ff79..406d965ea3 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_28.png and b/assets/dolphin/external/L1_Mods_128x64/frame_28.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_29.png b/assets/dolphin/external/L1_Mods_128x64/frame_29.png index 2fdb9d7364..1a46e8b014 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_29.png and b/assets/dolphin/external/L1_Mods_128x64/frame_29.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_3.png b/assets/dolphin/external/L1_Mods_128x64/frame_3.png index 1b0e77426c..ea3f7c0061 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_3.png and b/assets/dolphin/external/L1_Mods_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_30.png b/assets/dolphin/external/L1_Mods_128x64/frame_30.png index 785f19fd04..f3ca771915 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_30.png and b/assets/dolphin/external/L1_Mods_128x64/frame_30.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_31.png b/assets/dolphin/external/L1_Mods_128x64/frame_31.png index 36310f705a..13917efddb 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_31.png and b/assets/dolphin/external/L1_Mods_128x64/frame_31.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_32.png b/assets/dolphin/external/L1_Mods_128x64/frame_32.png index 92db8f024d..f4d0972d8b 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_32.png and b/assets/dolphin/external/L1_Mods_128x64/frame_32.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_33.png b/assets/dolphin/external/L1_Mods_128x64/frame_33.png index 768030b3c5..27e17fba68 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_33.png and b/assets/dolphin/external/L1_Mods_128x64/frame_33.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_34.png b/assets/dolphin/external/L1_Mods_128x64/frame_34.png index 12f22abdb9..d8fb6fa4a1 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_34.png and b/assets/dolphin/external/L1_Mods_128x64/frame_34.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_35.png b/assets/dolphin/external/L1_Mods_128x64/frame_35.png index 9fca976de9..0ac3ecf942 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_35.png and b/assets/dolphin/external/L1_Mods_128x64/frame_35.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_36.png b/assets/dolphin/external/L1_Mods_128x64/frame_36.png index 4b2ab5863a..b856989ed6 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_36.png and b/assets/dolphin/external/L1_Mods_128x64/frame_36.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_37.png b/assets/dolphin/external/L1_Mods_128x64/frame_37.png index 69c709adce..753deefee4 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_37.png and b/assets/dolphin/external/L1_Mods_128x64/frame_37.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_38.png b/assets/dolphin/external/L1_Mods_128x64/frame_38.png index 13caae7ca2..61e2dbac50 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_38.png and b/assets/dolphin/external/L1_Mods_128x64/frame_38.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_39.png b/assets/dolphin/external/L1_Mods_128x64/frame_39.png index b1d1e8bfe4..4952ff527d 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_39.png and b/assets/dolphin/external/L1_Mods_128x64/frame_39.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_4.png b/assets/dolphin/external/L1_Mods_128x64/frame_4.png index 45e47de12a..2260541b41 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_4.png and b/assets/dolphin/external/L1_Mods_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_40.png b/assets/dolphin/external/L1_Mods_128x64/frame_40.png index acf000827f..6bce5ee409 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_40.png and b/assets/dolphin/external/L1_Mods_128x64/frame_40.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_41.png b/assets/dolphin/external/L1_Mods_128x64/frame_41.png index b6c6fbb191..010ba0efa1 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_41.png and b/assets/dolphin/external/L1_Mods_128x64/frame_41.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_42.png b/assets/dolphin/external/L1_Mods_128x64/frame_42.png index 7d2dcda5d9..1197601e33 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_42.png and b/assets/dolphin/external/L1_Mods_128x64/frame_42.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_43.png b/assets/dolphin/external/L1_Mods_128x64/frame_43.png index 461270ba4b..c7ac5c4468 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_43.png and b/assets/dolphin/external/L1_Mods_128x64/frame_43.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_44.png b/assets/dolphin/external/L1_Mods_128x64/frame_44.png index b018a94c19..a10c370204 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_44.png and b/assets/dolphin/external/L1_Mods_128x64/frame_44.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_45.png b/assets/dolphin/external/L1_Mods_128x64/frame_45.png index fa2b303cca..47cce6619a 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_45.png and b/assets/dolphin/external/L1_Mods_128x64/frame_45.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_46.png b/assets/dolphin/external/L1_Mods_128x64/frame_46.png index ed38122f52..f9e3ec5f40 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_46.png and b/assets/dolphin/external/L1_Mods_128x64/frame_46.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_47.png b/assets/dolphin/external/L1_Mods_128x64/frame_47.png index 38610bb4b4..2e87539b48 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_47.png and b/assets/dolphin/external/L1_Mods_128x64/frame_47.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_48.png b/assets/dolphin/external/L1_Mods_128x64/frame_48.png index 7f6b4b29a3..ad22352cbf 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_48.png and b/assets/dolphin/external/L1_Mods_128x64/frame_48.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_5.png b/assets/dolphin/external/L1_Mods_128x64/frame_5.png index 7c293b4859..0162f0da0a 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_5.png and b/assets/dolphin/external/L1_Mods_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_6.png b/assets/dolphin/external/L1_Mods_128x64/frame_6.png index e72e7a30ee..5a3b350467 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_6.png and b/assets/dolphin/external/L1_Mods_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_7.png b/assets/dolphin/external/L1_Mods_128x64/frame_7.png index 5c840d6f64..344f02fd16 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_7.png and b/assets/dolphin/external/L1_Mods_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_8.png b/assets/dolphin/external/L1_Mods_128x64/frame_8.png index f689f190cc..0d029c93e1 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_8.png and b/assets/dolphin/external/L1_Mods_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L1_Mods_128x64/frame_9.png b/assets/dolphin/external/L1_Mods_128x64/frame_9.png index 628394e57a..713c4449ec 100644 Binary files a/assets/dolphin/external/L1_Mods_128x64/frame_9.png and b/assets/dolphin/external/L1_Mods_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_0.png b/assets/dolphin/external/L1_My_dude_128x64/frame_0.png index bf07d03d6e..4706786b76 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_0.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_1.png b/assets/dolphin/external/L1_My_dude_128x64/frame_1.png index 4402654c77..e81a3eae7c 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_1.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_10.png b/assets/dolphin/external/L1_My_dude_128x64/frame_10.png index 10dabe4c5c..0bc0462a78 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_10.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_11.png b/assets/dolphin/external/L1_My_dude_128x64/frame_11.png index 878712fe23..0b2a3e97be 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_11.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_12.png b/assets/dolphin/external/L1_My_dude_128x64/frame_12.png index 19fc985ac8..d01bb39f52 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_12.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_13.png b/assets/dolphin/external/L1_My_dude_128x64/frame_13.png index 39172f26f9..2f4cb59877 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_13.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_14.png b/assets/dolphin/external/L1_My_dude_128x64/frame_14.png index 9a3a84fff8..c8b3def2a4 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_14.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_15.png b/assets/dolphin/external/L1_My_dude_128x64/frame_15.png index 2472c2729f..e545002bdc 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_15.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_16.png b/assets/dolphin/external/L1_My_dude_128x64/frame_16.png index 4940aef672..8e906e4f4d 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_16.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_17.png b/assets/dolphin/external/L1_My_dude_128x64/frame_17.png index fd910ce5a6..56765ecb87 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_17.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_18.png b/assets/dolphin/external/L1_My_dude_128x64/frame_18.png index ed33f18a70..1deb8d82fd 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_18.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_19.png b/assets/dolphin/external/L1_My_dude_128x64/frame_19.png index d602a01d5b..ac288ba8a7 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_19.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_19.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_2.png b/assets/dolphin/external/L1_My_dude_128x64/frame_2.png index b680b4ae05..007419deca 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_2.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_20.png b/assets/dolphin/external/L1_My_dude_128x64/frame_20.png index 2dfa931f25..cd9d06d2ca 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_20.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_20.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_21.png b/assets/dolphin/external/L1_My_dude_128x64/frame_21.png index 272064d90d..20a22b06e6 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_21.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_21.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_22.png b/assets/dolphin/external/L1_My_dude_128x64/frame_22.png index 35d0149ad9..0f3dbd46a5 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_22.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_22.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_23.png b/assets/dolphin/external/L1_My_dude_128x64/frame_23.png index 83d02ef88a..f47a3d597a 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_23.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_23.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_24.png b/assets/dolphin/external/L1_My_dude_128x64/frame_24.png index f3ac441781..6ca6b40173 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_24.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_24.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_25.png b/assets/dolphin/external/L1_My_dude_128x64/frame_25.png index 832c2bde9f..1c768c19a6 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_25.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_25.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_26.png b/assets/dolphin/external/L1_My_dude_128x64/frame_26.png index 3836a3b01b..06cd12d2cd 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_26.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_26.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_27.png b/assets/dolphin/external/L1_My_dude_128x64/frame_27.png index ff621b73ee..17a20f5444 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_27.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_27.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_28.png b/assets/dolphin/external/L1_My_dude_128x64/frame_28.png index 94e05f94d9..2f9f7106e3 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_28.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_28.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_29.png b/assets/dolphin/external/L1_My_dude_128x64/frame_29.png index 1ce384b165..dffa2d7c5b 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_29.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_29.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_3.png b/assets/dolphin/external/L1_My_dude_128x64/frame_3.png index a5056eb4bc..314efc6321 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_3.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_30.png b/assets/dolphin/external/L1_My_dude_128x64/frame_30.png index 8d42b8b482..52b8d35f03 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_30.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_30.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_31.png b/assets/dolphin/external/L1_My_dude_128x64/frame_31.png index ac926d7be3..6c282c0afc 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_31.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_31.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_32.png b/assets/dolphin/external/L1_My_dude_128x64/frame_32.png index 35070eb6b4..1d1f631b0b 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_32.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_32.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_33.png b/assets/dolphin/external/L1_My_dude_128x64/frame_33.png index a6c973f679..4376fe29f5 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_33.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_33.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_34.png b/assets/dolphin/external/L1_My_dude_128x64/frame_34.png index 3f9407f385..d431b90905 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_34.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_34.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_35.png b/assets/dolphin/external/L1_My_dude_128x64/frame_35.png index 6059e00d54..e4ce5da4d8 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_35.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_35.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_36.png b/assets/dolphin/external/L1_My_dude_128x64/frame_36.png index d2cd0c970c..f9d8b6ebf2 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_36.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_36.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_37.png b/assets/dolphin/external/L1_My_dude_128x64/frame_37.png index e60fd08dee..18080af541 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_37.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_37.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_38.png b/assets/dolphin/external/L1_My_dude_128x64/frame_38.png index 70e56b168b..b9271ca8d5 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_38.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_38.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_39.png b/assets/dolphin/external/L1_My_dude_128x64/frame_39.png index 450b4d4f63..cc3b2c5e3f 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_39.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_39.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_4.png b/assets/dolphin/external/L1_My_dude_128x64/frame_4.png index 2d9f4e9633..4b7361a429 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_4.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_40.png b/assets/dolphin/external/L1_My_dude_128x64/frame_40.png index 369200345d..ac0c428349 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_40.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_40.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_41.png b/assets/dolphin/external/L1_My_dude_128x64/frame_41.png index e0f8822682..18fa9c0a16 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_41.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_41.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_42.png b/assets/dolphin/external/L1_My_dude_128x64/frame_42.png index a8a23536a4..86a79df74a 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_42.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_42.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_43.png b/assets/dolphin/external/L1_My_dude_128x64/frame_43.png index 6a402b350b..d71c76f05d 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_43.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_43.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_44.png b/assets/dolphin/external/L1_My_dude_128x64/frame_44.png index f425bcc179..9e9ed92f56 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_44.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_44.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_45.png b/assets/dolphin/external/L1_My_dude_128x64/frame_45.png index b0ea1a7e78..70da80e9ba 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_45.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_45.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_46.png b/assets/dolphin/external/L1_My_dude_128x64/frame_46.png index 3113ff2e62..ef0cd69bdc 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_46.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_46.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_47.png b/assets/dolphin/external/L1_My_dude_128x64/frame_47.png index 87403c610a..d4e5ccfe2c 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_47.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_47.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_48.png b/assets/dolphin/external/L1_My_dude_128x64/frame_48.png index 2734e2fcd5..30848e939e 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_48.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_48.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_5.png b/assets/dolphin/external/L1_My_dude_128x64/frame_5.png index df22559491..94ee5d1542 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_5.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_6.png b/assets/dolphin/external/L1_My_dude_128x64/frame_6.png index 4c00552ea2..34233f5bb4 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_6.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_7.png b/assets/dolphin/external/L1_My_dude_128x64/frame_7.png index 9703809405..f21b4f4064 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_7.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_8.png b/assets/dolphin/external/L1_My_dude_128x64/frame_8.png index 86e41e913b..1f574da945 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_8.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_9.png b/assets/dolphin/external/L1_My_dude_128x64/frame_9.png index 4334eefafb..5e75e2dffd 100644 Binary files a/assets/dolphin/external/L1_My_dude_128x64/frame_9.png and b/assets/dolphin/external/L1_My_dude_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L1_Painting_128x64/frame_0.png b/assets/dolphin/external/L1_Painting_128x64/frame_0.png index b2f9bc775c..154a85ffb2 100644 Binary files a/assets/dolphin/external/L1_Painting_128x64/frame_0.png and b/assets/dolphin/external/L1_Painting_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Painting_128x64/frame_1.png b/assets/dolphin/external/L1_Painting_128x64/frame_1.png index 02ac533ce7..e52dfd6285 100644 Binary files a/assets/dolphin/external/L1_Painting_128x64/frame_1.png and b/assets/dolphin/external/L1_Painting_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Painting_128x64/frame_10.png b/assets/dolphin/external/L1_Painting_128x64/frame_10.png index ae3148c323..39389a64fa 100644 Binary files a/assets/dolphin/external/L1_Painting_128x64/frame_10.png and b/assets/dolphin/external/L1_Painting_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L1_Painting_128x64/frame_11.png b/assets/dolphin/external/L1_Painting_128x64/frame_11.png index 89d003d071..e6ea79c377 100644 Binary files a/assets/dolphin/external/L1_Painting_128x64/frame_11.png and b/assets/dolphin/external/L1_Painting_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L1_Painting_128x64/frame_2.png b/assets/dolphin/external/L1_Painting_128x64/frame_2.png index 8bfe6b33c5..302d5be61e 100644 Binary files a/assets/dolphin/external/L1_Painting_128x64/frame_2.png and b/assets/dolphin/external/L1_Painting_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Painting_128x64/frame_3.png b/assets/dolphin/external/L1_Painting_128x64/frame_3.png index 1c6fc2144b..6227c4089d 100644 Binary files a/assets/dolphin/external/L1_Painting_128x64/frame_3.png and b/assets/dolphin/external/L1_Painting_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Painting_128x64/frame_4.png b/assets/dolphin/external/L1_Painting_128x64/frame_4.png index d39cddea14..8d76d9d0d2 100644 Binary files a/assets/dolphin/external/L1_Painting_128x64/frame_4.png and b/assets/dolphin/external/L1_Painting_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_Painting_128x64/frame_5.png b/assets/dolphin/external/L1_Painting_128x64/frame_5.png index 4f21a268ac..5e562ce054 100644 Binary files a/assets/dolphin/external/L1_Painting_128x64/frame_5.png and b/assets/dolphin/external/L1_Painting_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_Painting_128x64/frame_6.png b/assets/dolphin/external/L1_Painting_128x64/frame_6.png index 3f492eab5e..9284cbef95 100644 Binary files a/assets/dolphin/external/L1_Painting_128x64/frame_6.png and b/assets/dolphin/external/L1_Painting_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_Painting_128x64/frame_7.png b/assets/dolphin/external/L1_Painting_128x64/frame_7.png index 336cffcb4c..8212e629c7 100644 Binary files a/assets/dolphin/external/L1_Painting_128x64/frame_7.png and b/assets/dolphin/external/L1_Painting_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L1_Painting_128x64/frame_8.png b/assets/dolphin/external/L1_Painting_128x64/frame_8.png index a44a7315da..f13bf906ca 100644 Binary files a/assets/dolphin/external/L1_Painting_128x64/frame_8.png and b/assets/dolphin/external/L1_Painting_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L1_Painting_128x64/frame_9.png b/assets/dolphin/external/L1_Painting_128x64/frame_9.png index 7cd4252910..65c8816278 100644 Binary files a/assets/dolphin/external/L1_Painting_128x64/frame_9.png and b/assets/dolphin/external/L1_Painting_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L1_Read_books_128x64/frame_0.png b/assets/dolphin/external/L1_Read_books_128x64/frame_0.png index fbf2652864..240fc15d5f 100644 Binary files a/assets/dolphin/external/L1_Read_books_128x64/frame_0.png and b/assets/dolphin/external/L1_Read_books_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Read_books_128x64/frame_1.png b/assets/dolphin/external/L1_Read_books_128x64/frame_1.png index be9c5dc151..7037de7ba7 100644 Binary files a/assets/dolphin/external/L1_Read_books_128x64/frame_1.png and b/assets/dolphin/external/L1_Read_books_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Read_books_128x64/frame_2.png b/assets/dolphin/external/L1_Read_books_128x64/frame_2.png index eb8075ecb1..627edfaa4d 100644 Binary files a/assets/dolphin/external/L1_Read_books_128x64/frame_2.png and b/assets/dolphin/external/L1_Read_books_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Read_books_128x64/frame_3.png b/assets/dolphin/external/L1_Read_books_128x64/frame_3.png index 0f1fd5c525..babab2e47e 100644 Binary files a/assets/dolphin/external/L1_Read_books_128x64/frame_3.png and b/assets/dolphin/external/L1_Read_books_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Read_books_128x64/frame_4.png b/assets/dolphin/external/L1_Read_books_128x64/frame_4.png index dd2d918aff..1a3f38e48d 100644 Binary files a/assets/dolphin/external/L1_Read_books_128x64/frame_4.png and b/assets/dolphin/external/L1_Read_books_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_Read_books_128x64/frame_5.png b/assets/dolphin/external/L1_Read_books_128x64/frame_5.png index bfcc7bcd2d..5f864b0d8d 100644 Binary files a/assets/dolphin/external/L1_Read_books_128x64/frame_5.png and b/assets/dolphin/external/L1_Read_books_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_Read_books_128x64/frame_6.png b/assets/dolphin/external/L1_Read_books_128x64/frame_6.png index eabe9def33..aded14709c 100644 Binary files a/assets/dolphin/external/L1_Read_books_128x64/frame_6.png and b/assets/dolphin/external/L1_Read_books_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_Read_books_128x64/frame_7.png b/assets/dolphin/external/L1_Read_books_128x64/frame_7.png index 3ff0aee0c8..9540789e7e 100644 Binary files a/assets/dolphin/external/L1_Read_books_128x64/frame_7.png and b/assets/dolphin/external/L1_Read_books_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L1_Read_books_128x64/frame_8.png b/assets/dolphin/external/L1_Read_books_128x64/frame_8.png index ce663f75f6..2d87b962c2 100644 Binary files a/assets/dolphin/external/L1_Read_books_128x64/frame_8.png and b/assets/dolphin/external/L1_Read_books_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_0.png b/assets/dolphin/external/L1_Recording_128x51/frame_0.png index ed0f030b87..e1361d632e 100644 Binary files a/assets/dolphin/external/L1_Recording_128x51/frame_0.png and b/assets/dolphin/external/L1_Recording_128x51/frame_0.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_1.png b/assets/dolphin/external/L1_Recording_128x51/frame_1.png index f3b3f8a977..0b549c648c 100644 Binary files a/assets/dolphin/external/L1_Recording_128x51/frame_1.png and b/assets/dolphin/external/L1_Recording_128x51/frame_1.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_10.png b/assets/dolphin/external/L1_Recording_128x51/frame_10.png index a474c21479..e45ac86be5 100644 Binary files a/assets/dolphin/external/L1_Recording_128x51/frame_10.png and b/assets/dolphin/external/L1_Recording_128x51/frame_10.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_11.png b/assets/dolphin/external/L1_Recording_128x51/frame_11.png index cf654afb24..487e5ea4bb 100644 Binary files a/assets/dolphin/external/L1_Recording_128x51/frame_11.png and b/assets/dolphin/external/L1_Recording_128x51/frame_11.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_2.png b/assets/dolphin/external/L1_Recording_128x51/frame_2.png index f61e59efd3..2901debc4e 100644 Binary files a/assets/dolphin/external/L1_Recording_128x51/frame_2.png and b/assets/dolphin/external/L1_Recording_128x51/frame_2.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_3.png b/assets/dolphin/external/L1_Recording_128x51/frame_3.png index 87e297b2a7..c0e2388b79 100644 Binary files a/assets/dolphin/external/L1_Recording_128x51/frame_3.png and b/assets/dolphin/external/L1_Recording_128x51/frame_3.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_4.png b/assets/dolphin/external/L1_Recording_128x51/frame_4.png index 62428a4055..c81f905398 100644 Binary files a/assets/dolphin/external/L1_Recording_128x51/frame_4.png and b/assets/dolphin/external/L1_Recording_128x51/frame_4.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_5.png b/assets/dolphin/external/L1_Recording_128x51/frame_5.png index 93953024aa..22006b552d 100644 Binary files a/assets/dolphin/external/L1_Recording_128x51/frame_5.png and b/assets/dolphin/external/L1_Recording_128x51/frame_5.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_6.png b/assets/dolphin/external/L1_Recording_128x51/frame_6.png index 942f082b83..aecd99f1a4 100644 Binary files a/assets/dolphin/external/L1_Recording_128x51/frame_6.png and b/assets/dolphin/external/L1_Recording_128x51/frame_6.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_7.png b/assets/dolphin/external/L1_Recording_128x51/frame_7.png index 84ce00d235..c7b305372f 100644 Binary files a/assets/dolphin/external/L1_Recording_128x51/frame_7.png and b/assets/dolphin/external/L1_Recording_128x51/frame_7.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_8.png b/assets/dolphin/external/L1_Recording_128x51/frame_8.png index f6f45552bf..6fac0a661d 100644 Binary files a/assets/dolphin/external/L1_Recording_128x51/frame_8.png and b/assets/dolphin/external/L1_Recording_128x51/frame_8.png differ diff --git a/assets/dolphin/external/L1_Recording_128x51/frame_9.png b/assets/dolphin/external/L1_Recording_128x51/frame_9.png index dcd3aa0b98..448266cd2f 100644 Binary files a/assets/dolphin/external/L1_Recording_128x51/frame_9.png and b/assets/dolphin/external/L1_Recording_128x51/frame_9.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_0.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_0.png index 71e85fe8f9..36e5de4c91 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_0.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_1.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_1.png index 31ab932b96..f487ffdb76 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_1.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_10.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_10.png index da8f13680c..15a5d5379a 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_10.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_11.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_11.png index 9c87945b53..e66b473f71 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_11.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_12.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_12.png index 52ecb01c1f..3f11cc90e0 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_12.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_13.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_13.png index 165b0635a7..41abfcc610 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_13.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_14.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_14.png index 3ad1f1c2d6..93b0dfd43a 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_14.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_15.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_15.png index dace07e837..64780d71b3 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_15.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_16.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_16.png index 2f23218889..6372d943a9 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_16.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_17.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_17.png index ea67b36457..a61ef2ab82 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_17.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_18.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_18.png index e4526da940..52c250fe54 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_18.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_19.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_19.png index b6e3de1acd..39ce840761 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_19.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_19.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_2.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_2.png index a76a000224..4ec651e936 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_2.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_20.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_20.png index b33656867f..4cfcf5282a 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_20.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_20.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_21.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_21.png index 6048810f0b..0b04296e32 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_21.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_21.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_22.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_22.png index 657788f2b0..5b8635a515 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_22.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_22.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_23.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_23.png index 852e778bfa..9d7af682b4 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_23.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_23.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_24.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_24.png index d8497ee6af..324311a33d 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_24.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_24.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_25.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_25.png index d647aae1bf..eaea2d87e3 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_25.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_25.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_26.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_26.png index 83bc94316b..75eae29c7c 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_26.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_26.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_27.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_27.png index 9f4e0ce7b9..2c0de95be6 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_27.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_27.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_28.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_28.png index 894394ab37..f6a0c6e692 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_28.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_28.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_29.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_29.png index 63babe7937..de18082e5d 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_29.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_29.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_3.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_3.png index 630f42f2ec..05bb61c0b6 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_3.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_30.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_30.png index d062254d93..95def778cd 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_30.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_30.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_31.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_31.png index 01ebecda7c..5c12231bdf 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_31.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_31.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_32.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_32.png index a66d6a42d9..0524f50faf 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_32.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_32.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_33.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_33.png index e80a66743e..52af71e8b9 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_33.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_33.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_34.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_34.png index cea25e209d..4cebede66e 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_34.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_34.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_35.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_35.png index 56e05f8f9a..8558d74f72 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_35.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_35.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_36.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_36.png index 8e72a7c390..3f13b3c16e 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_36.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_36.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_37.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_37.png index 9f20081e53..f4fc155be1 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_37.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_37.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_38.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_38.png index 39e6209549..2c2968c9f6 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_38.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_38.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_39.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_39.png index febe3bf0b0..2326527f32 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_39.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_39.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_4.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_4.png index 7377c60803..711f8f7a93 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_4.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_40.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_40.png index 2540fd3831..a0aca8d5d4 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_40.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_40.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_41.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_41.png index 63106c87ae..1d8c4257d1 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_41.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_41.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_42.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_42.png index 21038b47a6..42d9a0d02e 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_42.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_42.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_43.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_43.png index 09309607ca..8d1a63ce49 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_43.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_43.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_44.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_44.png index 2d4b512253..9d5904cfde 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_44.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_44.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_45.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_45.png index 0501b735ac..b858fd89a6 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_45.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_45.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_46.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_46.png index 1edca6aed3..63af06f99d 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_46.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_46.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_47.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_47.png index 467fe93e0c..98f147ce92 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_47.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_47.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_48.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_48.png index fb2c54aa93..0ba0ccf906 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_48.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_48.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_49.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_49.png index 74cd345fa0..3b89c00a57 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_49.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_49.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_5.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_5.png index 70ed4f5590..2da8166018 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_5.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_50.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_50.png index 32221d3476..94d6d30877 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_50.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_50.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_51.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_51.png index a81457ddc2..626692b0b1 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_51.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_51.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_52.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_52.png index 3fc75d8706..261c424e2a 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_52.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_52.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_53.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_53.png index 2e4528c731..fd893efb91 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_53.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_53.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_54.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_54.png index abab319643..08f6455706 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_54.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_54.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_55.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_55.png index dfa5312f55..8c6d81c0f0 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_55.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_55.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_56.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_56.png index 59a194b143..301d61d376 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_56.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_56.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_57.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_57.png index d142a38db7..e4893fd0c9 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_57.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_57.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_58.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_58.png index d6a66da8b8..52f0ed99fd 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_58.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_58.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_59.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_59.png index 4ab56d31ed..95542d4a27 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_59.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_59.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_6.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_6.png index 7d4f0684e2..a28e22e4fc 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_6.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_60.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_60.png index 0cb8722e3f..5b311fbe6a 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_60.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_60.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_61.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_61.png index 7da7d1adff..ef4d9db7ee 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_61.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_61.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_62.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_62.png index 1bfd8d3030..c6d519fb42 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_62.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_62.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_7.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_7.png index 0ff0f5a3f0..4e363367e8 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_7.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_8.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_8.png index 6987767373..53a4652de4 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_8.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L1_Sad_song_128x64/frame_9.png b/assets/dolphin/external/L1_Sad_song_128x64/frame_9.png index 6062721194..24d0fc41c4 100644 Binary files a/assets/dolphin/external/L1_Sad_song_128x64/frame_9.png and b/assets/dolphin/external/L1_Sad_song_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_0.png b/assets/dolphin/external/L1_Senpai_128x64/frame_0.png index ed37723ac2..7390c84e82 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_0.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_1.png b/assets/dolphin/external/L1_Senpai_128x64/frame_1.png index ad708ee431..bf14f93191 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_1.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_10.png b/assets/dolphin/external/L1_Senpai_128x64/frame_10.png index e385018bf6..db0766f668 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_10.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_11.png b/assets/dolphin/external/L1_Senpai_128x64/frame_11.png index 553a979be1..92ad6d095a 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_11.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_12.png b/assets/dolphin/external/L1_Senpai_128x64/frame_12.png index 9f8ca7e9b8..02b5c78ff3 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_12.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_13.png b/assets/dolphin/external/L1_Senpai_128x64/frame_13.png index a996443fe4..b8537f4bf7 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_13.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_14.png b/assets/dolphin/external/L1_Senpai_128x64/frame_14.png index 628d58b93a..3e51ddea0b 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_14.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_15.png b/assets/dolphin/external/L1_Senpai_128x64/frame_15.png index cc8431ade8..a86e54c3f6 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_15.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_16.png b/assets/dolphin/external/L1_Senpai_128x64/frame_16.png index 3ec3727989..230ae8d895 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_16.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_17.png b/assets/dolphin/external/L1_Senpai_128x64/frame_17.png index 11b247eca2..e92acac9ce 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_17.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_18.png b/assets/dolphin/external/L1_Senpai_128x64/frame_18.png index bb15041331..47b716ef7e 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_18.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_19.png b/assets/dolphin/external/L1_Senpai_128x64/frame_19.png index f953c8ef19..9e084150a4 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_19.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_19.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_2.png b/assets/dolphin/external/L1_Senpai_128x64/frame_2.png index 36c3b4abe1..337bc2dd31 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_2.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_20.png b/assets/dolphin/external/L1_Senpai_128x64/frame_20.png index d683b9f625..2caed65c62 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_20.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_20.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_21.png b/assets/dolphin/external/L1_Senpai_128x64/frame_21.png index 66cbfe1d8f..4a7cfb5f89 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_21.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_21.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_22.png b/assets/dolphin/external/L1_Senpai_128x64/frame_22.png index dd241d24ae..21a7219940 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_22.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_22.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_23.png b/assets/dolphin/external/L1_Senpai_128x64/frame_23.png index 944bdc74e9..fd5d53b27d 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_23.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_23.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_24.png b/assets/dolphin/external/L1_Senpai_128x64/frame_24.png index 3f445593af..7e7d008bc3 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_24.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_24.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_25.png b/assets/dolphin/external/L1_Senpai_128x64/frame_25.png index ea7823bd74..5f1ea16efb 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_25.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_25.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_26.png b/assets/dolphin/external/L1_Senpai_128x64/frame_26.png index 0b378fbccd..e753eadf9c 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_26.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_26.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_27.png b/assets/dolphin/external/L1_Senpai_128x64/frame_27.png index 66eec542a9..e815ead02a 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_27.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_27.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_28.png b/assets/dolphin/external/L1_Senpai_128x64/frame_28.png index 1e232ba91b..24e579be15 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_28.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_28.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_29.png b/assets/dolphin/external/L1_Senpai_128x64/frame_29.png index e2767bd655..8edea2b089 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_29.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_29.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_3.png b/assets/dolphin/external/L1_Senpai_128x64/frame_3.png index 9a3c13f662..c610eddcf8 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_3.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_30.png b/assets/dolphin/external/L1_Senpai_128x64/frame_30.png index 36d1212bec..00edcb7f25 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_30.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_30.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_31.png b/assets/dolphin/external/L1_Senpai_128x64/frame_31.png index 037bdc8ed6..3d2d5d6f74 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_31.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_31.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_32.png b/assets/dolphin/external/L1_Senpai_128x64/frame_32.png index 91ce188694..819ae205e9 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_32.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_32.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_33.png b/assets/dolphin/external/L1_Senpai_128x64/frame_33.png index e3e7799db4..0e43a49878 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_33.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_33.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_34.png b/assets/dolphin/external/L1_Senpai_128x64/frame_34.png index a28aac4e0f..53c2ce75c1 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_34.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_34.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_35.png b/assets/dolphin/external/L1_Senpai_128x64/frame_35.png index 04f8c1a7f3..d6b2f16d86 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_35.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_35.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_4.png b/assets/dolphin/external/L1_Senpai_128x64/frame_4.png index d065b77a12..966e606811 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_4.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_5.png b/assets/dolphin/external/L1_Senpai_128x64/frame_5.png index 7a111afd03..838f46432b 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_5.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_6.png b/assets/dolphin/external/L1_Senpai_128x64/frame_6.png index 318c7eca0a..f5e8111888 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_6.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_7.png b/assets/dolphin/external/L1_Senpai_128x64/frame_7.png index b56b995dc6..aabcd529e3 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_7.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_8.png b/assets/dolphin/external/L1_Senpai_128x64/frame_8.png index 6c4b875706..4c18a154cc 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_8.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L1_Senpai_128x64/frame_9.png b/assets/dolphin/external/L1_Senpai_128x64/frame_9.png index 00b02330e1..577207e5ce 100644 Binary files a/assets/dolphin/external/L1_Senpai_128x64/frame_9.png and b/assets/dolphin/external/L1_Senpai_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L1_Sleep_128x64/frame_0.png b/assets/dolphin/external/L1_Sleep_128x64/frame_0.png index 851f1d01dc..69d0d671e8 100644 Binary files a/assets/dolphin/external/L1_Sleep_128x64/frame_0.png and b/assets/dolphin/external/L1_Sleep_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L1_Sleep_128x64/frame_1.png b/assets/dolphin/external/L1_Sleep_128x64/frame_1.png index 89b40b36fa..c29188dc4a 100644 Binary files a/assets/dolphin/external/L1_Sleep_128x64/frame_1.png and b/assets/dolphin/external/L1_Sleep_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L1_Sleep_128x64/frame_2.png b/assets/dolphin/external/L1_Sleep_128x64/frame_2.png index 70ad96ddee..20f3709d23 100644 Binary files a/assets/dolphin/external/L1_Sleep_128x64/frame_2.png and b/assets/dolphin/external/L1_Sleep_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L1_Sleep_128x64/frame_3.png b/assets/dolphin/external/L1_Sleep_128x64/frame_3.png index 03b2f529a1..ba0ce672f3 100644 Binary files a/assets/dolphin/external/L1_Sleep_128x64/frame_3.png and b/assets/dolphin/external/L1_Sleep_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L1_Waves_128x50/frame_0.png b/assets/dolphin/external/L1_Waves_128x50/frame_0.png index adad4f4130..aabae9cae6 100644 Binary files a/assets/dolphin/external/L1_Waves_128x50/frame_0.png and b/assets/dolphin/external/L1_Waves_128x50/frame_0.png differ diff --git a/assets/dolphin/external/L1_Waves_128x50/frame_1.png b/assets/dolphin/external/L1_Waves_128x50/frame_1.png index 462824be2a..4adada4f31 100644 Binary files a/assets/dolphin/external/L1_Waves_128x50/frame_1.png and b/assets/dolphin/external/L1_Waves_128x50/frame_1.png differ diff --git a/assets/dolphin/external/L1_Waves_128x50/frame_2.png b/assets/dolphin/external/L1_Waves_128x50/frame_2.png index a5a7288498..84b2453bae 100644 Binary files a/assets/dolphin/external/L1_Waves_128x50/frame_2.png and b/assets/dolphin/external/L1_Waves_128x50/frame_2.png differ diff --git a/assets/dolphin/external/L1_Waves_128x50/frame_3.png b/assets/dolphin/external/L1_Waves_128x50/frame_3.png index 4f454a7433..cccfabec17 100644 Binary files a/assets/dolphin/external/L1_Waves_128x50/frame_3.png and b/assets/dolphin/external/L1_Waves_128x50/frame_3.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_0.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_0.png index e34e796907..7f1c84c26d 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_0.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_1.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_1.png index cc6032ad33..4b8a3e2523 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_1.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_10.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_10.png index a28a21225a..ee9424ee54 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_10.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_11.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_11.png index 3d94c89103..7400b90eb8 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_11.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_12.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_12.png index 74e0b962c5..c8779d6b4a 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_12.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_13.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_13.png index 3269169e42..87b19aa308 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_13.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_14.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_14.png index 42f844d3d7..7209b545fd 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_14.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_15.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_15.png index 861b16c65e..b7725b3502 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_15.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_16.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_16.png index 2f4b3b839c..82b1feae09 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_16.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_17.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_17.png index 7cba6f7953..b92a8c2d14 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_17.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_18.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_18.png index 0b8fe650ea..3114dc5992 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_18.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_19.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_19.png index e3c50e3088..9c79cd16b4 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_19.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_19.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_2.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_2.png index c259b5a5ad..df558a7048 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_2.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_20.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_20.png index ae6e765320..96a1c159bd 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_20.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_20.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_21.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_21.png index e97affd7e3..e832983f32 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_21.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_21.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_22.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_22.png index b5c6159243..fcb5f44304 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_22.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_22.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_23.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_23.png index ef4876275d..df827d72ad 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_23.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_23.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_24.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_24.png index 4dfe3a0290..688fb69af0 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_24.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_24.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_25.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_25.png index 1f9d6ac547..9ee5743961 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_25.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_25.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_26.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_26.png index 379e29b50d..2c3fe69873 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_26.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_26.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_27.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_27.png index 16210a792b..3253a415fe 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_27.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_27.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_28.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_28.png index 7685c3bc3f..2152f449ec 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_28.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_28.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_29.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_29.png index 5f114a4792..2286f79367 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_29.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_29.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_3.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_3.png index 3f5c523acb..65b126e6cc 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_3.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_30.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_30.png index 645ffa6692..d67714a898 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_30.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_30.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_31.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_31.png index a086ba60c4..c2371bc4d1 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_31.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_31.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_32.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_32.png index 4fdc011d11..43c995266c 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_32.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_32.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_33.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_33.png index f9789d8b8f..41ff0cced5 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_33.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_33.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_34.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_34.png index e13f825fa7..05ae0f146e 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_34.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_34.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_35.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_35.png index 05f9639b95..61bd92f5f0 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_35.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_35.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_36.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_36.png index a968fd015c..6924299da0 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_36.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_36.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_37.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_37.png index 8393e3ce8c..72e71368d0 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_37.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_37.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_38.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_38.png index 5e6c324997..2fe57d02df 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_38.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_38.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_39.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_39.png index 7ca97b4a7d..8a7e28ebc2 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_39.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_39.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_4.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_4.png index 11253dd628..87b339fcfa 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_4.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_40.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_40.png index a1ac9f6f32..b471cf949e 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_40.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_40.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_41.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_41.png index c33f03e927..7126105ef1 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_41.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_41.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_42.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_42.png index dc51592c78..47c4fa6712 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_42.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_42.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_43.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_43.png index ff83fe7713..600c1d7736 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_43.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_43.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_44.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_44.png index a5488fcb19..248b26b367 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_44.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_44.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_45.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_45.png index 86630e83aa..e6da05bd15 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_45.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_45.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_46.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_46.png index a9147ae3c1..d4988a8195 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_46.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_46.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_47.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_47.png index f5b4529e44..3d631e3fe5 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_47.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_47.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_48.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_48.png index 1f27241b73..247bf9844f 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_48.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_48.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_49.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_49.png index f5656a7508..a8a57bee60 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_49.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_49.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_5.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_5.png index 1545c0ee71..c9aaa31fa0 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_5.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_50.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_50.png index 1ff2a8874d..37cd3d8938 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_50.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_50.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_51.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_51.png index 3608e114f1..0ece627b4d 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_51.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_51.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_52.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_52.png index f109b562b8..aa5b3112c2 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_52.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_52.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_53.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_53.png index a91b863c70..55574b441b 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_53.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_53.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_54.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_54.png index 052196298a..f909bd9f86 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_54.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_54.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_55.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_55.png index b8a8c65125..8711624f94 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_55.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_55.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_56.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_56.png index 44f5bf6d25..855375c08e 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_56.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_56.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_57.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_57.png index f7c1e8023e..753aa478e9 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_57.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_57.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_58.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_58.png index 61efe9f450..846266c123 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_58.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_58.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_59.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_59.png index d0bfc886cc..3d6b98dd2a 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_59.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_59.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_6.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_6.png index f99662e70f..119d8d3461 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_6.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_60.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_60.png index 950152b737..89ce154032 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_60.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_60.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_61.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_61.png index 4e430d5c50..ed02b62a35 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_61.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_61.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_7.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_7.png index cf09a7842a..bc407b6ff9 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_7.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_8.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_8.png index d12fa6abae..7935a77552 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_8.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_9.png b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_9.png index ace68d642e..99072fae97 100644 Binary files a/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_9.png and b/assets/dolphin/external/L2_Coding_in_the_shell_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_0.png b/assets/dolphin/external/L2_Dj_128x64/frame_0.png index 95f72f901a..18a5e83f6b 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_0.png and b/assets/dolphin/external/L2_Dj_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_1.png b/assets/dolphin/external/L2_Dj_128x64/frame_1.png index 32e13541d8..efd0fcfafd 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_1.png and b/assets/dolphin/external/L2_Dj_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_10.png b/assets/dolphin/external/L2_Dj_128x64/frame_10.png index 3cce11f998..1e33265d61 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_10.png and b/assets/dolphin/external/L2_Dj_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_11.png b/assets/dolphin/external/L2_Dj_128x64/frame_11.png index eca4a1296e..956d31d02c 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_11.png and b/assets/dolphin/external/L2_Dj_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_12.png b/assets/dolphin/external/L2_Dj_128x64/frame_12.png index 5f92e47fdd..a99135d7b1 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_12.png and b/assets/dolphin/external/L2_Dj_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_13.png b/assets/dolphin/external/L2_Dj_128x64/frame_13.png index 1b1017ce25..3c5ff7b337 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_13.png and b/assets/dolphin/external/L2_Dj_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_14.png b/assets/dolphin/external/L2_Dj_128x64/frame_14.png index 2cf408c979..79e28e9167 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_14.png and b/assets/dolphin/external/L2_Dj_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_15.png b/assets/dolphin/external/L2_Dj_128x64/frame_15.png index 9b796498c0..69d233ab57 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_15.png and b/assets/dolphin/external/L2_Dj_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_16.png b/assets/dolphin/external/L2_Dj_128x64/frame_16.png index c1545500cb..a3766106a1 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_16.png and b/assets/dolphin/external/L2_Dj_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_17.png b/assets/dolphin/external/L2_Dj_128x64/frame_17.png index 80863f0b69..f606afb4bf 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_17.png and b/assets/dolphin/external/L2_Dj_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_18.png b/assets/dolphin/external/L2_Dj_128x64/frame_18.png index b4527bc833..392b12e251 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_18.png and b/assets/dolphin/external/L2_Dj_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_19.png b/assets/dolphin/external/L2_Dj_128x64/frame_19.png index f1531da4ef..fba62faae0 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_19.png and b/assets/dolphin/external/L2_Dj_128x64/frame_19.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_2.png b/assets/dolphin/external/L2_Dj_128x64/frame_2.png index 391cfe1e10..85c5008be7 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_2.png and b/assets/dolphin/external/L2_Dj_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_20.png b/assets/dolphin/external/L2_Dj_128x64/frame_20.png index f63904f29b..c80e59d078 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_20.png and b/assets/dolphin/external/L2_Dj_128x64/frame_20.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_21.png b/assets/dolphin/external/L2_Dj_128x64/frame_21.png index 076448fa94..c3768e27b2 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_21.png and b/assets/dolphin/external/L2_Dj_128x64/frame_21.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_22.png b/assets/dolphin/external/L2_Dj_128x64/frame_22.png index 8651f12f8b..f5fe6855f8 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_22.png and b/assets/dolphin/external/L2_Dj_128x64/frame_22.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_23.png b/assets/dolphin/external/L2_Dj_128x64/frame_23.png index d2d8e7e514..f404dafc3c 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_23.png and b/assets/dolphin/external/L2_Dj_128x64/frame_23.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_24.png b/assets/dolphin/external/L2_Dj_128x64/frame_24.png index 6080e7aa3f..b5c59f09ca 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_24.png and b/assets/dolphin/external/L2_Dj_128x64/frame_24.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_25.png b/assets/dolphin/external/L2_Dj_128x64/frame_25.png index ec483addf8..7495a01694 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_25.png and b/assets/dolphin/external/L2_Dj_128x64/frame_25.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_26.png b/assets/dolphin/external/L2_Dj_128x64/frame_26.png index 90fc3b1380..6010157482 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_26.png and b/assets/dolphin/external/L2_Dj_128x64/frame_26.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_27.png b/assets/dolphin/external/L2_Dj_128x64/frame_27.png index 39ddf46ab3..48e08cf62a 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_27.png and b/assets/dolphin/external/L2_Dj_128x64/frame_27.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_28.png b/assets/dolphin/external/L2_Dj_128x64/frame_28.png index f433c969c6..a48aa0927d 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_28.png and b/assets/dolphin/external/L2_Dj_128x64/frame_28.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_29.png b/assets/dolphin/external/L2_Dj_128x64/frame_29.png index 263ffe15a8..1eae636a5c 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_29.png and b/assets/dolphin/external/L2_Dj_128x64/frame_29.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_3.png b/assets/dolphin/external/L2_Dj_128x64/frame_3.png index 40d1314c95..4772c92176 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_3.png and b/assets/dolphin/external/L2_Dj_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_30.png b/assets/dolphin/external/L2_Dj_128x64/frame_30.png index 27c297e8d5..631240dd01 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_30.png and b/assets/dolphin/external/L2_Dj_128x64/frame_30.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_31.png b/assets/dolphin/external/L2_Dj_128x64/frame_31.png index f2aefbfae2..5dcfb355d4 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_31.png and b/assets/dolphin/external/L2_Dj_128x64/frame_31.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_32.png b/assets/dolphin/external/L2_Dj_128x64/frame_32.png index 852c24233f..9021fdca14 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_32.png and b/assets/dolphin/external/L2_Dj_128x64/frame_32.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_33.png b/assets/dolphin/external/L2_Dj_128x64/frame_33.png index 665ac5eafd..e5467bcfbf 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_33.png and b/assets/dolphin/external/L2_Dj_128x64/frame_33.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_34.png b/assets/dolphin/external/L2_Dj_128x64/frame_34.png index 81f133ac55..e12c77c8a1 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_34.png and b/assets/dolphin/external/L2_Dj_128x64/frame_34.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_35.png b/assets/dolphin/external/L2_Dj_128x64/frame_35.png index c828207d33..335f819d81 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_35.png and b/assets/dolphin/external/L2_Dj_128x64/frame_35.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_36.png b/assets/dolphin/external/L2_Dj_128x64/frame_36.png index fc923b4023..39ce840761 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_36.png and b/assets/dolphin/external/L2_Dj_128x64/frame_36.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_4.png b/assets/dolphin/external/L2_Dj_128x64/frame_4.png index d372ff643b..57a9dd944b 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_4.png and b/assets/dolphin/external/L2_Dj_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_5.png b/assets/dolphin/external/L2_Dj_128x64/frame_5.png index 5b52f95175..c6f556fbf4 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_5.png and b/assets/dolphin/external/L2_Dj_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_6.png b/assets/dolphin/external/L2_Dj_128x64/frame_6.png index 8a1e84a11e..4a6f97d20d 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_6.png and b/assets/dolphin/external/L2_Dj_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_7.png b/assets/dolphin/external/L2_Dj_128x64/frame_7.png index 1fddffaa49..cf626fdae2 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_7.png and b/assets/dolphin/external/L2_Dj_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_8.png b/assets/dolphin/external/L2_Dj_128x64/frame_8.png index 14ef1aded6..40facba15c 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_8.png and b/assets/dolphin/external/L2_Dj_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_9.png b/assets/dolphin/external/L2_Dj_128x64/frame_9.png index 05de5d5c69..12a3e590d5 100644 Binary files a/assets/dolphin/external/L2_Dj_128x64/frame_9.png and b/assets/dolphin/external/L2_Dj_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_0.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_0.png index 43b26283e9..37d3e1ecd8 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_0.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_1.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_1.png index fecba5ad59..93ff00a848 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_1.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_10.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_10.png index 3c15e7ccfe..d4ab0e356c 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_10.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_11.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_11.png index 0f293281fa..2d98d57ab2 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_11.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_12.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_12.png index 733962d3a1..95d09d14be 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_12.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_13.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_13.png index 4b7ed184ff..c385a5ec45 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_13.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_14.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_14.png index 1efff0f21b..25b4ec5653 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_14.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_15.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_15.png index f2d76409d6..2e7a73bced 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_15.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_16.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_16.png index 125fb98fa6..29e39b5c14 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_16.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_17.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_17.png index 3a4a5f5a13..74bbee98ee 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_17.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_18.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_18.png index 13dd34859a..2a9e4884d9 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_18.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_2.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_2.png index ef3150fd80..a24187a1bf 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_2.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_3.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_3.png index 537ab523e2..16f36b3c44 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_3.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_4.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_4.png index 8735701269..eaa20698ec 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_4.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_5.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_5.png index dbbeb1fe16..272d99f742 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_5.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_6.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_6.png index d18085027d..7052724706 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_6.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_7.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_7.png index 24f9333fe7..37d3e1ecd8 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_7.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_8.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_8.png index 30b97cdf54..e2433ea584 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_8.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L2_Furippa2_128x64/frame_9.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_9.png index 7ceead056d..be1afd958a 100644 Binary files a/assets/dolphin/external/L2_Furippa2_128x64/frame_9.png and b/assets/dolphin/external/L2_Furippa2_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L2_Hacking_pc_128x64/frame_0.png b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_0.png index d303aef088..4c91dd60bd 100644 Binary files a/assets/dolphin/external/L2_Hacking_pc_128x64/frame_0.png and b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L2_Hacking_pc_128x64/frame_1.png b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_1.png index 45aeb57b55..88849fc6b7 100644 Binary files a/assets/dolphin/external/L2_Hacking_pc_128x64/frame_1.png and b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L2_Hacking_pc_128x64/frame_2.png b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_2.png index a4508f14b5..c2e1902034 100644 Binary files a/assets/dolphin/external/L2_Hacking_pc_128x64/frame_2.png and b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L2_Hacking_pc_128x64/frame_3.png b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_3.png index 350002167d..cb5868d3fc 100644 Binary files a/assets/dolphin/external/L2_Hacking_pc_128x64/frame_3.png and b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L2_Hacking_pc_128x64/frame_4.png b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_4.png index 7addbf9327..4b1f6a2aa8 100644 Binary files a/assets/dolphin/external/L2_Hacking_pc_128x64/frame_4.png and b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_0.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_0.png index 8f29d5e2c7..72cb959f02 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_0.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_1.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_1.png index f0756ff855..c973f205b8 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_1.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_10.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_10.png index 03d95e2af9..63a84b8766 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_10.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_11.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_11.png index e4cf6ea8d5..d7c9bce755 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_11.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_12.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_12.png index 6a7fe1bbba..4889580058 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_12.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_13.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_13.png index 38171c273c..74c418e366 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_13.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_14.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_14.png index 3eb9a1f632..50b8299e2a 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_14.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_15.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_15.png index 6244074889..8fb3240d77 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_15.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_16.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_16.png index f1306c2eb4..b59622a7ac 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_16.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_17.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_17.png index ed8d96bab1..0f6ec25ddc 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_17.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_18.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_18.png index e1df3ea495..45fd14e8ea 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_18.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_19.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_19.png index d231a65618..3fdc37116e 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_19.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_19.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_2.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_2.png index e2a864c762..1ba48033e0 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_2.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_20.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_20.png index ddf9d49310..3b2292c9cc 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_20.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_20.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_21.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_21.png index 0d407de64b..904d2931f1 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_21.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_21.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_22.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_22.png index f53ee05883..4e0235770b 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_22.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_22.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_23.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_23.png index 83be68d846..18b103c403 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_23.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_23.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_24.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_24.png index ae61e5831c..9cae5887cf 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_24.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_24.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_25.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_25.png index a2608a0e1b..c44defec71 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_25.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_25.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_26.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_26.png index 6602e3f578..8adee40b96 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_26.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_26.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_27.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_27.png index e82d7fcd14..b2521cee3c 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_27.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_27.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_28.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_28.png index b16dda91d5..5a5043ec52 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_28.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_28.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_29.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_29.png index cf91009bf3..04bb206bc5 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_29.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_29.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_3.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_3.png index 8bfdcabda9..2054724f99 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_3.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_30.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_30.png index 0807484984..44eec1f241 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_30.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_30.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_31.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_31.png index d4dfbce33f..fa18ea3454 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_31.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_31.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_32.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_32.png index c9c169f2eb..13bc7f1787 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_32.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_32.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_33.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_33.png index 0e939aa2d4..6cb3f7c8bf 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_33.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_33.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_34.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_34.png index d0f3a5383d..0b0d3e5b55 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_34.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_34.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_35.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_35.png index 2e3a3c64fb..ab2515fecf 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_35.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_35.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_36.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_36.png index 4b34fe377c..5dcd576da8 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_36.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_36.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_37.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_37.png index 4935b75a6f..a28bd7bd9c 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_37.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_37.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_38.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_38.png index ccf5bdf09e..ec57311554 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_38.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_38.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_39.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_39.png index d276c21233..dba19aeeb6 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_39.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_39.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_4.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_4.png index 354a96b6c5..84acd2bdab 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_4.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_40.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_40.png index 873386a57f..de8a4e7de1 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_40.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_40.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_41.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_41.png index 529f6cdd45..f614ecd7da 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_41.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_41.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_42.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_42.png index 15168cd111..4bd13c36fd 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_42.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_42.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_43.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_43.png index 16196a7062..bc9c6dc21d 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_43.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_43.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_44.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_44.png index 06fb279055..8e271e10a9 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_44.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_44.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_45.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_45.png index 5a2221cb92..026064c5a1 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_45.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_45.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_46.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_46.png index 7db77e935f..eac19b8cd5 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_46.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_46.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_47.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_47.png index a6d5407ad0..4dbb14ce97 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_47.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_47.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_48.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_48.png index c6a17fda8a..a6efbbdcf9 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_48.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_48.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_49.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_49.png index 0e6845ac24..58993db8b0 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_49.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_49.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_5.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_5.png index 45decf285f..8654008fd6 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_5.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_50.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_50.png index aa121a538c..bcebe86cd5 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_50.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_50.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_51.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_51.png index 38184aa75e..4d732c3926 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_51.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_51.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_52.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_52.png index 1259a591a4..b2a87c4421 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_52.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_52.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_6.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_6.png index cd916c4040..713e66f22a 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_6.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_7.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_7.png index d28bb5454d..da9f67db42 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_7.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_8.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_8.png index 3621243f71..567ac58acb 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_8.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_9.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_9.png index 4d3d537162..9798634373 100644 Binary files a/assets/dolphin/external/L2_Secret_door_128x64/frame_9.png and b/assets/dolphin/external/L2_Secret_door_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L2_Soldering_128x64/frame_0.png b/assets/dolphin/external/L2_Soldering_128x64/frame_0.png index bd20ae8436..db68772592 100644 Binary files a/assets/dolphin/external/L2_Soldering_128x64/frame_0.png and b/assets/dolphin/external/L2_Soldering_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L2_Soldering_128x64/frame_1.png b/assets/dolphin/external/L2_Soldering_128x64/frame_1.png index b9453d0568..0ff99dc587 100644 Binary files a/assets/dolphin/external/L2_Soldering_128x64/frame_1.png and b/assets/dolphin/external/L2_Soldering_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L2_Soldering_128x64/frame_10.png b/assets/dolphin/external/L2_Soldering_128x64/frame_10.png index 0519e851d3..a6d4d2f25b 100644 Binary files a/assets/dolphin/external/L2_Soldering_128x64/frame_10.png and b/assets/dolphin/external/L2_Soldering_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L2_Soldering_128x64/frame_2.png b/assets/dolphin/external/L2_Soldering_128x64/frame_2.png index 514241266b..c0adab3468 100644 Binary files a/assets/dolphin/external/L2_Soldering_128x64/frame_2.png and b/assets/dolphin/external/L2_Soldering_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L2_Soldering_128x64/frame_3.png b/assets/dolphin/external/L2_Soldering_128x64/frame_3.png index ba7ad99ae7..27808c97b4 100644 Binary files a/assets/dolphin/external/L2_Soldering_128x64/frame_3.png and b/assets/dolphin/external/L2_Soldering_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L2_Soldering_128x64/frame_4.png b/assets/dolphin/external/L2_Soldering_128x64/frame_4.png index ca696e4cf4..3249388656 100644 Binary files a/assets/dolphin/external/L2_Soldering_128x64/frame_4.png and b/assets/dolphin/external/L2_Soldering_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L2_Soldering_128x64/frame_5.png b/assets/dolphin/external/L2_Soldering_128x64/frame_5.png index aa7fc8ea0f..43cb2a283d 100644 Binary files a/assets/dolphin/external/L2_Soldering_128x64/frame_5.png and b/assets/dolphin/external/L2_Soldering_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L2_Soldering_128x64/frame_6.png b/assets/dolphin/external/L2_Soldering_128x64/frame_6.png index 85d1e30c9b..29d09c423d 100644 Binary files a/assets/dolphin/external/L2_Soldering_128x64/frame_6.png and b/assets/dolphin/external/L2_Soldering_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L2_Soldering_128x64/frame_7.png b/assets/dolphin/external/L2_Soldering_128x64/frame_7.png index 5ef6820f9c..b2730636ce 100644 Binary files a/assets/dolphin/external/L2_Soldering_128x64/frame_7.png and b/assets/dolphin/external/L2_Soldering_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L2_Soldering_128x64/frame_8.png b/assets/dolphin/external/L2_Soldering_128x64/frame_8.png index 12bed1b4a0..f74c6415dd 100644 Binary files a/assets/dolphin/external/L2_Soldering_128x64/frame_8.png and b/assets/dolphin/external/L2_Soldering_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L2_Soldering_128x64/frame_9.png b/assets/dolphin/external/L2_Soldering_128x64/frame_9.png index 46f9fd3788..3f4d80b042 100644 Binary files a/assets/dolphin/external/L2_Soldering_128x64/frame_9.png and b/assets/dolphin/external/L2_Soldering_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_0.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_0.png index 9120900325..f85f1df6bf 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_0.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_1.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_1.png index 0b99a32ff9..6b614c773b 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_1.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_10.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_10.png index 9da72ac1da..3e77491453 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_10.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_11.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_11.png index 8d54da6c61..a90b2f6c00 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_11.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_12.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_12.png index 84046a46c8..69605e7a20 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_12.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_13.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_13.png index 3e1c9c329a..9ff3e4dde9 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_13.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_14.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_14.png index f4f6ccd661..741e4b58fa 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_14.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_15.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_15.png index 5dc1a65256..c725d6a71f 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_15.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_16.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_16.png index bec472921c..4bc14bdc94 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_16.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_17.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_17.png index 82e5176c89..4e4fa0e52b 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_17.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_18.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_18.png index 3b5e60dfdb..f7302372b4 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_18.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_19.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_19.png index 5f76c7d237..d1d99f4891 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_19.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_19.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_2.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_2.png index 84d6aaf353..ffc82fd6f2 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_2.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_20.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_20.png index 2f8394fd51..99dbc3e084 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_20.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_20.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_3.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_3.png index 48adde113a..f13628011b 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_3.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_4.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_4.png index 5889835b7b..5a0c613c9b 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_4.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_5.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_5.png index 7f980f57f8..61e2d1981b 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_5.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_6.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_6.png index 4971360008..1c6402cecc 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_6.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_7.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_7.png index 03d67134aa..37ea651abd 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_7.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_8.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_8.png index 9f523cacee..5fdf6365df 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_8.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L2_Wake_up_128x64/frame_9.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_9.png index 5a565b1af9..9979896e42 100644 Binary files a/assets/dolphin/external/L2_Wake_up_128x64/frame_9.png and b/assets/dolphin/external/L2_Wake_up_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_0.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_0.png old mode 100755 new mode 100644 index 7d42cb57db..c727bd3f04 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_0.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_1.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_1.png old mode 100755 new mode 100644 index 25b4609c37..38e775d813 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_1.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_10.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_10.png old mode 100755 new mode 100644 index 575df3b9f5..81be06a77f Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_10.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_11.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_11.png old mode 100755 new mode 100644 index 2cfc582ef9..808dd08fbf Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_11.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_12.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_12.png old mode 100755 new mode 100644 index 4aa135cd6b..214455e57e Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_12.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_13.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_13.png old mode 100755 new mode 100644 index aae2827e85..d699393855 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_13.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_14.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_14.png old mode 100755 new mode 100644 index a66867a326..cf333a85e7 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_14.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_15.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_15.png old mode 100755 new mode 100644 index 7ec1216e30..173de44e87 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_15.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_16.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_16.png old mode 100755 new mode 100644 index 2632103d6c..be5e5fc3f9 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_16.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_17.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_17.png old mode 100755 new mode 100644 index f50cd0b88d..9857478f88 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_17.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_18.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_18.png old mode 100755 new mode 100644 index b5a85de1df..233f6aed64 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_18.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_19.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_19.png old mode 100755 new mode 100644 index d9a29def62..c02f58c523 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_19.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_19.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_2.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_2.png old mode 100755 new mode 100644 index ca4bf322ba..61880587fa Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_2.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_20.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_20.png old mode 100755 new mode 100644 index fe95a716c1..e9fd6041f2 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_20.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_20.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_21.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_21.png old mode 100755 new mode 100644 index 6a40d4148f..db36ad5fa3 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_21.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_21.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_22.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_22.png old mode 100755 new mode 100644 index 67189811d8..72a78cde2d Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_22.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_22.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_23.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_23.png old mode 100755 new mode 100644 index b770f32088..2a042e23e9 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_23.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_23.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_24.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_24.png old mode 100755 new mode 100644 index 4a899faf2f..f26aece8c1 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_24.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_24.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_25.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_25.png old mode 100755 new mode 100644 index c12a583f5a..e7bec7eed7 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_25.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_25.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_26.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_26.png old mode 100755 new mode 100644 index f62f6495e4..85b4e2ee9b Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_26.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_26.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_27.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_27.png old mode 100755 new mode 100644 index 37218c3961..ea3a6adf87 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_27.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_27.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_28.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_28.png old mode 100755 new mode 100644 index a28511c916..96328c9b26 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_28.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_28.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_29.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_29.png old mode 100755 new mode 100644 index f18f8798de..9334a3e831 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_29.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_29.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_3.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_3.png old mode 100755 new mode 100644 index 93e694375a..1705c1f90f Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_3.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_30.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_30.png old mode 100755 new mode 100644 index 64cf585803..67d6c1234f Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_30.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_30.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_31.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_31.png old mode 100755 new mode 100644 index 2502b3f21c..9cf2edd6f3 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_31.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_31.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_32.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_32.png old mode 100755 new mode 100644 index 417419f858..1737a82cfb Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_32.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_32.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_33.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_33.png old mode 100755 new mode 100644 index 5c79060755..a7a0ed8707 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_33.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_33.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_34.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_34.png old mode 100755 new mode 100644 index 26dfe53911..3ef1e8f611 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_34.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_34.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_35.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_35.png old mode 100755 new mode 100644 index b6d5070573..4f009f28cf Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_35.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_35.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_36.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_36.png old mode 100755 new mode 100644 index 7bd425e1d1..414041750d Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_36.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_36.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_37.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_37.png old mode 100755 new mode 100644 index 7edea62a16..5432c2e0d9 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_37.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_37.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_38.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_38.png old mode 100755 new mode 100644 index 7b51b6a34b..2ad368010d Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_38.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_38.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_39.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_39.png old mode 100755 new mode 100644 index 30b6bd67e1..6f8b4f0caa Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_39.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_39.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_4.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_4.png old mode 100755 new mode 100644 index ff0b1fb289..8ee956c4bd Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_4.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_40.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_40.png old mode 100755 new mode 100644 index d413cf0ede..24de01dabc Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_40.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_40.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_41.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_41.png old mode 100755 new mode 100644 index 2770772652..beac49ed87 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_41.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_41.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_42.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_42.png old mode 100755 new mode 100644 index baf3c7c79d..2a095979a8 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_42.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_42.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_43.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_43.png old mode 100755 new mode 100644 index b4cb1179f3..32e35f4ba3 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_43.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_43.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_44.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_44.png old mode 100755 new mode 100644 index 09dfc28e8b..4dfef4ff65 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_44.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_44.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_45.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_45.png old mode 100755 new mode 100644 index 94b26fe061..de4d7cacc9 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_45.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_45.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_46.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_46.png old mode 100755 new mode 100644 index 28f47d714d..bb57197952 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_46.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_46.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_47.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_47.png old mode 100755 new mode 100644 index a9cc34ca20..8aaceac98d Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_47.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_47.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_48.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_48.png old mode 100755 new mode 100644 index cc9a89dad3..11e017674d Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_48.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_48.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_49.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_49.png old mode 100755 new mode 100644 index ef68cf8661..c667c9f81a Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_49.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_49.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_5.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_5.png old mode 100755 new mode 100644 index b0367a6032..e7de890b4b Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_5.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_50.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_50.png old mode 100755 new mode 100644 index a44a566c7b..d3305472c7 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_50.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_50.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_51.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_51.png old mode 100755 new mode 100644 index ba00473ddd..3d7005fb69 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_51.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_51.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_52.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_52.png old mode 100755 new mode 100644 index 8045749acb..a7db03a332 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_52.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_52.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_53.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_53.png old mode 100755 new mode 100644 index 18337cd63c..f443ae5c30 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_53.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_53.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_54.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_54.png old mode 100755 new mode 100644 index 10be0ad16a..a322496415 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_54.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_54.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_55.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_55.png old mode 100755 new mode 100644 index fd8269bb4d..da7a84aea8 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_55.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_55.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_56.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_56.png old mode 100755 new mode 100644 index 300cbd9eca..7d0b0732ad Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_56.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_56.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_6.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_6.png old mode 100755 new mode 100644 index 56f37fbd89..6459530603 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_6.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_7.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_7.png old mode 100755 new mode 100644 index 0e4fb27a62..4be5ea9ac6 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_7.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_8.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_8.png old mode 100755 new mode 100644 index 641d06f39f..8cf252c9f7 Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_8.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_9.png b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_9.png old mode 100755 new mode 100644 index 5bcf7e588c..9cc334e0ab Binary files a/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_9.png and b/assets/dolphin/external/L3_Freedom_2_dolphins_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_0.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_0.png index 3b82285e66..87d1fc9d28 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_0.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_1.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_1.png index 7af08829b8..67d77257f2 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_1.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_10.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_10.png index 0ef6d471df..7bca8d134b 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_10.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_11.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_11.png index e6f397eb8e..be63ef5c40 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_11.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_12.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_12.png index 9221fb1564..95d09d14be 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_12.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_13.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_13.png index e43b1edb86..c385a5ec45 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_13.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_14.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_14.png index 64da8d8f9f..25b4ec5653 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_14.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_15.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_15.png index 96b1966967..228c294823 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_15.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_16.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_16.png index 620dbca296..49e01f3173 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_16.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_17.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_17.png index 49aa979d74..f5871e49c1 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_17.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_18.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_18.png index 7739e294ac..d2a276eea0 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_18.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_2.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_2.png index c36e54b2fa..c5e8a2a5b9 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_2.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_3.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_3.png index dce96b74cf..6849b5011e 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_3.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_4.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_4.png index 2c096689a8..41575e79f9 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_4.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_5.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_5.png index 792719974b..f7965d9f7c 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_5.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_6.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_6.png index 689e7dd790..3288f6ab9a 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_6.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_7.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_7.png index 7b468ab837..87d1fc9d28 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_7.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_8.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_8.png index e9246c0b7e..2cd571dff7 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_8.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L3_Furippa3_128x64/frame_9.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_9.png index c2e164c51d..e2f84bac55 100644 Binary files a/assets/dolphin/external/L3_Furippa3_128x64/frame_9.png and b/assets/dolphin/external/L3_Furippa3_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_0.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_0.png index 6fb7de66c4..0c47516c25 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_0.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_1.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_1.png index eaf39cff41..dd02ff2e93 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_1.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_10.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_10.png index 1e3890a7bc..60556a9dd7 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_10.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_11.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_11.png index fc8aef13a7..a0b7ea6c85 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_11.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_12.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_12.png index 8174af0d17..6faa6fd5ba 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_12.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_13.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_13.png index b5e75921a2..d92aeb984e 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_13.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_2.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_2.png index 6a239a1b69..a4da82eaba 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_2.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_3.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_3.png index 8cec74395e..c5ba8af0ef 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_3.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_4.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_4.png index d034b0a533..23166c1a65 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_4.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_5.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_5.png index 472241e56f..7cd73e35bd 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_5.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_6.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_6.png index db53a0bb41..fe9a996a17 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_6.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_7.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_7.png index f2015a77d1..06e38fddc6 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_7.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_8.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_8.png index 39b8d5f8f5..7240e048b5 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_8.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_9.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_9.png index 8b5e6f5ee7..c074f68818 100644 Binary files a/assets/dolphin/external/L3_Hijack_radio_128x64/frame_9.png and b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_0.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_0.png old mode 100755 new mode 100644 index b937cc0860..3b179a0d46 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_0.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_0.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_1.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_1.png old mode 100755 new mode 100644 index a3b494dda4..bba17279d4 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_1.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_1.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_10.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_10.png old mode 100755 new mode 100644 index b8163164b2..5016136e5d Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_10.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_10.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_11.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_11.png old mode 100755 new mode 100644 index e685ff86aa..95c1a8a32e Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_11.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_11.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_12.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_12.png old mode 100755 new mode 100644 index 10a52400b0..fd0a6c6259 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_12.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_12.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_13.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_13.png old mode 100755 new mode 100644 index 9cdea5002f..4f4a2623c3 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_13.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_13.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_14.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_14.png old mode 100755 new mode 100644 index 590d0bf891..4d27df289f Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_14.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_14.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_15.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_15.png old mode 100755 new mode 100644 index 97cf05dd07..e6be088470 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_15.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_15.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_16.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_16.png old mode 100755 new mode 100644 index e2bae209f1..779de319e5 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_16.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_16.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_17.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_17.png old mode 100755 new mode 100644 index 63db9fa0e2..b9e89ebd0b Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_17.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_17.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_18.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_18.png old mode 100755 new mode 100644 index ad66f34efc..255818b91f Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_18.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_18.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_19.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_19.png old mode 100755 new mode 100644 index 213fb76369..23e10f5536 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_19.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_19.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_2.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_2.png old mode 100755 new mode 100644 index 81174f7fa8..d0426c0fc7 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_2.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_2.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_20.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_20.png old mode 100755 new mode 100644 index 7f4ce3bacc..e80dee3204 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_20.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_20.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_21.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_21.png old mode 100755 new mode 100644 index dc90311fed..64b38cbff5 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_21.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_21.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_22.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_22.png old mode 100755 new mode 100644 index cda17cb609..52793ffae6 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_22.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_22.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_23.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_23.png old mode 100755 new mode 100644 index 7a048dbaee..fefe0d834b Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_23.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_23.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_24.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_24.png old mode 100755 new mode 100644 index c5a80a9255..0e46efde1f Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_24.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_24.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_25.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_25.png old mode 100755 new mode 100644 index e80fdfb005..69b8e9d5a8 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_25.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_25.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_26.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_26.png old mode 100755 new mode 100644 index b3955ac8a9..d93dc9aa74 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_26.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_26.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_27.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_27.png old mode 100755 new mode 100644 index 4b003d0349..c7f848cb79 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_27.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_27.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_28.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_28.png old mode 100755 new mode 100644 index df2008d932..adcae64da4 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_28.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_28.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_29.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_29.png old mode 100755 new mode 100644 index c0afacdfa2..05dd84317a Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_29.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_29.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_3.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_3.png old mode 100755 new mode 100644 index 97c138235c..d8155c7e2d Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_3.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_3.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_30.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_30.png old mode 100755 new mode 100644 index 6f693de4f3..9b60bc189b Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_30.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_30.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_31.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_31.png old mode 100755 new mode 100644 index c971b21783..19ae6d56fc Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_31.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_31.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_32.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_32.png old mode 100755 new mode 100644 index 856c845571..dcc5cfdde8 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_32.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_32.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_33.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_33.png old mode 100755 new mode 100644 index 7e99a4a820..6548ece20c Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_33.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_33.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_34.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_34.png old mode 100755 new mode 100644 index 949d845d45..2660213709 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_34.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_34.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_35.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_35.png old mode 100755 new mode 100644 index ee7be1409a..c44b65adc5 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_35.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_35.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_36.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_36.png old mode 100755 new mode 100644 index ae6fca1cdc..28aa1539cd Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_36.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_36.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_37.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_37.png old mode 100755 new mode 100644 index 2567cf087d..95ac16500c Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_37.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_37.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_38.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_38.png old mode 100755 new mode 100644 index b3d0c7acfb..796df31f43 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_38.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_38.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_39.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_39.png old mode 100755 new mode 100644 index dd98cfcbd8..320de262de Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_39.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_39.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_4.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_4.png old mode 100755 new mode 100644 index 0f81cd5dcd..bf55efc7db Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_4.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_4.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_40.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_40.png old mode 100755 new mode 100644 index 8e55dd9edf..4af4b80a66 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_40.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_40.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_41.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_41.png old mode 100755 new mode 100644 index 459f0c8e65..707dc05bbd Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_41.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_41.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_42.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_42.png old mode 100755 new mode 100644 index 3c09559931..19de275d9c Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_42.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_42.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_43.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_43.png old mode 100755 new mode 100644 index 32d4eb4f1a..95e61d24fd Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_43.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_43.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_44.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_44.png old mode 100755 new mode 100644 index 11bd640ae9..376b23ee90 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_44.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_44.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_45.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_45.png old mode 100755 new mode 100644 index 27af626e8a..5e2b91f0b9 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_45.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_45.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_46.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_46.png old mode 100755 new mode 100644 index cfc81bd3f3..b19f70c54d Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_46.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_46.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_47.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_47.png old mode 100755 new mode 100644 index f9480b1e38..1d6afe6ff5 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_47.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_47.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_48.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_48.png old mode 100755 new mode 100644 index 6793a3df6e..38e8bc3295 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_48.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_48.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_49.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_49.png old mode 100755 new mode 100644 index 6b58a0fa78..f22a84b66c Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_49.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_49.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_5.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_5.png old mode 100755 new mode 100644 index cb62bb7b35..7c0c0539d4 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_5.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_5.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_50.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_50.png old mode 100755 new mode 100644 index 8b5ab6a9b6..a08a141dbd Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_50.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_50.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_51.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_51.png old mode 100755 new mode 100644 index 9a2c6b1509..3f631fe4ef Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_51.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_51.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_52.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_52.png old mode 100755 new mode 100644 index f7da1b5875..043481281a Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_52.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_52.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_53.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_53.png old mode 100755 new mode 100644 index d8e390bb59..cb8d0f15f8 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_53.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_53.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_54.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_54.png old mode 100755 new mode 100644 index 8dfe5defe0..66179fcd1a Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_54.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_54.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_55.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_55.png old mode 100755 new mode 100644 index fae299733c..0c25fab74f Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_55.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_55.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_6.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_6.png old mode 100755 new mode 100644 index 2d111a7a17..15034fad32 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_6.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_6.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_7.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_7.png old mode 100755 new mode 100644 index 4c8a9d2e5d..d5d30c8ed9 Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_7.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_7.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_8.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_8.png old mode 100755 new mode 100644 index aa0d1e6a77..dab8497c8f Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_8.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_8.png differ diff --git a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_9.png b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_9.png old mode 100755 new mode 100644 index 9f2d03b7ef..e445ae752b Binary files a/assets/dolphin/external/L3_Intruder_alert_128x64/frame_9.png and b/assets/dolphin/external/L3_Intruder_alert_128x64/frame_9.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_0.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_0.png index c85bb77c41..3d170012c7 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_0.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_0.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_1.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_1.png index dedff60241..2c4b102343 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_1.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_1.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_10.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_10.png index 1a53ab75d5..02a91f9baa 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_10.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_10.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_11.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_11.png index 1768d50dd2..12e5454198 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_11.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_11.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_12.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_12.png index 2beb237d98..489c530352 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_12.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_12.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_13.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_13.png index c46dc3babf..daa7667cc1 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_13.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_13.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_2.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_2.png index 01f07c68df..34650daa63 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_2.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_2.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_3.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_3.png index 148fe46405..7da00632d5 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_3.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_3.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_4.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_4.png index 0d402b0dbf..9a5d688cfb 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_4.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_4.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_5.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_5.png index 6853e1d612..697b307cbe 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_5.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_5.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_6.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_6.png index 9a92ba8d81..daa7667cc1 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_6.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_6.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_7.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_7.png index 910ae58521..91fd1cbafb 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_7.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_7.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_8.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_8.png index 0f681e6abb..7fc99ca893 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_8.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_8.png differ diff --git a/assets/dolphin/external/L3_Lab_research_128x54/frame_9.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_9.png index 0f391b75e5..6b237672e4 100644 Binary files a/assets/dolphin/external/L3_Lab_research_128x54/frame_9.png and b/assets/dolphin/external/L3_Lab_research_128x54/frame_9.png differ diff --git a/assets/dolphin/internal/L1_BadBattery_128x47/frame_0.png b/assets/dolphin/internal/L1_BadBattery_128x47/frame_0.png index 7d3f3dcdf4..4977401e18 100644 Binary files a/assets/dolphin/internal/L1_BadBattery_128x47/frame_0.png and b/assets/dolphin/internal/L1_BadBattery_128x47/frame_0.png differ diff --git a/assets/dolphin/internal/L1_BadBattery_128x47/frame_1.png b/assets/dolphin/internal/L1_BadBattery_128x47/frame_1.png index 98c2979cf2..ef1f17fcc0 100644 Binary files a/assets/dolphin/internal/L1_BadBattery_128x47/frame_1.png and b/assets/dolphin/internal/L1_BadBattery_128x47/frame_1.png differ diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_0.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_0.png index 9a48d15f7a..0ba376d653 100644 Binary files a/assets/dolphin/internal/L1_NoSd_128x49/frame_0.png and b/assets/dolphin/internal/L1_NoSd_128x49/frame_0.png differ diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_1.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_1.png index b58936d817..4764b4888f 100644 Binary files a/assets/dolphin/internal/L1_NoSd_128x49/frame_1.png and b/assets/dolphin/internal/L1_NoSd_128x49/frame_1.png differ diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_2.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_2.png index 5b474fff26..554fe01569 100644 Binary files a/assets/dolphin/internal/L1_NoSd_128x49/frame_2.png and b/assets/dolphin/internal/L1_NoSd_128x49/frame_2.png differ diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_3.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_3.png index 952f968fb6..692a584a34 100644 Binary files a/assets/dolphin/internal/L1_NoSd_128x49/frame_3.png and b/assets/dolphin/internal/L1_NoSd_128x49/frame_3.png differ diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_4.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_4.png index 2bb43b306f..9efdaf23a1 100644 Binary files a/assets/dolphin/internal/L1_NoSd_128x49/frame_4.png and b/assets/dolphin/internal/L1_NoSd_128x49/frame_4.png differ diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_5.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_5.png index d7f8c6402a..657cbf815a 100644 Binary files a/assets/dolphin/internal/L1_NoSd_128x49/frame_5.png and b/assets/dolphin/internal/L1_NoSd_128x49/frame_5.png differ diff --git a/assets/dolphin/internal/L1_Tv_128x47/frame_0.png b/assets/dolphin/internal/L1_Tv_128x47/frame_0.png index acc24df00c..f225aa993a 100644 Binary files a/assets/dolphin/internal/L1_Tv_128x47/frame_0.png and b/assets/dolphin/internal/L1_Tv_128x47/frame_0.png differ diff --git a/assets/dolphin/internal/L1_Tv_128x47/frame_1.png b/assets/dolphin/internal/L1_Tv_128x47/frame_1.png index b0ead79941..81f12ca091 100644 Binary files a/assets/dolphin/internal/L1_Tv_128x47/frame_1.png and b/assets/dolphin/internal/L1_Tv_128x47/frame_1.png differ diff --git a/assets/dolphin/internal/L1_Tv_128x47/frame_2.png b/assets/dolphin/internal/L1_Tv_128x47/frame_2.png index c1541b2dd9..ce0d854114 100644 Binary files a/assets/dolphin/internal/L1_Tv_128x47/frame_2.png and b/assets/dolphin/internal/L1_Tv_128x47/frame_2.png differ diff --git a/assets/dolphin/internal/L1_Tv_128x47/frame_3.png b/assets/dolphin/internal/L1_Tv_128x47/frame_3.png index 1e13b0951f..40bf13a4d3 100644 Binary files a/assets/dolphin/internal/L1_Tv_128x47/frame_3.png and b/assets/dolphin/internal/L1_Tv_128x47/frame_3.png differ diff --git a/assets/dolphin/internal/L1_Tv_128x47/frame_4.png b/assets/dolphin/internal/L1_Tv_128x47/frame_4.png index 7d87fa2f84..13d3074c9d 100644 Binary files a/assets/dolphin/internal/L1_Tv_128x47/frame_4.png and b/assets/dolphin/internal/L1_Tv_128x47/frame_4.png differ diff --git a/assets/dolphin/internal/L1_Tv_128x47/frame_5.png b/assets/dolphin/internal/L1_Tv_128x47/frame_5.png index 282f430595..b11e81b8da 100644 Binary files a/assets/dolphin/internal/L1_Tv_128x47/frame_5.png and b/assets/dolphin/internal/L1_Tv_128x47/frame_5.png differ diff --git a/assets/dolphin/internal/L1_Tv_128x47/frame_6.png b/assets/dolphin/internal/L1_Tv_128x47/frame_6.png index 8516cbe754..52fdba4630 100644 Binary files a/assets/dolphin/internal/L1_Tv_128x47/frame_6.png and b/assets/dolphin/internal/L1_Tv_128x47/frame_6.png differ diff --git a/assets/dolphin/internal/L1_Tv_128x47/frame_7.png b/assets/dolphin/internal/L1_Tv_128x47/frame_7.png index 42196cab13..d2834c6ed5 100644 Binary files a/assets/dolphin/internal/L1_Tv_128x47/frame_7.png and b/assets/dolphin/internal/L1_Tv_128x47/frame_7.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_00.png b/assets/icons/Animations/Levelup1_128x64/frame_00.png index bf97f8d6ea..d0d8bc82fe 100644 Binary files a/assets/icons/Animations/Levelup1_128x64/frame_00.png and b/assets/icons/Animations/Levelup1_128x64/frame_00.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_01.png b/assets/icons/Animations/Levelup1_128x64/frame_01.png index 39c910d3a4..1429d994e5 100644 Binary files a/assets/icons/Animations/Levelup1_128x64/frame_01.png and b/assets/icons/Animations/Levelup1_128x64/frame_01.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_02.png b/assets/icons/Animations/Levelup1_128x64/frame_02.png index 4975adf862..4b3bf5f83e 100644 Binary files a/assets/icons/Animations/Levelup1_128x64/frame_02.png and b/assets/icons/Animations/Levelup1_128x64/frame_02.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_03.png b/assets/icons/Animations/Levelup1_128x64/frame_03.png index 5a05529c55..188a38bbf6 100644 Binary files a/assets/icons/Animations/Levelup1_128x64/frame_03.png and b/assets/icons/Animations/Levelup1_128x64/frame_03.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_04.png b/assets/icons/Animations/Levelup1_128x64/frame_04.png index e6c88df92b..3d97117312 100644 Binary files a/assets/icons/Animations/Levelup1_128x64/frame_04.png and b/assets/icons/Animations/Levelup1_128x64/frame_04.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_05.png b/assets/icons/Animations/Levelup1_128x64/frame_05.png index e7bae4d6c8..639d7fc179 100644 Binary files a/assets/icons/Animations/Levelup1_128x64/frame_05.png and b/assets/icons/Animations/Levelup1_128x64/frame_05.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_06.png b/assets/icons/Animations/Levelup1_128x64/frame_06.png index 489bce368d..4227e1784b 100644 Binary files a/assets/icons/Animations/Levelup1_128x64/frame_06.png and b/assets/icons/Animations/Levelup1_128x64/frame_06.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_07.png b/assets/icons/Animations/Levelup1_128x64/frame_07.png index 32e864e982..d596229938 100644 Binary files a/assets/icons/Animations/Levelup1_128x64/frame_07.png and b/assets/icons/Animations/Levelup1_128x64/frame_07.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_08.png b/assets/icons/Animations/Levelup1_128x64/frame_08.png index c692f48952..23b9a9bd0d 100644 Binary files a/assets/icons/Animations/Levelup1_128x64/frame_08.png and b/assets/icons/Animations/Levelup1_128x64/frame_08.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_09.png b/assets/icons/Animations/Levelup1_128x64/frame_09.png index fb1c8bb904..1fdedbc190 100644 Binary files a/assets/icons/Animations/Levelup1_128x64/frame_09.png and b/assets/icons/Animations/Levelup1_128x64/frame_09.png differ diff --git a/assets/icons/Animations/Levelup1_128x64/frame_10.png b/assets/icons/Animations/Levelup1_128x64/frame_10.png index 3b0205a484..79e0b15432 100644 Binary files a/assets/icons/Animations/Levelup1_128x64/frame_10.png and b/assets/icons/Animations/Levelup1_128x64/frame_10.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_00.png b/assets/icons/Animations/Levelup2_128x64/frame_00.png index 77b531076d..0bf23b5c58 100644 Binary files a/assets/icons/Animations/Levelup2_128x64/frame_00.png and b/assets/icons/Animations/Levelup2_128x64/frame_00.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_01.png b/assets/icons/Animations/Levelup2_128x64/frame_01.png index b534372659..b9990b406a 100644 Binary files a/assets/icons/Animations/Levelup2_128x64/frame_01.png and b/assets/icons/Animations/Levelup2_128x64/frame_01.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_02.png b/assets/icons/Animations/Levelup2_128x64/frame_02.png index 9623af7d87..a57641e449 100644 Binary files a/assets/icons/Animations/Levelup2_128x64/frame_02.png and b/assets/icons/Animations/Levelup2_128x64/frame_02.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_03.png b/assets/icons/Animations/Levelup2_128x64/frame_03.png index f182690196..deeff97c58 100644 Binary files a/assets/icons/Animations/Levelup2_128x64/frame_03.png and b/assets/icons/Animations/Levelup2_128x64/frame_03.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_04.png b/assets/icons/Animations/Levelup2_128x64/frame_04.png index 677a3367e8..4b7367a37f 100644 Binary files a/assets/icons/Animations/Levelup2_128x64/frame_04.png and b/assets/icons/Animations/Levelup2_128x64/frame_04.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_05.png b/assets/icons/Animations/Levelup2_128x64/frame_05.png index fb58fed1e0..a033448f77 100644 Binary files a/assets/icons/Animations/Levelup2_128x64/frame_05.png and b/assets/icons/Animations/Levelup2_128x64/frame_05.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_06.png b/assets/icons/Animations/Levelup2_128x64/frame_06.png index b2cbd699b3..5389124dc1 100644 Binary files a/assets/icons/Animations/Levelup2_128x64/frame_06.png and b/assets/icons/Animations/Levelup2_128x64/frame_06.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_07.png b/assets/icons/Animations/Levelup2_128x64/frame_07.png index 4f3dfc8c4a..cd4324f0d1 100644 Binary files a/assets/icons/Animations/Levelup2_128x64/frame_07.png and b/assets/icons/Animations/Levelup2_128x64/frame_07.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_08.png b/assets/icons/Animations/Levelup2_128x64/frame_08.png index 3a5a28805a..fea3628085 100644 Binary files a/assets/icons/Animations/Levelup2_128x64/frame_08.png and b/assets/icons/Animations/Levelup2_128x64/frame_08.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_09.png b/assets/icons/Animations/Levelup2_128x64/frame_09.png index 76267a2a8d..fd4a3de1d4 100644 Binary files a/assets/icons/Animations/Levelup2_128x64/frame_09.png and b/assets/icons/Animations/Levelup2_128x64/frame_09.png differ diff --git a/assets/icons/Animations/Levelup2_128x64/frame_10.png b/assets/icons/Animations/Levelup2_128x64/frame_10.png index bda1bf44ce..fae5359978 100644 Binary files a/assets/icons/Animations/Levelup2_128x64/frame_10.png and b/assets/icons/Animations/Levelup2_128x64/frame_10.png differ diff --git a/assets/icons/Archive/125_10px.png b/assets/icons/Archive/125_10px.png index ce01284a2c..fd3947ff36 100644 Binary files a/assets/icons/Archive/125_10px.png and b/assets/icons/Archive/125_10px.png differ diff --git a/assets/icons/Archive/Nfc_10px.png b/assets/icons/Archive/Nfc_10px.png index 6bc027111a..e998d291ee 100644 Binary files a/assets/icons/Archive/Nfc_10px.png and b/assets/icons/Archive/Nfc_10px.png differ diff --git a/assets/icons/Archive/back_10px.png b/assets/icons/Archive/back_10px.png index f9c615a99e..b7ffd4efbd 100644 Binary files a/assets/icons/Archive/back_10px.png and b/assets/icons/Archive/back_10px.png differ diff --git a/assets/icons/Archive/badusb_10px.png b/assets/icons/Archive/badusb_10px.png index 037474aa3b..2b5a3bf973 100644 Binary files a/assets/icons/Archive/badusb_10px.png and b/assets/icons/Archive/badusb_10px.png differ diff --git a/assets/icons/Archive/dir_10px.png b/assets/icons/Archive/dir_10px.png index a4cdf453e3..1b64022c2c 100644 Binary files a/assets/icons/Archive/dir_10px.png and b/assets/icons/Archive/dir_10px.png differ diff --git a/assets/icons/Archive/ibutt_10px.png b/assets/icons/Archive/ibutt_10px.png index 2fdaf123a6..f73af065f4 100644 Binary files a/assets/icons/Archive/ibutt_10px.png and b/assets/icons/Archive/ibutt_10px.png differ diff --git a/assets/icons/Archive/ir_10px.png b/assets/icons/Archive/ir_10px.png index 22c986180a..36c214f3b8 100644 Binary files a/assets/icons/Archive/ir_10px.png and b/assets/icons/Archive/ir_10px.png differ diff --git a/assets/icons/Archive/js_script_10px.png b/assets/icons/Archive/js_script_10px.png index 77ac76337e..48210a0497 100644 Binary files a/assets/icons/Archive/js_script_10px.png and b/assets/icons/Archive/js_script_10px.png differ diff --git a/assets/icons/Archive/keyboard_10px.png b/assets/icons/Archive/keyboard_10px.png index 74a10e6db2..dc3e3cee21 100644 Binary files a/assets/icons/Archive/keyboard_10px.png and b/assets/icons/Archive/keyboard_10px.png differ diff --git a/assets/icons/Archive/loading_10px.png b/assets/icons/Archive/loading_10px.png index 4f626b3d58..a6065b6c0b 100644 Binary files a/assets/icons/Archive/loading_10px.png and b/assets/icons/Archive/loading_10px.png differ diff --git a/assets/icons/Archive/music_10px.png b/assets/icons/Archive/music_10px.png index d41eb0db8c..98fed6d926 100644 Binary files a/assets/icons/Archive/music_10px.png and b/assets/icons/Archive/music_10px.png differ diff --git a/assets/icons/Archive/sub1_10px.png b/assets/icons/Archive/sub1_10px.png index 5a25fdf4ef..70940ad779 100644 Binary files a/assets/icons/Archive/sub1_10px.png and b/assets/icons/Archive/sub1_10px.png differ diff --git a/assets/icons/Archive/u2f_10px.png b/assets/icons/Archive/u2f_10px.png index fcd87a2ef5..6f46b0e783 100644 Binary files a/assets/icons/Archive/u2f_10px.png and b/assets/icons/Archive/u2f_10px.png differ diff --git a/assets/icons/Archive/unknown_10px.png b/assets/icons/Archive/unknown_10px.png index 18d31c67ca..2d2668e853 100644 Binary files a/assets/icons/Archive/unknown_10px.png and b/assets/icons/Archive/unknown_10px.png differ diff --git a/assets/icons/Archive/update_10px.png b/assets/icons/Archive/update_10px.png index 5a97651c48..94c96769fa 100644 Binary files a/assets/icons/Archive/update_10px.png and b/assets/icons/Archive/update_10px.png differ diff --git a/assets/icons/BLE/BLE_HID/Ble_connected_15x15.png b/assets/icons/BLE/BLE_HID/Ble_connected_15x15.png index 64dab9b530..1301399da9 100644 Binary files a/assets/icons/BLE/BLE_HID/Ble_connected_15x15.png and b/assets/icons/BLE/BLE_HID/Ble_connected_15x15.png differ diff --git a/assets/icons/BLE/BLE_HID/Ble_disconnected_15x15.png b/assets/icons/BLE/BLE_HID/Ble_disconnected_15x15.png index 0858bb93f4..f926ce2128 100644 Binary files a/assets/icons/BLE/BLE_HID/Ble_disconnected_15x15.png and b/assets/icons/BLE/BLE_HID/Ble_disconnected_15x15.png differ diff --git a/assets/icons/BLE/BLE_HID/Button_18x18.png b/assets/icons/BLE/BLE_HID/Button_18x18.png index 30a5b4fab2..2334dd8be0 100644 Binary files a/assets/icons/BLE/BLE_HID/Button_18x18.png and b/assets/icons/BLE/BLE_HID/Button_18x18.png differ diff --git a/assets/icons/BLE/BLE_HID/Circles_47x47.png b/assets/icons/BLE/BLE_HID/Circles_47x47.png index 6a16ebf7bb..bf72412f55 100644 Binary files a/assets/icons/BLE/BLE_HID/Circles_47x47.png and b/assets/icons/BLE/BLE_HID/Circles_47x47.png differ diff --git a/assets/icons/BLE/BLE_HID/Left_mouse_icon_9x9.png b/assets/icons/BLE/BLE_HID/Left_mouse_icon_9x9.png index c533d85729..5bd2d395f5 100644 Binary files a/assets/icons/BLE/BLE_HID/Left_mouse_icon_9x9.png and b/assets/icons/BLE/BLE_HID/Left_mouse_icon_9x9.png differ diff --git a/assets/icons/BLE/BLE_HID/Ok_btn_9x9.png b/assets/icons/BLE/BLE_HID/Ok_btn_9x9.png index 9a1539da20..ceff4e8a88 100644 Binary files a/assets/icons/BLE/BLE_HID/Ok_btn_9x9.png and b/assets/icons/BLE/BLE_HID/Ok_btn_9x9.png differ diff --git a/assets/icons/BLE/BLE_HID/Ok_btn_pressed_13x13.png b/assets/icons/BLE/BLE_HID/Ok_btn_pressed_13x13.png index 6b46ba3a82..ced2369b4f 100644 Binary files a/assets/icons/BLE/BLE_HID/Ok_btn_pressed_13x13.png and b/assets/icons/BLE/BLE_HID/Ok_btn_pressed_13x13.png differ diff --git a/assets/icons/BLE/BLE_HID/Pressed_Button_13x13.png b/assets/icons/BLE/BLE_HID/Pressed_Button_13x13.png index 823926b842..d0e2c3a373 100644 Binary files a/assets/icons/BLE/BLE_HID/Pressed_Button_13x13.png and b/assets/icons/BLE/BLE_HID/Pressed_Button_13x13.png differ diff --git a/assets/icons/BLE/BLE_HID/Right_mouse_icon_9x9.png b/assets/icons/BLE/BLE_HID/Right_mouse_icon_9x9.png index 446d7176c8..1da29ee436 100644 Binary files a/assets/icons/BLE/BLE_HID/Right_mouse_icon_9x9.png and b/assets/icons/BLE/BLE_HID/Right_mouse_icon_9x9.png differ diff --git a/assets/icons/BLE/BLE_HID/Space_65x18.png b/assets/icons/BLE/BLE_HID/Space_65x18.png index b60ae50970..eb417f6746 100644 Binary files a/assets/icons/BLE/BLE_HID/Space_65x18.png and b/assets/icons/BLE/BLE_HID/Space_65x18.png differ diff --git a/assets/icons/BLE/BLE_HID/Voldwn_6x6.png b/assets/icons/BLE/BLE_HID/Voldwn_6x6.png index d7a82a2df8..d6d7e286a3 100644 Binary files a/assets/icons/BLE/BLE_HID/Voldwn_6x6.png and b/assets/icons/BLE/BLE_HID/Voldwn_6x6.png differ diff --git a/assets/icons/BLE/BLE_HID/Volup_8x6.png b/assets/icons/BLE/BLE_HID/Volup_8x6.png index 4b7ec66d65..66477bc7b5 100644 Binary files a/assets/icons/BLE/BLE_HID/Volup_8x6.png and b/assets/icons/BLE/BLE_HID/Volup_8x6.png differ diff --git a/assets/icons/BLE/BLE_Pairing_128x64.png b/assets/icons/BLE/BLE_Pairing_128x64.png index 34068c3003..97800403f7 100644 Binary files a/assets/icons/BLE/BLE_Pairing_128x64.png and b/assets/icons/BLE/BLE_Pairing_128x64.png differ diff --git a/assets/icons/BadUsb/Clock_18x18.png b/assets/icons/BadUsb/Clock_18x18.png index ab06d008ee..71ba0274fb 100644 Binary files a/assets/icons/BadUsb/Clock_18x18.png and b/assets/icons/BadUsb/Clock_18x18.png differ diff --git a/assets/icons/BadUsb/Error_18x18.png b/assets/icons/BadUsb/Error_18x18.png index 16a5a74d96..28de03da89 100644 Binary files a/assets/icons/BadUsb/Error_18x18.png and b/assets/icons/BadUsb/Error_18x18.png differ diff --git a/assets/icons/BadUsb/EviSmile1_18x21.png b/assets/icons/BadUsb/EviSmile1_18x21.png index 987af32587..1ba168c618 100644 Binary files a/assets/icons/BadUsb/EviSmile1_18x21.png and b/assets/icons/BadUsb/EviSmile1_18x21.png differ diff --git a/assets/icons/BadUsb/EviSmile2_18x21.png b/assets/icons/BadUsb/EviSmile2_18x21.png index 7e28c9f018..0318d425aa 100644 Binary files a/assets/icons/BadUsb/EviSmile2_18x21.png and b/assets/icons/BadUsb/EviSmile2_18x21.png differ diff --git a/assets/icons/BadUsb/EviWaiting1_18x21.png b/assets/icons/BadUsb/EviWaiting1_18x21.png index d39d217332..82fc0f3302 100644 Binary files a/assets/icons/BadUsb/EviWaiting1_18x21.png and b/assets/icons/BadUsb/EviWaiting1_18x21.png differ diff --git a/assets/icons/BadUsb/EviWaiting2_18x21.png b/assets/icons/BadUsb/EviWaiting2_18x21.png index 15ca088fd7..7209d35811 100644 Binary files a/assets/icons/BadUsb/EviWaiting2_18x21.png and b/assets/icons/BadUsb/EviWaiting2_18x21.png differ diff --git a/assets/icons/BadUsb/Percent_10x14.png b/assets/icons/BadUsb/Percent_10x14.png index 677911fd44..97b304f1ad 100644 Binary files a/assets/icons/BadUsb/Percent_10x14.png and b/assets/icons/BadUsb/Percent_10x14.png differ diff --git a/assets/icons/BadUsb/Smile_18x18.png b/assets/icons/BadUsb/Smile_18x18.png index d2aae0dc37..c0ff50c0bb 100644 Binary files a/assets/icons/BadUsb/Smile_18x18.png and b/assets/icons/BadUsb/Smile_18x18.png differ diff --git a/assets/icons/BadUsb/UsbTree_48x22.png b/assets/icons/BadUsb/UsbTree_48x22.png index cc41b5b9a9..33ce1bf5ae 100644 Binary files a/assets/icons/BadUsb/UsbTree_48x22.png and b/assets/icons/BadUsb/UsbTree_48x22.png differ diff --git a/assets/icons/Common/ActiveConnection_50x64.png b/assets/icons/Common/ActiveConnection_50x64.png index 1d7686dddf..c5ebb83523 100644 Binary files a/assets/icons/Common/ActiveConnection_50x64.png and b/assets/icons/Common/ActiveConnection_50x64.png differ diff --git a/assets/icons/Common/ButtonCenter_7x7.png b/assets/icons/Common/ButtonCenter_7x7.png index a66461b227..e1e015ab51 100644 Binary files a/assets/icons/Common/ButtonCenter_7x7.png and b/assets/icons/Common/ButtonCenter_7x7.png differ diff --git a/assets/icons/Common/ButtonDown_7x4.png b/assets/icons/Common/ButtonDown_7x4.png index 2954bb6a67..0cda838e05 100644 Binary files a/assets/icons/Common/ButtonDown_7x4.png and b/assets/icons/Common/ButtonDown_7x4.png differ diff --git a/assets/icons/Common/ButtonLeftSmall_3x5.png b/assets/icons/Common/ButtonLeftSmall_3x5.png index 51411acaf8..0fb7fb3139 100644 Binary files a/assets/icons/Common/ButtonLeftSmall_3x5.png and b/assets/icons/Common/ButtonLeftSmall_3x5.png differ diff --git a/assets/icons/Common/ButtonLeft_4x7.png b/assets/icons/Common/ButtonLeft_4x7.png index 0b4655d432..7c43f3b04d 100644 Binary files a/assets/icons/Common/ButtonLeft_4x7.png and b/assets/icons/Common/ButtonLeft_4x7.png differ diff --git a/assets/icons/Common/ButtonRightSmall_3x5.png b/assets/icons/Common/ButtonRightSmall_3x5.png index b9d5f87db1..c25ba7261b 100644 Binary files a/assets/icons/Common/ButtonRightSmall_3x5.png and b/assets/icons/Common/ButtonRightSmall_3x5.png differ diff --git a/assets/icons/Common/ButtonRight_4x7.png b/assets/icons/Common/ButtonRight_4x7.png index 8e1c74c1c0..31de21c0e2 100644 Binary files a/assets/icons/Common/ButtonRight_4x7.png and b/assets/icons/Common/ButtonRight_4x7.png differ diff --git a/assets/icons/Common/ButtonUp_7x4.png b/assets/icons/Common/ButtonUp_7x4.png index 1be79328b4..48d0f9f018 100644 Binary files a/assets/icons/Common/ButtonUp_7x4.png and b/assets/icons/Common/ButtonUp_7x4.png differ diff --git a/assets/icons/Common/DFU_128x50.png b/assets/icons/Common/DFU_128x50.png index 951cdc198d..256a61b6bf 100644 Binary files a/assets/icons/Common/DFU_128x50.png and b/assets/icons/Common/DFU_128x50.png differ diff --git a/assets/icons/Common/Hashmark_7x7.png b/assets/icons/Common/Hashmark_7x7.png index 93fb147be2..6ede005dda 100644 Binary files a/assets/icons/Common/Hashmark_7x7.png and b/assets/icons/Common/Hashmark_7x7.png differ diff --git a/assets/icons/Common/Loading_24/frame_01.png b/assets/icons/Common/Loading_24/frame_01.png index 9c49dcad1c..7fafe05cab 100644 Binary files a/assets/icons/Common/Loading_24/frame_01.png and b/assets/icons/Common/Loading_24/frame_01.png differ diff --git a/assets/icons/Common/Loading_24/frame_02.png b/assets/icons/Common/Loading_24/frame_02.png index 93a59fe681..8684b4f344 100644 Binary files a/assets/icons/Common/Loading_24/frame_02.png and b/assets/icons/Common/Loading_24/frame_02.png differ diff --git a/assets/icons/Common/Loading_24/frame_03.png b/assets/icons/Common/Loading_24/frame_03.png index 7bb66fca0a..01c99c56e7 100644 Binary files a/assets/icons/Common/Loading_24/frame_03.png and b/assets/icons/Common/Loading_24/frame_03.png differ diff --git a/assets/icons/Common/Loading_24/frame_04.png b/assets/icons/Common/Loading_24/frame_04.png index adefde921e..15019fbc67 100644 Binary files a/assets/icons/Common/Loading_24/frame_04.png and b/assets/icons/Common/Loading_24/frame_04.png differ diff --git a/assets/icons/Common/Loading_24/frame_05.png b/assets/icons/Common/Loading_24/frame_05.png index 80bf88e965..c144a72ede 100644 Binary files a/assets/icons/Common/Loading_24/frame_05.png and b/assets/icons/Common/Loading_24/frame_05.png differ diff --git a/assets/icons/Common/Loading_24/frame_06.png b/assets/icons/Common/Loading_24/frame_06.png index b768a7875f..fe66f11c67 100644 Binary files a/assets/icons/Common/Loading_24/frame_06.png and b/assets/icons/Common/Loading_24/frame_06.png differ diff --git a/assets/icons/Common/Loading_24/frame_07.png b/assets/icons/Common/Loading_24/frame_07.png index 190d2edf34..a7843a35bf 100644 Binary files a/assets/icons/Common/Loading_24/frame_07.png and b/assets/icons/Common/Loading_24/frame_07.png differ diff --git a/assets/icons/Common/More_data_placeholder_5x7.png b/assets/icons/Common/More_data_placeholder_5x7.png index 85025d9f0a..bbfdae047b 100644 Binary files a/assets/icons/Common/More_data_placeholder_5x7.png and b/assets/icons/Common/More_data_placeholder_5x7.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_01.png b/assets/icons/Common/Round_loader_8x8/frame_01.png index a5dc239d85..b8db2a4b5e 100644 Binary files a/assets/icons/Common/Round_loader_8x8/frame_01.png and b/assets/icons/Common/Round_loader_8x8/frame_01.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_02.png b/assets/icons/Common/Round_loader_8x8/frame_02.png index 162d8a8f42..aa0f22a4c9 100644 Binary files a/assets/icons/Common/Round_loader_8x8/frame_02.png and b/assets/icons/Common/Round_loader_8x8/frame_02.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_03.png b/assets/icons/Common/Round_loader_8x8/frame_03.png index 5483e47345..cba466ef68 100644 Binary files a/assets/icons/Common/Round_loader_8x8/frame_03.png and b/assets/icons/Common/Round_loader_8x8/frame_03.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_04.png b/assets/icons/Common/Round_loader_8x8/frame_04.png index ce2fbbd476..4e90ed650e 100644 Binary files a/assets/icons/Common/Round_loader_8x8/frame_04.png and b/assets/icons/Common/Round_loader_8x8/frame_04.png differ diff --git a/assets/icons/Common/Round_loader_8x8/frame_05.png b/assets/icons/Common/Round_loader_8x8/frame_05.png index 8b786c0293..ed319f764d 100644 Binary files a/assets/icons/Common/Round_loader_8x8/frame_05.png and b/assets/icons/Common/Round_loader_8x8/frame_05.png differ diff --git a/assets/icons/Common/Warning_30x23.png b/assets/icons/Common/Warning_30x23.png index 5f7e02dd85..f307436f50 100644 Binary files a/assets/icons/Common/Warning_30x23.png and b/assets/icons/Common/Warning_30x23.png differ diff --git a/assets/icons/Common/arrow_nano_down.png b/assets/icons/Common/arrow_nano_down.png index da66350bd1..244b022a55 100644 Binary files a/assets/icons/Common/arrow_nano_down.png and b/assets/icons/Common/arrow_nano_down.png differ diff --git a/assets/icons/Common/arrow_nano_up.png b/assets/icons/Common/arrow_nano_up.png index 4a1d5be85c..ccaf88b6e5 100644 Binary files a/assets/icons/Common/arrow_nano_up.png and b/assets/icons/Common/arrow_nano_up.png differ diff --git a/assets/icons/Dolphin/DolphinDone_80x58.png b/assets/icons/Dolphin/DolphinDone_80x58.png index 594d62d529..881aaa8d2a 100644 Binary files a/assets/icons/Dolphin/DolphinDone_80x58.png and b/assets/icons/Dolphin/DolphinDone_80x58.png differ diff --git a/assets/icons/Dolphin/DolphinMafia_119x62.png b/assets/icons/Dolphin/DolphinMafia_119x62.png index 1bbbec84ad..4d47ed5b11 100644 Binary files a/assets/icons/Dolphin/DolphinMafia_119x62.png and b/assets/icons/Dolphin/DolphinMafia_119x62.png differ diff --git a/assets/icons/Dolphin/DolphinReadingSuccess_59x63.png b/assets/icons/Dolphin/DolphinReadingSuccess_59x63.png index 46f559f65f..1380d2dd7c 100644 Binary files a/assets/icons/Dolphin/DolphinReadingSuccess_59x63.png and b/assets/icons/Dolphin/DolphinReadingSuccess_59x63.png differ diff --git a/assets/icons/Dolphin/DolphinSaved_92x58.png b/assets/icons/Dolphin/DolphinSaved_92x58.png index e8704295c6..4d8195b805 100644 Binary files a/assets/icons/Dolphin/DolphinSaved_92x58.png and b/assets/icons/Dolphin/DolphinSaved_92x58.png differ diff --git a/assets/icons/Dolphin/DolphinSuccess_91x55.png b/assets/icons/Dolphin/DolphinSuccess_91x55.png index 80caeb203c..1dc514db64 100644 Binary files a/assets/icons/Dolphin/DolphinSuccess_91x55.png and b/assets/icons/Dolphin/DolphinSuccess_91x55.png differ diff --git a/assets/icons/Dolphin/DolphinWait_59x54.png b/assets/icons/Dolphin/DolphinWait_59x54.png index bdf8171b80..b906916d2a 100644 Binary files a/assets/icons/Dolphin/DolphinWait_59x54.png and b/assets/icons/Dolphin/DolphinWait_59x54.png differ diff --git a/assets/icons/Dolphin/WarningDolphinFlip_45x42.png b/assets/icons/Dolphin/WarningDolphinFlip_45x42.png index 2ba54afce0..a2554eaa6a 100644 Binary files a/assets/icons/Dolphin/WarningDolphinFlip_45x42.png and b/assets/icons/Dolphin/WarningDolphinFlip_45x42.png differ diff --git a/assets/icons/Dolphin/WarningDolphin_45x42.png b/assets/icons/Dolphin/WarningDolphin_45x42.png index d766ffbb44..310be0f70f 100644 Binary files a/assets/icons/Dolphin/WarningDolphin_45x42.png and b/assets/icons/Dolphin/WarningDolphin_45x42.png differ diff --git a/assets/icons/ErasePin/Erase_pin_128x64.png b/assets/icons/ErasePin/Erase_pin_128x64.png index 92ca5f91cb..847146b789 100644 Binary files a/assets/icons/ErasePin/Erase_pin_128x64.png and b/assets/icons/ErasePin/Erase_pin_128x64.png differ diff --git a/assets/icons/GPIO/ArrowUpEmpty_14x15.png b/assets/icons/GPIO/ArrowUpEmpty_14x15.png index 261c6d89e3..01209712e1 100644 Binary files a/assets/icons/GPIO/ArrowUpEmpty_14x15.png and b/assets/icons/GPIO/ArrowUpEmpty_14x15.png differ diff --git a/assets/icons/GPIO/ArrowUpFilled_14x15.png b/assets/icons/GPIO/ArrowUpFilled_14x15.png index fa35eb2f82..2c6dfd9cc6 100644 Binary files a/assets/icons/GPIO/ArrowUpFilled_14x15.png and b/assets/icons/GPIO/ArrowUpFilled_14x15.png differ diff --git a/assets/icons/Infrared/InfraredArrowDown_4x8.png b/assets/icons/Infrared/InfraredArrowDown_4x8.png index 2ac7bcdbef..086fa43fb6 100644 Binary files a/assets/icons/Infrared/InfraredArrowDown_4x8.png and b/assets/icons/Infrared/InfraredArrowDown_4x8.png differ diff --git a/assets/icons/Infrared/InfraredArrowUp_4x8.png b/assets/icons/Infrared/InfraredArrowUp_4x8.png index 4c9a16b3fd..1be28a53a0 100644 Binary files a/assets/icons/Infrared/InfraredArrowUp_4x8.png and b/assets/icons/Infrared/InfraredArrowUp_4x8.png differ diff --git a/assets/icons/Infrared/InfraredLearnShort_128x31.png b/assets/icons/Infrared/InfraredLearnShort_128x31.png index 783ad0877c..cd71a69dbe 100644 Binary files a/assets/icons/Infrared/InfraredLearnShort_128x31.png and b/assets/icons/Infrared/InfraredLearnShort_128x31.png differ diff --git a/assets/icons/Infrared/celsius_24x23.png b/assets/icons/Infrared/celsius_24x23.png index 64d7a1db15..9a6c30c759 100644 Binary files a/assets/icons/Infrared/celsius_24x23.png and b/assets/icons/Infrared/celsius_24x23.png differ diff --git a/assets/icons/Infrared/celsius_hover_24x23.png b/assets/icons/Infrared/celsius_hover_24x23.png index 0488b40f57..f5eb3f4bd7 100644 Binary files a/assets/icons/Infrared/celsius_hover_24x23.png and b/assets/icons/Infrared/celsius_hover_24x23.png differ diff --git a/assets/icons/Infrared/ch_down_24x21.png b/assets/icons/Infrared/ch_down_24x21.png index 8c3f81c3d0..a3803c745c 100644 Binary files a/assets/icons/Infrared/ch_down_24x21.png and b/assets/icons/Infrared/ch_down_24x21.png differ diff --git a/assets/icons/Infrared/ch_down_hover_24x21.png b/assets/icons/Infrared/ch_down_hover_24x21.png index 9b840f9ce3..5320c82a7e 100644 Binary files a/assets/icons/Infrared/ch_down_hover_24x21.png and b/assets/icons/Infrared/ch_down_hover_24x21.png differ diff --git a/assets/icons/Infrared/ch_text_31x34.png b/assets/icons/Infrared/ch_text_31x34.png index 30e0f584c2..88f5c3890d 100644 Binary files a/assets/icons/Infrared/ch_text_31x34.png and b/assets/icons/Infrared/ch_text_31x34.png differ diff --git a/assets/icons/Infrared/ch_up_24x21.png b/assets/icons/Infrared/ch_up_24x21.png index fa4074d12b..356d124f6a 100644 Binary files a/assets/icons/Infrared/ch_up_24x21.png and b/assets/icons/Infrared/ch_up_24x21.png differ diff --git a/assets/icons/Infrared/ch_up_hover_24x21.png b/assets/icons/Infrared/ch_up_hover_24x21.png index 944a973f4a..bef0ab0cce 100644 Binary files a/assets/icons/Infrared/ch_up_hover_24x21.png and b/assets/icons/Infrared/ch_up_hover_24x21.png differ diff --git a/assets/icons/Infrared/cool_30x51.png b/assets/icons/Infrared/cool_30x51.png index 38a8014bd6..5dd42782da 100644 Binary files a/assets/icons/Infrared/cool_30x51.png and b/assets/icons/Infrared/cool_30x51.png differ diff --git a/assets/icons/Infrared/dry_19x20.png b/assets/icons/Infrared/dry_19x20.png index c689c06758..aab1e650fc 100644 Binary files a/assets/icons/Infrared/dry_19x20.png and b/assets/icons/Infrared/dry_19x20.png differ diff --git a/assets/icons/Infrared/dry_hover_19x20.png b/assets/icons/Infrared/dry_hover_19x20.png index 5b7196ae22..5cd1a28144 100644 Binary files a/assets/icons/Infrared/dry_hover_19x20.png and b/assets/icons/Infrared/dry_hover_19x20.png differ diff --git a/assets/icons/Infrared/dry_text_15x5.png b/assets/icons/Infrared/dry_text_15x5.png index 7696e1fc8a..49e2d4ab53 100644 Binary files a/assets/icons/Infrared/dry_text_15x5.png and b/assets/icons/Infrared/dry_text_15x5.png differ diff --git a/assets/icons/Infrared/fahren_24x23.png b/assets/icons/Infrared/fahren_24x23.png index d6f55e806e..df6ce92cf1 100644 Binary files a/assets/icons/Infrared/fahren_24x23.png and b/assets/icons/Infrared/fahren_24x23.png differ diff --git a/assets/icons/Infrared/fahren_hover_24x23.png b/assets/icons/Infrared/fahren_hover_24x23.png index db922c5576..9a1f73a087 100644 Binary files a/assets/icons/Infrared/fahren_hover_24x23.png and b/assets/icons/Infrared/fahren_hover_24x23.png differ diff --git a/assets/icons/Infrared/heat_30x51.png b/assets/icons/Infrared/heat_30x51.png index aca27c7c89..f702816d6e 100644 Binary files a/assets/icons/Infrared/heat_30x51.png and b/assets/icons/Infrared/heat_30x51.png differ diff --git a/assets/icons/Infrared/hourglass0_24x24.png b/assets/icons/Infrared/hourglass0_24x24.png index a382d84e21..ce627b002f 100644 Binary files a/assets/icons/Infrared/hourglass0_24x24.png and b/assets/icons/Infrared/hourglass0_24x24.png differ diff --git a/assets/icons/Infrared/hourglass1_24x24.png b/assets/icons/Infrared/hourglass1_24x24.png index b4cc7b4623..ef048a7bda 100644 Binary files a/assets/icons/Infrared/hourglass1_24x24.png and b/assets/icons/Infrared/hourglass1_24x24.png differ diff --git a/assets/icons/Infrared/hourglass2_24x24.png b/assets/icons/Infrared/hourglass2_24x24.png index d2c3709f70..918bd79d86 100644 Binary files a/assets/icons/Infrared/hourglass2_24x24.png and b/assets/icons/Infrared/hourglass2_24x24.png differ diff --git a/assets/icons/Infrared/hourglass3_24x24.png b/assets/icons/Infrared/hourglass3_24x24.png index e7be1e9955..dccaf46cd7 100644 Binary files a/assets/icons/Infrared/hourglass3_24x24.png and b/assets/icons/Infrared/hourglass3_24x24.png differ diff --git a/assets/icons/Infrared/hourglass4_24x24.png b/assets/icons/Infrared/hourglass4_24x24.png index 49eee2f53a..7ed58a5b4b 100644 Binary files a/assets/icons/Infrared/hourglass4_24x24.png and b/assets/icons/Infrared/hourglass4_24x24.png differ diff --git a/assets/icons/Infrared/hourglass5_24x24.png b/assets/icons/Infrared/hourglass5_24x24.png index 90e1d4b4e7..f3a3ed308b 100644 Binary files a/assets/icons/Infrared/hourglass5_24x24.png and b/assets/icons/Infrared/hourglass5_24x24.png differ diff --git a/assets/icons/Infrared/hourglass6_24x24.png b/assets/icons/Infrared/hourglass6_24x24.png index e68c744f0c..1383bbbb9f 100644 Binary files a/assets/icons/Infrared/hourglass6_24x24.png and b/assets/icons/Infrared/hourglass6_24x24.png differ diff --git a/assets/icons/Infrared/max_24x23.png b/assets/icons/Infrared/max_24x23.png index d4163a65f8..b7836abbf0 100644 Binary files a/assets/icons/Infrared/max_24x23.png and b/assets/icons/Infrared/max_24x23.png differ diff --git a/assets/icons/Infrared/max_hover_24x23.png b/assets/icons/Infrared/max_hover_24x23.png index 65f97b0ce3..f3e87a5817 100644 Binary files a/assets/icons/Infrared/max_hover_24x23.png and b/assets/icons/Infrared/max_hover_24x23.png differ diff --git a/assets/icons/Infrared/mute_19x20.png b/assets/icons/Infrared/mute_19x20.png index 410e88ac2e..d767e2f9c0 100644 Binary files a/assets/icons/Infrared/mute_19x20.png and b/assets/icons/Infrared/mute_19x20.png differ diff --git a/assets/icons/Infrared/mute_hover_19x20.png b/assets/icons/Infrared/mute_hover_19x20.png index e9a5b35102..cf899b8835 100644 Binary files a/assets/icons/Infrared/mute_hover_19x20.png and b/assets/icons/Infrared/mute_hover_19x20.png differ diff --git a/assets/icons/Infrared/mute_text_19x5.png b/assets/icons/Infrared/mute_text_19x5.png index fa2d042a67..62183e5ac8 100644 Binary files a/assets/icons/Infrared/mute_text_19x5.png and b/assets/icons/Infrared/mute_text_19x5.png differ diff --git a/assets/icons/Infrared/next_19x20.png b/assets/icons/Infrared/next_19x20.png index 512b68745a..6d48639b88 100644 Binary files a/assets/icons/Infrared/next_19x20.png and b/assets/icons/Infrared/next_19x20.png differ diff --git a/assets/icons/Infrared/next_hover_19x20.png b/assets/icons/Infrared/next_hover_19x20.png index c84bfdb901..006b92a09a 100644 Binary files a/assets/icons/Infrared/next_hover_19x20.png and b/assets/icons/Infrared/next_hover_19x20.png differ diff --git a/assets/icons/Infrared/next_text_19x6.png b/assets/icons/Infrared/next_text_19x6.png index 74d53171f5..8146e688d1 100644 Binary files a/assets/icons/Infrared/next_text_19x6.png and b/assets/icons/Infrared/next_text_19x6.png differ diff --git a/assets/icons/Infrared/off_19x20.png b/assets/icons/Infrared/off_19x20.png index 6d68d7e6e1..8c97c072ed 100644 Binary files a/assets/icons/Infrared/off_19x20.png and b/assets/icons/Infrared/off_19x20.png differ diff --git a/assets/icons/Infrared/off_hover_19x20.png b/assets/icons/Infrared/off_hover_19x20.png index fddd3f9172..98c384838c 100644 Binary files a/assets/icons/Infrared/off_hover_19x20.png and b/assets/icons/Infrared/off_hover_19x20.png differ diff --git a/assets/icons/Infrared/off_text_12x5.png b/assets/icons/Infrared/off_text_12x5.png index 500adbf27e..7ee27fc7af 100644 Binary files a/assets/icons/Infrared/off_text_12x5.png and b/assets/icons/Infrared/off_text_12x5.png differ diff --git a/assets/icons/Infrared/pause_19x20.png b/assets/icons/Infrared/pause_19x20.png index 99196d23b5..f3fda0fc45 100644 Binary files a/assets/icons/Infrared/pause_19x20.png and b/assets/icons/Infrared/pause_19x20.png differ diff --git a/assets/icons/Infrared/pause_hover_19x20.png b/assets/icons/Infrared/pause_hover_19x20.png index 33e7d8eb21..465c150a96 100644 Binary files a/assets/icons/Infrared/pause_hover_19x20.png and b/assets/icons/Infrared/pause_hover_19x20.png differ diff --git a/assets/icons/Infrared/pause_text_23x5.png b/assets/icons/Infrared/pause_text_23x5.png index 72c7b04036..fd991be3b9 100644 Binary files a/assets/icons/Infrared/pause_text_23x5.png and b/assets/icons/Infrared/pause_text_23x5.png differ diff --git a/assets/icons/Infrared/play_19x20.png b/assets/icons/Infrared/play_19x20.png index 880e977d2e..cb1d4ad809 100644 Binary files a/assets/icons/Infrared/play_19x20.png and b/assets/icons/Infrared/play_19x20.png differ diff --git a/assets/icons/Infrared/play_hover_19x20.png b/assets/icons/Infrared/play_hover_19x20.png index 4c837a1445..35ab014481 100644 Binary files a/assets/icons/Infrared/play_hover_19x20.png and b/assets/icons/Infrared/play_hover_19x20.png differ diff --git a/assets/icons/Infrared/play_text_19x5.png b/assets/icons/Infrared/play_text_19x5.png index c5f067bcf4..375f8155e4 100644 Binary files a/assets/icons/Infrared/play_text_19x5.png and b/assets/icons/Infrared/play_text_19x5.png differ diff --git a/assets/icons/Infrared/power_19x20.png b/assets/icons/Infrared/power_19x20.png index 12b9279739..eef764158d 100644 Binary files a/assets/icons/Infrared/power_19x20.png and b/assets/icons/Infrared/power_19x20.png differ diff --git a/assets/icons/Infrared/power_hover_19x20.png b/assets/icons/Infrared/power_hover_19x20.png index 3a41249ff3..c8e30cafa8 100644 Binary files a/assets/icons/Infrared/power_hover_19x20.png and b/assets/icons/Infrared/power_hover_19x20.png differ diff --git a/assets/icons/Infrared/power_text_24x5.png b/assets/icons/Infrared/power_text_24x5.png index 88fff8e33d..8f2fda83a6 100644 Binary files a/assets/icons/Infrared/power_text_24x5.png and b/assets/icons/Infrared/power_text_24x5.png differ diff --git a/assets/icons/Infrared/prev_19x20.png b/assets/icons/Infrared/prev_19x20.png index 8d17cec57c..69ac3bccb1 100644 Binary files a/assets/icons/Infrared/prev_19x20.png and b/assets/icons/Infrared/prev_19x20.png differ diff --git a/assets/icons/Infrared/prev_hover_19x20.png b/assets/icons/Infrared/prev_hover_19x20.png index be9dce7004..51f5779f06 100644 Binary files a/assets/icons/Infrared/prev_hover_19x20.png and b/assets/icons/Infrared/prev_hover_19x20.png differ diff --git a/assets/icons/Infrared/prev_text_19x5.png b/assets/icons/Infrared/prev_text_19x5.png index 473b897456..115887bbee 100644 Binary files a/assets/icons/Infrared/prev_text_19x5.png and b/assets/icons/Infrared/prev_text_19x5.png differ diff --git a/assets/icons/Infrared/vol_ac_text_30x30.png b/assets/icons/Infrared/vol_ac_text_30x30.png index 068266d624..2286627c86 100644 Binary files a/assets/icons/Infrared/vol_ac_text_30x30.png and b/assets/icons/Infrared/vol_ac_text_30x30.png differ diff --git a/assets/icons/Infrared/vol_tv_text_29x34.png b/assets/icons/Infrared/vol_tv_text_29x34.png index caef54c258..166cbdce6d 100644 Binary files a/assets/icons/Infrared/vol_tv_text_29x34.png and b/assets/icons/Infrared/vol_tv_text_29x34.png differ diff --git a/assets/icons/Infrared/voldown_24x21.png b/assets/icons/Infrared/voldown_24x21.png index a80c59594a..d6f8d2f329 100644 Binary files a/assets/icons/Infrared/voldown_24x21.png and b/assets/icons/Infrared/voldown_24x21.png differ diff --git a/assets/icons/Infrared/voldown_hover_24x21.png b/assets/icons/Infrared/voldown_hover_24x21.png index 6bc57c70eb..b9ac48b4e0 100644 Binary files a/assets/icons/Infrared/voldown_hover_24x21.png and b/assets/icons/Infrared/voldown_hover_24x21.png differ diff --git a/assets/icons/Infrared/volup_24x21.png b/assets/icons/Infrared/volup_24x21.png index 688552751c..ebc3f3e42b 100644 Binary files a/assets/icons/Infrared/volup_24x21.png and b/assets/icons/Infrared/volup_24x21.png differ diff --git a/assets/icons/Infrared/volup_hover_24x21.png b/assets/icons/Infrared/volup_hover_24x21.png index 5d790e7966..1d35173d1a 100644 Binary files a/assets/icons/Infrared/volup_hover_24x21.png and b/assets/icons/Infrared/volup_hover_24x21.png differ diff --git a/assets/icons/Interface/DoorLeft_70x55.png b/assets/icons/Interface/DoorLeft_70x55.png index 5df87ba3ce..6f795c5e09 100644 Binary files a/assets/icons/Interface/DoorLeft_70x55.png and b/assets/icons/Interface/DoorLeft_70x55.png differ diff --git a/assets/icons/Interface/DoorRight_70x55.png b/assets/icons/Interface/DoorRight_70x55.png index 0cc1e65e65..01abc3865a 100644 Binary files a/assets/icons/Interface/DoorRight_70x55.png and b/assets/icons/Interface/DoorRight_70x55.png differ diff --git a/assets/icons/Interface/SmallArrowDown_3x5.png b/assets/icons/Interface/SmallArrowDown_3x5.png index 1912e5d246..e795d67087 100644 Binary files a/assets/icons/Interface/SmallArrowDown_3x5.png and b/assets/icons/Interface/SmallArrowDown_3x5.png differ diff --git a/assets/icons/Interface/SmallArrowDown_4x7.png b/assets/icons/Interface/SmallArrowDown_4x7.png index 5c5252b167..0cda838e05 100644 Binary files a/assets/icons/Interface/SmallArrowDown_4x7.png and b/assets/icons/Interface/SmallArrowDown_4x7.png differ diff --git a/assets/icons/Interface/SmallArrowUp_3x5.png b/assets/icons/Interface/SmallArrowUp_3x5.png index 9c6242078d..4a4dc8a779 100644 Binary files a/assets/icons/Interface/SmallArrowUp_3x5.png and b/assets/icons/Interface/SmallArrowUp_3x5.png differ diff --git a/assets/icons/Interface/SmallArrowUp_4x7.png b/assets/icons/Interface/SmallArrowUp_4x7.png index 886369abc6..48d0f9f018 100644 Binary files a/assets/icons/Interface/SmallArrowUp_4x7.png and b/assets/icons/Interface/SmallArrowUp_4x7.png differ diff --git a/assets/icons/Keyboard/KeyBackspaceSelected_16x9.png b/assets/icons/Keyboard/KeyBackspaceSelected_16x9.png index 7cc0759a8c..1df3f7fc99 100644 Binary files a/assets/icons/Keyboard/KeyBackspaceSelected_16x9.png and b/assets/icons/Keyboard/KeyBackspaceSelected_16x9.png differ diff --git a/assets/icons/Keyboard/KeyBackspace_16x9.png b/assets/icons/Keyboard/KeyBackspace_16x9.png index 9946232d95..895124807c 100644 Binary files a/assets/icons/Keyboard/KeyBackspace_16x9.png and b/assets/icons/Keyboard/KeyBackspace_16x9.png differ diff --git a/assets/icons/Keyboard/KeySaveBlockedSelected_24x11.png b/assets/icons/Keyboard/KeySaveBlockedSelected_24x11.png new file mode 100644 index 0000000000..fe570a10c3 Binary files /dev/null and b/assets/icons/Keyboard/KeySaveBlockedSelected_24x11.png differ diff --git a/assets/icons/Keyboard/KeySaveBlocked_24x11.png b/assets/icons/Keyboard/KeySaveBlocked_24x11.png new file mode 100644 index 0000000000..d67b294ada Binary files /dev/null and b/assets/icons/Keyboard/KeySaveBlocked_24x11.png differ diff --git a/assets/icons/Keyboard/KeySaveSelected_24x11.png b/assets/icons/Keyboard/KeySaveSelected_24x11.png index eeb3569d3a..abfced776f 100644 Binary files a/assets/icons/Keyboard/KeySaveSelected_24x11.png and b/assets/icons/Keyboard/KeySaveSelected_24x11.png differ diff --git a/assets/icons/Keyboard/KeySave_24x11.png b/assets/icons/Keyboard/KeySave_24x11.png index e7dba987a0..f97838d954 100644 Binary files a/assets/icons/Keyboard/KeySave_24x11.png and b/assets/icons/Keyboard/KeySave_24x11.png differ diff --git a/assets/icons/Keyboard/KeySignSelected_21x11.png b/assets/icons/Keyboard/KeySignSelected_21x11.png new file mode 100644 index 0000000000..23ec2a9c44 Binary files /dev/null and b/assets/icons/Keyboard/KeySignSelected_21x11.png differ diff --git a/assets/icons/Keyboard/KeySign_21x11.png b/assets/icons/Keyboard/KeySign_21x11.png new file mode 100644 index 0000000000..f31e9e0fae Binary files /dev/null and b/assets/icons/Keyboard/KeySign_21x11.png differ diff --git a/assets/icons/Loader/err_01.png b/assets/icons/Loader/err_01.png index 7ffdf761da..f8a43d892c 100644 Binary files a/assets/icons/Loader/err_01.png and b/assets/icons/Loader/err_01.png differ diff --git a/assets/icons/Loader/err_02.png b/assets/icons/Loader/err_02.png index e00b1cb3b8..94fab160f1 100644 Binary files a/assets/icons/Loader/err_02.png and b/assets/icons/Loader/err_02.png differ diff --git a/assets/icons/Loader/err_03.png b/assets/icons/Loader/err_03.png index bb28c29abe..83b12af0a2 100644 Binary files a/assets/icons/Loader/err_03.png and b/assets/icons/Loader/err_03.png differ diff --git a/assets/icons/Loader/err_04.png b/assets/icons/Loader/err_04.png index 40d9f9b9ea..503652196e 100644 Binary files a/assets/icons/Loader/err_04.png and b/assets/icons/Loader/err_04.png differ diff --git a/assets/icons/Loader/err_05.png b/assets/icons/Loader/err_05.png index c606f9a331..b639ba5d88 100644 Binary files a/assets/icons/Loader/err_05.png and b/assets/icons/Loader/err_05.png differ diff --git a/assets/icons/MainMenu/125khz_14/frame_01.png b/assets/icons/MainMenu/125khz_14/frame_01.png index 0f46d42622..d00392a1b1 100644 Binary files a/assets/icons/MainMenu/125khz_14/frame_01.png and b/assets/icons/MainMenu/125khz_14/frame_01.png differ diff --git a/assets/icons/MainMenu/125khz_14/frame_02.png b/assets/icons/MainMenu/125khz_14/frame_02.png index 13c252b14f..6ffd7fe166 100644 Binary files a/assets/icons/MainMenu/125khz_14/frame_02.png and b/assets/icons/MainMenu/125khz_14/frame_02.png differ diff --git a/assets/icons/MainMenu/125khz_14/frame_03.png b/assets/icons/MainMenu/125khz_14/frame_03.png index cdc882e7e1..afd20d3476 100644 Binary files a/assets/icons/MainMenu/125khz_14/frame_03.png and b/assets/icons/MainMenu/125khz_14/frame_03.png differ diff --git a/assets/icons/MainMenu/125khz_14/frame_04.png b/assets/icons/MainMenu/125khz_14/frame_04.png index bdbc7adf53..cf93c63f81 100644 Binary files a/assets/icons/MainMenu/125khz_14/frame_04.png and b/assets/icons/MainMenu/125khz_14/frame_04.png differ diff --git a/assets/icons/MainMenu/BadUsb_14/frame_01.png b/assets/icons/MainMenu/BadUsb_14/frame_01.png index 162753d8aa..b2fb1d6532 100644 Binary files a/assets/icons/MainMenu/BadUsb_14/frame_01.png and b/assets/icons/MainMenu/BadUsb_14/frame_01.png differ diff --git a/assets/icons/MainMenu/BadUsb_14/frame_02.png b/assets/icons/MainMenu/BadUsb_14/frame_02.png index 50e12f8baa..4060dc72f0 100644 Binary files a/assets/icons/MainMenu/BadUsb_14/frame_02.png and b/assets/icons/MainMenu/BadUsb_14/frame_02.png differ diff --git a/assets/icons/MainMenu/BadUsb_14/frame_03.png b/assets/icons/MainMenu/BadUsb_14/frame_03.png index 5dafb2597a..6b720f8a9a 100644 Binary files a/assets/icons/MainMenu/BadUsb_14/frame_03.png and b/assets/icons/MainMenu/BadUsb_14/frame_03.png differ diff --git a/assets/icons/MainMenu/BadUsb_14/frame_04.png b/assets/icons/MainMenu/BadUsb_14/frame_04.png index 6ca08f842d..f1931ef5ef 100644 Binary files a/assets/icons/MainMenu/BadUsb_14/frame_04.png and b/assets/icons/MainMenu/BadUsb_14/frame_04.png differ diff --git a/assets/icons/MainMenu/BadUsb_14/frame_05.png b/assets/icons/MainMenu/BadUsb_14/frame_05.png index a3b06a0e70..8e32911da7 100644 Binary files a/assets/icons/MainMenu/BadUsb_14/frame_05.png and b/assets/icons/MainMenu/BadUsb_14/frame_05.png differ diff --git a/assets/icons/MainMenu/BadUsb_14/frame_06.png b/assets/icons/MainMenu/BadUsb_14/frame_06.png index 7d8f43653a..47e0a7a390 100644 Binary files a/assets/icons/MainMenu/BadUsb_14/frame_06.png and b/assets/icons/MainMenu/BadUsb_14/frame_06.png differ diff --git a/assets/icons/MainMenu/BadUsb_14/frame_07.png b/assets/icons/MainMenu/BadUsb_14/frame_07.png index a3b06a0e70..8e32911da7 100644 Binary files a/assets/icons/MainMenu/BadUsb_14/frame_07.png and b/assets/icons/MainMenu/BadUsb_14/frame_07.png differ diff --git a/assets/icons/MainMenu/BadUsb_14/frame_08.png b/assets/icons/MainMenu/BadUsb_14/frame_08.png index 6ca08f842d..f1931ef5ef 100644 Binary files a/assets/icons/MainMenu/BadUsb_14/frame_08.png and b/assets/icons/MainMenu/BadUsb_14/frame_08.png differ diff --git a/assets/icons/MainMenu/BadUsb_14/frame_09.png b/assets/icons/MainMenu/BadUsb_14/frame_09.png index 5dafb2597a..6b720f8a9a 100644 Binary files a/assets/icons/MainMenu/BadUsb_14/frame_09.png and b/assets/icons/MainMenu/BadUsb_14/frame_09.png differ diff --git a/assets/icons/MainMenu/BadUsb_14/frame_10.png b/assets/icons/MainMenu/BadUsb_14/frame_10.png index 50e12f8baa..4060dc72f0 100644 Binary files a/assets/icons/MainMenu/BadUsb_14/frame_10.png and b/assets/icons/MainMenu/BadUsb_14/frame_10.png differ diff --git a/assets/icons/MainMenu/BadUsb_14/frame_11.png b/assets/icons/MainMenu/BadUsb_14/frame_11.png index 162753d8aa..b2fb1d6532 100644 Binary files a/assets/icons/MainMenu/BadUsb_14/frame_11.png and b/assets/icons/MainMenu/BadUsb_14/frame_11.png differ diff --git a/assets/icons/MainMenu/Debug_14/frame_01.png b/assets/icons/MainMenu/Debug_14/frame_01.png index 59b61fea86..0f0cdad8cf 100644 Binary files a/assets/icons/MainMenu/Debug_14/frame_01.png and b/assets/icons/MainMenu/Debug_14/frame_01.png differ diff --git a/assets/icons/MainMenu/Debug_14/frame_02.png b/assets/icons/MainMenu/Debug_14/frame_02.png index 93b4f950e3..31a43bd692 100644 Binary files a/assets/icons/MainMenu/Debug_14/frame_02.png and b/assets/icons/MainMenu/Debug_14/frame_02.png differ diff --git a/assets/icons/MainMenu/Debug_14/frame_03.png b/assets/icons/MainMenu/Debug_14/frame_03.png index cf55953c88..a77b9de082 100644 Binary files a/assets/icons/MainMenu/Debug_14/frame_03.png and b/assets/icons/MainMenu/Debug_14/frame_03.png differ diff --git a/assets/icons/MainMenu/Debug_14/frame_04.png b/assets/icons/MainMenu/Debug_14/frame_04.png index 5f89c2e1b7..74c7e7fe8d 100644 Binary files a/assets/icons/MainMenu/Debug_14/frame_04.png and b/assets/icons/MainMenu/Debug_14/frame_04.png differ diff --git a/assets/icons/MainMenu/FileManager_14/frame_01.png b/assets/icons/MainMenu/FileManager_14/frame_01.png index 3403ec8a67..aaf107ae24 100644 Binary files a/assets/icons/MainMenu/FileManager_14/frame_01.png and b/assets/icons/MainMenu/FileManager_14/frame_01.png differ diff --git a/assets/icons/MainMenu/FileManager_14/frame_02.png b/assets/icons/MainMenu/FileManager_14/frame_02.png index 53cbfc5415..c6faf6c296 100644 Binary files a/assets/icons/MainMenu/FileManager_14/frame_02.png and b/assets/icons/MainMenu/FileManager_14/frame_02.png differ diff --git a/assets/icons/MainMenu/FileManager_14/frame_03.png b/assets/icons/MainMenu/FileManager_14/frame_03.png index af43137080..fa7b04e78e 100644 Binary files a/assets/icons/MainMenu/FileManager_14/frame_03.png and b/assets/icons/MainMenu/FileManager_14/frame_03.png differ diff --git a/assets/icons/MainMenu/FileManager_14/frame_04.png b/assets/icons/MainMenu/FileManager_14/frame_04.png index edeed16d52..d2909d00b6 100644 Binary files a/assets/icons/MainMenu/FileManager_14/frame_04.png and b/assets/icons/MainMenu/FileManager_14/frame_04.png differ diff --git a/assets/icons/MainMenu/FileManager_14/frame_05.png b/assets/icons/MainMenu/FileManager_14/frame_05.png index 71e4f76a0d..bdf66a9b6b 100644 Binary files a/assets/icons/MainMenu/FileManager_14/frame_05.png and b/assets/icons/MainMenu/FileManager_14/frame_05.png differ diff --git a/assets/icons/MainMenu/FileManager_14/frame_06.png b/assets/icons/MainMenu/FileManager_14/frame_06.png index fd5e950207..49181b3c44 100644 Binary files a/assets/icons/MainMenu/FileManager_14/frame_06.png and b/assets/icons/MainMenu/FileManager_14/frame_06.png differ diff --git a/assets/icons/MainMenu/FileManager_14/frame_07.png b/assets/icons/MainMenu/FileManager_14/frame_07.png index 71e4f76a0d..bdf66a9b6b 100644 Binary files a/assets/icons/MainMenu/FileManager_14/frame_07.png and b/assets/icons/MainMenu/FileManager_14/frame_07.png differ diff --git a/assets/icons/MainMenu/FileManager_14/frame_08.png b/assets/icons/MainMenu/FileManager_14/frame_08.png index edeed16d52..d2909d00b6 100644 Binary files a/assets/icons/MainMenu/FileManager_14/frame_08.png and b/assets/icons/MainMenu/FileManager_14/frame_08.png differ diff --git a/assets/icons/MainMenu/FileManager_14/frame_09.png b/assets/icons/MainMenu/FileManager_14/frame_09.png index af43137080..fa7b04e78e 100644 Binary files a/assets/icons/MainMenu/FileManager_14/frame_09.png and b/assets/icons/MainMenu/FileManager_14/frame_09.png differ diff --git a/assets/icons/MainMenu/FileManager_14/frame_10.png b/assets/icons/MainMenu/FileManager_14/frame_10.png index 53cbfc5415..c6faf6c296 100644 Binary files a/assets/icons/MainMenu/FileManager_14/frame_10.png and b/assets/icons/MainMenu/FileManager_14/frame_10.png differ diff --git a/assets/icons/MainMenu/GPIO_14/frame_01.png b/assets/icons/MainMenu/GPIO_14/frame_01.png index 23e27d59c5..97c2ccaf20 100644 Binary files a/assets/icons/MainMenu/GPIO_14/frame_01.png and b/assets/icons/MainMenu/GPIO_14/frame_01.png differ diff --git a/assets/icons/MainMenu/GPIO_14/frame_02.png b/assets/icons/MainMenu/GPIO_14/frame_02.png index aa171cfaf7..7e227af421 100644 Binary files a/assets/icons/MainMenu/GPIO_14/frame_02.png and b/assets/icons/MainMenu/GPIO_14/frame_02.png differ diff --git a/assets/icons/MainMenu/GPIO_14/frame_03.png b/assets/icons/MainMenu/GPIO_14/frame_03.png index 42fef03271..e2d7a420ef 100644 Binary files a/assets/icons/MainMenu/GPIO_14/frame_03.png and b/assets/icons/MainMenu/GPIO_14/frame_03.png differ diff --git a/assets/icons/MainMenu/GPIO_14/frame_04.png b/assets/icons/MainMenu/GPIO_14/frame_04.png index 52ac41fb8c..e801c88f53 100644 Binary files a/assets/icons/MainMenu/GPIO_14/frame_04.png and b/assets/icons/MainMenu/GPIO_14/frame_04.png differ diff --git a/assets/icons/MainMenu/GPIO_14/frame_05.png b/assets/icons/MainMenu/GPIO_14/frame_05.png index 30a2593714..ebdc1382a5 100644 Binary files a/assets/icons/MainMenu/GPIO_14/frame_05.png and b/assets/icons/MainMenu/GPIO_14/frame_05.png differ diff --git a/assets/icons/MainMenu/GPIO_14/frame_06.png b/assets/icons/MainMenu/GPIO_14/frame_06.png index be19567f3e..5ebb0953fa 100644 Binary files a/assets/icons/MainMenu/GPIO_14/frame_06.png and b/assets/icons/MainMenu/GPIO_14/frame_06.png differ diff --git a/assets/icons/MainMenu/GPIO_14/frame_07.png b/assets/icons/MainMenu/GPIO_14/frame_07.png index 2f7a42368c..7138b727d8 100644 Binary files a/assets/icons/MainMenu/GPIO_14/frame_07.png and b/assets/icons/MainMenu/GPIO_14/frame_07.png differ diff --git a/assets/icons/MainMenu/GPIO_14/frame_08.png b/assets/icons/MainMenu/GPIO_14/frame_08.png index aa4ad384d0..a753127a8e 100644 Binary files a/assets/icons/MainMenu/GPIO_14/frame_08.png and b/assets/icons/MainMenu/GPIO_14/frame_08.png differ diff --git a/assets/icons/MainMenu/Infrared_14/frame_01.png b/assets/icons/MainMenu/Infrared_14/frame_01.png index 63256dfff9..b9ea5b6f94 100644 Binary files a/assets/icons/MainMenu/Infrared_14/frame_01.png and b/assets/icons/MainMenu/Infrared_14/frame_01.png differ diff --git a/assets/icons/MainMenu/Infrared_14/frame_02.png b/assets/icons/MainMenu/Infrared_14/frame_02.png index b31366d606..172c2eba75 100644 Binary files a/assets/icons/MainMenu/Infrared_14/frame_02.png and b/assets/icons/MainMenu/Infrared_14/frame_02.png differ diff --git a/assets/icons/MainMenu/Infrared_14/frame_03.png b/assets/icons/MainMenu/Infrared_14/frame_03.png index aed6b807c2..8b6667b5bd 100644 Binary files a/assets/icons/MainMenu/Infrared_14/frame_03.png and b/assets/icons/MainMenu/Infrared_14/frame_03.png differ diff --git a/assets/icons/MainMenu/Infrared_14/frame_04.png b/assets/icons/MainMenu/Infrared_14/frame_04.png index df78294085..bf2e55641e 100644 Binary files a/assets/icons/MainMenu/Infrared_14/frame_04.png and b/assets/icons/MainMenu/Infrared_14/frame_04.png differ diff --git a/assets/icons/MainMenu/Infrared_14/frame_05.png b/assets/icons/MainMenu/Infrared_14/frame_05.png index bc1229a25f..8a08e093c3 100644 Binary files a/assets/icons/MainMenu/Infrared_14/frame_05.png and b/assets/icons/MainMenu/Infrared_14/frame_05.png differ diff --git a/assets/icons/MainMenu/Infrared_14/frame_06.png b/assets/icons/MainMenu/Infrared_14/frame_06.png index 711390213c..50590d6bb5 100644 Binary files a/assets/icons/MainMenu/Infrared_14/frame_06.png and b/assets/icons/MainMenu/Infrared_14/frame_06.png differ diff --git a/assets/icons/MainMenu/NFC_14/frame_01.png b/assets/icons/MainMenu/NFC_14/frame_01.png index 84b79da132..e96d0293cc 100644 Binary files a/assets/icons/MainMenu/NFC_14/frame_01.png and b/assets/icons/MainMenu/NFC_14/frame_01.png differ diff --git a/assets/icons/MainMenu/NFC_14/frame_02.png b/assets/icons/MainMenu/NFC_14/frame_02.png index d8da3d730d..7ba638842b 100644 Binary files a/assets/icons/MainMenu/NFC_14/frame_02.png and b/assets/icons/MainMenu/NFC_14/frame_02.png differ diff --git a/assets/icons/MainMenu/NFC_14/frame_03.png b/assets/icons/MainMenu/NFC_14/frame_03.png index d33251fbf4..442dde8ca7 100644 Binary files a/assets/icons/MainMenu/NFC_14/frame_03.png and b/assets/icons/MainMenu/NFC_14/frame_03.png differ diff --git a/assets/icons/MainMenu/NFC_14/frame_04.png b/assets/icons/MainMenu/NFC_14/frame_04.png index 568151d7d6..6a0b8acb95 100644 Binary files a/assets/icons/MainMenu/NFC_14/frame_04.png and b/assets/icons/MainMenu/NFC_14/frame_04.png differ diff --git a/assets/icons/MainMenu/Plugins_14/frame_01.png b/assets/icons/MainMenu/Plugins_14/frame_01.png index a3e192b839..bc7cc779a9 100644 Binary files a/assets/icons/MainMenu/Plugins_14/frame_01.png and b/assets/icons/MainMenu/Plugins_14/frame_01.png differ diff --git a/assets/icons/MainMenu/Plugins_14/frame_02.png b/assets/icons/MainMenu/Plugins_14/frame_02.png index f025f2309f..c914a3e9fc 100644 Binary files a/assets/icons/MainMenu/Plugins_14/frame_02.png and b/assets/icons/MainMenu/Plugins_14/frame_02.png differ diff --git a/assets/icons/MainMenu/Plugins_14/frame_03.png b/assets/icons/MainMenu/Plugins_14/frame_03.png index f82dd553aa..47a1473ff7 100644 Binary files a/assets/icons/MainMenu/Plugins_14/frame_03.png and b/assets/icons/MainMenu/Plugins_14/frame_03.png differ diff --git a/assets/icons/MainMenu/Plugins_14/frame_04.png b/assets/icons/MainMenu/Plugins_14/frame_04.png index bc22d3b00e..0230d16a71 100644 Binary files a/assets/icons/MainMenu/Plugins_14/frame_04.png and b/assets/icons/MainMenu/Plugins_14/frame_04.png differ diff --git a/assets/icons/MainMenu/Plugins_14/frame_05.png b/assets/icons/MainMenu/Plugins_14/frame_05.png index ddbe5f7001..9518161489 100644 Binary files a/assets/icons/MainMenu/Plugins_14/frame_05.png and b/assets/icons/MainMenu/Plugins_14/frame_05.png differ diff --git a/assets/icons/MainMenu/Plugins_14/frame_06.png b/assets/icons/MainMenu/Plugins_14/frame_06.png index 3ce0f8acab..affe37cfa1 100644 Binary files a/assets/icons/MainMenu/Plugins_14/frame_06.png and b/assets/icons/MainMenu/Plugins_14/frame_06.png differ diff --git a/assets/icons/MainMenu/Plugins_14/frame_07.png b/assets/icons/MainMenu/Plugins_14/frame_07.png index 91a1125de5..0ccf3f271e 100644 Binary files a/assets/icons/MainMenu/Plugins_14/frame_07.png and b/assets/icons/MainMenu/Plugins_14/frame_07.png differ diff --git a/assets/icons/MainMenu/Plugins_14/frame_08.png b/assets/icons/MainMenu/Plugins_14/frame_08.png index c302db0ab3..360cae32ce 100644 Binary files a/assets/icons/MainMenu/Plugins_14/frame_08.png and b/assets/icons/MainMenu/Plugins_14/frame_08.png differ diff --git a/assets/icons/MainMenu/Plugins_14/frame_09.png b/assets/icons/MainMenu/Plugins_14/frame_09.png index 2be3057210..15c2e0a8e1 100644 Binary files a/assets/icons/MainMenu/Plugins_14/frame_09.png and b/assets/icons/MainMenu/Plugins_14/frame_09.png differ diff --git a/assets/icons/MainMenu/Settings_14/frame_01.png b/assets/icons/MainMenu/Settings_14/frame_01.png index aad9e35588..1f8f45ee18 100644 Binary files a/assets/icons/MainMenu/Settings_14/frame_01.png and b/assets/icons/MainMenu/Settings_14/frame_01.png differ diff --git a/assets/icons/MainMenu/Settings_14/frame_02.png b/assets/icons/MainMenu/Settings_14/frame_02.png index 124ffde213..8127986f36 100644 Binary files a/assets/icons/MainMenu/Settings_14/frame_02.png and b/assets/icons/MainMenu/Settings_14/frame_02.png differ diff --git a/assets/icons/MainMenu/Settings_14/frame_03.png b/assets/icons/MainMenu/Settings_14/frame_03.png index e4d72fe6fe..0479bef216 100644 Binary files a/assets/icons/MainMenu/Settings_14/frame_03.png and b/assets/icons/MainMenu/Settings_14/frame_03.png differ diff --git a/assets/icons/MainMenu/Settings_14/frame_04.png b/assets/icons/MainMenu/Settings_14/frame_04.png index fec89bb856..192df5fdbc 100644 Binary files a/assets/icons/MainMenu/Settings_14/frame_04.png and b/assets/icons/MainMenu/Settings_14/frame_04.png differ diff --git a/assets/icons/MainMenu/Settings_14/frame_05.png b/assets/icons/MainMenu/Settings_14/frame_05.png index fadaebc9fc..5aaa830105 100644 Binary files a/assets/icons/MainMenu/Settings_14/frame_05.png and b/assets/icons/MainMenu/Settings_14/frame_05.png differ diff --git a/assets/icons/MainMenu/Settings_14/frame_06.png b/assets/icons/MainMenu/Settings_14/frame_06.png index 5b7b6423b5..89082d7e20 100644 Binary files a/assets/icons/MainMenu/Settings_14/frame_06.png and b/assets/icons/MainMenu/Settings_14/frame_06.png differ diff --git a/assets/icons/MainMenu/Settings_14/frame_07.png b/assets/icons/MainMenu/Settings_14/frame_07.png index 6301512e8f..424e68a089 100644 Binary files a/assets/icons/MainMenu/Settings_14/frame_07.png and b/assets/icons/MainMenu/Settings_14/frame_07.png differ diff --git a/assets/icons/MainMenu/Settings_14/frame_08.png b/assets/icons/MainMenu/Settings_14/frame_08.png index ce0611e346..347b760e9c 100644 Binary files a/assets/icons/MainMenu/Settings_14/frame_08.png and b/assets/icons/MainMenu/Settings_14/frame_08.png differ diff --git a/assets/icons/MainMenu/Settings_14/frame_09.png b/assets/icons/MainMenu/Settings_14/frame_09.png index 11e93da379..64794e7ee5 100644 Binary files a/assets/icons/MainMenu/Settings_14/frame_09.png and b/assets/icons/MainMenu/Settings_14/frame_09.png differ diff --git a/assets/icons/MainMenu/Settings_14/frame_10.png b/assets/icons/MainMenu/Settings_14/frame_10.png index aad9e35588..1f8f45ee18 100644 Binary files a/assets/icons/MainMenu/Settings_14/frame_10.png and b/assets/icons/MainMenu/Settings_14/frame_10.png differ diff --git a/assets/icons/MainMenu/Sub1ghz_14/frame_01.png b/assets/icons/MainMenu/Sub1ghz_14/frame_01.png index 52dc4ad21f..ba1b89f9fb 100644 Binary files a/assets/icons/MainMenu/Sub1ghz_14/frame_01.png and b/assets/icons/MainMenu/Sub1ghz_14/frame_01.png differ diff --git a/assets/icons/MainMenu/Sub1ghz_14/frame_02.png b/assets/icons/MainMenu/Sub1ghz_14/frame_02.png index 2dff1c031d..c34b691bc9 100644 Binary files a/assets/icons/MainMenu/Sub1ghz_14/frame_02.png and b/assets/icons/MainMenu/Sub1ghz_14/frame_02.png differ diff --git a/assets/icons/MainMenu/Sub1ghz_14/frame_03.png b/assets/icons/MainMenu/Sub1ghz_14/frame_03.png index c1e438b01c..420e568ce9 100644 Binary files a/assets/icons/MainMenu/Sub1ghz_14/frame_03.png and b/assets/icons/MainMenu/Sub1ghz_14/frame_03.png differ diff --git a/assets/icons/MainMenu/Sub1ghz_14/frame_04.png b/assets/icons/MainMenu/Sub1ghz_14/frame_04.png index 169fb61476..c40eee7b2c 100644 Binary files a/assets/icons/MainMenu/Sub1ghz_14/frame_04.png and b/assets/icons/MainMenu/Sub1ghz_14/frame_04.png differ diff --git a/assets/icons/MainMenu/Sub1ghz_14/frame_05.png b/assets/icons/MainMenu/Sub1ghz_14/frame_05.png index 79b2bc9725..08a6a61940 100644 Binary files a/assets/icons/MainMenu/Sub1ghz_14/frame_05.png and b/assets/icons/MainMenu/Sub1ghz_14/frame_05.png differ diff --git a/assets/icons/MainMenu/Sub1ghz_14/frame_06.png b/assets/icons/MainMenu/Sub1ghz_14/frame_06.png index 8fce0c44d6..291fa8ace4 100644 Binary files a/assets/icons/MainMenu/Sub1ghz_14/frame_06.png and b/assets/icons/MainMenu/Sub1ghz_14/frame_06.png differ diff --git a/assets/icons/MainMenu/U2F_14/frame_01.png b/assets/icons/MainMenu/U2F_14/frame_01.png index 6903a28b8d..0dc3edfab8 100644 Binary files a/assets/icons/MainMenu/U2F_14/frame_01.png and b/assets/icons/MainMenu/U2F_14/frame_01.png differ diff --git a/assets/icons/MainMenu/U2F_14/frame_02.png b/assets/icons/MainMenu/U2F_14/frame_02.png index e4bba739d2..21dc5fa7da 100644 Binary files a/assets/icons/MainMenu/U2F_14/frame_02.png and b/assets/icons/MainMenu/U2F_14/frame_02.png differ diff --git a/assets/icons/MainMenu/U2F_14/frame_03.png b/assets/icons/MainMenu/U2F_14/frame_03.png index 4c903182c9..d516bf7f62 100644 Binary files a/assets/icons/MainMenu/U2F_14/frame_03.png and b/assets/icons/MainMenu/U2F_14/frame_03.png differ diff --git a/assets/icons/MainMenu/U2F_14/frame_04.png b/assets/icons/MainMenu/U2F_14/frame_04.png index e4bba739d2..21dc5fa7da 100644 Binary files a/assets/icons/MainMenu/U2F_14/frame_04.png and b/assets/icons/MainMenu/U2F_14/frame_04.png differ diff --git a/assets/icons/MainMenu/iButton_14/frame_01.png b/assets/icons/MainMenu/iButton_14/frame_01.png index d9f10748ea..6e7398d869 100644 Binary files a/assets/icons/MainMenu/iButton_14/frame_01.png and b/assets/icons/MainMenu/iButton_14/frame_01.png differ diff --git a/assets/icons/MainMenu/iButton_14/frame_02.png b/assets/icons/MainMenu/iButton_14/frame_02.png index cf3422c03c..531364566b 100644 Binary files a/assets/icons/MainMenu/iButton_14/frame_02.png and b/assets/icons/MainMenu/iButton_14/frame_02.png differ diff --git a/assets/icons/MainMenu/iButton_14/frame_03.png b/assets/icons/MainMenu/iButton_14/frame_03.png index 1b0ed62e06..31354eeff2 100644 Binary files a/assets/icons/MainMenu/iButton_14/frame_03.png and b/assets/icons/MainMenu/iButton_14/frame_03.png differ diff --git a/assets/icons/MainMenu/iButton_14/frame_04.png b/assets/icons/MainMenu/iButton_14/frame_04.png index 0caa9956b6..78bc561785 100644 Binary files a/assets/icons/MainMenu/iButton_14/frame_04.png and b/assets/icons/MainMenu/iButton_14/frame_04.png differ diff --git a/assets/icons/MainMenu/iButton_14/frame_05.png b/assets/icons/MainMenu/iButton_14/frame_05.png index 79f217b962..82dbaedeb6 100644 Binary files a/assets/icons/MainMenu/iButton_14/frame_05.png and b/assets/icons/MainMenu/iButton_14/frame_05.png differ diff --git a/assets/icons/MainMenu/iButton_14/frame_06.png b/assets/icons/MainMenu/iButton_14/frame_06.png index eabb2b1903..5d7163d541 100644 Binary files a/assets/icons/MainMenu/iButton_14/frame_06.png and b/assets/icons/MainMenu/iButton_14/frame_06.png differ diff --git a/assets/icons/MainMenu/iButton_14/frame_07.png b/assets/icons/MainMenu/iButton_14/frame_07.png index 3a30aa7fbc..3020c8105f 100644 Binary files a/assets/icons/MainMenu/iButton_14/frame_07.png and b/assets/icons/MainMenu/iButton_14/frame_07.png differ diff --git a/assets/icons/NFC/ArrowC_1_36x36.png b/assets/icons/NFC/ArrowC_1_36x36.png index 3a0c6dd0cb..0f4d3e1b2d 100644 Binary files a/assets/icons/NFC/ArrowC_1_36x36.png and b/assets/icons/NFC/ArrowC_1_36x36.png differ diff --git a/assets/icons/NFC/Detailed_chip_17x13.png b/assets/icons/NFC/Detailed_chip_17x13.png index 9aaa1c5552..71c56f60c5 100644 Binary files a/assets/icons/NFC/Detailed_chip_17x13.png and b/assets/icons/NFC/Detailed_chip_17x13.png differ diff --git a/assets/icons/NFC/Keychain_39x36.png b/assets/icons/NFC/Keychain_39x36.png index d15850b5b7..773f388d56 100644 Binary files a/assets/icons/NFC/Keychain_39x36.png and b/assets/icons/NFC/Keychain_39x36.png differ diff --git a/assets/icons/NFC/MFKey_qr_25x25.png b/assets/icons/NFC/MFKey_qr_25x25.png index feb07e2807..7059260ea6 100644 Binary files a/assets/icons/NFC/MFKey_qr_25x25.png and b/assets/icons/NFC/MFKey_qr_25x25.png differ diff --git a/assets/icons/NFC/Medium-chip-22x21.png b/assets/icons/NFC/Medium-chip-22x21.png index b1f15432d4..28250ca9c0 100644 Binary files a/assets/icons/NFC/Medium-chip-22x21.png and b/assets/icons/NFC/Medium-chip-22x21.png differ diff --git a/assets/icons/NFC/Modern_reader_18x34.png b/assets/icons/NFC/Modern_reader_18x34.png index b19c0f30c9..aac13396ae 100644 Binary files a/assets/icons/NFC/Modern_reader_18x34.png and b/assets/icons/NFC/Modern_reader_18x34.png differ diff --git a/assets/icons/NFC/Move_flipper_26x39.png b/assets/icons/NFC/Move_flipper_26x39.png index ff4af9ff05..981c172368 100644 Binary files a/assets/icons/NFC/Move_flipper_26x39.png and b/assets/icons/NFC/Move_flipper_26x39.png differ diff --git a/assets/icons/NFC/NFC_dolphin_emulation_51x64.png b/assets/icons/NFC/NFC_dolphin_emulation_51x64.png index ad5646d164..ef57f73c4e 100644 Binary files a/assets/icons/NFC/NFC_dolphin_emulation_51x64.png and b/assets/icons/NFC/NFC_dolphin_emulation_51x64.png differ diff --git a/assets/icons/NFC/NFC_manual_60x50.png b/assets/icons/NFC/NFC_manual_60x50.png index 787c0bcfe0..6a7f75499e 100644 Binary files a/assets/icons/NFC/NFC_manual_60x50.png and b/assets/icons/NFC/NFC_manual_60x50.png differ diff --git a/assets/icons/NFC/Release_arrow_18x15.png b/assets/icons/NFC/Release_arrow_18x15.png index 187a903454..bd487fdb5e 100644 Binary files a/assets/icons/NFC/Release_arrow_18x15.png and b/assets/icons/NFC/Release_arrow_18x15.png differ diff --git a/assets/icons/NFC/check_big_20x17.png b/assets/icons/NFC/check_big_20x17.png index 0e84cfa071..ddc7d3721c 100644 Binary files a/assets/icons/NFC/check_big_20x17.png and b/assets/icons/NFC/check_big_20x17.png differ diff --git a/assets/icons/PIN/Pin_arrow_up_7x9.png b/assets/icons/PIN/Pin_arrow_up_7x9.png index a91a6fd5e9..4e199c7d05 100644 Binary files a/assets/icons/PIN/Pin_arrow_up_7x9.png and b/assets/icons/PIN/Pin_arrow_up_7x9.png differ diff --git a/assets/icons/PIN/Pin_attention_dpad_29x29.png b/assets/icons/PIN/Pin_attention_dpad_29x29.png index 984db9cc77..65a2670a0d 100644 Binary files a/assets/icons/PIN/Pin_attention_dpad_29x29.png and b/assets/icons/PIN/Pin_attention_dpad_29x29.png differ diff --git a/assets/icons/PIN/Pin_back_arrow_10x8.png b/assets/icons/PIN/Pin_back_arrow_10x8.png index 3bafabd144..64b25db5af 100644 Binary files a/assets/icons/PIN/Pin_back_arrow_10x8.png and b/assets/icons/PIN/Pin_back_arrow_10x8.png differ diff --git a/assets/icons/PIN/Pin_pointer_5x3.png b/assets/icons/PIN/Pin_pointer_5x3.png index edf3d41bb5..4a4dc8a779 100644 Binary files a/assets/icons/PIN/Pin_pointer_5x3.png and b/assets/icons/PIN/Pin_pointer_5x3.png differ diff --git a/assets/icons/PIN/Pin_star_7x7.png b/assets/icons/PIN/Pin_star_7x7.png index 42fdea86e4..3ab57222df 100644 Binary files a/assets/icons/PIN/Pin_star_7x7.png and b/assets/icons/PIN/Pin_star_7x7.png differ diff --git a/assets/icons/Passport/passport_bad1_46x49.png b/assets/icons/Passport/passport_bad1_46x49.png index 9b0e7c74ef..94bce9c4b1 100644 Binary files a/assets/icons/Passport/passport_bad1_46x49.png and b/assets/icons/Passport/passport_bad1_46x49.png differ diff --git a/assets/icons/Passport/passport_bad2_46x49.png b/assets/icons/Passport/passport_bad2_46x49.png index d11682ab89..8909412572 100644 Binary files a/assets/icons/Passport/passport_bad2_46x49.png and b/assets/icons/Passport/passport_bad2_46x49.png differ diff --git a/assets/icons/Passport/passport_bad3_46x49.png b/assets/icons/Passport/passport_bad3_46x49.png index e39e6629d6..ae21ac9eea 100644 Binary files a/assets/icons/Passport/passport_bad3_46x49.png and b/assets/icons/Passport/passport_bad3_46x49.png differ diff --git a/assets/icons/Passport/passport_bottom_128x18.png b/assets/icons/Passport/passport_bottom_128x18.png index 691ed8b4ad..26d2fb53b4 100644 Binary files a/assets/icons/Passport/passport_bottom_128x18.png and b/assets/icons/Passport/passport_bottom_128x18.png differ diff --git a/assets/icons/Passport/passport_happy1_46x49.png b/assets/icons/Passport/passport_happy1_46x49.png index 56ea000cd0..4e58303cda 100644 Binary files a/assets/icons/Passport/passport_happy1_46x49.png and b/assets/icons/Passport/passport_happy1_46x49.png differ diff --git a/assets/icons/Passport/passport_happy2_46x49.png b/assets/icons/Passport/passport_happy2_46x49.png index f64e770e5a..ba66d94fc9 100644 Binary files a/assets/icons/Passport/passport_happy2_46x49.png and b/assets/icons/Passport/passport_happy2_46x49.png differ diff --git a/assets/icons/Passport/passport_happy3_46x49.png b/assets/icons/Passport/passport_happy3_46x49.png index 7aef176743..9f5e845719 100644 Binary files a/assets/icons/Passport/passport_happy3_46x49.png and b/assets/icons/Passport/passport_happy3_46x49.png differ diff --git a/assets/icons/Passport/passport_left_6x46.png b/assets/icons/Passport/passport_left_6x46.png index 17d3ad2656..8e9d00b13c 100644 Binary files a/assets/icons/Passport/passport_left_6x46.png and b/assets/icons/Passport/passport_left_6x46.png differ diff --git a/assets/icons/Passport/passport_okay1_46x49.png b/assets/icons/Passport/passport_okay1_46x49.png index 198ba54360..94b9dbf745 100644 Binary files a/assets/icons/Passport/passport_okay1_46x49.png and b/assets/icons/Passport/passport_okay1_46x49.png differ diff --git a/assets/icons/Passport/passport_okay2_46x49.png b/assets/icons/Passport/passport_okay2_46x49.png index 34fd3767b9..62f39ba215 100644 Binary files a/assets/icons/Passport/passport_okay2_46x49.png and b/assets/icons/Passport/passport_okay2_46x49.png differ diff --git a/assets/icons/Passport/passport_okay3_46x49.png b/assets/icons/Passport/passport_okay3_46x49.png index e65da5b0e5..d81f788193 100644 Binary files a/assets/icons/Passport/passport_okay3_46x49.png and b/assets/icons/Passport/passport_okay3_46x49.png differ diff --git a/assets/icons/Power/BatteryBody_52x28.png b/assets/icons/Power/BatteryBody_52x28.png index 1fe5683461..7f32403daa 100644 Binary files a/assets/icons/Power/BatteryBody_52x28.png and b/assets/icons/Power/BatteryBody_52x28.png differ diff --git a/assets/icons/Power/Battery_16x16.png b/assets/icons/Power/Battery_16x16.png index 49af3c2259..d59b884faa 100644 Binary files a/assets/icons/Power/Battery_16x16.png and b/assets/icons/Power/Battery_16x16.png differ diff --git a/assets/icons/Power/FaceCharging_29x14.png b/assets/icons/Power/FaceCharging_29x14.png index 106ededbf9..7ee7f74148 100644 Binary files a/assets/icons/Power/FaceCharging_29x14.png and b/assets/icons/Power/FaceCharging_29x14.png differ diff --git a/assets/icons/Power/FaceConfused_29x14.png b/assets/icons/Power/FaceConfused_29x14.png index dcd2e3c673..0f07c87251 100644 Binary files a/assets/icons/Power/FaceConfused_29x14.png and b/assets/icons/Power/FaceConfused_29x14.png differ diff --git a/assets/icons/Power/FaceNopower_29x14.png b/assets/icons/Power/FaceNopower_29x14.png index f3da0c8caa..df9028d44f 100644 Binary files a/assets/icons/Power/FaceNopower_29x14.png and b/assets/icons/Power/FaceNopower_29x14.png differ diff --git a/assets/icons/Power/FaceNormal_29x14.png b/assets/icons/Power/FaceNormal_29x14.png index 52d78c0869..84e5d031f3 100644 Binary files a/assets/icons/Power/FaceNormal_29x14.png and b/assets/icons/Power/FaceNormal_29x14.png differ diff --git a/assets/icons/Power/Health_16x16.png b/assets/icons/Power/Health_16x16.png index af343c5205..8ef39f64a7 100644 Binary files a/assets/icons/Power/Health_16x16.png and b/assets/icons/Power/Health_16x16.png differ diff --git a/assets/icons/Power/Temperature_16x16.png b/assets/icons/Power/Temperature_16x16.png index aade43882b..7add413833 100644 Binary files a/assets/icons/Power/Temperature_16x16.png and b/assets/icons/Power/Temperature_16x16.png differ diff --git a/assets/icons/Power/Unplug_bg_bottom_128x10.png b/assets/icons/Power/Unplug_bg_bottom_128x10.png index 35d73ba76e..18fd7bf9c2 100644 Binary files a/assets/icons/Power/Unplug_bg_bottom_128x10.png and b/assets/icons/Power/Unplug_bg_bottom_128x10.png differ diff --git a/assets/icons/Power/Unplug_bg_top_128x14.png b/assets/icons/Power/Unplug_bg_top_128x14.png index bafa2c4947..e9b6971046 100644 Binary files a/assets/icons/Power/Unplug_bg_top_128x14.png and b/assets/icons/Power/Unplug_bg_top_128x14.png differ diff --git a/assets/icons/Power/Voltage_16x16.png b/assets/icons/Power/Voltage_16x16.png index 94e7968729..4484e3af77 100644 Binary files a/assets/icons/Power/Voltage_16x16.png and b/assets/icons/Power/Voltage_16x16.png differ diff --git a/assets/icons/RFID/RFIDDolphinReceive_97x61.png b/assets/icons/RFID/RFIDDolphinReceive_97x61.png index e1f5f9f801..06deb0a27a 100644 Binary files a/assets/icons/RFID/RFIDDolphinReceive_97x61.png and b/assets/icons/RFID/RFIDDolphinReceive_97x61.png differ diff --git a/assets/icons/RFID/RFIDDolphinSend_97x61.png b/assets/icons/RFID/RFIDDolphinSend_97x61.png index 380a970d90..65dff82412 100644 Binary files a/assets/icons/RFID/RFIDDolphinSend_97x61.png and b/assets/icons/RFID/RFIDDolphinSend_97x61.png differ diff --git a/assets/icons/SDCard/SDQuestion_35x43.png b/assets/icons/SDCard/SDQuestion_35x43.png index 257ab1d852..a07a98e4b7 100644 Binary files a/assets/icons/SDCard/SDQuestion_35x43.png and b/assets/icons/SDCard/SDQuestion_35x43.png differ diff --git a/assets/icons/Settings/LoadingHourglass_24x24.png b/assets/icons/Settings/LoadingHourglass_24x24.png index 9c49dcad1c..7fafe05cab 100644 Binary files a/assets/icons/Settings/LoadingHourglass_24x24.png and b/assets/icons/Settings/LoadingHourglass_24x24.png differ diff --git a/assets/icons/Settings/dolph_cry_49x54.png b/assets/icons/Settings/dolph_cry_49x54.png index 351a849b09..1ebb69e3e9 100644 Binary files a/assets/icons/Settings/dolph_cry_49x54.png and b/assets/icons/Settings/dolph_cry_49x54.png differ diff --git a/assets/icons/Settings/qr_benchmark_25x25.png b/assets/icons/Settings/qr_benchmark_25x25.png index c5f9df1195..908821b6b5 100644 Binary files a/assets/icons/Settings/qr_benchmark_25x25.png and b/assets/icons/Settings/qr_benchmark_25x25.png differ diff --git a/assets/icons/StatusBar/Alert_9x8.png b/assets/icons/StatusBar/Alert_9x8.png index d03f107ef1..fe82828f6c 100644 Binary files a/assets/icons/StatusBar/Alert_9x8.png and b/assets/icons/StatusBar/Alert_9x8.png differ diff --git a/assets/icons/StatusBar/Attention_5x8.png b/assets/icons/StatusBar/Attention_5x8.png index 137d4c4d05..225a56ee39 100644 Binary files a/assets/icons/StatusBar/Attention_5x8.png and b/assets/icons/StatusBar/Attention_5x8.png differ diff --git a/assets/icons/StatusBar/BLE_beacon_7x8.png b/assets/icons/StatusBar/BLE_beacon_7x8.png index e8480287ce..9f955de83f 100644 Binary files a/assets/icons/StatusBar/BLE_beacon_7x8.png and b/assets/icons/StatusBar/BLE_beacon_7x8.png differ diff --git a/assets/icons/StatusBar/Background_128x11.png b/assets/icons/StatusBar/Background_128x11.png index 78ef029ae7..b2fe0bb977 100644 Binary files a/assets/icons/StatusBar/Background_128x11.png and b/assets/icons/StatusBar/Background_128x11.png differ diff --git a/assets/icons/StatusBar/Battery_26x8.png b/assets/icons/StatusBar/Battery_26x8.png index 5fc1b0cd6d..a9fea13095 100644 Binary files a/assets/icons/StatusBar/Battery_26x8.png and b/assets/icons/StatusBar/Battery_26x8.png differ diff --git a/assets/icons/StatusBar/Bluetooth_Connected_16x8.png b/assets/icons/StatusBar/Bluetooth_Connected_16x8.png index c77bc1494f..667c6d8921 100644 Binary files a/assets/icons/StatusBar/Bluetooth_Connected_16x8.png and b/assets/icons/StatusBar/Bluetooth_Connected_16x8.png differ diff --git a/assets/icons/StatusBar/Bluetooth_Idle_5x8.png b/assets/icons/StatusBar/Bluetooth_Idle_5x8.png index dc4a8733cd..8d7b05ca02 100644 Binary files a/assets/icons/StatusBar/Bluetooth_Idle_5x8.png and b/assets/icons/StatusBar/Bluetooth_Idle_5x8.png differ diff --git a/assets/icons/StatusBar/Charging-lightning_9x10.png b/assets/icons/StatusBar/Charging-lightning_9x10.png index c2eaa47d08..0e4629ff58 100644 Binary files a/assets/icons/StatusBar/Charging-lightning_9x10.png and b/assets/icons/StatusBar/Charging-lightning_9x10.png differ diff --git a/assets/icons/StatusBar/Charging-lightning_mask_9x10.png b/assets/icons/StatusBar/Charging-lightning_mask_9x10.png index d44a32ae08..9c0cc455c4 100644 Binary files a/assets/icons/StatusBar/Charging-lightning_mask_9x10.png and b/assets/icons/StatusBar/Charging-lightning_mask_9x10.png differ diff --git a/assets/icons/StatusBar/Exp_module_connected_12x8.png b/assets/icons/StatusBar/Exp_module_connected_12x8.png index a5f0966826..fc136087bc 100644 Binary files a/assets/icons/StatusBar/Exp_module_connected_12x8.png and b/assets/icons/StatusBar/Exp_module_connected_12x8.png differ diff --git a/assets/icons/StatusBar/GameMode_11x8.png b/assets/icons/StatusBar/GameMode_11x8.png index 49f2e25bf3..88f1a87c1d 100644 Binary files a/assets/icons/StatusBar/GameMode_11x8.png and b/assets/icons/StatusBar/GameMode_11x8.png differ diff --git a/assets/icons/StatusBar/Hidden_window_9x8.png b/assets/icons/StatusBar/Hidden_window_9x8.png index d6fc2b326d..7fce0d5f65 100644 Binary files a/assets/icons/StatusBar/Hidden_window_9x8.png and b/assets/icons/StatusBar/Hidden_window_9x8.png differ diff --git a/assets/icons/StatusBar/Muted_8x8.png b/assets/icons/StatusBar/Muted_8x8.png index fee4e09f5e..8d35be7fa8 100644 Binary files a/assets/icons/StatusBar/Muted_8x8.png and b/assets/icons/StatusBar/Muted_8x8.png differ diff --git a/assets/icons/StatusBar/Rpc_active_7x8.png b/assets/icons/StatusBar/Rpc_active_7x8.png index f643a82aa1..75ab10b4be 100644 Binary files a/assets/icons/StatusBar/Rpc_active_7x8.png and b/assets/icons/StatusBar/Rpc_active_7x8.png differ diff --git a/assets/icons/StatusBar/SDcardFail_11x8.png b/assets/icons/StatusBar/SDcardFail_11x8.png index 876cfa2290..cad9c4fcc3 100644 Binary files a/assets/icons/StatusBar/SDcardFail_11x8.png and b/assets/icons/StatusBar/SDcardFail_11x8.png differ diff --git a/assets/icons/StatusBar/SDcardMounted_11x8.png b/assets/icons/StatusBar/SDcardMounted_11x8.png index 68bc619216..3a3227adbb 100644 Binary files a/assets/icons/StatusBar/SDcardMounted_11x8.png and b/assets/icons/StatusBar/SDcardMounted_11x8.png differ diff --git a/assets/icons/SubGhz/Lock_7x8.png b/assets/icons/SubGhz/Lock_7x8.png index f7c9ca2c70..df07af6b80 100644 Binary files a/assets/icons/SubGhz/Lock_7x8.png and b/assets/icons/SubGhz/Lock_7x8.png differ diff --git a/assets/icons/SubGhz/MHz_25x11.png b/assets/icons/SubGhz/MHz_25x11.png index b995549566..2dae11a7e2 100644 Binary files a/assets/icons/SubGhz/MHz_25x11.png and b/assets/icons/SubGhz/MHz_25x11.png differ diff --git a/assets/icons/SubGhz/Quest_7x8.png b/assets/icons/SubGhz/Quest_7x8.png index 6825247fbe..95b4a7907c 100644 Binary files a/assets/icons/SubGhz/Quest_7x8.png and b/assets/icons/SubGhz/Quest_7x8.png differ diff --git a/assets/icons/SubGhz/Unlock_7x8.png b/assets/icons/SubGhz/Unlock_7x8.png index 9d82b4daf3..da11e49cbf 100644 Binary files a/assets/icons/SubGhz/Unlock_7x8.png and b/assets/icons/SubGhz/Unlock_7x8.png differ diff --git a/assets/icons/U2F/Auth_62x31.png b/assets/icons/U2F/Auth_62x31.png index 40f094ac9b..0c22865b26 100644 Binary files a/assets/icons/U2F/Auth_62x31.png and b/assets/icons/U2F/Auth_62x31.png differ diff --git a/assets/icons/U2F/Connect_me_62x31.png b/assets/icons/U2F/Connect_me_62x31.png index 68c48c0e68..d7def86b0c 100644 Binary files a/assets/icons/U2F/Connect_me_62x31.png and b/assets/icons/U2F/Connect_me_62x31.png differ diff --git a/assets/icons/U2F/Connected_62x31.png b/assets/icons/U2F/Connected_62x31.png index eeaf660b12..ee415989dc 100644 Binary files a/assets/icons/U2F/Connected_62x31.png and b/assets/icons/U2F/Connected_62x31.png differ diff --git a/assets/icons/U2F/Drive_112x35.png b/assets/icons/U2F/Drive_112x35.png index 6f7b9c8342..b910c7920f 100644 Binary files a/assets/icons/U2F/Drive_112x35.png and b/assets/icons/U2F/Drive_112x35.png differ diff --git a/assets/icons/U2F/Error_62x31.png b/assets/icons/U2F/Error_62x31.png index bb280e7512..c8b3b7a304 100644 Binary files a/assets/icons/U2F/Error_62x31.png and b/assets/icons/U2F/Error_62x31.png differ diff --git a/assets/icons/Update/Updating_32x40.png b/assets/icons/Update/Updating_32x40.png index d8f7654b8d..ed15073235 100644 Binary files a/assets/icons/Update/Updating_32x40.png and b/assets/icons/Update/Updating_32x40.png differ diff --git a/assets/icons/iButton/iButtonDolphinVerySuccess_92x55.png b/assets/icons/iButton/iButtonDolphinVerySuccess_92x55.png index 0a85465cc5..0d8263c5ed 100644 Binary files a/assets/icons/iButton/iButtonDolphinVerySuccess_92x55.png and b/assets/icons/iButton/iButtonDolphinVerySuccess_92x55.png differ diff --git a/assets/icons/iButton/iButtonKey_49x44.png b/assets/icons/iButton/iButtonKey_49x44.png index db895ec528..d3bf6e20fe 100644 Binary files a/assets/icons/iButton/iButtonKey_49x44.png and b/assets/icons/iButton/iButtonKey_49x44.png differ diff --git a/assets/slideshow/first_start/frame_00.png b/assets/slideshow/first_start/frame_00.png index 67f23bd31b..b464e0c55d 100644 Binary files a/assets/slideshow/first_start/frame_00.png and b/assets/slideshow/first_start/frame_00.png differ diff --git a/assets/slideshow/first_start/frame_01.png b/assets/slideshow/first_start/frame_01.png index 5ac995c397..5687e44df2 100644 Binary files a/assets/slideshow/first_start/frame_01.png and b/assets/slideshow/first_start/frame_01.png differ diff --git a/assets/slideshow/first_start/frame_02.png b/assets/slideshow/first_start/frame_02.png index adff6af667..f9d1fafb7d 100644 Binary files a/assets/slideshow/first_start/frame_02.png and b/assets/slideshow/first_start/frame_02.png differ diff --git a/assets/slideshow/first_start/frame_03.png b/assets/slideshow/first_start/frame_03.png index bd6ae73f7a..c8fc8e1b0b 100644 Binary files a/assets/slideshow/first_start/frame_03.png and b/assets/slideshow/first_start/frame_03.png differ diff --git a/assets/slideshow/first_start/frame_04.png b/assets/slideshow/first_start/frame_04.png index 59f62dcc70..942eded49e 100644 Binary files a/assets/slideshow/first_start/frame_04.png and b/assets/slideshow/first_start/frame_04.png differ diff --git a/assets/slideshow/first_start/frame_05.png b/assets/slideshow/first_start/frame_05.png index 3682c6d0c8..2df80976a1 100644 Binary files a/assets/slideshow/first_start/frame_05.png and b/assets/slideshow/first_start/frame_05.png differ diff --git a/documentation/AppManifests.md b/documentation/AppManifests.md index 98a38ffd85..493c9253bb 100644 --- a/documentation/AppManifests.md +++ b/documentation/AppManifests.md @@ -16,18 +16,18 @@ Only two parameters are mandatory: **appid** and **apptype**. Others are optiona - **apptype**: member of FlipperAppType.\* enumeration. Valid values are: -| Enum member | Firmware component type | -| ----------- | ------------------------------------------------------------------------------------------- | -| SERVICE | System service, created at early startup | -| SYSTEM | Application is not being shown in any menus. It can be started by other apps or from CLI | -| APP | Regular application for the main menu | -| PLUGIN | Application to be built as a part of the firmware and to be placed in the Plugins menu | -| DEBUG | Application only visible in Debug menu with debug mode enabled | -| ARCHIVE | One and only Archive app | -| SETTINGS | Application to be placed in the system settings menu | -| STARTUP | Callback function to run at system startup. Does not define a separate app | -| EXTERNAL | Application to be built as `.fap` plugin | -| METAPACKAGE | Does not define any code to be run, used for declaring dependencies and application bundles | +| Enum member | Firmware component type | +|:----------------|--------------------------------------------------------------------------------------------------| +| SERVICE | System service, created at early startup | +| SYSTEM | Application is not being shown in any menus. It can be started by other apps or from CLI | +| APP | Regular application for the main menu | +| PLUGIN | Application to be built as a part of the firmware and to be placed in the Plugins menu | +| DEBUG | Application only visible in Debug menu with debug mode enabled | +| ARCHIVE | One and only Archive app | +| SETTINGS | Application to be placed in the system settings menu | +| STARTUP | Callback function to run at system startup. Does not define a separate app | +| EXTERNAL | Application to be built as `.fap` plugin | +| METAPACKAGE | Does not define any code to be run, used for declaring dependencies and application bundles | - **name**: name displayed in menus. - **entry_point**: C function to be used as the application's entry point. Note that C++ function names are mangled, so you need to wrap them in `extern "C"` to use them as entry points. @@ -43,7 +43,7 @@ Only two parameters are mandatory: **appid** and **apptype**. Others are optiona - **targets**: list of strings and target names with which this application is compatible. If not specified, the application is built for all targets. The default value is `["all"]`. - **resources**: name of a folder within the application's source folder to be used for packacking SD card resources for this application. They will only be used if application is included in build configuration. The default value is `""`, meaning no resources are packaged. -#### Parameters for external applications +### Parameters for external applications The following parameters are used only for [FAPs](./AppsOnSDCard.md): @@ -59,7 +59,10 @@ The following parameters are used only for [FAPs](./AppsOnSDCard.md): - **fap_extbuild**: provides support for parts of application sources to be built by external tools. Contains a list of `ExtFile(path="file name", command="shell command")` definitions. `fbt` will run the specified command for each file in the list. - **fal_embedded**: boolean, default `False`. Applies only to PLUGIN type. If `True`, the plugin will be embedded into host application's .fap file as a resource and extracted to `apps_assets/APPID` folder on its start. This allows plugins to be distributed as a part of the host application. -Note that commands are executed at the firmware root folder, and all intermediate files must be placed in an application's temporary build folder. For that, you can use pattern expansion by `fbt`: `${FAP_WORK_DIR}` will be replaced with the path to the application's temporary build folder, and `${FAP_SRC_DIR}` will be replaced with the path to the application's source folder. You can also use other variables defined internally by `fbt`. +> [!NOTE] +> These commands are executed at the firmware root folder, and all intermediate files must be placed in an application's temporary build folder. +> For that, you can use pattern expansion by `fbt`: `${FAP_WORK_DIR}` will be replaced with the path to the application's temporary build folder, +> and `${FAP_SRC_DIR}` will be replaced with the path to the application's source folder. You can also use other variables defined internally by `fbt`. Example for building an app from Rust sources: diff --git a/documentation/BarcodeGenerator.md b/documentation/BarcodeGenerator.md index f2b5b2213b..0f429fda16 100644 --- a/documentation/BarcodeGenerator.md +++ b/documentation/BarcodeGenerator.md @@ -1,15 +1,16 @@ # This is a UPC-A Barcode Generator for the Flipper Zero hardware. -## Author: [McAzzaMan](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator) +> Author: [McAzzaMan](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator) - + It will eventually be expanded into other barcode types. It currently only generates UPC-A type barcodes. - + - -Controls-
-Hitting the centre button on the Flipper toggles edit mode. -When in edit mode, left and right will change the digit to be changed, and up and down will adjust the digit value. +## Controls - +Hitting the `centre` button on the Flipper toggles edit mode. +When in edit mode, `Left` and `Right` will change the digit to be changed, and up and down will adjust the digit value. + + diff --git a/documentation/Doxyfile b/documentation/Doxyfile index 5b93cf8b18..f980c42f01 100644 --- a/documentation/Doxyfile +++ b/documentation/Doxyfile @@ -1021,7 +1021,6 @@ RECURSIVE = YES EXCLUDE = $(DOXY_SRC_ROOT)/lib/mlib \ $(DOXY_SRC_ROOT)/lib/STM32CubeWB \ - $(DOXY_SRC_ROOT)/lib/littlefs \ $(DOXY_SRC_ROOT)/lib/nanopb \ $(DOXY_SRC_ROOT)/assets/protobuf \ $(DOXY_SRC_ROOT)/lib/libusb_stm32 \ diff --git a/documentation/FAQ.md b/documentation/FAQ.md index 8f912c517f..67581999e3 100644 --- a/documentation/FAQ.md +++ b/documentation/FAQ.md @@ -1,215 +1,244 @@ # FAQ ## I bought Flipper Zero and I don't know what I can do with it, pls help -- Start with reading official main page: https://flipperzero.one/ -- Then check out official docs where you can find answers to most questions: https://docs.flipper.net/ + +- Start with reading [official main page](https://flipperzero.one/) +- Then check out official docs where you can find answers to [most questions](https://docs.flipper.net/) ## How do I install Unleashed firmware? -https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md -### What version I should install? What do letters `e`, `r`, `c`... mean? -Follow this link for details:
-https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#recommended-update-option---web-updater +See [this](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md) + +## What version I should install? What do letters `e`, `r`, `c`... mean? + +Follow this link for [details](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md#recommended-update-option---web-updater). + +## INSTALLED UNLEASHED AND NOW BACKLIGHT DOESNT WORK? -**INSTALLED UNLEASHED AND NOW BACKLIGHT DOESNT WORK?**
-You’ve installed a version made for custom RGB modded flippers. The version ending in `“r”` is specifically for “RGB” modded flippers.
-Please do not use that version if your flipper isn’t modded! +You’ve installed a version made for custom RGB modded flippers. The version ending in `r` is specifically for `RGB` modded flippers.
+ +Please, do not use that version if your flipper isn’t modded! ## What apps (plugins) are included with Unleashed FW? -See default pack and extra pack (for `e` build) list here:
-https://github.com/xMasterX/all-the-plugins/tree/dev + +See default pack and extra pack (for `e` build) list [here](https://github.com/xMasterX/all-the-plugins/tree/dev). ## Where I can find differences between original (official) firmware and Unleashed firmware? -Right here:
-https://github.com/DarkFlippers/unleashed-firmware#whats-changed + +[Right here](https://github.com/DarkFlippers/unleashed-firmware#whats-changed) ## How to use SubGHz Remote app? -1. Open app, press Back button, select New map file + +1. Open app, press `Back` button, select `New map file` 2. Configure signal files and their names for every button (also you can add only one signal and make other buttons empty - just don't select any files for them in config) 3. Save new map file 4. Open map file and select your previously created file 5. Use buttons to send subghz signal files that you selected in map config at step 2 - ## How to build (compile) firmware? -Follow this link:
-https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToBuild.md#how-to-build-by-yourself + +Follow this [link](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToBuild.md#how-to-build-by-yourself). ## I installed Unleashed firmware and now my mobile app doesn't connect to flipper ( OR I changed flipper device name and my mobile app now doesn't connect to flipper ) + 1. Click Forget flipper in mobile app - 2. Open your phone settings - bluetooth, find flipper - if it present here - open its options and click forget device - 3. On flipper itself open Settings -> Bluetooth -> Forget all devices -> and confirm - 4. Make sure your flipper has bluetooth ON and open Mobile app and pair it to flipper + 2. Open your `phone settings - bluetooth`, find flipper - if it present here - open its options and click forget device + 3. On flipper itself open `Settings -> Bluetooth -> Forget all devices` and confirm + 4. Make sure your flipper has bluetooth `ON` and open Mobile app and pair it to flipper 5. Done ## My desktop (pin, favourites, etc..) (or other) settings was reset to default after update, what to do? + Just configure that settings again, all is fine, and make sure you seen changelogs for the releases that came out after your previous version, when settings struct is changed, settings file are reset after update, this happens only when struct changes is required, so don't assume that settings will be reset in every release, this will happen only in specific ones -## Why is flipper not connecting to chrome? -The most common cause of the flipper not connecting to google chrome is having qFlipper open while trying to connect your flipper. Or having second flipper lab page open at same time.
+## Why is flipper not connecting to Chrome? + +The most common cause of the flipper not connecting to google chrome is having qFlipper open while trying to connect your flipper.
-You must close qFlipper (or other flipper lab web pages) before attempting to connect your flipper to chrome. +Or having second flipper lab page open at same time.
+ +You must close qFlipper (or other flipper lab web pages) before attempting to connect your flipper to Chrome. ## Flipper doesn't work! How to restore firmware??? -Follow this guide:
-https://docs.flipper.net/basics/firmware-update/firmware-recovery - +Follow this [guide](https://docs.flipper.net/basics/firmware-update/firmware-recovery) ## Useful links and files -Flipper Awesome - place where you can find almost all links that you might need:
-https://github.com/djsime1/awesome-flipperzero - -Dict files for iButton Fuzzer and RFID Fuzzer:
-https://t.me/flipperzero_unofficial_ru/37058
-https://t.me/flipperzero_unofficial_ru/37072 - -UL Releases in Telegram:
-https://t.me/unleashed_fw
-UL Dev Builds in Telegram:
-https://t.me/kotnehleb
-Our Discord:
-https://discord.unleashedflip.com +Flipper Awesome - place where you can find almost all links that you might need:
+* [Awesome-FlipperZero](https://github.com/djsime1/awesome-flipperzero) +* Dict files for iButton Fuzzer and RFID Fuzzer:
+ * https://t.me/flipperzero_unofficial_ru/37058
+ * https://t.me/flipperzero_unofficial_ru/37072 +* UL Releases in [Telegram](https://t.me/unleashed_fw) +* UL Dev Builds in [Telegram](https://t.me/kotnehleb) +* Our [Discord](https://discord.unleashedflip.com) ## How to change flipper name? + All is simple: -1. Open Settings -> Desktop -> Change Flipper Name -2. Enter new name and click Save +1. Open `Settings -> Desktop -> Change Flipper Name` +2. Enter new name and click `Save` 3. Exit from settings - Flipper will automatically reboot 4. Done, you have custom name which will stay until you reset it to default or replace with new one -How to reset name to default: -1. Open Settings -> Desktop -> Change Flipper Name +## How to reset name to default? + +1. Open `Settings -> Desktop -> Change Flipper Name` 2. Do not enter anything, just click Save 3. Exit from settings - Flipper will automatically reboot 4. Done, name is reset to original one. -## How do I copy files from Github to my Flipper Zero? -Follow this detailed guide:
-https://github.com/wrenchathome/flipperfiles/blob/main/_Guides/How2Flipper.pdf +## How do I copy files from GitHub to my Flipper Zero? +Follow this detailed [guide](https://github.com/wrenchathome/flipperfiles/blob/main/_Guides/How2Flipper.pdf). ## Where can I find “This file” or “That file” for my flipper? -These 2 repos will cover most(99.9%) of your needs:
-https://github.com/UberGuidoZ/Flipper/tree/main -
-https://github.com/UberGuidoZ/Flipper-IRDB/tree/main +These 2 repos will cover most (99.9%) of your needs:
+* https://github.com/UberGuidoZ/Flipper/tree/main +* https://github.com/UberGuidoZ/Flipper-IRDB/tree/main ## How can I support Unleashed firmware project? -https://github.com/DarkFlippers/unleashed-firmware#please-support-development-of-the-project + +Please follow this [link](https://github.com/DarkFlippers/unleashed-firmware#please-support-development-of-the-project). ## What are the dev builds? Where I can get latest build for dev branch? -This is an automatic assembly of the latest commits from the repository that have not yet been released, the previous build is deleted when a new one is uploaded and old remains only as file in the telegram channel
-Be aware that this is not release ready builds! They may have bugs and issues, if you are using dev build and found issue, report it! In github issues -
-Dev builds is available in Discord, ⁠in channel - `unleashed-development`
-Builds also can be found here - https://t.me/kotnehleb
-And here - https://dev.unleashedflip.com/
+This is an automatic assembly of the latest commits from the repository that have not yet been released, the previous build is deleted when a new one is uploaded and old remains only as file in the telegram channel + +> [!CAUTION] +> +> Be aware that this is not release ready builds! +> +> They may have bugs and issues, +> if you are using dev build and found issue, +> report it! In [GitHub issues](https://github.com/DarkFlippers/unleashed-firmware/issues) + +Dev builds is available in Discord, Win channel - `unleashed-development`
+Builds also can be found [here](https://t.me/kotnehleb).
+And [here](https://dev.unleashedflip.com/)
## What is the update server? -We have our own update server https://up.unleashedflip.com/directory.json
-It is identical to the official one, it is impossible to change it in applications without rebuilding the application, it is hardcoded there
-If you want to use it, you need to patch or build your own build of the application you are interested in
-Also you can use it with uFBT to build apps for UL SDK, uFBT will accept that link as one of args
+We have our own update server https://up.unleashedflip.com/directory.json

+It is identical to the official one, it is impossible to change it in applications without rebuilding the application, it is hardcoded there

+If you want to use it, you need to patch or build your own build of the application you are interested in
+ +Also you can use it with uFBT to build apps for UL SDK, uFBT will accept that link as one of args
The server will remain active and will be automatically updated ## External Radio: How to connect CC1101 module -https://github.com/quen0n/flipperzero-ext-cc1101 + +[Guide](https://github.com/quen0n/flipperzero-ext-cc1101) ## How to add extra Sub-GHz frequencies -https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md + +[Guide](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md) ## How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis, Aprimatic, AN-Motors, etc..) -https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md -## How Can I Unlock/Remove SubGHz restriction? -If you are using Unleashed firmware - **all region locks are removed by default**! +[Guide](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md) + +## How Can I Unlock / Remove SubGHz restriction? -Also there is a way to go outside of frequencies stated in CC1101 datasheet, but transmission on those frequencies may cause chip damage, make sure you know what you are doing! Do not edit this settings to bypass region lock since there is no region locks in unleashed, all chip supported frequencies will work without any extra steps.
-But, if you know that you need to bypass subghz chip safety restriction you can unlock the safety restriction which will allow you to go outside the chips supported frequency.
-This covers how to do it and information regarding the risks of damage to the flipper by doing so
-https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md +> [!TIP] +> +> If you are using Unleashed firmware - **all region locks are removed by default**! + +Also, there is a way to go outside of frequencies stated in `CC1101 datasheet`, but transmission on those frequencies may cause chip damage, make sure you know what you are doing! + +Do not edit this settings to bypass region lock since there is no region locks in unleashed, all chip supported frequencies will work without any extra steps.

+ +But, if you know that you need to bypass subghz chip safety restriction you can unlock the safety restriction which will allow you to go outside the chips supported frequency.

+This covers how to do it and information regarding the risks of damage to the flipper by doing so. + +Please read [this](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md) before. ## Can I clone a car key fob for my own car to use flipper as a key? + No, and trying to do so with Read RAW will lead to key desync or unpair with blacklist which means re-pair is very hard and requires service tools ## Will Unleashed FW support car keyfobs decoding, cloning, emulating? + No, never ## Where can I find jamming files? + Nowhere, this is illegal in almost every country in the world -## I saw something on tiktok and want to ask how to do it, I just wanna be like real hacker -And you might be banned for that in our communities, since 99% of that content is fake, or showing illegal actions, and we don't like tiktok related questions +## I saw something on TikTok and want to ask how to do it, I just wanna be like real hacker + +And you might be banned for that in our communities, since 99% of that content is fake, or showing illegal actions, and we don't like TikTok related questions. + +## I was banned in Unleashed Discord / Telegram / etc.. How to remove ban? I created GitHub issue and it was removed too! -## I was banned in Unleashed Discord/Telegram/etc.. How to remove ban? I created github issue and it was removed too! Not possible, rules is rules, read them before sending messages in our communities ## How to clean .DS_Store and other dot files left from macOS + `sudo dot_clean -mn /Volumes/Flipper\ SD` -> `Flipper\ SD` may be named differently for you, replace with your microSD card name -## How to sort files on flipper microSD on macOS/Linux -`will make sorting faster, and will work for OFW` -1. `brew install fatsort` -> Install fatsort using brew.sh (only on macOS) +## How to sort files on flipper microSD on macOS / Linux? + +Will make sorting faster, and will work for OFW +1. `brew install fatsort` -> Install fatsort using `brew.sh` (only on macOS) 2. `diskutil list` -> Find your disk name for flipper microSD 3. `diskutil unmount /Volumes/Flipper\ SD` 4. `sudo fatsort -n /dev/disk4s1` -> Replace `disk4s1` with your microSD id found on step 2 - ## Your Flipper feels slow and unresponsive? -1. Make sure you using good microSD card from known brand, flipper works with microSD via SPI that means not any microSD will work good even if it works ok with other devices -2. Go into **Settings -> System** and make sure that you have -`Log Level = None` -`Debug = OFF` -`Heap Trace = None` -If some of that settings is set to something different - change it to `None` / `OFF` -3. Make sure your battery is charged, that can affect performance too -## Flipper crashed, stuck, frozen ? -Reboot it by holding Left + Back buttons +1. Make sure you using good microSD card from known brand, flipper works with microSD via SPI that means not any microSD will work good even if it works ok with other devices. +2. Go into `Settings -> System` and make sure that you have + ```text + Log Level = None + Debug = OFF + Heap Trace = None + ``` +3. If some of that settings is set to something different - change it to `None` / `OFF` +4. Make sure your battery is charged, that can affect performance too -![how to reboot flipper gif, shows how to hold left and back button](https://media.tenor.com/eUbBDDEzmwMAAAAC/flipper-zero-flipper-zero-reboot.gif) +## Flipper crashed, stuck, frozen? +Reboot it by holding `Left` + `Back` buttons + +![how to reboot flipper gif, shows how to hold left and back button](https://media.tenor.com/eUbBDDEzmwMAAAAC/flipper-zero-flipper-zero-reboot.gif) ## How to reset forgotten Flipper pin code? **Disconnect USB Cable if it was connected** -1. Turn off the device - hold back button -> Turn Off +1. Turn off the device - hold back button -> `Turn Off` **If you can't turn it off, try next step but hold buttons for 30-40 seconds)** -2. Hold Up + Back for ~5 sec -> You will see reset screen -> Hold Right to reset (and down arrow to exit if you don't want to reset pin code) +2. Hold Up + Back for `~5 sec` -> You will see reset screen -> Hold Right to reset (and Down arrow to exit if you don't want to reset pin code) 3. Done, internal memory (dolphin level, settings, pin code, is erased to default settings) ## What are the differences between x, y and z firmware? -If you just got your flipper and not sure what will work better for you, start with original official firmware, if you think you need more features or want to remove subghz region locks then
-Try installing Unleashed firmware, which is fork of official firmware with many new features and preinstalled plugins (check out `e` build)
-In other case If you want to experiment more with UI and other things look for existing forks of Unleashed firmware
-Or create your own fork with your own customisations
-Also before reporting any found issue make sure you are in correct repo, if you are using not Unleashed but different fork or original firmware, do not report issue in Unleashed firmware repo or UL communities (telegram, discord, etc..) +If you just got your flipper and not sure what will work better for you, start with original official firmware, if you think you need more features or want to remove subghz region locks then:
+* Try installing **Unleashed firmware**, which is fork of official firmware with many new features and preinstalled plugins (check out `e` build).
+* In other case, If you want to experiment more with UI and other things look for existing forks of Unleashed firmware.
+* Or, create your own fork with your own customisations
+* Also, before reporting any found issue make sure you are in correct repo, if you are using not **Unleashed**, but different fork or original firmware, do not report issue in **Unleashed firmware** repo or UL communities (Telegram, Discord, etc..) ## Is there a correct way to capturing Infrared signals? There is indeed especially with AC units, a new documentation has been released with some notes and steps on capturing infrared signals correctly along with some example data so you are able to understand the difference visually between the two. -https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/InfraredCaptures.md +[More info](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/InfraredCaptures.md) +## NFC / RFID FAQ -# NFC/RFID FAQ -From our good friend `@Equip` and `@np0`
-**------------------------------------------------------** +From our good friend `@Equip` and `@np0`
### MIFARE Ultralight -- Scan the card, hold the Flipper Zero up to the reader to get the password to unlock the rest of the sectors, then scan the card again. +Scan the card, hold the Flipper Zero up to the reader to get the password to unlock the rest of the sectors, then scan the card again. -### MIFARE DESFire/MIFARE Ultralight C +### MIFARE DESFire / MIFARE Ultralight C -- The Flipper Zero has no available attacks for this card currently. +The Flipper Zero has no available attacks for this card currently. ### Bank cards @@ -219,60 +248,63 @@ From our good friend `@Equip` and `@np0`
### Amiibos -- NTAG215. that's it. It's not going on a MIFARE Classic. +- `NTAG215`. That's it. It's not going on a MIFARE Classic. - Currently, you cannot write Amiibos to new physical tags. yet. -### HID/iClass +### HID / iClass -- Picopass iClass can be read using the Picopass reader plugin +- `Picopass` iClass can be read using the `Picopass` reader plugin - 26bit Picopass can be downgraded to H10301 RFID credentials (note, it is not guaranteed to work if the reader is not configured to read low frequency) - Readers will need to be configured and have an LF RFID antenna in order to be read. Certain iClass readers are HF only, and do not have the ability to have LF configured -- **Emulation for Picopass** was added on July 26th, and the updated version can be found in latest releases of Unleashed firmware with apps preinstalled, or in official Apps Hub via Flipper Mobile app +- **Emulation for Picopass** was added on July 26th, and the updated version can be found in latest releases of **Unleashed** firmware with apps preinstalled, or in official Apps Hub via Flipper Mobile app - Write support for personalization mode cards is doable with app -- The Seader app and a SAM expansion board < https://www.redteamtools.com/nard-sam-expansion-board-for-flipper-zero-with-hid-seos-iclass-sam/ > will allow reading more secure HID cards, which may be helpful in downgrade attacks +- The Seader app and a [SAM expansion board](https://www.redteamtools.com/nard-sam-expansion-board-for-flipper-zero-with-hid-seos-iclass-sam/) will allow reading more secure HID cards, which may be helpful in downgrade attacks ### LF-RFID -If you're wanting to make clones of low frequency RFID chips you need to write to T5577's. "Blanks" do not exist. All of the chips the Flipper Zero can interact with are read-only and cannot be overwritten or purchased blank. -T5577s are multiemulator chips that the Flipper Zero can program to be other tags +If you're wanting to make clones of low frequency RFID chips you need to write to T5577's. `Blanks` do not exist. All of the chips the Flipper Zero can interact with are read-only and cannot be overwritten or purchased blank. + +T5577s are multi-emulator chips that the Flipper Zero can program to be other tags -### Unknown Card/Fob +### Unknown Card / Fob -If you have exhausted all options of scanning via NFC/RFID/PICOPASS then take a photo of: +If you have exhausted all options of scanning via NFC / RFID / PICOPASS then take a photo of: - The front and back of your credential - The reader you use with the credential - If your credential is a card, hold it up to a very bright light source e.g. a lightbulb and take a photo of the exposed antenna. This is useful for identification, post it for us to identify! -**------------------------------------------------------** +## How do I access the CLI / Logs? + +To access the Serial CLI, click one of the following based on your platform. -## How do I access the CLI/Logs?
- To access the Serial CLI, click one of the following based on your platform.
Desktop web browser* - *Chromium browsers only, such as: Google Chrome, Microsoft Edge, Opera/Opera GX, Brave, and Vivaldi. + *Chromium browsers only, such as: Google Chrome, Microsoft Edge, Opera / Opera GX, Brave, and Vivaldi.
  • Connect your Flipper via USB.
  • Ensure qFlipper and any other serial terminals are closed.
  • Open my.flipp.dev in one of the aforementioned browsers.
  • -
  • Click CONNECT and select "USB Serial Device" from the list.
  • +
  • Click CONNECT and select USB Serial Device from the list.
  • Wait until you can see your device details on screen.
  • Select the 💻 CLI item from the left sidebar.
  • Done!
+
+
Windows
  • Install PuTTY if it isn't already.
  • Connect your Flipper via USB.
  • -
  • Open qFlipper and look for the COM port next to the Flipper's name. (Should say COM followed by a number, like COM1)
  • +
  • Open qFlipper and look for the COM port next to the Flipper's name. (Should say COM followed by a number, like COM1)
  • Take note of the COM port number.
  • CLOSE qFlipper, otherwise the next steps won't work.
  • Open PuTTY and ensure you're on the Session screen.
  • -
  • Select "Serial" under connection type.
  • -
  • Set serial line to the COM port. (Just COM followed by the number, like COM1)
  • +
  • Select Serial under connection type.
  • +
  • Set serial line to the COM port. (Just COM followed by the number, like COM1)
  • Set speed to 115200
  • Optional: Save the session settings for easy connection later.
  • Finally, click Open to enter the CLI.
  • @@ -280,6 +312,8 @@ If you have exhausted all options of scanning via NFC/RFID/PICOPASS then take a
  • If you get an "Access Denied" error, make sure qFlipper isn't running!
+
+
MacOS/Linux Note: I'm a filthy Windows user without any way to verify this procedure. Let me know if it's wrong! @@ -295,6 +329,8 @@ If you have exhausted all options of scanning via NFC/RFID/PICOPASS then take a
  • Done!
  • +
    +
    Android
      @@ -308,16 +344,20 @@ If you have exhausted all options of scanning via NFC/RFID/PICOPASS then take a
    • Note: To exit log mode, you'll have to disconnect and reconnect using the icon.
    +
    +
    iPhone - Unfortunately, iOS is incapable of accessing a serial terminal over USB; try one of the other methods. -
    - On the Flipper, open the settings, go to System, and set Log Level to Debug. (You can keep Debug set to off unless someone asks you to turn it on) - Once you have the CLI open, type log and press enter to start watching logs. Press Ctrl-C or Cmd-C to exit log mode. + Unfortunately, iOS is incapable of accessing a serial terminal over USB; try one of the other methods
    +
      +
    • On the Flipper, open the settings, go to System, and set Log Level to Debug. (You can keep Debug set to off unless someone asks you to turn it on)
    • +
    • Once you have the CLI open, type log and press enter to start watching logs. Press Ctrl-C or Cmd-C to exit log mode.
    • +
    +
    -
    -
    +
    +
    -**CLI FAQ Source + Check out this FAQ for more info:** +**CLI FAQ Source + Check out this FAQ for more info:**

    https://github.com/djsime1/awesome-flipperzero/blob/main/FAQ.md diff --git a/documentation/FuriHalBus.md b/documentation/FuriHalBus.md index 12c5a70ece..7077e3abf0 100644 --- a/documentation/FuriHalBus.md +++ b/documentation/FuriHalBus.md @@ -3,15 +3,21 @@ ## Basic info On system startup, most of the peripheral devices are under reset and not clocked by default. This is done to reduce power consumption and to guarantee that the device will always be in the same state before use. + Some crucial peripherals are enabled right away by the system, others must be explicitly enabled by the user code. -**NOTE:** Here and afterwards the word *"system"* refers to any code belonging to the operating system, hardware drivers or built-in applications. +> [!NOTE] +> +> Here and afterwards the word `system` refers to any code belonging to the operating system, +> hardware drivers or built-in applications. -To **ENABLE** a peripheral, call `furi_hal_bus_enable()`. At the time of the call, the peripheral in question MUST be disabled, otherwise a crash will occur to indicate improper use. This means that any given peripheral cannot be enabled twice or more without disabling it first. +To **ENABLE** a peripheral, call `furi_hal_bus_enable()`. At the time of the call, the peripheral in question **MUST** be disabled; +otherwise a crash will occur to indicate improper use. This means that any given peripheral cannot be enabled twice or more without disabling it first. -To **DISABLE** a peripheral, call `furi_hal_bus_disable()`. Likewise, the peripheral in question MUST be enabled, otherwise a crash will occur. +To **DISABLE** a peripheral, call `furi_hal_bus_disable()`. Likewise, the peripheral in question **MUST** be enabled, otherwise a crash will occur. -To **RESET** a peripheral, call `furi_hal_bus_reset()`. The peripheral in question MUST be enabled, otherwise a crash will occur. This method is used whenever it is necessary to reset all the peripheral's registers to their initial states without disabling it. +To **RESET** a peripheral, call `furi_hal_bus_reset()`. The peripheral in question MUST be enabled, otherwise a crash will occur. +This method is used whenever it is necessary to reset all the peripheral's registers to their initial states without disabling it. ## Peripherals @@ -22,26 +28,28 @@ Built-in peripherals are divided into three categories: ### Always-on peripherals -Below is the list of peripherals that are enabled by the system. The user code must NEVER attempt to disable them. If a corresponding API is provided, the user code must employ it in order to access the peripheral. +Below is the list of peripherals that are enabled by the system. The user code must **NEVER** attempt to disable them. + +If a corresponding API is provided, the user code must employ it in order to access the peripheral. *Table 1* - Peripherals enabled by the system -| Peripheral | Enabled at | -| :-----------: | :-----------------------: | -| DMA1 | `furi_hal_dma.c` | -| DMA2 | -- | -| DMAMUX | -- | -| GPIOA | `furi_hal_resources.c` | -| GPIOB | -- | -| GPIOC | -- | -| GPIOD | -- | -| GPIOE | -- | -| GPIOH | -- | -| PKA | `furi_hal_bt.c` | -| AES2 | -- | -| HSEM | -- | -| IPCC | -- | -| FLASH | enabled by hardware | +| Peripheral | Enabled at | +|:-------------:|:---------------------------:| +| DMA1 | `furi_hal_dma.c` | +| DMA2 | -- | +| DMAMUX | -- | +| GPIOA | `furi_hal_resources.c` | +| GPIOB | -- | +| GPIOC | -- | +| GPIOD | -- | +| GPIOE | -- | +| GPIOH | -- | +| PKA | `furi_hal_bt.c` | +| AES2 | -- | +| HSEM | -- | +| IPCC | -- | +| FLASH | enabled by hardware | ### On-demand system peripherals @@ -51,63 +59,64 @@ When not using the API, these peripherals MUST be enabled by the user code and t *Table 2* - Peripherals enabled and disabled by the system -| Peripheral | API header file | -| :-----------: | :-------------------: | -| RNG | `furi_hal_random.h` | -| SPI1 | `furi_hal_spi.h` | -| SPI2 | -- | -| I2C1 | `furi_hal_i2c.h` | -| I2C3 | -- | -| USART1 | `furi_hal_serial.h` | -| LPUART1 | -- | -| USB | `furi_hal_usb.h` | +| Peripheral | API header file | +|:--------------:|:------------------------:| +| RNG | `furi_hal_random.h` | +| SPI1 | `furi_hal_spi.h` | +| SPI2 | -- | +| I2C1 | `furi_hal_i2c.h` | +| I2C3 | -- | +| USART1 | `furi_hal_serial.h` | +| LPUART1 | -- | +| USB | `furi_hal_usb.h` | ### On-demand shared peripherals -Below is the list of peripherals that are not enabled by default and MUST be enabled by the user code each time it accesses them. +Below is the list of peripherals that are not enabled by default and **MUST** be enabled by the user code each time it accesses them. Note that some of these peripherals may also be used by the system to implement its certain features. + The system will take over any given peripheral only when the respective feature is in use. *Table 3* - Peripherals enabled and disabled by user -| Peripheral | System | Purpose | -| :-----------: | :-------: | ------------------------------------- | -| CRC | | | -| TSC | | | -| ADC | | | -| QUADSPI | | | -| TIM1 | yes | subghz, lfrfid, nfc, infrared, etc... | -| TIM2 | yes | subghz, infrared, etc... | -| TIM16 | yes | speaker | -| TIM17 | yes | cc1101_ext | -| LPTIM1 | yes | tickless idle timer | -| LPTIM2 | yes | pwm | -| SAI1 | | | -| LCD | | | - +| Peripheral | System | Purpose | +|:----------:|:------:|:----------------------------------------| +| CRC | | | +| TSC | | | +| ADC | | | +| QUADSPI | | | +| TIM1 | yes | subghz, lfrfid, nfc, infrared, etc... | +| TIM2 | yes | subghz, infrared, etc... | +| TIM16 | yes | speaker | +| TIM17 | yes | cc1101_ext | +| LPTIM1 | yes | tickless idle timer | +| LPTIM2 | yes | pwm | +| SAI1 | | | +| LCD | | | ## DMA -The DMA1,2 peripherals are a special case in that they have multiple independent channels. Some of the channels may be in use by the system. +The `DMA1`, `DMA2` peripherals are a special case in that they have multiple independent channels. +Some channels may be in use by the system. Below is the list of DMA channels and their usage by the system. *Table 4* - DMA channels -| DMA | Channel | System | Purpose | -| :---: | :-------: | :-------: | ------------------------- | -| DMA1 | 1 | yes | digital signal | -| -- | 2 | yes | -- | -| -- | 3 | | | -| -- | 4 | yes | pulse reader | -| -- | 5 | | | -| -- | 6 | yes | USART_Rx | -| -- | 7 | yes | LPUART_Rx | -| DMA2 | 1 | yes | infrared, lfrfid, subghz, | -| -- | 2 | yes | -- | -| -- | 3 | yes | cc1101_ext | -| -- | 4 | yes | cc1101_ext | -| -- | 5 | yes | cc1101_ext | -| -- | 6 | yes | SPI | -| -- | 7 | yes | SPI | +| DMA | Channel | System | Purpose | +|:------:|:-------:|:------:|:-----------------------------| +| DMA1 | 1 | yes | digital signal | +| -- | 2 | yes | -- | +| -- | 3 | | | +| -- | 4 | yes | pulse reader | +| -- | 5 | | | +| -- | 6 | yes | USART_Rx | +| -- | 7 | yes | LPUART_Rx | +| DMA2 | 1 | yes | infrared, lfrfid, subghz, | +| -- | 2 | yes | -- | +| -- | 3 | yes | cc1101_ext | +| -- | 4 | yes | cc1101_ext | +| -- | 5 | yes | cc1101_ext | +| -- | 6 | yes | SPI | +| -- | 7 | yes | SPI | diff --git a/documentation/HowToBuild.md b/documentation/HowToBuild.md index ddf759f1b8..eec2e632a9 100644 --- a/documentation/HowToBuild.md +++ b/documentation/HowToBuild.md @@ -1,4 +1,3 @@ - # How to Build by yourself: ## Install required software @@ -15,9 +14,10 @@ You should clone with ```shell $ git clone --recursive https://github.com/DarkFlippers/unleashed-firmware.git ``` + ## VSCode integration -`fbt` includes basic development environment configuration for VS Code. Run `./fbt vscode_dist` to deploy it. That will copy the initial environment configuration to the `.vscode` folder. After that, you can use that configuration by starting VS Code and choosing the firmware root folder in the "File > Open Folder" menu. +`fbt` includes basic development environment configuration for VSCode. Run `./fbt vscode_dist` to deploy it. That will copy the initial environment configuration to the `.vscode` folder. After that, you can use that configuration by starting VSCode and choosing the firmware root folder in the `File > Open Folder` menu. # Build on Linux/macOS @@ -31,7 +31,6 @@ Check out `documentation/fbt.md` for details on building and flashing firmware. ### Compile everything for development - ```sh ./fbt updater_package ``` @@ -44,8 +43,7 @@ Check out `documentation/fbt.md` for details on building and flashing firmware. Check `dist/` for build outputs. -Use **`flipper-z-{target}-update-{suffix}.tgz`** to flash your device. - +Use `flipper-z-{target}-update-{suffix}.tgz` to flash your device. # Build on Windows @@ -53,23 +51,20 @@ Check out `documentation/fbt.md` for details on building and flashing firmware. ### Compile everything for development - -```sh +```powershell ./fbt.cmd updater_package ``` ### Compile everything for release + get updater package to update from microSD card -```sh +```powershell ./fbt.cmd COMPACT=1 DEBUG=0 updater_package ``` -**You may need to change** `/` **to** `\` **in front of fbt command (Only for Windows)!** +**You may need to change `/` to `\` in front of fbt command (Only for Windows)!** Check `dist/` for build outputs. -Use **`flipper-z-{target}-update-{suffix}.tgz`** to flash your device. - - +Use `flipper-z-{target}-update-{suffix}.tgz` to flash your device. If compilation fails, make sure all submodules are all initialized. Either clone with `--recursive` or use `git submodule update --init --recursive`. diff --git a/documentation/devboard/Firmware update on Developer Board.md b/documentation/devboard/Firmware update on Developer Board.md index f6a81d97b6..0df5c1f7de 100644 --- a/documentation/devboard/Firmware update on Developer Board.md +++ b/documentation/devboard/Firmware update on Developer Board.md @@ -1,10 +1,13 @@ # Firmware update on Developer Board {#dev_board_fw_update} -It's important to regularly update your Developer Board to ensure that you have access to the latest features and bug fixes. This tutorial will guide you through the necessary steps to update the firmware of your Developer Board. +> [!IMPORTANT] +> +> It's important to regularly update your Developer Board to ensure that you have access to the latest features and bug fixes. +> This tutorial will guide you through the necessary steps to update the firmware of your Developer Board. -This tutorial assumes that you're familiar with the basics of the command line. If you’re not, please refer to the [Windows](https://www.digitalcitizen.life/command-prompt-how-use-basic-commands/) or [MacOS/Linux](https://ubuntu.com/tutorials/command-line-for-beginners#1-overview) command line tutorials. +This tutorial assumes that you're familiar with the basics of the command line. -*** +If you’re not, please refer to the [Windows](https://www.digitalcitizen.life/command-prompt-how-use-basic-commands/) or [MacOS / Linux](https://ubuntu.com/tutorials/command-line-for-beginners#1-overview) command line tutorials. ## Installing the micro Flipper Build Tool @@ -14,20 +17,18 @@ Install uFBT on your computer by running the following command in the Terminal: **For Linux & macOS:** -```text +```bash python3 -m pip install --upgrade ufbt ``` **For Windows:** -```text -py -m pip install --upgrade ufbt +```powershell +python -m pip install --upgrade ufbt ``` If you want to learn more about uFBT, visit [the project's page](https://pypi.org/project/ufbt/). -*** - ## Connecting the Developer Board to your computer 1. List all of the serial devices on your computer. @@ -38,49 +39,38 @@ If you want to learn more about uFBT, visit [the project's page](https://pypi.or **macOS** - On macOS, you can run the following command in the Terminal: - - ```text + On macOS, you can run the following command in the Terminal: + ```bash ls /dev/cu.* ``` **Linux** - On Linux, you can run the following command in the Terminal: - + On Linux, you can run the following command in the Terminal: ```text ls /dev/tty* ``` - View the devices in the list. - 2. Connect the Developer Board to your computer using a USB-C cable. -![The Developer Board in Wired mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/Aq7gfMI-m_5H6sGGjwb4I_monosnap-miro-2023-07-19-19-47-39.jpg) - -3. Switch your Developer Board to Bootloader mode: - +![The Developer Board in Wired mode](https://github.com/user-attachments/assets/d13e4e90-d83d-45bf-8787-6eadba590795) +4. Switch your Developer Board to Bootloader mode: 3.1. Press and hold the **BOOT** button. - 3.2. Press the **RESET** button while holding the **BOOT** button. - - 3.3. Release the **BOOT** button.\ -![You can easily switch the Dev Board to Bootloader mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/KynP9iT6sJ3mXLaLyI82__image.png) - -4. Repeat Step 1 and view the name of your Developer Board that appeared in the list. + 3.3. Release the **BOOT** button. + ![You can easily switch the Dev Board to Bootloader mode](https://github.com/user-attachments/assets/aecc957f-f37b-4bec-af9f-9efd4837152e) +6. Repeat Step 1 and view the name of your Developer Board that appeared in the list. For example, on macOS: - ```text + ```shell /dev/cu.usbmodem01 ``` -*** - ## Flashing the firmware To flash the firmware onto your Developer Board, run the following command in the terminal: -```text +```shell python3 -m ufbt devboard_flash ``` @@ -90,33 +80,25 @@ You should see the following message: `WiFi board flashed successfully`. If you get an error message during the flashing process, such as this: -```text +```shell A fatal error occurred: Serial data stream stopped: Possible serial noise or corruption. ``` Or this: -```text +```shell FileNotFoundError: [Errno 2] No such file or directory: '/dev/cu.usbmodem01' ``` Try doing the following: - * Disconnect the Developer Board from your computer, then reconnect it. - * Use a different USB port on your computer. - * Use a different USB-C cable. -*** - ## Finishing the installation After flashing the firmware: - -1. Reboot the Developer Board by pressing the **RESET** button. -![Reset the Developer Board](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/rcQeKARgrVwa51tLoo-qY_monosnap-miro-2023-07-20-18-29-33.jpg) - -2. Disconnect and reconnect the USB-C cable. +1. Reboot the Developer Board by pressing the **RESET** button. ![Reset the Developer Board](https://github.com/user-attachments/assets/7527dd7b-eaa5-4fac-8d67-7ba52e552756) +3. Disconnect and reconnect the USB-C cable. The Developer Board should appear as a serial device on your computer. Now, you can use it with the Black Magic Debug client of your choice. diff --git a/documentation/devboard/Get started with the Dev Board.md b/documentation/devboard/Get started with the Dev Board.md index 04fa9d3589..a679ccb11e 100644 --- a/documentation/devboard/Get started with the Dev Board.md +++ b/documentation/devboard/Get started with the Dev Board.md @@ -2,35 +2,34 @@ The Wi-Fi Developer Board serves as a tool to debug the Flipper Zero firmware. To debug the firmware, the initial step involves compiling the firmware from its source code. This process enables the debugging functionality within the firmware and generates all the necessary files required for debugging purposes. -> **NOTE:** Building and debugging the Flipper Zero firmware is fully supported on MacOS and Linux. Support for Windows is in beta test. - -*** +> [!IMPORTANT] +> +> Building and debugging the Flipper Zero firmware is fully supported on MacOS and Linux. +> Support for Windows is in beta test. ## Updating the firmware of your Developer Board Update the firmware of your Developer Board before using it. For more information, visit [Firmware update on Developer Board](https://docs.flipperzero.one/development/hardware/wifi-debugger-module/update). -*** - ## Installing Git You'll need Git installed on your computer to clone the firmware repository. If you don't have Git, install it by doing the following: -* **MacOS** +### MacOS - On MacOS, install the **Xcode Command Line Tools** package, which includes Git as one of the pre-installed command-line utilities, by running in the Terminal the following command: +On MacOS, install the **Xcode Command Line Tools** package, which includes Git as one of the pre-installed command-line utilities, by running in the Terminal the following command: - ```text - xcode-select --install - ``` +```bash +xcode-select --install +``` -* **Linux** +### Linux - On Linux, you can install Git using your package manager. For example, on Ubuntu, run in the Terminal the following command: +On Linux, you can install Git using your package manager. For example, on Ubuntu, run in the Terminal the following command: - ```text - sudo apt install git - ``` +```bash +sudo apt install git +``` For other distributions, refer to your package manager documentation. @@ -40,14 +39,14 @@ For other distributions, refer to your package manager documentation. First, clone the firmware repository: -```text +```bash git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git cd flipperzero-firmware ``` Then, run the **Flipper Build Tool** (FBT) to build the firmware: -```text +```bash ./fbt ``` @@ -57,13 +56,15 @@ Then, run the **Flipper Build Tool** (FBT) to build the firmware: The Developer Board can work in the **Wired** mode and two **Wireless** modes: **Wi-Fi access point (AP)** mode and **Wi-Fi client (STA)** mode. The Wired mode is the simplest to set up, but requires a USB Type-C cable. The Wireless modes are more complex to set up, but they allow you to debug your Flipper Zero wirelessly. - > **NOTE:** Use the following credentials when connecting to the Developer Board in **Wi-Fi access point** mode:\n - Name: **blackmagic**\n - Password: **iamwitcher** +> [!TIP] +> +> Use the following credentials when connecting to the Developer Board in **Wi-Fi access point** mode: +> Name: **blackmagic** +> Password: **iamwitcher** ## Wired -![The Developer Board in Wired mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/jZdVlRTPVdSQVegzCyXp7_monosnap-miro-2023-06-22-16-28-06.jpg) +![The Developer Board in Wired mode](https://github.com/user-attachments/assets/32938d4a-20b7-4a53-8b36-608cf0112c9a) To connect the Developer Board in **Wired** mode, do the following: @@ -71,83 +72,81 @@ To connect the Developer Board in **Wired** mode, do the following: 2. On your computer, open the **Terminal** and run the following: - * **MacOS** - - ```text - ls /dev/cu.* - ``` - - * **Linux** - - ```text - ls /dev/tty* - ``` - - Note the list of devices. + ### MacOS + + ```shell + ls /dev/cu.* + ``` + + ### Linux + + ```bash + ls /dev/tty* + ``` + + Note the list of devices. 3. Connect the Developer Board to your computer via a USB-C cable. 4. Rerun the command. Two new devices have to appear: this is the Developer Board. - > **NOTE:** If the Developer Board doesn't appear in the list of devices, try using a different cable, USB port, or computer. - > - > **NOTE:** Flipper Zero logs can only be viewed when the Developer Board is connected via USB. The option to view logs over Wi-Fi will be added in future updates. For more information, visit [Reading logs via the Dev Board](https://docs.flipperzero.one/development/hardware/wifi-debugger-module/reading-logs). +> [!NOTE] +> +> If the Developer Board doesn't appear in the list of devices, try using a different cable, USB port, or computer. + +
    + +> [!IMPORTANT] +> +> Flipper Zero logs can only be viewed when the Developer Board is connected via USB. +> The option to view logs over Wi-Fi will be added in future updates. +> For more information, visit [Reading logs via the Dev Board](https://docs.flipperzero.one/development/hardware/wifi-debugger-module/reading-logs). ## Wireless ### Wi-Fi access point (AP) mode -![The Developer Board in Wi-Fi access point mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/tKRTMHAuruiLSEce2a8Ve_monosnap-miro-2023-06-22-16-39-17.jpg) +![The Developer Board in Wi-Fi access point mode](https://github.com/user-attachments/assets/1f210e91-3ac8-4f4c-a910-cc7c52b94346) Out of the box, the Developer Board is configured to work as a **Wi-Fi access point**. This means it'll create its own Wi-Fi network to which you can connect. If your Developer Board doesn't create a Wi-Fi network, it is probably configured to work in **Wi-Fi client** mode. To reset your Developer Board back to **Wi-Fi access point** mode, press and hold the **BOOT** button for 10 seconds, then wait for the module to reboot. -![You can reconfigure the Developer Board mode by pressing and holding the BOOT button](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/57eELJsAwMxeZCEA1NMJw_monosnap-miro-2023-06-22-20-33-27.jpg) +![You can reconfigure the Developer Board mode by pressing and holding the BOOT button](https://github.com/user-attachments/assets/8fee05de-fb1e-475a-b23a-d1ddca9cd701) To connect the Developer Board in **Wi-Fi access point** mode, do the following: 1. Cold-plug the Developer Board by turning off your Flipper Zero and connecting the Developer Board, and then turning it back on. - 2. Open Wi-Fi settings on your client device (phone, laptop, or other). - 3. Connect to the network: - - * Name: **blackmagic** - - * Password: **iamwitcher** - + * Name: `blackmagic` + * Password: `iamwitcher` 4. To configure the Developer Board, open a browser and go to `http://192.168.4.1`. ### Wi-Fi client (STA) mode -![The Developer Board in Wi-Fi client mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/xLQpFyYPfUS5Cx0uQhrNd_monosnap-miro-2023-06-23-12-34-36.jpg) +![The Developer Board in Wi-Fi client mode](https://github.com/user-attachments/assets/42e7e69e-51b0-4914-b082-431c68bc75d3) To connect the Developer Board in **Wi-Fi client** mode, you need to configure it to connect to your Wi-Fi network by doing the following: 1. Cold-plug the Developer Board by turning off your Flipper Zero and connecting the Developer Board, and then turning it back on. - 2. Connect to the Developer Board in **Wi-Fi access point** mode. - 3. In a browser, go to the configuration page on `http://192.168.4.1`. - 4. Select the **STA** mode and enter your network's **SSID** (name) and **password**. For convenience, you can click the **+** button to see the list of nearby networks. - 5. Save the configuration and reboot the Developer Board. +6. In the Wi-Fi tab, you can set the Developer Board mode -![In the Wi-Fi tab, you can set the Developer Board mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/klbLVj8lz2bEvm7j4wRaj_monosnap-miro-2023-06-23-13-06-32.jpg) +![Developer Board mode](https://github.com/user-attachments/assets/fbeea000-1117-4297-8a0d-5d580123e938) -After rebooting, the Developer Board connects to your Wi-Fi network. You can connect to the device using the mDNS name **blackmagic.local** or the IP address it got from your router (you'll have to figure this out yourself, every router is different). +After rebooting, the Developer Board connects to your Wi-Fi network. You can connect to the device using the mDNS name `blackmagic.local` or the IP address it got from your router (you'll have to figure this out yourself, every router is different). -After connecting to your debugger via , you can find its IP address in the **SYS** tab. You can also change the debugger's mode to **AP** or **STA** there. +After connecting to your debugger via [http://blackmagic.local](http://blackmagic.local), you can find its IP address in the **SYS** tab. You can also change the debugger's mode to **AP** or **STA** there. -![In the SYS tab, you can view the IP address of your Developer Board](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/5XbUptlfqzlV0p6hRUqiG_monosnap-miro-2023-06-22-18-11-30.jpg) - -*** +![In the SYS tab, you can view the IP address of your Developer Board](https://github.com/user-attachments/assets/aa3afc64-a2ec-46a6-a827-eea187a97c04) ## Debugging the firmware -Open the **Terminal** in the **flipperzero-firmware** directory that you cloned earlier and run the following command: +Open the **Terminal** in the `flipperzero-firmware` directory that you cloned earlier and run the following command: -```text +```bash ./fbt flash ``` @@ -155,24 +154,22 @@ This will upload the firmware you've just built to your Flipper Zero via the Dev To debug in **VSCode**, do the following: -1. In VSCode, open the **flipperzero-firmware** directory. - +1. In VSCode, open the `flipperzero-firmware` directory. 2. You should see a notification about recommended extensions. Install them. - - If there were no notifications, open the **Extensions** tab, enter `@recommended` in the search bar, and install the workspace recommendations. - +> [!TIP] +> +> If there were no notifications, open the `Extensions` tab, +> enter `@recommended` in the search bar, +> and install the workspace recommendations. +> 3. In the **Terminal**, run the `./fbt vscode_dist` command. This will generate the VSCode configuration files needed for debugging. - 4. In VSCode, open the **Run and Debug** tab and select **Attach FW (blackmagic)** from the dropdown menu. - 5. If needed, flash your Flipper Zero with the `./fbt flash` command, then click the **Play** button in the debug sidebar to start the debugging session. - 6. Note that starting a debug session halts the execution of the firmware, so you'll need to click the **Continue** button on the toolbar at the top of your VSCode window to continue execution. -![Click Continue in the toolbar to continue execution of the firmware](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/lp8ygGaZ3DvWD3OSI9yGO_monosnap-miro-2023-06-23-17-58-09.jpg) +![Click Continue in the toolbar to continue execution of the firmware](https://github.com/user-attachments/assets/74f26bdb-8511-4e5a-8aa8-c44212aa6228) To learn about debugging, visit the following pages: * [Debugging with GDB](https://sourceware.org/gdb/current/onlinedocs/gdb.pdf) - -* [Debugging in VS Code](https://code.visualstudio.com/docs/editor/debugging) +* [Debugging in VSCode](https://code.visualstudio.com/docs/editor/debugging) diff --git a/documentation/devboard/Reading logs via the Dev Board.md b/documentation/devboard/Reading logs via the Dev Board.md index e9fc0e2ca8..41461b1cdc 100644 --- a/documentation/devboard/Reading logs via the Dev Board.md +++ b/documentation/devboard/Reading logs via the Dev Board.md @@ -2,17 +2,16 @@ The Developer Board allows you to read Flipper Zero logs via UART. Unlike reading logs via the command-line interface (CLI), the Developer Board enables you to collect logs from the device directly to a serial console independently from the operating system of Flipper Zero. It allows you to see the device's logs when it's loading, updating, or crashing. It's useful for debugging and troubleshooting during software development. -> **NOTE:** Flipper Zero logs can only be viewed when the developer board is connected via USB. The option to view logs over Wi-Fi will be added in future updates. - -*** +> [!NOTE] +> +> Flipper Zero logs can only be viewed when the developer board is connected via USB. +> The option to view logs over Wi-Fi will be added in future updates. ## Setting the log level -Depending on your needs, you can set the log level by going to **Main Menu -> Settings -> Log Level**. To learn more about logging levels, visit [Settings](https://docs.flipperzero.one/basics/settings#d5TAt). - -![You can manually set the preferred log level](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/INzQMw8QUsG9PXi30WFS0_monosnap-miro-2023-07-11-13-29-47.jpg) +Depending on your needs, you can set the log level by going to `Main Menu -> Settings -> Log Level`. To learn more about logging levels, visit [Settings](https://docs.flipperzero.one/basics/settings#d5TAt). -*** +![You can manually set the preferred log level](https://github.com/user-attachments/assets/b1317d01-8b9b-4544-8720-303c87b85324) ## Viewing Flipper Zero logs @@ -20,118 +19,94 @@ Depending on your operating system, you need to install an additional applicatio ### MacOS -On MacOS, you need to install the **minicom** communication program by doing the following: +On MacOS, you need to install the `minicom` communication program by doing the following: 1. [Install Homebrew](https://brew.sh/) by running the following command in the Terminal: - - ```text - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - ``` - -2. After installation of Homebrew, run the following command to install minicom: - - ```text + ```bash + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + ``` +2. After installation of Homebrew, run the following command to install `minicom`: + ```bash brew install minicom ``` -After installation of minicom on your macOS computer, you can connect to the Developer Board to read Flipper Zero logs by doing the following: +After installation of `minicom` on your macOS computer, you can connect to the Developer Board to read Flipper Zero logs by doing the following: 1. Cold-plug the Developer Board into your Flipper Zero by turning off the Flipper Zero, connecting the developer board, and then turning it back on. - 2. On your computer, open the Terminal and run the following command: - - ```text + ```bash ls /dev/cu.* ``` - - Note the list of devices. - +> [!NOTE] +> +> The list of devices. 3. Connect the developer board to your computer using a USB Type-C cable. -![Connect the developer board with a USB-C cable](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/iPpsMt2-is4aIjiVeFu5t_hjxs2i1oovrnps74v5jgsimage.png) - -4. Rerun the command. Two new devices have to appear: this is the Developer Board. - - ```text + ![Connect the developer board with a USB-C cable](https://github.com/user-attachments/assets/0f469a31-2dd1-4559-918a-ff3ca3309531) +5. Rerun the command. Two new devices have to appear: this is the Developer Board. + ```bash /dev/cu.usbmodemblackmagic1 ``` - - ```text + ```bash /dev/cu.usbmodemblackmagic3 ``` - - Your Developer Board might have different names. - -5. Run the following command: - - ```text - minicom -D /dev/ -b 230400 - ``` - +> [!NOTE] +> +> Your Developer Board might have different names. +6. Run the following command: + ```bash + minicom -D /dev/ -b 230400 + ``` Where `` is the name of your device with a bigger number. - Example: - - ```text + ```bash minicom -D /dev/cu.usbmodemblackmagic3 -b 230400 ``` - -6. View logs of your Flipper Zero in the Terminal. - -7. To quit, close the minicom window or quit via the minicom menu. +7. View logs of your Flipper Zero in the Terminal. +8. To quit, close the `minicom` window or quit via the `minicom` menu. ### Linux -On Linux, you need to install the **minicom** communication program. For example, on Ubuntu, run in the Terminal the following command: +On Linux, you need to install the `minicom` communication program. For example, on Ubuntu, run in the Terminal the following command: -```text +```bash sudo apt install minicom - ``` +``` -After installation of minicom on your Linux computer, you can connect to the Developer Board to read Flipper Zero logs by doing the following: +After installation of `minicom` on your Linux computer, you can connect to the Developer Board to read Flipper Zero logs by doing the following: 1. Cold-plug the Developer Board into your Flipper Zero by turning off the Flipper Zero, connecting the developer board, and then turning it back on. - 2. On your computer, open the Terminal and run the following command: - - ```text + ```bash ls /dev/tty* ``` - Note the list of devices. - 3. Connect the developer board to your computer using a USB Type-C cable. -![Connect the developer board with a USB-C cable](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/iPpsMt2-is4aIjiVeFu5t_hjxs2i1oovrnps74v5jgsimage.png) - + ![Connect the developer board with a USB-C cable](https://github.com/user-attachments/assets/0f469a31-2dd1-4559-918a-ff3ca3309531) 4. Rerun the command. Two new devices have to appear: this is the Developer Board. - - ```text + ```bash /dev/ttyACM0 ``` - - ```text + ```bash /dev/ttyACM1 ``` - - Your Developer Board might have different names. - +> [!NOTE] +> +> Your Developer Board might have different names. 5. Run the following command: - - ```text + ```bash minicom -D /dev/ -b 230400 ``` - Where `` is the name of your device with a bigger number. - Example: - - ```text + ```bash minicom -D /dev/cu.usbmodemblackmagic3 -b 230400 ``` - 6. View logs of your Flipper Zero in the Terminal. - - **NOTE:** If no logs are shown in the Terminal, try running the command from Step 5 with another device name. - +> [!NOTE] +> +> If no logs are shown in the Terminal, +> try running the command from Step 5 with another device name. +> 7. To quit, close the minicom window or quit via the minicom menu. ### Windows @@ -139,22 +114,14 @@ After installation of minicom on your Linux computer, you can connect to the Dev On Windows, do the following: 1. On your computer, [install the PuTTY application](https://www.chiark.greenend.org.uk/\~sgtatham/putty/latest.html). - 2. Cold-plug the Developer Board into your Flipper Zero by turning off the Flipper Zero, connecting the developer board, and then turning it back on. - 3. Connect the developer board to your computer using a USB Type-C cable. -![Connect the developer board with a USB-C cable](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/iPpsMt2-is4aIjiVeFu5t_hjxs2i1oovrnps74v5jgsimage.png) - -4. Find the serial port that the developer board is connected to by going to **Device Manager -> Ports (COM & LPT)** and looking for a new port that appears when you connect the Wi-Fi developer board. -![Find the serial port in your Device Manager](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/KKLQJK1lvqmI5iab3d__C_image.png) - -5. Run the PuTTY application and select **Serial** as the connection type. - -6. Enter the port number you found in the previous step into the **Serial line** field. - -7. Set the **Speed** parameter to **230400** and click **Open**. -![Set speed to 230400](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/ROBSJyfQ_CXiy4GUZcPbs_monosnap-miro-2023-07-12-13-56-47.jpg) - -8. View logs of your Flipper Zero in the PuTTY terminal window. - -9. To quit, close the PuTTY window. + ![Connect the developer board with a USB-C cable](https://github.com/user-attachments/assets/0f469a31-2dd1-4559-918a-ff3ca3309531) +4. Find the serial port that the developer board is connected to by going to `Device Manager -> Ports (COM & LPT)` and looking for a new port that appears when you connect the Wi-Fi developer board. + ![Find the serial port in your Device Manager](https://github.com/user-attachments/assets/aa542fe6-4781-45dc-86f6-e98ab34952b0) +6. Run the `PuTTY` application and select `Serial` as the connection type. +7. Enter the port number you found in the previous step into the `Serial line` field. +8. Set the `Speed` parameter to `230400` and click `Open`. + ![Set speed to 230400](https://github.com/user-attachments/assets/93463c78-9776-479b-a6cc-d68ed712d0c4) +10. View logs of your Flipper Zero in the PuTTY terminal window. +11. To quit, close the PuTTY window. diff --git a/documentation/fbt.md b/documentation/fbt.md index 8e083349f7..4009822f85 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -9,24 +9,35 @@ If you don't need all features of `fbt` - like building the whole firmware - and To use `fbt`, you only need `git` installed in your system. -`fbt` by default downloads and unpacks a pre-built toolchain, and then modifies environment variables for itself to use it. It does not contaminate your global system's path with the toolchain. - > However, if you wish to use tools supplied with the toolchain outside `fbt`, you can open an *fbt shell*, with properly configured environment. - > - On Windows, simply run `scripts/toolchain/fbtenv.cmd`. - > - On Linux & MacOS, run `source scripts/toolchain/fbtenv.sh` in a new shell. - > - You can also type ```. `./fbt -s env` ``` in your shell. (Keep the "." at the beginning.) +`fbt` by default downloads and unpacks a pre-built toolchain, and then modifies environment variables for itself to use it. +It does not contaminate your global system's path with the toolchain. + +> [!NOTE] +> +> However, if you wish to use tools supplied with the toolchain outside `fbt`, +> you can open an *fbt shell*, with properly configured environment. +> +> - On Windows, simply run `scripts/toolchain/fbtenv.cmd`. +> - On Linux & MacOS, run `source scripts/toolchain/fbtenv.sh` in a new shell. +> - You can also type ```. `./fbt -s env` ``` in your shell. (Keep the "." at the beginning.) - If your system is not supported by pre-built toolchain variants or you want to use custom versions of dependencies, you can `set FBT_NOENV=1`. `fbt` will skip toolchain & environment configuration and will expect all tools to be available on your system's `PATH`. *(this option is not available on Windows)* +If your system is not supported by pre-built toolchain variants or you want to use custom versions of dependencies, you can `set FBT_NOENV=1`. - If `FBT_TOOLCHAIN_PATH` variable is set, `fbt` will use that directory to unpack toolchain into. By default, it downloads toolchain into `toolchain` subdirectory repo's root. +`fbt` will skip toolchain & environment configuration and will expect all tools to be available on your system's `PATH`. *(this option is not available on Windows)* + +If `FBT_TOOLCHAIN_PATH` variable is set, `fbt` will use that directory to unpack toolchain into. By default, it downloads toolchain into `toolchain` subdirectory repo's root. If you want to enable extra debug output for `fbt` and toolchain management scripts, you can `set FBT_VERBOSE=1`. `fbt` always performs `git submodule update --init` on start, unless you set `FBT_NO_SYNC=1` in the environment: - - On Windows, it's `set "FBT_NO_SYNC=1"` in the shell you're running `fbt` from - - On \*nix, it's `$ FBT_NO_SYNC=1 ./fbt ...` - - > There are more variables controlling basic `fbt` behavior. See `fbt` & `fbtenv` scripts' sources for details. +- On Windows, it's `set "FBT_NO_SYNC=1"` in the shell you're running `fbt` from +- On \*nix, it's `$ FBT_NO_SYNC=1 ./fbt ...` +> [!NOTE] +> +> There are more variables controlling basic `fbt` behavior. +> See `fbt` & `fbtenv` scripts' sources for details. +> ## Invoking FBT @@ -38,22 +49,34 @@ To run cleanup (think of `make clean`) for specified targets, add the `-c` optio ## Build directories -`fbt` builds updater & firmware in separate subdirectories in `build`, and their names depend on optimization settings (`COMPACT` & `DEBUG` options). However, for ease of integration with IDEs, the latest built variant's directory is always linked as `built/latest`. Additionally, `compile_commands.json` is generated in that folder (it is used for code completion support in IDEs). +`fbt` builds updater & firmware in separate subdirectories in `build`, and their names depend on optimization settings (`COMPACT` & `DEBUG` options). + +However, for ease of integration with IDEs, the latest built variant's directory is always linked as `built/latest`. + +Additionally, `compile_commands.json` is generated in that folder (it is used for code completion support in IDEs). -`build/latest` symlink & compilation database are only updated upon *firmware build targets* - that is, when you're re-building the firmware itself. Running other tasks, like firmware flashing or building update bundles *for a different debug/release configuration or hardware target*, does not update `built/latest` dir to point to that configuration. +`build/latest` symlink & compilation database are only updated upon *firmware build targets* - that is, when you're re-building the firmware itself. + +Running other tasks, like firmware flashing or building update bundles *for a different debug/release configuration or hardware target*, does not update `built/latest` dir to point to that configuration. ## VSCode integration -`fbt` includes basic development environment configuration for VS Code. Run `./fbt vscode_dist` to deploy it. That will copy the initial environment configuration to the `.vscode` folder. After that, you can use that configuration by starting VS Code and choosing the firmware root folder in the "File > Open Folder" menu. +`fbt` includes basic development environment configuration for VSCode. Run `./fbt vscode_dist` to deploy it. + +That will copy the initial environment configuration to the `.vscode` folder. -To use language servers other than the default VS Code C/C++ language server, use `./fbt vscode_dist LANG_SERVER=` instead. Currently `fbt` supports the default language server (`cpptools`) and `clangd`. +After that, you can use that configuration by starting VSCode and choosing the firmware root folder in the File > Open Folder menu. + +To use language servers other than the default VS Code C/C++ language server, use `./fbt vscode_dist LANG_SERVER=` instead. + +Currently `fbt` supports the default language server (`cpptools`) and `clangd`. - On the first start, you'll be prompted to install recommended plugins. We highly recommend installing them for the best development experience. _You can find a list of them in `.vscode/extensions.json`._ -- Basic build tasks are invoked in the Ctrl+Shift+B menu. +- Basic build tasks are invoked in the Ctrl + Shift + B menu. - Debugging requires a supported probe. That includes: - Wi-Fi devboard with stock firmware (blackmagic). - ST-Link and compatible devices. - - J-Link for flashing and debugging (in VSCode only). _Note that J-Link tools are not included with our toolchain and you have to [download](https://www.segger.com/downloads/jlink/) them yourself and put them on your system's PATH._ + - J-Link for flashing and debugging (in VSCode only). _Note that J-Link tools are not included with our toolchain and you have to [download](https://www.segger.com/downloads/jlink/) them yourself and put them on your system's `PATH`. - Without a supported probe, you can install firmware on Flipper using the USB installation method. ## FBT targets @@ -68,7 +91,7 @@ To use language servers other than the default VS Code C/C++ language server, us - `copro_dist` - bundle Core2 FUS+stack binaries for qFlipper. - `flash` - flash the attached device over SWD interface with supported probes. Probe is detected automatically; you can override it with `SWD_TRANSPORT=...` variable. If multiple probes are attached, you can specify the serial number of the probe to use with `SWD_TRANSPORT_SERIAL=...`. - `flash_usb`, `flash_usb_full` - build, upload and install the update package to the device over USB. See details on `updater_package` and `updater_minpackage`. -- `debug` - build and flash firmware, then attach with gdb with firmware's .elf loaded. +- `debug` - build and flash firmware, then attach with gdb with firmware's `.elf` loaded. - `debug_other`, `debug_other_blackmagic` - attach GDB without loading any `.elf`. It will allow you to manually add external `.elf` files with `add-symbol-file` in GDB. - `updater_debug` - attach GDB with the updater's `.elf` loaded. - `devboard_flash` - Update WiFi dev board. Supports `ARGS="..."` to pass extra arguments to the update script, e.g. `ARGS="-c dev"`. @@ -76,8 +99,10 @@ To use language servers other than the default VS Code C/C++ language server, us - `openocd` - just start OpenOCD. You can pass extra arguments with `ARGS="..."`. - `get_blackmagic` - output the blackmagic address in the GDB remote format. Useful for IDE integration. - `get_stlink` - output serial numbers for attached STLink probes. Used for specifying an adapter with `SWD_TRANSPORT_SERIAL=...`. -- `lint`, `format` - run clang-format on the C source code to check and reformat it according to the `.clang-format` specs. Supports `ARGS="..."` to pass extra arguments to clang-format. +- `lint`, `format` - run `clang-format` on the C source code to check and reformat it according to the `.clang-format` specs. Supports `ARGS="..."` to pass extra arguments to clang-format. - `lint_py`, `format_py` - run [black](https://black.readthedocs.io/en/stable/index.html) on the Python source code, build system files & application manifests. Supports `ARGS="..."` to pass extra arguments to black. +- `lint_img`, `format_img` - check the image assets for errors and format them. Enforces color depth and strips metadata. +- `lint_all`, `format_all` - run all linters and formatters. - `firmware_pvs` - generate a PVS Studio report for the firmware. Requires PVS Studio to be available on your system's `PATH`. - `doxygen` - generate Doxygen documentation for the firmware. `doxy` target also opens web browser to view the generated documentation. - `cli` - start a Flipper CLI session over USB. @@ -115,6 +140,7 @@ To use language servers other than the default VS Code C/C++ language server, us ## Configuration Default configuration variables are set in the configuration file: `fbt_options.py`. + Values set in the command line have higher precedence over the configuration file. You can also create a file called `fbt_options_local.py` that will be evaluated when loading default options file, enabling persisent overriding of default options without modifying default configuration. @@ -123,7 +149,12 @@ You can find out available options with `./fbt -h`. ### Firmware application set -You can create customized firmware builds by modifying the list of applications to be included in the build. Application presets are configured with the `FIRMWARE_APPS` option, which is a `map(configuration_name:str -> application_list:tuple(str))`. To specify an application set to use in the build, set `FIRMWARE_APP_SET` to its name. +You can create customized firmware builds by modifying the list of applications to be included in the build. + +Application presets are configured with the `FIRMWARE_APPS` option, which is a `map(configuration_name:str -> application_list:tuple(str))`. + +To specify an application set to use in the build, set `FIRMWARE_APP_SET` to its name. + For example, to build a firmware image with unit tests, run `./fbt FIRMWARE_APP_SET=unit_tests`. Check out `fbt_options.py` for details. diff --git a/documentation/file_formats/BadUsbScriptFormat.md b/documentation/file_formats/BadUsbScriptFormat.md index 1bac3c4aa4..0b8381c1e8 100644 --- a/documentation/file_formats/BadUsbScriptFormat.md +++ b/documentation/file_formats/BadUsbScriptFormat.md @@ -2,7 +2,10 @@ ## Command syntax -BadUsb app uses extended Duckyscript syntax. It is compatible with classic USB Rubber Ducky 1.0 scripts but provides some additional commands and features, such as custom USB ID, ALT+Numpad input method, SYSRQ command, and more functional keys. +BadUsb app uses extended DuckyScript syntax. + +It is compatible with classic USB Rubber Ducky 1.0 scripts but provides some additional commands and features, +such as custom USB ID, `ALT` + `Numpad` input method, `SYSRQ` command, and more functional keys. ## Script file format @@ -12,168 +15,181 @@ BadUsb app can execute only text scripts from `.txt` files, no compilation is re ### Comment line -Just a single comment line. The interpreter will ignore all text after the REM command. -| Command | Parameters | Notes | -| ------- | ------------ | ----- | -| REM | Comment text | | +Just a single comment line. The interpreter will ignore all text after the `REM` command. + +| Command | Parameters | Notes | +|:---------|:--------------|:--------| +| REM | Comment text | | ### Delay Pause script execution by a defined time. -| Command | Parameters | Notes | -| ------------- | ----------------- | ----------------------------------- | -| DELAY | Delay value in ms | Single delay | -| DEFAULT_DELAY | Delay value in ms | Add delay before every next command | -| DEFAULTDELAY | Delay value in ms | Same as DEFAULT_DELAY | + +| Command | Parameters | Notes | +|:--------------|:--------------------------|:--------------------------------------| +| DELAY | Delay value in ms | Single delay | +| DEFAULT_DELAY | Delay value in ms | Add delay before every next command | +| DEFAULTDELAY | Delay value in ms | Same as DEFAULT_DELAY | ### Special keys -| Command | Notes | -| ------------------ | ---------------- | -| DOWNARROW / DOWN | | -| LEFTARROW / LEFT | | -| RIGHTARROW / RIGHT | | -| UPARROW / UP | | -| ENTER | | -| DELETE | | -| BACKSPACE | | -| END | | -| HOME | | -| ESCAPE / ESC | | -| INSERT | | -| PAGEUP | | -| PAGEDOWN | | -| CAPSLOCK | | -| NUMLOCK | | -| SCROLLLOCK | | -| PRINTSCREEN | | -| BREAK | Pause/Break key | -| PAUSE | Pause/Break key | -| SPACE | | -| TAB | | -| MENU | Context menu key | -| APP | Same as MENU | -| Fx | F1-F12 keys | +| Command | Notes | +|:--------------------|:------------------| +| DOWNARROW / DOWN | | +| LEFTARROW / LEFT | | +| RIGHTARROW / RIGHT | | +| UPARROW / UP | | +| ENTER | | +| DELETE | | +| BACKSPACE | | +| END | | +| HOME | | +| ESCAPE / ESC | | +| INSERT | | +| PAGEUP | | +| PAGEDOWN | | +| CAPSLOCK | | +| NUMLOCK | | +| SCROLLLOCK | | +| PRINTSCREEN | | +| BREAK | Pause/Break key | +| PAUSE | Pause/Break key | +| SPACE | | +| TAB | | +| MENU | Context menu key | +| APP | Same as MENU | +| Fx | F1-F12 keys | ### Modifier keys Can be combined with a special key command or a single character. -| Command | Notes | -| -------------- | ---------- | -| CONTROL / CTRL | | -| SHIFT | | -| ALT | | -| WINDOWS / GUI | | -| CTRL-ALT | CTRL+ALT | -| CTRL-SHIFT | CTRL+SHIFT | -| ALT-SHIFT | ALT+SHIFT | -| ALT-GUI | ALT+WIN | -| GUI-SHIFT | WIN+SHIFT | -| GUI-CTRL | WIN+CTRL | + +| Command | Notes | +|:----------------|:-------------| +| CONTROL / CTRL | | +| SHIFT | | +| ALT | | +| WINDOWS / GUI | | +| CTRL-ALT | CTRL+ALT | +| CTRL-SHIFT | CTRL+SHIFT | +| ALT-SHIFT | ALT+SHIFT | +| ALT-GUI | ALT+WIN | +| GUI-SHIFT | WIN+SHIFT | +| GUI-CTRL | WIN+CTRL | ## Key hold and release Up to 5 keys can be hold simultaneously. -| Command | Parameters | Notes | -| ------- | ------------------------------- | ---------------------------------------- | -| HOLD | Special key or single character | Press and hold key until RELEASE command | -| RELEASE | Special key or single character | Release key | + +| Command | Parameters | Notes | +|:---------|:---------------------------------|:------------------------------------------| +| HOLD | Special key or single character | Press and hold key until RELEASE command | +| RELEASE | Special key or single character | Release key | ## String -| Command | Parameters | Notes | -| ------- | ----------- | ----------------- | -| STRING | Text string | Print text string | -| STRINGLN | Text string | Print text string and press enter after it | +| Command | Parameters | Notes | +|:----------|:-------------|:--------------------------------------------| +| STRING | Text string | Print text string | +| STRINGLN | Text string | Print text string and press enter after it | ## String delay -Delay between keypresses. -| Command | Parameters | Notes | -| -------------------- | ----------------- | --------------------------------------------- | -| STRING_DELAY | Delay value in ms | Applied once to next appearing STRING command | -| STRINGDELAY | Delay value in ms | Same as STRING_DELAY | -| DEFAULT_STRING_DELAY | Delay value in ms | Apply to every appearing STRING command | -| DEFAULTSTRINGDELAY | Delay value in ms | Same as DEFAULT_STRING_DELAY | +Delay between key presses. + +| Command | Parameters | Notes | +|:----------------------|:-------------------|:-----------------------------------------------| +| STRING_DELAY | Delay value in ms | Applied once to next appearing STRING command | +| STRINGDELAY | Delay value in ms | Same as STRING_DELAY | +| DEFAULT_STRING_DELAY | Delay value in ms | Apply to every appearing STRING command | +| DEFAULTSTRINGDELAY | Delay value in ms | Same as DEFAULT_STRING_DELAY | ### Repeat -| Command | Parameters | Notes | -| ------- | ---------------------------- | ----------------------- | -| REPEAT | Number of additional repeats | Repeat previous command | +| Command | Parameters | Notes | +|:---------|:------------------------------|:-------------------------| +| REPEAT | Number of additional repeats | Repeat previous command | ### ALT+Numpad input On Windows and some Linux systems, you can print characters by holding `ALT` key and entering its code on Numpad. | Command | Parameters | Notes | -| --------- | -------------- | --------------------------------------------------------------- | +| :---------- | :--------------- | :--------------------------------------------------------------- | | ALTCHAR | Character code | Print single character | | ALTSTRING | Text string | Print text string using ALT+Numpad method | -| ALTCODE | Text string | Same as ALTSTRING, presents in some Duckyscript implementations | +| ALTCODE | Text string | Same as ALTSTRING, presents in some DuckyScript implementations | ### SysRq Send [SysRq command](https://en.wikipedia.org/wiki/Magic_SysRq_key) -| Command | Parameters | Notes | -| ------- | ---------------- | ----- | -| SYSRQ | Single character | | + +| Command | Parameters | Notes | +|:---------|:------------------|:-------| +| SYSRQ | Single character | | ## Media keys -Some Media/Consumer Control keys can be pressed with "MEDIA" command - -| Command | Parameters | Notes | -| ------- | ------------------------- | ----- | -| MEDIA | Media key, see list below | | - -| Key name | Notes | -| ----------------- | ----------------------------- | -| POWER | | -| REBOOT | | -| SLEEP | | -| LOGOFF | | -| EXIT | | -| HOME | | -| BACK | | -| FORWARD | | -| REFRESH | | -| SNAPSHOT | Take photo in a camera app | -| PLAY | | -| PAUSE | | -| PLAY_PAUSE | | -| NEXT_TRACK | | -| PREV_TRACK | | -| STOP | | -| EJECT | | -| MUTE | | -| VOLUME_UP | | -| VOLUME_DOWN | | -| FN | Fn/Globe key on Mac keyboard | -| BRIGHT_UP | Increase display brightness | -| BRIGHT_DOWN | Decrease display brightness | +Some Media/Consumer Control keys can be pressed with `MEDIA` command + +| Command | Parameters | Notes | +|:---------|:---------------------------|:------| +| MEDIA | Media key, see list below | | + + +| Key name | Notes | +|:-------------------|:-------------------------------| +| POWER | | +| REBOOT | | +| SLEEP | | +| LOGOFF | | +| EXIT | | +| HOME | | +| BACK | | +| FORWARD | | +| REFRESH | | +| SNAPSHOT | Take photo in a camera app | +| PLAY | | +| PAUSE | | +| PLAY_PAUSE | | +| NEXT_TRACK | | +| PREV_TRACK | | +| STOP | | +| EJECT | | +| MUTE | | +| VOLUME_UP | | +| VOLUME_DOWN | | +| FN | Fn/Globe key on Mac keyboard | +| BRIGHT_UP | Increase display brightness | +| BRIGHT_DOWN | Decrease display brightness | ## Fn/Globe key commands (Mac/iPad) -| Command | Parameters | Notes | -| ------- | ------------------------------- | ----- | -| GLOBE | Special key or single character | | +| Command | Parameters | Notes | +|:---------|:---------------------------------|:-------| +| GLOBE | Special key or single character | | ## Wait for button press Will wait indefinitely for a button to be pressed -| Command | Parameters | Notes | -| --------------------- | ------------ | --------------------------------------------------------------------- | -| WAIT_FOR_BUTTON_PRESS | None | Will wait for the user to press a button to continue script execution | + +| Command | Parameters | Notes | +|:----------------------|:-----------|:------------------------------------------------------------------------------| +| WAIT_FOR_BUTTON_PRESS | None | Will wait for the user to press a button to continue script execution | ## USB device ID You can set the custom ID of the Flipper USB HID device. ID command should be in the **first line** of script, it is executed before script run. -| Command | Parameters | Notes | -| ------- | ---------------------------- | ----- | -| ID | VID:PID Manufacturer:Product | | +| Command | Parameters | Notes | +|:---------|:------------------------------|:-------| +| ID | VID:PID Manufacturer:Product | | Example: -`ID 1234:abcd Flipper Devices:Flipper Zero` - -VID and PID are hex codes and are mandatory. Manufacturer and Product are text strings and are optional. +```text +ID 1234:abcd Flipper Devices:Flipper Zero +``` + +> [!IMPORTANT] +> +> VID and PID are hex codes and are mandatory. +> Manufacturer and Product are text strings and are optional. diff --git a/documentation/file_formats/LfRfidFileFormat.md b/documentation/file_formats/LfRfidFileFormat.md index 2463195e40..6bad4a3c08 100644 --- a/documentation/file_formats/LfRfidFileFormat.md +++ b/documentation/file_formats/LfRfidFileFormat.md @@ -47,3 +47,4 @@ The file stores a single RFID key of the type defined by the `Key type` paramete | PAC/Stanley | PAC/Stanley | | Keri | Keri | | Gallagher | Gallagher | +| GProxII | Guardall GProx II | diff --git a/furi/core/event_loop.c b/furi/core/event_loop.c index 26401c84b2..2a6cd51d32 100644 --- a/furi/core/event_loop.c +++ b/furi/core/event_loop.c @@ -1,5 +1,4 @@ #include "event_loop_i.h" -#include "message_queue_i.h" #include "log.h" #include "check.h" @@ -22,13 +21,17 @@ static FuriEventLoopItem* furi_event_loop_item_alloc( static void furi_event_loop_item_free(FuriEventLoopItem* instance); +static void furi_event_loop_item_free_later(FuriEventLoopItem* instance); + static void furi_event_loop_item_set_callback( FuriEventLoopItem* instance, - FuriEventLoopMessageQueueCallback callback, + FuriEventLoopEventCallback callback, void* callback_context); static void furi_event_loop_item_notify(FuriEventLoopItem* instance); +static bool furi_event_loop_item_is_waiting(FuriEventLoopItem* instance); + static void furi_event_loop_process_pending_callbacks(FuriEventLoop* instance) { for(; !PendingQueue_empty_p(instance->pending_queue); PendingQueue_pop_back(NULL, instance->pending_queue)) { @@ -37,6 +40,21 @@ static void furi_event_loop_process_pending_callbacks(FuriEventLoop* instance) { } } +static bool furi_event_loop_signal_callback(uint32_t signal, void* arg, void* context) { + furi_assert(context); + FuriEventLoop* instance = context; + UNUSED(arg); + + switch(signal) { + case FuriSignalExit: + furi_event_loop_stop(instance); + return true; + // Room for possible other standard signal handlers + default: + return false; + } +} + /* * Main public API */ @@ -67,6 +85,7 @@ void furi_event_loop_free(FuriEventLoop* instance) { furi_event_loop_process_timer_queue(instance); furi_check(TimerList_empty_p(instance->timer_list)); + furi_check(WaitingList_empty_p(instance->waiting_list)); FuriEventLoopTree_clear(instance->tree); PendingQueue_clear(instance->pending_queue); @@ -81,21 +100,81 @@ void furi_event_loop_free(FuriEventLoop* instance) { free(instance); } -static FuriEventLoopProcessStatus - furi_event_loop_poll_process_event(FuriEventLoop* instance, FuriEventLoopItem* item) { - UNUSED(instance); - +static inline FuriEventLoopProcessStatus + furi_event_loop_poll_process_level_event(FuriEventLoopItem* item) { if(!item->contract->get_level(item->object, item->event)) { return FuriEventLoopProcessStatusComplete; + } else if(item->callback(item->object, item->callback_context)) { + return FuriEventLoopProcessStatusIncomplete; + } else { + return FuriEventLoopProcessStatusAgain; } +} +static inline FuriEventLoopProcessStatus + furi_event_loop_poll_process_edge_event(FuriEventLoopItem* item) { if(item->callback(item->object, item->callback_context)) { - return FuriEventLoopProcessStatusIncomplete; + return FuriEventLoopProcessStatusComplete; } else { return FuriEventLoopProcessStatusAgain; } } +static inline FuriEventLoopProcessStatus + furi_event_loop_poll_process_event(FuriEventLoop* instance, FuriEventLoopItem* item) { + FuriEventLoopProcessStatus status; + if(item->event & FuriEventLoopEventFlagOnce) { + furi_event_loop_unsubscribe(instance, item->object); + } + + if(item->event & FuriEventLoopEventFlagEdge) { + status = furi_event_loop_poll_process_edge_event(item); + } else { + status = furi_event_loop_poll_process_level_event(item); + } + + if(item->owner == NULL) { + status = FuriEventLoopProcessStatusFreeLater; + } + + return status; +} + +static void furi_event_loop_process_waiting_list(FuriEventLoop* instance) { + FuriEventLoopItem* item = NULL; + + FURI_CRITICAL_ENTER(); + + if(!WaitingList_empty_p(instance->waiting_list)) { + item = WaitingList_pop_front(instance->waiting_list); + WaitingList_init_field(item); + } + + FURI_CRITICAL_EXIT(); + + if(!item) return; + + while(true) { + FuriEventLoopProcessStatus ret = furi_event_loop_poll_process_event(instance, item); + + if(ret == FuriEventLoopProcessStatusComplete) { + // Event processing complete, break from loop + break; + } else if(ret == FuriEventLoopProcessStatusIncomplete) { + // Event processing incomplete more processing needed + } else if(ret == FuriEventLoopProcessStatusAgain) { //-V547 + furi_event_loop_item_notify(item); + break; + // Unsubscribed from inside the callback, delete item + } else if(ret == FuriEventLoopProcessStatusFreeLater) { //-V547 + furi_event_loop_item_free(item); + break; + } else { + furi_crash(); + } + } +} + static void furi_event_loop_restore_flags(FuriEventLoop* instance, uint32_t flags) { if(flags) { xTaskNotifyIndexed( @@ -107,10 +186,13 @@ void furi_event_loop_run(FuriEventLoop* instance) { furi_check(instance); furi_check(instance->thread_id == furi_thread_get_current_id()); - furi_event_loop_init_tick(instance); + // Set the default signal callback if none was previously set + if(furi_thread_get_signal_callback(instance->thread_id) == NULL) { + furi_thread_set_signal_callback( + instance->thread_id, furi_event_loop_signal_callback, instance); + } - furi_thread_set_signal_callback( - instance->thread_id, furi_event_loop_signal_callback, instance); + furi_event_loop_init_tick(instance); while(true) { instance->state = FuriEventLoopStateIdle; @@ -131,34 +213,7 @@ void furi_event_loop_run(FuriEventLoop* instance) { break; } else if(flags & FuriEventLoopFlagEvent) { - FuriEventLoopItem* item = NULL; - FURI_CRITICAL_ENTER(); - - if(!WaitingList_empty_p(instance->waiting_list)) { - item = WaitingList_pop_front(instance->waiting_list); - WaitingList_init_field(item); - } - - FURI_CRITICAL_EXIT(); - - if(item) { - while(true) { - FuriEventLoopProcessStatus ret = - furi_event_loop_poll_process_event(instance, item); - if(ret == FuriEventLoopProcessStatusComplete) { - // Event processing complete, break from loop - break; - } else if(ret == FuriEventLoopProcessStatusIncomplete) { - // Event processing incomplete more processing needed - } else if(ret == FuriEventLoopProcessStatusAgain) { //-V547 - furi_event_loop_item_notify(item); - break; - } else { - furi_crash(); - } - } - } - + furi_event_loop_process_waiting_list(instance); furi_event_loop_restore_flags(instance, flags & ~FuriEventLoopFlagEvent); } else if(flags & FuriEventLoopFlagTimer) { @@ -177,7 +232,10 @@ void furi_event_loop_run(FuriEventLoop* instance) { } } - furi_thread_set_signal_callback(instance->thread_id, NULL, NULL); + // Disable the default signal callback + if(furi_thread_get_signal_callback(instance->thread_id) == furi_event_loop_signal_callback) { + furi_thread_set_signal_callback(instance->thread_id, NULL, NULL); + } } void furi_event_loop_stop(FuriEventLoop* instance) { @@ -211,87 +269,150 @@ void furi_event_loop_pend_callback( } /* - * Message queue API + * Private generic susbscription API */ -void furi_event_loop_message_queue_subscribe( +static void furi_event_loop_object_subscribe( FuriEventLoop* instance, - FuriMessageQueue* message_queue, + FuriEventLoopObject* object, + const FuriEventLoopContract* contract, FuriEventLoopEvent event, - FuriEventLoopMessageQueueCallback callback, + FuriEventLoopEventCallback callback, void* context) { furi_check(instance); furi_check(instance->thread_id == furi_thread_get_current_id()); - furi_check(instance->state == FuriEventLoopStateStopped); - furi_check(message_queue); + furi_check(object); + furi_assert(contract); + furi_check(callback); FURI_CRITICAL_ENTER(); - furi_check(FuriEventLoopTree_get(instance->tree, message_queue) == NULL); + furi_check(FuriEventLoopTree_get(instance->tree, object) == NULL); // Allocate and setup item - FuriEventLoopItem* item = furi_event_loop_item_alloc( - instance, &furi_message_queue_event_loop_contract, message_queue, event); + FuriEventLoopItem* item = furi_event_loop_item_alloc(instance, contract, object, event); furi_event_loop_item_set_callback(item, callback, context); - FuriEventLoopTree_set_at(instance->tree, message_queue, item); + FuriEventLoopTree_set_at(instance->tree, object, item); - FuriEventLoopLink* link = item->contract->get_link(message_queue); + FuriEventLoopLink* link = item->contract->get_link(object); + FuriEventLoopEvent event_noflags = item->event & FuriEventLoopEventMask; - if(item->event == FuriEventLoopEventIn) { + if(event_noflags == FuriEventLoopEventIn) { furi_check(link->item_in == NULL); link->item_in = item; - } else if(item->event == FuriEventLoopEventOut) { + } else if(event_noflags == FuriEventLoopEventOut) { furi_check(link->item_out == NULL); link->item_out = item; } else { furi_crash(); } - if(item->contract->get_level(item->object, item->event)) { - furi_event_loop_item_notify(item); + if(!(item->event & FuriEventLoopEventFlagEdge)) { + if(item->contract->get_level(item->object, event_noflags)) { + furi_event_loop_item_notify(item); + } } FURI_CRITICAL_EXIT(); } -void furi_event_loop_message_queue_unsubscribe( +/** + * Public specialized subscription API + */ + +void furi_event_loop_subscribe_message_queue( + FuriEventLoop* instance, + FuriMessageQueue* message_queue, + FuriEventLoopEvent event, + FuriEventLoopEventCallback callback, + void* context) { + extern const FuriEventLoopContract furi_message_queue_event_loop_contract; + + furi_event_loop_object_subscribe( + instance, message_queue, &furi_message_queue_event_loop_contract, event, callback, context); +} + +void furi_event_loop_subscribe_stream_buffer( + FuriEventLoop* instance, + FuriStreamBuffer* stream_buffer, + FuriEventLoopEvent event, + FuriEventLoopEventCallback callback, + void* context) { + extern const FuriEventLoopContract furi_stream_buffer_event_loop_contract; + + furi_event_loop_object_subscribe( + instance, stream_buffer, &furi_stream_buffer_event_loop_contract, event, callback, context); +} + +void furi_event_loop_subscribe_semaphore( + FuriEventLoop* instance, + FuriSemaphore* semaphore, + FuriEventLoopEvent event, + FuriEventLoopEventCallback callback, + void* context) { + extern const FuriEventLoopContract furi_semaphore_event_loop_contract; + + furi_event_loop_object_subscribe( + instance, semaphore, &furi_semaphore_event_loop_contract, event, callback, context); +} + +void furi_event_loop_subscribe_mutex( FuriEventLoop* instance, - FuriMessageQueue* message_queue) { + FuriMutex* mutex, + FuriEventLoopEvent event, + FuriEventLoopEventCallback callback, + void* context) { + extern const FuriEventLoopContract furi_mutex_event_loop_contract; + + furi_event_loop_object_subscribe( + instance, mutex, &furi_mutex_event_loop_contract, event, callback, context); +} + +/** + * Public generic unsubscription API + */ + +void furi_event_loop_unsubscribe(FuriEventLoop* instance, FuriEventLoopObject* object) { furi_check(instance); - furi_check(instance->state == FuriEventLoopStateStopped); furi_check(instance->thread_id == furi_thread_get_current_id()); FURI_CRITICAL_ENTER(); - FuriEventLoopItem** item_ptr = FuriEventLoopTree_get(instance->tree, message_queue); - furi_check(item_ptr); + FuriEventLoopItem* item = NULL; + furi_check(FuriEventLoopTree_pop_at(&item, instance->tree, object)); - FuriEventLoopItem* item = *item_ptr; furi_check(item); furi_check(item->owner == instance); - FuriEventLoopLink* link = item->contract->get_link(message_queue); + FuriEventLoopLink* link = item->contract->get_link(object); + FuriEventLoopEvent event_noflags = item->event & FuriEventLoopEventMask; - if(item->event == FuriEventLoopEventIn) { + if(event_noflags == FuriEventLoopEventIn) { furi_check(link->item_in == item); link->item_in = NULL; - } else if(item->event == FuriEventLoopEventOut) { + } else if(event_noflags == FuriEventLoopEventOut) { furi_check(link->item_out == item); link->item_out = NULL; } else { furi_crash(); } - furi_event_loop_item_free(item); + if(furi_event_loop_item_is_waiting(item)) { + WaitingList_unlink(item); + } - FuriEventLoopTree_erase(instance->tree, message_queue); + if(instance->state == FuriEventLoopStateProcessing) { + furi_event_loop_item_free_later(item); + } else { + furi_event_loop_item_free(item); + } FURI_CRITICAL_EXIT(); } /* - * Event Loop Item API, used internally + * Private Event Loop Item functions */ static FuriEventLoopItem* furi_event_loop_item_alloc( @@ -316,12 +437,19 @@ static FuriEventLoopItem* furi_event_loop_item_alloc( static void furi_event_loop_item_free(FuriEventLoopItem* instance) { furi_assert(instance); + furi_assert(!furi_event_loop_item_is_waiting(instance)); free(instance); } +static void furi_event_loop_item_free_later(FuriEventLoopItem* instance) { + furi_assert(instance); + furi_assert(!furi_event_loop_item_is_waiting(instance)); + instance->owner = NULL; +} + static void furi_event_loop_item_set_callback( FuriEventLoopItem* instance, - FuriEventLoopMessageQueueCallback callback, + FuriEventLoopEventCallback callback, void* callback_context) { furi_assert(instance); furi_assert(!instance->callback); @@ -335,27 +463,35 @@ static void furi_event_loop_item_notify(FuriEventLoopItem* instance) { FURI_CRITICAL_ENTER(); - if(!instance->WaitingList.prev && !instance->WaitingList.next) { - WaitingList_push_back(instance->owner->waiting_list, instance); + FuriEventLoop* owner = instance->owner; + furi_assert(owner); + + if(!furi_event_loop_item_is_waiting(instance)) { + WaitingList_push_back(owner->waiting_list, instance); } FURI_CRITICAL_EXIT(); xTaskNotifyIndexed( - instance->owner->thread_id, - FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, - FuriEventLoopFlagEvent, - eSetBits); + owner->thread_id, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, FuriEventLoopFlagEvent, eSetBits); +} + +static bool furi_event_loop_item_is_waiting(FuriEventLoopItem* instance) { + return instance->WaitingList.prev || instance->WaitingList.next; } +/* + * Internal event loop link API, used by supported primitives + */ + void furi_event_loop_link_notify(FuriEventLoopLink* instance, FuriEventLoopEvent event) { furi_assert(instance); FURI_CRITICAL_ENTER(); - if(event == FuriEventLoopEventIn) { + if(event & FuriEventLoopEventIn) { if(instance->item_in) furi_event_loop_item_notify(instance->item_in); - } else if(event == FuriEventLoopEventOut) { + } else if(event & FuriEventLoopEventOut) { if(instance->item_out) furi_event_loop_item_notify(instance->item_out); } else { furi_crash(); @@ -363,18 +499,3 @@ void furi_event_loop_link_notify(FuriEventLoopLink* instance, FuriEventLoopEvent FURI_CRITICAL_EXIT(); } - -bool furi_event_loop_signal_callback(uint32_t signal, void* arg, void* context) { - furi_assert(context); - FuriEventLoop* instance = context; - UNUSED(arg); - - switch(signal) { - case FuriSignalExit: - furi_event_loop_stop(instance); - return true; - // Room for possible other standard signal handlers - default: - return false; - } -} diff --git a/furi/core/event_loop.h b/furi/core/event_loop.h index 9ae9f6c4dd..af5987101d 100644 --- a/furi/core/event_loop.h +++ b/furi/core/event_loop.h @@ -20,10 +20,83 @@ extern "C" { #endif -/** Event Loop events */ +/** + * @brief Enumeration of event types, flags and masks. + * + * Only one event direction (In or Out) can be used per subscription. + * An object can have no more than one subscription for each direction. + * + * Additional flags that modify the behaviour can be + * set using the bitwise OR operation (see flag description). + */ typedef enum { - FuriEventLoopEventOut, /**< On departure: item was retrieved from container, flag reset, etc... */ - FuriEventLoopEventIn, /**< On arrival: item was inserted into container, flag set, etc... */ + /** + * @brief Subscribe to In events. + * + * In events occur on the following conditions: + * - One or more items were inserted into a FuriMessageQueue, + * - Enough data has been written to a FuriStreamBuffer, + * - A FuriSemaphore has been released at least once, + * - A FuriMutex has been released. + */ + FuriEventLoopEventIn = 0x00000001U, + /** + * @brief Subscribe to Out events. + * + * Out events occur on the following conditions: + * - One or more items were removed from a FuriMessageQueue, + * - Any amount of data has been read out of a FuriStreamBuffer, + * - A FuriSemaphore has been acquired at least once, + * - A FuriMutex has been acquired. + */ + FuriEventLoopEventOut = 0x00000002U, + /** + * @brief Special value containing the event direction bits, used internally. + */ + FuriEventLoopEventMask = 0x00000003U, + /** + * @brief Use edge triggered events. + * + * By default, level triggered events are used. A level above zero + * is reported based on the following conditions: + * + * In events: + * - a FuriMessageQueue contains one or more items, + * - a FuriStreamBuffer contains one or more bytes, + * - a FuriSemaphore can be acquired at least once, + * - a FuriMutex can be acquired. + * + * Out events: + * - a FuriMessageQueue has at least one item of free space, + * - a FuriStreamBuffer has at least one byte of free space, + * - a FuriSemaphore has been acquired at least once, + * - a FuriMutex has been acquired. + * + * If this flag is NOT set, the event will be generated repeatedly until + * the level becomes zero (e.g. all items have been removed from + * a FuriMessageQueue in case of the "In" event, etc.) + * + * If this flag IS set, then the above check is skipped and the event + * is generated ONLY when a change occurs, with the event direction + * (In or Out) taken into account. + */ + FuriEventLoopEventFlagEdge = 0x00000004U, + /** + * @brief Automatically unsubscribe from events after one time. + * + * By default, events will be generated each time the specified conditions + * have been met. If this flag IS set, the event subscription will be cancelled + * upon the first occurred event and no further events will be generated. + */ + FuriEventLoopEventFlagOnce = 0x00000008U, + /** + * @brief Special value containing the event flag bits, used internally. + */ + FuriEventLoopEventFlagMask = 0xFFFFFFFCU, + /** + * @brief Special value to force the enum to 32-bit values. + */ + FuriEventLoopEventReserved = UINT32_MAX, } FuriEventLoopEvent; /** Anonymous message queue type */ @@ -115,21 +188,22 @@ void furi_event_loop_pend_callback( void* context); /* - * Message queue related APIs + * Event subscription/notification APIs */ -/** Anonymous message queue type */ -typedef struct FuriMessageQueue FuriMessageQueue; +typedef void FuriEventLoopObject; -/** Callback type for message queue +/** Callback type for event loop events * - * @param queue The queue that triggered event - * @param context The context that was provided on - * furi_event_loop_message_queue_subscribe call + * @param object The object that triggered the event + * @param context The context that was provided upon subscription * * @return true if event was processed, false if we need to delay processing */ -typedef bool (*FuriEventLoopMessageQueueCallback)(FuriMessageQueue* queue, void* context); +typedef bool (*FuriEventLoopEventCallback)(FuriEventLoopObject* object, void* context); + +/** Opaque message queue type */ +typedef struct FuriMessageQueue FuriMessageQueue; /** Subscribe to message queue events * @@ -141,21 +215,79 @@ typedef bool (*FuriEventLoopMessageQueueCallback)(FuriMessageQueue* queue, void* * @param[in] callback The callback to call on event * @param context The context for callback */ -void furi_event_loop_message_queue_subscribe( +void furi_event_loop_subscribe_message_queue( FuriEventLoop* instance, FuriMessageQueue* message_queue, FuriEventLoopEvent event, - FuriEventLoopMessageQueueCallback callback, + FuriEventLoopEventCallback callback, + void* context); + +/** Opaque stream buffer type */ +typedef struct FuriStreamBuffer FuriStreamBuffer; + +/** Subscribe to stream buffer events + * + * @warning you can only have one subscription for one event type. + * + * @param instance The Event Loop instance + * @param stream_buffer The stream buffer to add + * @param[in] event The Event Loop event to trigger on + * @param[in] callback The callback to call on event + * @param context The context for callback + */ +void furi_event_loop_subscribe_stream_buffer( + FuriEventLoop* instance, + FuriStreamBuffer* stream_buffer, + FuriEventLoopEvent event, + FuriEventLoopEventCallback callback, + void* context); + +/** Opaque semaphore type */ +typedef struct FuriSemaphore FuriSemaphore; + +/** Subscribe to semaphore events + * + * @warning you can only have one subscription for one event type. + * + * @param instance The Event Loop instance + * @param semaphore The semaphore to add + * @param[in] event The Event Loop event to trigger on + * @param[in] callback The callback to call on event + * @param context The context for callback + */ +void furi_event_loop_subscribe_semaphore( + FuriEventLoop* instance, + FuriSemaphore* semaphore, + FuriEventLoopEvent event, + FuriEventLoopEventCallback callback, void* context); -/** Unsubscribe from message queue +/** Opaque mutex type */ +typedef struct FuriMutex FuriMutex; + +/** Subscribe to mutex events + * + * @warning you can only have one subscription for one event type. * * @param instance The Event Loop instance - * @param message_queue The message queue + * @param mutex The mutex to add + * @param[in] event The Event Loop event to trigger on + * @param[in] callback The callback to call on event + * @param context The context for callback */ -void furi_event_loop_message_queue_unsubscribe( +void furi_event_loop_subscribe_mutex( FuriEventLoop* instance, - FuriMessageQueue* message_queue); + FuriMutex* mutex, + FuriEventLoopEvent event, + FuriEventLoopEventCallback callback, + void* context); + +/** Unsubscribe from events (common) + * + * @param instance The Event Loop instance + * @param object The object to unsubscribe from + */ +void furi_event_loop_unsubscribe(FuriEventLoop* instance, FuriEventLoopObject* object); #ifdef __cplusplus } diff --git a/furi/core/event_loop_i.h b/furi/core/event_loop_i.h index cd10148673..15efa8f864 100644 --- a/furi/core/event_loop_i.h +++ b/furi/core/event_loop_i.h @@ -16,16 +16,16 @@ struct FuriEventLoopItem { FuriEventLoop* owner; // Tracking item - const FuriEventLoopContract* contract; - void* object; FuriEventLoopEvent event; + FuriEventLoopObject* object; + const FuriEventLoopContract* contract; // Callback and context - FuriEventLoopMessageQueueCallback callback; + FuriEventLoopEventCallback callback; void* callback_context; // Waiting list - ILIST_INTERFACE(WaitingList, struct FuriEventLoopItem); + ILIST_INTERFACE(WaitingList, FuriEventLoopItem); }; ILIST_DEF(WaitingList, FuriEventLoopItem, M_POD_OPLIST) @@ -36,7 +36,7 @@ ILIST_DEF(WaitingList, FuriEventLoopItem, M_POD_OPLIST) BPTREE_DEF2( // NOLINT FuriEventLoopTree, FURI_EVENT_LOOP_TREE_RANK, - void*, /* pointer to object we track */ + FuriEventLoopObject*, /* pointer to object we track */ M_PTR_OPLIST, FuriEventLoopItem*, /* pointer to the FuriEventLoopItem */ M_PTR_OPLIST) @@ -60,6 +60,7 @@ typedef enum { FuriEventLoopProcessStatusComplete, FuriEventLoopProcessStatusIncomplete, FuriEventLoopProcessStatusAgain, + FuriEventLoopProcessStatusFreeLater, } FuriEventLoopProcessStatus; typedef enum { diff --git a/furi/core/event_loop_link_i.h b/furi/core/event_loop_link_i.h index 5c0b144a1b..992ca65555 100644 --- a/furi/core/event_loop_link_i.h +++ b/furi/core/event_loop_link_i.h @@ -19,17 +19,16 @@ void furi_event_loop_link_notify(FuriEventLoopLink* instance, FuriEventLoopEvent /* Contract between event loop and an object */ -typedef FuriEventLoopLink* (*FuriEventLoopContractGetLink)(void* object); +typedef FuriEventLoopLink* (*FuriEventLoopContractGetLink)(FuriEventLoopObject* object); -typedef uint32_t (*FuriEventLoopContractGetLevel)(void* object, FuriEventLoopEvent event); +typedef uint32_t ( + *FuriEventLoopContractGetLevel)(FuriEventLoopObject* object, FuriEventLoopEvent event); typedef struct { const FuriEventLoopContractGetLink get_link; const FuriEventLoopContractGetLevel get_level; } FuriEventLoopContract; -bool furi_event_loop_signal_callback(uint32_t signal, void* arg, void* context); - #ifdef __cplusplus } #endif diff --git a/furi/core/message_queue.c b/furi/core/message_queue.c index 3521ceb30b..bd0cec0214 100644 --- a/furi/core/message_queue.c +++ b/furi/core/message_queue.c @@ -1,4 +1,4 @@ -#include "message_queue_i.h" +#include "message_queue.h" #include #include @@ -6,6 +6,8 @@ #include "kernel.h" #include "check.h" +#include "event_loop_link_i.h" + // Internal FreeRTOS member names #define uxMessagesWaiting uxDummy4[0] #define uxLength uxDummy4[1] @@ -13,10 +15,7 @@ struct FuriMessageQueue { StaticQueue_t container; - - // Event Loop Link FuriEventLoopLink event_loop_link; - uint8_t buffer[]; }; @@ -208,13 +207,14 @@ FuriStatus furi_message_queue_reset(FuriMessageQueue* instance) { return stat; } -static FuriEventLoopLink* furi_message_queue_event_loop_get_link(void* object) { +static FuriEventLoopLink* furi_message_queue_event_loop_get_link(FuriEventLoopObject* object) { FuriMessageQueue* instance = object; furi_assert(instance); return &instance->event_loop_link; } -static uint32_t furi_message_queue_event_loop_get_level(void* object, FuriEventLoopEvent event) { +static uint32_t + furi_message_queue_event_loop_get_level(FuriEventLoopObject* object, FuriEventLoopEvent event) { FuriMessageQueue* instance = object; furi_assert(instance); diff --git a/furi/core/message_queue_i.h b/furi/core/message_queue_i.h deleted file mode 100644 index a88d04131a..0000000000 --- a/furi/core/message_queue_i.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include "message_queue.h" -#include "event_loop_link_i.h" - -extern const FuriEventLoopContract furi_message_queue_event_loop_contract; diff --git a/furi/core/mutex.c b/furi/core/mutex.c index f59ae83ada..f9848e1baa 100644 --- a/furi/core/mutex.c +++ b/furi/core/mutex.c @@ -1,15 +1,18 @@ #include "mutex.h" -#include "check.h" -#include "common_defines.h" #include #include +#include "check.h" + +#include "event_loop_link_i.h" + // Internal FreeRTOS member names #define ucQueueType ucDummy9 struct FuriMutex { StaticSemaphore_t container; + FuriEventLoopLink event_loop_link; }; // IMPORTANT: container MUST be the FIRST struct member @@ -39,6 +42,10 @@ void furi_mutex_free(FuriMutex* instance) { furi_check(!FURI_IS_IRQ_MODE()); furi_check(instance); + // Event Loop must be disconnected + furi_check(!instance->event_loop_link.item_in); + furi_check(!instance->event_loop_link.item_out); + vSemaphoreDelete((SemaphoreHandle_t)instance); free(instance); } @@ -76,6 +83,10 @@ FuriStatus furi_mutex_acquire(FuriMutex* instance, uint32_t timeout) { furi_crash(); } + if(stat == FuriStatusOk) { + furi_event_loop_link_notify(&instance->event_loop_link, FuriEventLoopEventOut); + } + return stat; } @@ -104,6 +115,10 @@ FuriStatus furi_mutex_release(FuriMutex* instance) { furi_crash(); } + if(stat == FuriStatusOk) { + furi_event_loop_link_notify(&instance->event_loop_link, FuriEventLoopEventIn); + } + return stat; } @@ -122,3 +137,26 @@ FuriThreadId furi_mutex_get_owner(FuriMutex* instance) { return owner; } + +static FuriEventLoopLink* furi_mutex_event_loop_get_link(FuriEventLoopObject* object) { + FuriMutex* instance = object; + furi_assert(instance); + return &instance->event_loop_link; +} + +static uint32_t + furi_mutex_event_loop_get_level(FuriEventLoopObject* object, FuriEventLoopEvent event) { + FuriMutex* instance = object; + furi_assert(instance); + + if(event == FuriEventLoopEventIn || event == FuriEventLoopEventOut) { + return furi_mutex_get_owner(instance) ? 0 : 1; + } else { + furi_crash(); + } +} + +const FuriEventLoopContract furi_mutex_event_loop_contract = { + .get_link = furi_mutex_event_loop_get_link, + .get_level = furi_mutex_event_loop_get_level, +}; diff --git a/furi/core/semaphore.c b/furi/core/semaphore.c index 6413eb65f5..850169ad6e 100644 --- a/furi/core/semaphore.c +++ b/furi/core/semaphore.c @@ -1,12 +1,20 @@ #include "semaphore.h" -#include "check.h" -#include "common_defines.h" #include #include +#include "check.h" +#include "kernel.h" + +#include "event_loop_link_i.h" + +// Internal FreeRTOS member names +#define uxMessagesWaiting uxDummy4[0] +#define uxLength uxDummy4[1] + struct FuriSemaphore { StaticSemaphore_t container; + FuriEventLoopLink event_loop_link; }; // IMPORTANT: container MUST be the FIRST struct member @@ -40,6 +48,10 @@ void furi_semaphore_free(FuriSemaphore* instance) { furi_check(instance); furi_check(!FURI_IS_IRQ_MODE()); + // Event Loop must be disconnected + furi_check(!instance->event_loop_link.item_in); + furi_check(!instance->event_loop_link.item_out); + vSemaphoreDelete((SemaphoreHandle_t)instance); free(instance); } @@ -76,6 +88,10 @@ FuriStatus furi_semaphore_acquire(FuriSemaphore* instance, uint32_t timeout) { } } + if(stat == FuriStatusOk) { + furi_event_loop_link_notify(&instance->event_loop_link, FuriEventLoopEventOut); + } + return stat; } @@ -103,6 +119,10 @@ FuriStatus furi_semaphore_release(FuriSemaphore* instance) { } } + if(stat == FuriStatusOk) { + furi_event_loop_link_notify(&instance->event_loop_link, FuriEventLoopEventIn); + } + return stat; } @@ -120,3 +140,46 @@ uint32_t furi_semaphore_get_count(FuriSemaphore* instance) { return count; } + +uint32_t furi_semaphore_get_space(FuriSemaphore* instance) { + furi_assert(instance); + + uint32_t space; + + if(furi_kernel_is_irq_or_masked() != 0U) { + uint32_t isrm = taskENTER_CRITICAL_FROM_ISR(); + + space = instance->container.uxLength - instance->container.uxMessagesWaiting; + + taskEXIT_CRITICAL_FROM_ISR(isrm); + } else { + space = uxQueueSpacesAvailable((QueueHandle_t)instance); + } + + return space; +} + +static FuriEventLoopLink* furi_semaphore_event_loop_get_link(FuriEventLoopObject* object) { + FuriSemaphore* instance = object; + furi_assert(instance); + return &instance->event_loop_link; +} + +static uint32_t + furi_semaphore_event_loop_get_level(FuriEventLoopObject* object, FuriEventLoopEvent event) { + FuriSemaphore* instance = object; + furi_assert(instance); + + if(event == FuriEventLoopEventIn) { + return furi_semaphore_get_count(instance); + } else if(event == FuriEventLoopEventOut) { + return furi_semaphore_get_space(instance); + } else { + furi_crash(); + } +} + +const FuriEventLoopContract furi_semaphore_event_loop_contract = { + .get_link = furi_semaphore_event_loop_get_link, + .get_level = furi_semaphore_event_loop_get_level, +}; diff --git a/furi/core/semaphore.h b/furi/core/semaphore.h index c6b9a1176a..47a77ed558 100644 --- a/furi/core/semaphore.h +++ b/furi/core/semaphore.h @@ -53,6 +53,14 @@ FuriStatus furi_semaphore_release(FuriSemaphore* instance); */ uint32_t furi_semaphore_get_count(FuriSemaphore* instance); +/** Get available space + * + * @param instance The pointer to FuriSemaphore instance + * + * @return Semaphore available space + */ +uint32_t furi_semaphore_get_space(FuriSemaphore* instance); + #ifdef __cplusplus } #endif diff --git a/furi/core/stream_buffer.c b/furi/core/stream_buffer.c index ef8869dea0..f35abec647 100644 --- a/furi/core/stream_buffer.c +++ b/furi/core/stream_buffer.c @@ -1,13 +1,19 @@ #include "stream_buffer.h" +#include +#include + #include "check.h" #include "common_defines.h" -#include -#include +#include "event_loop_link_i.h" + +// Internal FreeRTOS member names +#define xTriggerLevelBytes uxDummy1[3] struct FuriStreamBuffer { StaticStreamBuffer_t container; + FuriEventLoopLink event_loop_link; uint8_t buffer[]; }; @@ -34,6 +40,10 @@ FuriStreamBuffer* furi_stream_buffer_alloc(size_t size, size_t trigger_level) { void furi_stream_buffer_free(FuriStreamBuffer* stream_buffer) { furi_check(stream_buffer); + // Event Loop must be disconnected + furi_check(!stream_buffer->event_loop_link.item_in); + furi_check(!stream_buffer->event_loop_link.item_out); + vStreamBufferDelete((StreamBufferHandle_t)stream_buffer); free(stream_buffer); } @@ -61,6 +71,16 @@ size_t furi_stream_buffer_send( ret = xStreamBufferSend((StreamBufferHandle_t)stream_buffer, data, length, timeout); } + if(ret > 0) { + const size_t bytes_available = + xStreamBufferBytesAvailable((StreamBufferHandle_t)stream_buffer); + const size_t trigger_level = ((StaticStreamBuffer_t*)stream_buffer)->xTriggerLevelBytes; + + if(bytes_available >= trigger_level) { + furi_event_loop_link_notify(&stream_buffer->event_loop_link, FuriEventLoopEventIn); + } + } + return ret; } @@ -82,6 +102,10 @@ size_t furi_stream_buffer_receive( ret = xStreamBufferReceive((StreamBufferHandle_t)stream_buffer, data, length, timeout); } + if(ret > 0) { + furi_event_loop_link_notify(&stream_buffer->event_loop_link, FuriEventLoopEventOut); + } + return ret; } @@ -112,9 +136,42 @@ bool furi_stream_buffer_is_empty(FuriStreamBuffer* stream_buffer) { FuriStatus furi_stream_buffer_reset(FuriStreamBuffer* stream_buffer) { furi_check(stream_buffer); + FuriStatus status; + if(xStreamBufferReset((StreamBufferHandle_t)stream_buffer) == pdPASS) { - return FuriStatusOk; + status = FuriStatusOk; } else { - return FuriStatusError; + status = FuriStatusError; + } + + if(status == FuriStatusOk) { + furi_event_loop_link_notify(&stream_buffer->event_loop_link, FuriEventLoopEventOut); + } + + return status; +} + +static FuriEventLoopLink* furi_stream_buffer_event_loop_get_link(FuriEventLoopObject* object) { + FuriStreamBuffer* stream_buffer = object; + furi_assert(stream_buffer); + return &stream_buffer->event_loop_link; +} + +static uint32_t + furi_stream_buffer_event_loop_get_level(FuriEventLoopObject* object, FuriEventLoopEvent event) { + FuriStreamBuffer* stream_buffer = object; + furi_assert(stream_buffer); + + if(event == FuriEventLoopEventIn) { + return xStreamBufferBytesAvailable((StreamBufferHandle_t)stream_buffer); + } else if(event == FuriEventLoopEventOut) { + return xStreamBufferSpacesAvailable((StreamBufferHandle_t)stream_buffer); + } else { + furi_crash(); } } + +const FuriEventLoopContract furi_stream_buffer_event_loop_contract = { + .get_link = furi_stream_buffer_event_loop_get_link, + .get_level = furi_stream_buffer_event_loop_get_level, +}; diff --git a/furi/core/string.c b/furi/core/string.c index f3e40fe5eb..804445e22d 100644 --- a/furi/core/string.c +++ b/furi/core/string.c @@ -17,6 +17,7 @@ struct FuriString { #undef furi_string_replace_all #undef furi_string_start_with #undef furi_string_end_with +#undef furi_string_end_withi #undef furi_string_search_char #undef furi_string_search_rchar #undef furi_string_trim @@ -218,10 +219,28 @@ bool furi_string_end_with(const FuriString* v, const FuriString* v2) { return string_end_with_string_p(v->string, v2->string); } +bool furi_string_end_withi(const FuriString* v, const FuriString* v2) { + return furi_string_end_withi_str(v, string_get_cstr(v2->string)); +} + bool furi_string_end_with_str(const FuriString* v, const char str[]) { return string_end_with_str_p(v->string, str); } +bool furi_string_end_withi_str(const FuriString* v, const char str[]) { + M_STR1NG_CONTRACT(v); + M_ASSERT(str != NULL); + + const size_t str_len = strlen(str); + const size_t v_len = string_size(v->string); + + if(v_len < str_len) { + return false; + } + + return strcasecmp(&string_get_cstr(v->string)[v_len - str_len], str) == 0; +} + size_t furi_string_search_char(const FuriString* v, char c, size_t start) { return string_search_char(v->string, c, start); } diff --git a/furi/core/string.h b/furi/core/string.h index bcdf9336c7..84b8c6a240 100644 --- a/furi/core/string.h +++ b/furi/core/string.h @@ -1,7 +1,10 @@ -/** +/** Furi string container + * + * And various method to manipulate strings + * * @file string.h - * Furi string primitive */ + #pragma once #include @@ -14,66 +17,72 @@ extern "C" { #endif -/** - * @brief Furi string failure constant. - */ +/** Furi string failure constant. */ #define FURI_STRING_FAILURE ((size_t) - 1) -/** - * @brief Furi string primitive. - */ +/** Furi string primitive. */ typedef struct FuriString FuriString; //--------------------------------------------------------------------------- // Constructors //--------------------------------------------------------------------------- -/** - * @brief Allocate new FuriString. - * @return FuriString* +/** Allocate new FuriString. + * + * @return pointer to the instance of FuriString */ FuriString* furi_string_alloc(void); -/** - * @brief Allocate new FuriString and set it to string. +/** Allocate new FuriString and set it to string. + * * Allocate & Set the string a to the string. - * @param source - * @return FuriString* + * + * @param source The source FuriString instance + * + * @return pointer to the new instance of FuriString */ FuriString* furi_string_alloc_set(const FuriString* source); -/** - * @brief Allocate new FuriString and set it to C string. +/** Allocate new FuriString and set it to C string. + * * Allocate & Set the string a to the C string. - * @param cstr_source - * @return FuriString* + * + * @param cstr_source The C-string instance + * + * @return pointer to the new instance of FuriString */ FuriString* furi_string_alloc_set_str(const char cstr_source[]); -/** - * @brief Allocate new FuriString and printf to it. +/** Allocate new FuriString and printf to it. + * * Initialize and set a string to the given formatted value. - * @param format - * @param ... - * @return FuriString* + * + * @param format The printf format + * @param[in] ... args to format + * + * @return pointer to the new instance of FuriString */ FuriString* furi_string_alloc_printf(const char format[], ...) _ATTRIBUTE((__format__(__printf__, 1, 2))); -/** - * @brief Allocate new FuriString and printf to it. +/** Allocate new FuriString and printf to it. + * * Initialize and set a string to the given formatted value. - * @param format - * @param args - * @return FuriString* + * + * @param format The printf format + * @param args The format arguments + * + * @return pointer to the new instance of FuriString */ FuriString* furi_string_alloc_vprintf(const char format[], va_list args); -/** - * @brief Allocate new FuriString and move source string content to it. +/** Allocate new FuriString and move source string content to it. + * * Allocate the string, set it to the other one, and destroy the other one. - * @param source - * @return FuriString* + * + * @param source The source FuriString instance + * + * @return pointer to the new instance of FuriString */ FuriString* furi_string_alloc_move(FuriString* source); @@ -81,9 +90,9 @@ FuriString* furi_string_alloc_move(FuriString* source); // Destructors //--------------------------------------------------------------------------- -/** - * @brief Free FuriString. - * @param string +/** Free FuriString. + * + * @param string The FuriString instance to free */ void furi_string_free(FuriString* string); @@ -91,55 +100,63 @@ void furi_string_free(FuriString* string); // String memory management //--------------------------------------------------------------------------- -/** - * @brief Reserve memory for string. - * Modify the string capacity to be able to handle at least 'alloc' characters (including final null char). - * @param string - * @param size +/** Reserve memory for string. + * + * Modify the string capacity to be able to handle at least 'alloc' characters + * (including final null char). + * + * @param string The FuriString instance + * @param size The size to reserve */ void furi_string_reserve(FuriString* string, size_t size); -/** - * @brief Reset string. +/** Reset string. + * * Make the string empty. - * @param string + * + * @param string The FuriString instance */ void furi_string_reset(FuriString* string); -/** - * @brief Swap two strings. +/** Swap two strings. + * * Swap the two strings string_1 and string_2. - * @param string_1 - * @param string_2 + * + * @param string_1 The FuriString instance 1 + * @param string_2 The FuriString instance 2 */ void furi_string_swap(FuriString* string_1, FuriString* string_2); -/** - * @brief Move string_2 content to string_1. +/** Move string_2 content to string_1. + * * Set the string to the other one, and destroy the other one. - * @param string_1 - * @param string_2 + * + * @param string_1 The FuriString instance 1 + * @param string_2 The FuriString instance 2 */ void furi_string_move(FuriString* string_1, FuriString* string_2); -/** - * @brief Compute a hash for the string. - * @param string - * @return size_t +/** Compute a hash for the string. + * + * @param string The FuriString instance + * + * @return hash value */ size_t furi_string_hash(const FuriString* string); -/** - * @brief Get string size (usually length, but not for UTF-8) - * @param string - * @return size_t +/** Get string size (usually length, but not for UTF-8) + * + * @param string The FuriString instance + * + * @return size of the string */ size_t furi_string_size(const FuriString* string); -/** - * @brief Check that string is empty or not - * @param string - * @return bool +/** Check that string is empty or not + * + * @param string The FuriString instance + * + * @return true if empty otherwise false */ bool furi_string_empty(const FuriString* string); @@ -147,19 +164,22 @@ bool furi_string_empty(const FuriString* string); // Getters //--------------------------------------------------------------------------- -/** - * @brief Get the character at the given index. +/** Get the character at the given index. + * * Return the selected character of the string. - * @param string - * @param index - * @return char + * + * @param string The FuriString instance + * @param index The index + * + * @return character at index */ char furi_string_get_char(const FuriString* string, size_t index); -/** - * @brief Return the string view a classic C string. - * @param string - * @return const char* +/** Return the string view a classic C string. + * + * @param string The FuriString instance + * + * @return const C-string, usable till first container change */ const char* furi_string_get_cstr(const FuriString* string); @@ -167,63 +187,67 @@ const char* furi_string_get_cstr(const FuriString* string); // Setters //--------------------------------------------------------------------------- -/** - * @brief Set the string to the other string. +/** Set the string to the other string. + * * Set the string to the source string. - * @param string - * @param source + * + * @param string The FuriString instance + * @param source The source */ void furi_string_set(FuriString* string, FuriString* source); -/** - * @brief Set the string to the other C string. +/** Set the string to the other C string. + * * Set the string to the source C string. - * @param string - * @param source + * + * @param string The FuriString instance + * @param source The source */ void furi_string_set_str(FuriString* string, const char source[]); -/** - * @brief Set the string to the n first characters of the C string. - * @param string - * @param source - * @param length +/** Set the string to the n first characters of the C string. + * + * @param string The FuriString instance + * @param source The source + * @param length The length */ void furi_string_set_strn(FuriString* string, const char source[], size_t length); -/** - * @brief Set the character at the given index. - * @param string - * @param index - * @param c +/** Set the character at the given index. + * + * @param string The FuriString instance + * @param index The index + * @param c The character */ void furi_string_set_char(FuriString* string, size_t index, const char c); -/** - * @brief Set the string to the n first characters of other one. - * @param string - * @param source - * @param offset - * @param length +/** Set the string to the n first characters of other one. + * + * @param string The FuriString instance + * @param source The source + * @param offset The offset + * @param length The length */ void furi_string_set_n(FuriString* string, const FuriString* source, size_t offset, size_t length); -/** - * @brief Format in the string the given printf format - * @param string - * @param format - * @param ... - * @return int +/** Format in the string the given printf format + * + * @param string The string + * @param format The format + * @param[in] ... The args + * + * @return number of characters printed or negative value on error */ int furi_string_printf(FuriString* string, const char format[], ...) _ATTRIBUTE((__format__(__printf__, 2, 3))); -/** - * @brief Format in the string the given printf format - * @param string - * @param format - * @param args - * @return int +/** Format in the string the given printf format + * + * @param string The FuriString instance + * @param format The format + * @param args The arguments + * + * @return number of characters printed or negative value on error */ int furi_string_vprintf(FuriString* string, const char format[], va_list args); @@ -231,45 +255,49 @@ int furi_string_vprintf(FuriString* string, const char format[], va_list args); // Appending //--------------------------------------------------------------------------- -/** - * @brief Append a character to the string. - * @param string - * @param c +/** Append a character to the string. + * + * @param string The FuriString instance + * @param c The character */ void furi_string_push_back(FuriString* string, char c); -/** - * @brief Append a string to the string. +/** Append a string to the string. + * * Concatenate the string with the other string. - * @param string_1 - * @param string_2 + * + * @param string_1 The string 1 + * @param string_2 The string 2 */ void furi_string_cat(FuriString* string_1, const FuriString* string_2); -/** - * @brief Append a C string to the string. +/** Append a C string to the string. + * * Concatenate the string with the C string. - * @param string_1 - * @param cstring_2 + * + * @param string_1 The string 1 + * @param cstring_2 The cstring 2 */ void furi_string_cat_str(FuriString* string_1, const char cstring_2[]); -/** - * @brief Append to the string the formatted string of the given printf format. - * @param string - * @param format - * @param ... - * @return int +/** Append to the string the formatted string of the given printf format. + * + * @param string The string + * @param format The format + * @param[in] ... The args + * + * @return number of characters printed or negative value on error */ int furi_string_cat_printf(FuriString* string, const char format[], ...) _ATTRIBUTE((__format__(__printf__, 2, 3))); -/** - * @brief Append to the string the formatted string of the given printf format. - * @param string - * @param format - * @param args - * @return int +/** Append to the string the formatted string of the given printf format. + * + * @param string The FuriString instance + * @param format The format + * @param args The arguments + * + * @return number of characters printed or negative value on error */ int furi_string_cat_vprintf(FuriString* string, const char format[], va_list args); @@ -277,37 +305,45 @@ int furi_string_cat_vprintf(FuriString* string, const char format[], va_list arg // Comparators //--------------------------------------------------------------------------- -/** - * @brief Compare two strings and return the sort order. - * @param string_1 - * @param string_2 - * @return int +/** Compare two strings and return the sort order. + * + * @param string_1 The string 1 + * @param string_2 The string 2 + * + * @return zero if equal */ int furi_string_cmp(const FuriString* string_1, const FuriString* string_2); -/** - * @brief Compare string with C string and return the sort order. - * @param string_1 - * @param cstring_2 - * @return int +/** Compare string with C string and return the sort order. + * + * @param string_1 The string 1 + * @param cstring_2 The cstring 2 + * + * @return zero if equal */ int furi_string_cmp_str(const FuriString* string_1, const char cstring_2[]); -/** - * @brief Compare two strings (case insensitive according to the current locale) and return the sort order. +/** Compare two strings (case insensitive according to the current locale) and + * return the sort order. + * * Note: doesn't work with UTF-8 strings. - * @param string_1 - * @param string_2 - * @return int + * + * @param string_1 The string 1 + * @param string_2 The string 2 + * + * @return zero if equal */ int furi_string_cmpi(const FuriString* string_1, const FuriString* string_2); -/** - * @brief Compare string with C string (case insensitive according to the current locale) and return the sort order. +/** Compare string with C string (case insensitive according to the current + * locale) and return the sort order. + * * Note: doesn't work with UTF-8 strings. - * @param string_1 - * @param cstring_2 - * @return int + * + * @param string_1 The string 1 + * @param cstring_2 The cstring 2 + * + * @return zero if equal */ int furi_string_cmpi_str(const FuriString* string_1, const char cstring_2[]); @@ -315,46 +351,47 @@ int furi_string_cmpi_str(const FuriString* string_1, const char cstring_2[]); // Search //--------------------------------------------------------------------------- -/** - * @brief Search the first occurrence of the needle in the string from the position start. - * Return STRING_FAILURE if not found. - * By default, start is zero. - * @param string - * @param needle - * @param start - * @return size_t +/** Search the first occurrence of the needle in the string from the position + * start. + * + * @param string The FuriString instance + * @param needle The needle + * @param start The start (By default, start is zero) + * + * @return position or FURI_STRING_FAILURE if not found */ size_t furi_string_search(const FuriString* string, const FuriString* needle, size_t start); -/** - * @brief Search the first occurrence of the needle in the string from the position start. - * Return STRING_FAILURE if not found. - * @param string - * @param needle - * @param start - * @return size_t +/** Search the first occurrence of the needle in the string from the position + * start. + * + * @param string The FuriString instance + * @param needle The needle + * @param start The start (By default, start is zero) + * + * @return position or FURI_STRING_FAILURE if not found */ size_t furi_string_search_str(const FuriString* string, const char needle[], size_t start); -/** - * @brief Search for the position of the character c from the position start (include) in the string. - * Return STRING_FAILURE if not found. - * By default, start is zero. - * @param string - * @param c - * @param start - * @return size_t +/** Search for the position of the character c from the position start (include) + * in the string. + * + * @param string The FuriString instance + * @param c The character + * @param start The start (By default, start is zero) + * + * @return position or FURI_STRING_FAILURE if not found */ size_t furi_string_search_char(const FuriString* string, char c, size_t start); -/** - * @brief Reverse search for the position of the character c from the position start (include) in the string. - * Return STRING_FAILURE if not found. - * By default, start is zero. - * @param string - * @param c - * @param start - * @return size_t +/** Reverse search for the position of the character c from the position start + * (include) in the string. + * + * @param string The FuriString instance + * @param c The character + * @param start The start (By default, start is zero) + * + * @return position or FURI_STRING_FAILURE if not found */ size_t furi_string_search_rchar(const FuriString* string, char c, size_t start); @@ -362,19 +399,21 @@ size_t furi_string_search_rchar(const FuriString* string, char c, size_t start); // Equality //--------------------------------------------------------------------------- -/** - * @brief Test if two strings are equal. - * @param string_1 - * @param string_2 - * @return bool +/** Test if two strings are equal. + * + * @param string_1 The string 1 + * @param string_2 The string 2 + * + * @return true if equal false otherwise */ bool furi_string_equal(const FuriString* string_1, const FuriString* string_2); -/** - * @brief Test if the string is equal to the C string. - * @param string_1 - * @param cstring_2 - * @return bool +/** Test if the string is equal to the C string. + * + * @param string_1 The string 1 + * @param cstring_2 The cstring 2 + * + * @return true if equal false otherwise */ bool furi_string_equal_str(const FuriString* string_1, const char cstring_2[]); @@ -382,37 +421,38 @@ bool furi_string_equal_str(const FuriString* string_1, const char cstring_2[]); // Replace //--------------------------------------------------------------------------- -/** - * @brief Replace in the string the sub-string at position 'pos' for 'len' bytes into the C string 'replace'. - * @param string - * @param pos - * @param len - * @param replace +/** Replace in the string the sub-string at position 'pos' for 'len' bytes into + * the C string 'replace'. + * + * @param string The string + * @param pos The position + * @param len The length + * @param replace The replace */ void furi_string_replace_at(FuriString* string, size_t pos, size_t len, const char replace[]); -/** - * @brief Replace a string 'needle' to string 'replace' in a string from 'start' position. - * By default, start is zero. - * Return STRING_FAILURE if 'needle' not found or replace position. - * @param string - * @param needle - * @param replace - * @param start - * @return size_t +/** Replace a string 'needle' to string 'replace' in a string from 'start' + * position. + * + * @param string The string + * @param needle The needle + * @param replace The replace + * @param start The start (By default, start is zero) + * + * @return Return FURI_STRING_FAILURE if 'needle' not found or replace position. */ size_t furi_string_replace(FuriString* string, FuriString* needle, FuriString* replace, size_t start); -/** - * @brief Replace a C string 'needle' to C string 'replace' in a string from 'start' position. - * By default, start is zero. - * Return STRING_FAILURE if 'needle' not found or replace position. - * @param string - * @param needle - * @param replace - * @param start - * @return size_t +/** Replace a C string 'needle' to C string 'replace' in a string from 'start' + * position. + * + * @param string The string + * @param needle The needle + * @param replace The replace + * @param start The start (By default, start is zero) + * + * @return Return FURI_STRING_FAILURE if 'needle' not found or replace position. */ size_t furi_string_replace_str( FuriString* string, @@ -420,22 +460,22 @@ size_t furi_string_replace_str( const char replace[], size_t start); -/** - * @brief Replace all occurrences of 'needle' string into 'replace' string. - * @param string - * @param needle - * @param replace +/** Replace all occurrences of 'needle' string into 'replace' string. + * + * @param string The string + * @param needle The needle + * @param replace The replace */ void furi_string_replace_all( FuriString* string, const FuriString* needle, const FuriString* replace); -/** - * @brief Replace all occurrences of 'needle' C string into 'replace' C string. - * @param string - * @param needle - * @param replace +/** Replace all occurrences of 'needle' C string into 'replace' C string. + * + * @param string The string + * @param needle The needle + * @param replace The replace */ void furi_string_replace_all_str(FuriString* string, const char needle[], const char replace[]); @@ -443,69 +483,92 @@ void furi_string_replace_all_str(FuriString* string, const char needle[], const // Start / End tests //--------------------------------------------------------------------------- -/** - * @brief Test if the string starts with the given string. - * @param string - * @param start - * @return bool +/** Test if the string starts with the given string. + * + * @param string The FuriString instance + * @param start The FuriString instance + * + * @return true if string starts with */ bool furi_string_start_with(const FuriString* string, const FuriString* start); -/** - * @brief Test if the string starts with the given C string. - * @param string - * @param start - * @return bool +/** Test if the string starts with the given C string. + * + * @param string The FuriString instance + * @param start The start + * + * @return true if string starts with */ bool furi_string_start_with_str(const FuriString* string, const char start[]); -/** - * @brief Test if the string ends with the given string. - * @param string - * @param end - * @return bool +/** Test if the string ends with the given string. + * + * @param string The FuriString instance + * @param end The end + * + * @return true if string ends with */ bool furi_string_end_with(const FuriString* string, const FuriString* end); -/** - * @brief Test if the string ends with the given C string. - * @param string - * @param end - * @return bool +/** Test if the string ends with the given string (case insensitive according to the current locale). + * + * @param string The FuriString instance + * @param end The end + * + * @return true if string ends with + */ +bool furi_string_end_withi(const FuriString* string, const FuriString* end); + +/** Test if the string ends with the given C string. + * + * @param string The FuriString instance + * @param end The end + * + * @return true if string ends with */ bool furi_string_end_with_str(const FuriString* string, const char end[]); +/** Test if the string ends with the given C string (case insensitive according to the current locale). + * + * @param string The FuriString instance + * @param end The end + * + * @return true if string ends with + */ +bool furi_string_end_withi_str(const FuriString* string, const char end[]); + //--------------------------------------------------------------------------- // Trim //--------------------------------------------------------------------------- -/** - * @brief Trim the string left to the first 'index' bytes. - * @param string - * @param index +/** Trim the string left to the first 'index' bytes. + * + * @param string The FuriString instance + * @param index The index */ void furi_string_left(FuriString* string, size_t index); -/** - * @brief Trim the string right from the 'index' position to the last position. - * @param string - * @param index +/** Trim the string right from the 'index' position to the last position. + * + * @param string The FuriString instance + * @param index The index */ void furi_string_right(FuriString* string, size_t index); -/** - * @brief Trim the string from position index to size bytes. +/** Trim the string from position index to size bytes. + * * See also furi_string_set_n. - * @param string - * @param index - * @param size + * + * @param string The FuriString instance + * @param index The index + * @param size The size */ void furi_string_mid(FuriString* string, size_t index, size_t size); -/** - * @brief Trim a string from the given set of characters (default is " \n\r\t"). - * @param string - * @param chars +/** Trim a string from the given set of characters (default is " \n\r\t"). + * + * @param string The FuriString instance + * @param chars The characters */ void furi_string_trim(FuriString* string, const char chars[]); @@ -513,28 +576,25 @@ void furi_string_trim(FuriString* string, const char chars[]); // UTF8 //--------------------------------------------------------------------------- -/** - * @brief An unicode value. - */ +/** An unicode value */ typedef unsigned int FuriStringUnicodeValue; -/** - * @brief Compute the length in UTF8 characters in the string. - * @param string - * @return size_t +/** Compute the length in UTF8 characters in the string. + * + * @param string The FuriString instance + * + * @return strings size */ size_t furi_string_utf8_length(FuriString* string); -/** - * @brief Push unicode into string, encoding it in UTF8. - * @param string - * @param unicode +/** Push unicode into string, encoding it in UTF8. + * + * @param string The string + * @param unicode The unicode */ void furi_string_utf8_push(FuriString* string, FuriStringUnicodeValue unicode); -/** - * @brief State of the UTF8 decoding machine state. - */ +/** State of the UTF8 decoding machine state */ typedef enum { FuriStringUTF8StateStarting, FuriStringUTF8StateDecoding1, @@ -543,14 +603,16 @@ typedef enum { FuriStringUTF8StateError } FuriStringUTF8State; -/** - * @brief Main generic UTF8 decoder. - * It takes a character, and the previous state and the previous value of the unicode value. - * It updates the state and the decoded unicode value. - * A decoded unicode encoded value is valid only when the state is FuriStringUTF8StateStarting. - * @param c - * @param state - * @param unicode +/** Main generic UTF8 decoder + * + * It takes a character, and the previous state and the previous value of the + * unicode value. It updates the state and the decoded unicode value. A decoded + * unicode encoded value is valid only when the state is + * FuriStringUTF8StateStarting. + * + * @param c The character + * @param state The state + * @param unicode The unicode */ void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnicodeValue* unicode); @@ -565,76 +627,68 @@ void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnico * func1 is the string function / func2 is the str function. */ -/** - * @brief Select for 1 argument - */ +/** Select for 1 argument */ #define FURI_STRING_SELECT1(func1, func2, a) \ _Generic((a), char*: func2, const char*: func2, FuriString*: func1, const FuriString*: func1)( \ a) -/** - * @brief Select for 2 arguments - */ +/** Select for 2 arguments */ #define FURI_STRING_SELECT2(func1, func2, a, b) \ _Generic((b), char*: func2, const char*: func2, FuriString*: func1, const FuriString*: func1)( \ a, b) -/** - * @brief Select for 3 arguments - */ +/** Select for 3 arguments */ #define FURI_STRING_SELECT3(func1, func2, a, b, c) \ _Generic((b), char*: func2, const char*: func2, FuriString*: func1, const FuriString*: func1)( \ a, b, c) -/** - * @brief Select for 4 arguments - */ +/** Select for 4 arguments */ #define FURI_STRING_SELECT4(func1, func2, a, b, c, d) \ _Generic((b), char*: func2, const char*: func2, FuriString*: func1, const FuriString*: func1)( \ a, b, c, d) -/** - * @brief Allocate new FuriString and set it content to string (or C string). +/** Allocate new FuriString and set it content to string (or C string). + * * ([c]string) */ #define furi_string_alloc_set(a) \ FURI_STRING_SELECT1(furi_string_alloc_set, furi_string_alloc_set_str, a) -/** - * @brief Set the string content to string (or C string). +/** Set the string content to string (or C string). + * * (string, [c]string) */ #define furi_string_set(a, b) FURI_STRING_SELECT2(furi_string_set, furi_string_set_str, a, b) -/** - * @brief Compare string with string (or C string) and return the sort order. +/** Compare string with string (or C string) and return the sort order. + * * Note: doesn't work with UTF-8 strings. * (string, [c]string) */ #define furi_string_cmp(a, b) FURI_STRING_SELECT2(furi_string_cmp, furi_string_cmp_str, a, b) -/** - * @brief Compare string with string (or C string) (case insensitive according to the current locale) and return the sort order. +/** Compare string with string (or C string) (case insensitive according to the current locale) and return the sort order. + * * Note: doesn't work with UTF-8 strings. * (string, [c]string) */ #define furi_string_cmpi(a, b) FURI_STRING_SELECT2(furi_string_cmpi, furi_string_cmpi_str, a, b) -/** - * @brief Test if the string is equal to the string (or C string). +/** Test if the string is equal to the string (or C string). + * * (string, [c]string) */ #define furi_string_equal(a, b) FURI_STRING_SELECT2(furi_string_equal, furi_string_equal_str, a, b) -/** - * @brief Replace all occurrences of string into string (or C string to another C string) in a string. +/** Replace all occurrences of string into string (or C string to another C string) in a string. + * * (string, [c]string, [c]string) */ #define furi_string_replace_all(a, b, c) \ FURI_STRING_SELECT3(furi_string_replace_all, furi_string_replace_all_str, a, b, c) -/** - * @brief Search for a string (or C string) in a string +/** Search for a string (or C string) in a string + * * (string, [c]string[, start=0]) */ #define furi_string_search(...) \ @@ -643,52 +697,59 @@ void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnico furi_string_search, \ furi_string_search_str, \ M_DEFAULT_ARGS(3, (0), __VA_ARGS__)) -/** - * @brief Search for a C string in a string +/** Search for a C string in a string + * * (string, cstring[, start=0]) */ #define furi_string_search_str(...) furi_string_search_str(M_DEFAULT_ARGS(3, (0), __VA_ARGS__)) -/** - * @brief Test if the string starts with the given string (or C string). +/** Test if the string starts with the given string (or C string). + * * (string, [c]string) */ #define furi_string_start_with(a, b) \ FURI_STRING_SELECT2(furi_string_start_with, furi_string_start_with_str, a, b) -/** - * @brief Test if the string ends with the given string (or C string). +/** Test if the string ends with the given string (or C string). + * * (string, [c]string) */ #define furi_string_end_with(a, b) \ FURI_STRING_SELECT2(furi_string_end_with, furi_string_end_with_str, a, b) -/** - * @brief Append a string (or C string) to the string. +/** Test if the string ends with the given string (or C string) (case insensitive according to the current locale). + * + * (string, [c]string) + */ +#define furi_string_end_withi(a, b) \ + FURI_STRING_SELECT2(furi_string_end_withi, furi_string_end_withi_str, a, b) + +/** Append a string (or C string) to the string. + * * (string, [c]string) */ #define furi_string_cat(a, b) FURI_STRING_SELECT2(furi_string_cat, furi_string_cat_str, a, b) -/** - * @brief Trim a string from the given set of characters (default is " \n\r\t"). +/** Trim a string from the given set of characters (default is " \n\r\t"). + * * (string[, set=" \n\r\t"]) */ #define furi_string_trim(...) furi_string_trim(M_DEFAULT_ARGS(2, (" \n\r\t"), __VA_ARGS__)) -/** - * @brief Search for a character in a string. +/** Search for a character in a string. + * * (string, character[, start=0]) */ #define furi_string_search_char(...) furi_string_search_char(M_DEFAULT_ARGS(3, (0), __VA_ARGS__)) -/** - * @brief Reverse Search for a character in a string. +/** Reverse Search for a character in a string. + * * (string, character[, start=0]) */ #define furi_string_search_rchar(...) furi_string_search_rchar(M_DEFAULT_ARGS(3, (0), __VA_ARGS__)) -/** - * @brief Replace a string to another string (or C string to another C string) in a string. +/** Replace a string to another string (or C string to another C string) in a string. + * * (string, [c]string, [c]string[, start=0]) */ #define furi_string_replace(...) \ @@ -698,30 +759,22 @@ void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnico furi_string_replace_str, \ M_DEFAULT_ARGS(4, (0), __VA_ARGS__)) -/** - * @brief Replace a C string to another C string in a string. +/** Replace a C string to another C string in a string. + * * (string, cstring, cstring[, start=0]) */ #define furi_string_replace_str(...) furi_string_replace_str(M_DEFAULT_ARGS(4, (0), __VA_ARGS__)) -/** - * @brief INIT OPLIST for FuriString. - */ +/** INIT OPLIST for FuriString */ #define F_STR_INIT(a) ((a) = furi_string_alloc()) -/** - * @brief INIT SET OPLIST for FuriString. - */ +/** INIT SET OPLIST for FuriString */ #define F_STR_INIT_SET(a, b) ((a) = furi_string_alloc_set(b)) -/** - * @brief INIT MOVE OPLIST for FuriString. - */ +/** INIT MOVE OPLIST for FuriString */ #define F_STR_INIT_MOVE(a, b) ((a) = furi_string_alloc_move(b)) -/** - * @brief OPLIST for FuriString. - */ +/** OPLIST for FuriString */ #define FURI_STRING_OPLIST \ (INIT(F_STR_INIT), \ INIT_SET(F_STR_INIT_SET), \ diff --git a/furi/core/thread.c b/furi/core/thread.c index c47df55e49..69c6b0f04e 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -318,6 +318,12 @@ void furi_thread_set_signal_callback( thread->signal_context = context; } +FuriThreadSignalCallback furi_thread_get_signal_callback(const FuriThread* thread) { + furi_check(thread); + + return thread->signal_callback; +} + bool furi_thread_signal(const FuriThread* thread, uint32_t signal, void* arg) { furi_check(thread); diff --git a/furi/core/thread.h b/furi/core/thread.h index be09e040ea..e8cdeaeafb 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -270,7 +270,7 @@ FuriThreadState furi_thread_get_state(FuriThread* thread); /** * @brief Set a signal handler callback for a FuriThread instance. * - * The thread MUST be stopped when calling this function. + * The thread MUST be stopped when calling this function if calling it from another thread. * * @param[in,out] thread pointer to the FuriThread instance to be modified * @param[in] callback pointer to a user-specified callback function @@ -281,6 +281,14 @@ void furi_thread_set_signal_callback( FuriThreadSignalCallback callback, void* context); +/** + * @brief Get a signal callback for a FuriThread instance. + * + * @param[in] thread pointer to the FuriThread instance to be queried + * @return pointer to the callback function or NULL if none has been set + */ +FuriThreadSignalCallback furi_thread_get_signal_callback(const FuriThread* thread); + /** * @brief Send a signal to a FuriThread instance. * diff --git a/furi/furi.c b/furi/furi.c index dca674da57..f4e64ee099 100644 --- a/furi/furi.c +++ b/furi/furi.c @@ -15,13 +15,6 @@ void furi_run(void) { furi_check(!furi_kernel_is_irq_or_masked()); furi_check(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED); -#if(__ARM_ARCH_7A__ == 0U) - /* Service Call interrupt might be configured before kernel start */ - /* and when its priority is lower or equal to BASEPRI, svc instruction */ - /* causes a Hard Fault. */ - NVIC_SetPriority(SVCall_IRQn, 0U); -#endif - /* Start the kernel scheduler */ vTaskStartScheduler(); } diff --git a/furi/furi.h b/furi/furi.h index 80ee30457c..d75debe987 100644 --- a/furi/furi.h +++ b/furi/furi.h @@ -2,8 +2,8 @@ #include -#include "core/check.h" #include "core/common_defines.h" +#include "core/check.h" #include "core/event_loop.h" #include "core/event_loop_timer.h" #include "core/event_flag.h" diff --git a/lib/ReadMe.md b/lib/ReadMe.md index 64da39e358..4656f187b6 100644 --- a/lib/ReadMe.md +++ b/lib/ReadMe.md @@ -18,7 +18,6 @@ - `infrared` - Infrared library, used by Infrared application - `lfrfid` - LF-RFID library, used by LF RFID application - `libusb_stm32` - LibUSB for STM32 series MCU -- `littlefs` - LittleFS file system driver, used by internal storage - `mbedtls` - MbedTLS cryptography library - `microtar` - MicroTAR library - `mjs` - MJs, javascript engine library diff --git a/lib/SConscript b/lib/SConscript index f331198a42..fb0473f8d4 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -27,13 +27,11 @@ libs = env.BuildModules( "one_wire", "ibutton", "infrared", - "littlefs", "subghz", "nfc", "digital_signal", "pulse_reader", "signal_reader", - "appframe", "u8g2", "lfrfid", "flipper_application", diff --git a/lib/app-scened-template/generic_scene.hpp b/lib/app-scened-template/generic_scene.hpp deleted file mode 100644 index 580346c8c0..0000000000 --- a/lib/app-scened-template/generic_scene.hpp +++ /dev/null @@ -1,10 +0,0 @@ -template -class GenericScene { -public: - virtual void on_enter(TApp* app, bool need_restore) = 0; - virtual bool on_event(TApp* app, typename TApp::Event* event) = 0; - virtual void on_exit(TApp* app) = 0; - virtual ~GenericScene() {}; - -private: -}; diff --git a/lib/app-scened-template/record_controller.hpp b/lib/app-scened-template/record_controller.hpp deleted file mode 100644 index 3453c12f3a..0000000000 --- a/lib/app-scened-template/record_controller.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once -#include - -/** - * @brief Class for opening, casting, holding and closing records - * - * @tparam TRecordClass record class - */ -template -class RecordController { -public: - /** - * @brief Construct a new Record Controller object for record with record name - * - * @param record_name record name - */ - RecordController(const char* record_name) { - name = record_name; - value = static_cast(furi_record_open(name)); - } - - ~RecordController() { - furi_record_close(name); - } - - /** - * @brief Record getter - * - * @return TRecordClass* record value - */ - TRecordClass* get() { - return value; - } - - /** - * @brief Record getter (by cast) - * - * @return TRecordClass* record value - */ - operator TRecordClass*() const { - return value; - } - -private: - const char* name; - TRecordClass* value; -}; diff --git a/lib/app-scened-template/scene_controller.hpp b/lib/app-scened-template/scene_controller.hpp deleted file mode 100644 index eb43109584..0000000000 --- a/lib/app-scened-template/scene_controller.hpp +++ /dev/null @@ -1,246 +0,0 @@ -#include -#include -#include - -#define GENERIC_SCENE_ENUM_VALUES Exit, Start -#define GENERIC_EVENT_ENUM_VALUES Tick, Back - -/** - * @brief Controller for scene navigation in application - * - * @tparam TScene generic scene class - * @tparam TApp application class - */ -template -class SceneController { -public: - /** - * @brief Add scene to scene container - * - * @param scene_index scene index - * @param scene_pointer scene object pointer - */ - void add_scene(typename TApp::SceneType scene_index, TScene* scene_pointer) { - furi_check(scenes.count(scene_index) == 0); - scenes[scene_index] = scene_pointer; - } - - /** - * @brief Switch to next scene and store current scene in previous scenes list - * - * @param scene_index next scene index - * @param need_restore true, if we want the scene to restore its parameters - */ - void switch_to_next_scene(typename TApp::SceneType scene_index, bool need_restore = false) { - previous_scenes_list.push_front(current_scene_index); - switch_to_scene(scene_index, need_restore); - } - - /** - * @brief Switch to next scene without ability to return to current scene - * - * @param scene_index next scene index - * @param need_restore true, if we want the scene to restore its parameters - */ - void switch_to_scene(typename TApp::SceneType scene_index, bool need_restore = false) { - if(scene_index != TApp::SceneType::Exit) { - scenes[current_scene_index]->on_exit(app); - current_scene_index = scene_index; - scenes[current_scene_index]->on_enter(app, need_restore); - } - } - - /** - * @brief Search the scene in the list of previous scenes and switch to it - * - * @param scene_index_list list of scene indexes to which you want to switch - */ - bool search_and_switch_to_previous_scene( - const std::initializer_list& scene_index_list) { - auto previous_scene_index = TApp::SceneType::Exit; - bool scene_found = false; - bool result = false; - - while(!scene_found) { - previous_scene_index = get_previous_scene_index(); - for(const auto& element : scene_index_list) { - if(previous_scene_index == element) { - scene_found = true; - result = true; - break; - } - - if(previous_scene_index == TApp::SceneType::Exit) { - scene_found = true; - break; - } - } - } - - if(result) { - switch_to_scene(previous_scene_index, true); - } - - return result; - } - - bool search_and_switch_to_another_scene( - const std::initializer_list& scene_index_list, - typename TApp::SceneType scene_index) { - auto previous_scene_index = TApp::SceneType::Exit; - bool scene_found = false; - bool result = false; - - while(!scene_found) { - previous_scene_index = get_previous_scene_index(); - for(const auto& element : scene_index_list) { - if(previous_scene_index == element) { - scene_found = true; - result = true; - break; - } - - if(previous_scene_index == TApp::SceneType::Exit) { - scene_found = true; - break; - } - } - } - - if(result) { - switch_to_scene(scene_index, true); - } - - return result; - } - - bool has_previous_scene( - const std::initializer_list& scene_index_list) { - bool result = false; - - for(auto const& previous_element : previous_scenes_list) { - for(const auto& element : scene_index_list) { - if(previous_element == element) { - result = true; - break; - } - - if(previous_element == TApp::SceneType::Exit) { - break; - } - } - - if(result) break; - } - - return result; - } - - /** - * @brief Start application main cycle - * - * @param tick_length_ms tick event length in milliseconds - */ - void process( - uint32_t /* tick_length_ms */ = 100, - typename TApp::SceneType start_scene_index = TApp::SceneType::Start) { - typename TApp::Event event; - bool consumed; - bool exit = false; - - current_scene_index = start_scene_index; - scenes[current_scene_index]->on_enter(app, false); - - while(!exit) { - app->view_controller.receive_event(&event); - - consumed = scenes[current_scene_index]->on_event(app, &event); - - if(!consumed) { - if(event.type == TApp::EventType::Back) { - exit = switch_to_previous_scene(); - } - } - }; - - scenes[current_scene_index]->on_exit(app); - } - - /** - * @brief Switch to previous scene - * - * @param count how many steps back - * @return true if app need to exit - */ - bool switch_to_previous_scene(uint8_t count = 1) { - auto previous_scene_index = TApp::SceneType::Start; - - for(uint8_t i = 0; i < count; i++) - previous_scene_index = get_previous_scene_index(); - - if(previous_scene_index == TApp::SceneType::Exit) return true; - - switch_to_scene(previous_scene_index, true); - return false; - } - - /** - * @brief Construct a new Scene Controller object - * - * @param app_pointer pointer to application class - */ - SceneController(TApp* app_pointer) { - app = app_pointer; - current_scene_index = TApp::SceneType::Exit; - } - - /** - * @brief Destroy the Scene Controller object - * - */ - ~SceneController() { - for(auto& it : scenes) - delete it.second; - } - -private: - /** - * @brief Scenes pointers container - * - */ - std::map scenes; - - /** - * @brief List of indexes of previous scenes - * - */ - std::forward_list previous_scenes_list; - - /** - * @brief Current scene index holder - * - */ - typename TApp::SceneType current_scene_index; - - /** - * @brief Application pointer holder - * - */ - TApp* app; - - /** - * @brief Get the previous scene index - * - * @return previous scene index - */ - typename TApp::SceneType get_previous_scene_index() { - auto scene_index = TApp::SceneType::Exit; - - if(!previous_scenes_list.empty()) { - scene_index = previous_scenes_list.front(); - previous_scenes_list.pop_front(); - } - - return scene_index; - } -}; diff --git a/lib/app-scened-template/text_store.cpp b/lib/app-scened-template/text_store.cpp deleted file mode 100644 index c81a2c4e78..0000000000 --- a/lib/app-scened-template/text_store.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "text_store.h" -#include - -TextStore::TextStore(uint8_t _text_size) - : text_size(_text_size) { - text = static_cast(malloc(text_size + 1)); -} - -TextStore::~TextStore() { - free(text); -} - -void TextStore::set(const char* _text...) { - va_list args; - va_start(args, _text); - vsnprintf(text, text_size, _text, args); - va_end(args); -} diff --git a/lib/app-scened-template/text_store.h b/lib/app-scened-template/text_store.h deleted file mode 100644 index 3fe58ed1df..0000000000 --- a/lib/app-scened-template/text_store.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include - -class TextStore { -public: - TextStore(uint8_t text_size); - ~TextStore(void); - - void set(const char* text...); - const uint8_t text_size; - char* text; -}; diff --git a/lib/app-scened-template/typeindex_no_rtti.hpp b/lib/app-scened-template/typeindex_no_rtti.hpp deleted file mode 100644 index 579a0189d9..0000000000 --- a/lib/app-scened-template/typeindex_no_rtti.hpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * type_index without RTTI - * - * Copyright frickiericker 2016. - * Distributed under the Boost Software License, Version 1.0. - * - * Permission is hereby granted, free of charge, to any person or organization - * obtaining a copy of the software and accompanying documentation covered by - * this license (the "Software") to use, reproduce, display, distribute, - * execute, and transmit the Software, and to prepare derivative works of the - * Software, and to permit third-parties to whom the Software is furnished to - * do so, all subject to the following: - * - * The copyright notices in the Software and this entire statement, including - * the above license grant, this restriction and the following disclaimer, - * must be included in all copies of the Software, in whole or in part, and - * all derivative works of the Software, unless such copies or derivative - * works are solely in the form of machine-executable object code generated by - * a source language processor. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT - * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE - * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include - -namespace ext { -/** - * Dummy type for tag-dispatching. - */ -template -struct tag_type {}; - -/** - * A value of tag_type. - */ -template -constexpr tag_type tag{}; - -/** - * A type_index implementation without RTTI. - */ -struct type_index { - /** - * Creates a type_index object for the specified type. - */ - template - type_index(tag_type) noexcept - : hash_code_{index} { - } - - /** - * Returns the hash code. - */ - std::size_t hash_code() const noexcept { - return hash_code_; - } - -private: - /** - * Unique integral index associated to template type argument. - */ - template - static std::size_t const index; - - /** - * Global counter for generating index values. - */ - static std::size_t& counter() noexcept { - static std::size_t counter_; - return counter_; - } - -private: - std::size_t hash_code_; -}; - -template -std::size_t const type_index::index = type_index::counter()++; - -/** - * Creates a type_index object for the specified type. - * - * Equivalent to `ext::type_index{ext::tag}`. - */ -template -type_index make_type_index() noexcept { - return tag; -} - -inline bool operator==(type_index const& a, type_index const& b) noexcept { - return a.hash_code() == b.hash_code(); -} - -inline bool operator!=(type_index const& a, type_index const& b) noexcept { - return !(a == b); -} - -inline bool operator<(type_index const& a, type_index const& b) noexcept { - return a.hash_code() < b.hash_code(); -} - -inline bool operator<=(type_index const& a, type_index const& b) noexcept { - return a.hash_code() <= b.hash_code(); -} - -inline bool operator>(type_index const& a, type_index const& b) noexcept { - return !(a <= b); -} - -inline bool operator>=(type_index const& a, type_index const& b) noexcept { - return !(a < b); -} -} - -template <> -struct std::hash { - using argument_type = ext::type_index; - using result_type = std::size_t; - - result_type operator()(argument_type const& t) const noexcept { - return t.hash_code(); - } -}; diff --git a/lib/app-scened-template/view_controller.hpp b/lib/app-scened-template/view_controller.hpp deleted file mode 100644 index ccd3c0fd39..0000000000 --- a/lib/app-scened-template/view_controller.hpp +++ /dev/null @@ -1,170 +0,0 @@ -#pragma once -#include "view_modules/generic_view_module.h" -#include -#include -#include -#include -#include "typeindex_no_rtti.hpp" - -/** - * @brief Controller for switching application views and handling inputs and events - * - * @tparam TApp application class - * @tparam TViewModules variadic list of ViewModules - */ -template -class ViewController { -public: - ViewController() { - event_queue = furi_message_queue_alloc(10, sizeof(typename TApp::Event)); - - view_dispatcher = view_dispatcher_alloc(); - previous_view_callback_pointer = cbc::obtain_connector( - this, &ViewController::previous_view_callback); - - [](...) { - }((this->add_view(ext::make_type_index().hash_code(), new TViewModules()), - 0)...); - - gui = static_cast(furi_record_open("gui")); - } - - ~ViewController() { - for(auto& it : holder) { - view_dispatcher_remove_view(view_dispatcher, static_cast(it.first)); - delete it.second; - } - - view_dispatcher_free(view_dispatcher); - furi_message_queue_free(event_queue); - } - - /** - * @brief Get ViewModule pointer - * - * @tparam T Concrete ViewModule class - * @return T* ViewModule pointer - */ - template - T* get() { - uint32_t view_index = ext::make_type_index().hash_code(); - furi_check(holder.count(view_index) != 0); - return static_cast(holder[view_index]); - } - - /** - * @brief Get ViewModule pointer by cast - * - * @tparam T Concrete ViewModule class - * @return T* ViewModule pointer - */ - template - operator T*() { - uint32_t view_index = ext::make_type_index().hash_code(); - furi_check(holder.count(view_index) != 0); - return static_cast(holder[view_index]); - } - - /** - * @brief Switch view to ViewModule - * - * @tparam T Concrete ViewModule class - * @return T* ViewModule pointer - */ - template - void switch_to() { - uint32_t view_index = ext::make_type_index().hash_code(); - furi_check(holder.count(view_index) != 0); - view_dispatcher_switch_to_view(view_dispatcher, view_index); - } - - /** - * @brief Receive event from app event queue - * - * @param event event pointer - */ - void receive_event(typename TApp::Event* event) { - if(furi_message_queue_get(event_queue, event, 100) != FuriStatusOk) { - event->type = TApp::EventType::Tick; - } - } - - /** - * @brief Send event to app event queue - * - * @param event event pointer - */ - void send_event(typename TApp::Event* event) { - FuriStatus result = furi_message_queue_put(event_queue, event, FuriWaitForever); - furi_check(result == FuriStatusOk); - } - - void attach_to_gui(ViewDispatcherType type) { - view_dispatcher_attach_to_gui(view_dispatcher, gui, type); - } - -private: - /** - * @brief ViewModulesHolder - * - */ - std::map holder; - - /** - * @brief App event queue - * - */ - FuriMessageQueue* event_queue; - - /** - * @brief Main ViewDispatcher pointer - * - */ - ViewDispatcher* view_dispatcher; - - /** - * @brief Gui record pointer - * - */ - Gui* gui; - - /** - * @brief Previous view callback fn pointer - * - */ - ViewNavigationCallback previous_view_callback_pointer; - - /** - * @brief Previous view callback fn - * - * @param context not used - * @return uint32_t VIEW_IGNORE - */ - uint32_t previous_view_callback(void* context) { - (void)context; - - typename TApp::Event event; - event.type = TApp::EventType::Back; - - if(event_queue != NULL) { - send_event(&event); - } - - return VIEW_IGNORE; - } - - /** - * @brief Add ViewModule to holder - * - * @param view_index view index in holder - * @param view_module view module pointer - */ - void add_view(size_t view_index, GenericViewModule* view_module) { - furi_check(holder.count(view_index) == 0); - holder[view_index] = view_module; - - View* view = view_module->get_view(); - view_dispatcher_add_view(view_dispatcher, static_cast(view_index), view); - view_set_previous_callback(view, previous_view_callback_pointer); - } -}; diff --git a/lib/app-scened-template/view_modules/byte_input_vm.cpp b/lib/app-scened-template/view_modules/byte_input_vm.cpp deleted file mode 100644 index 754de9111e..0000000000 --- a/lib/app-scened-template/view_modules/byte_input_vm.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "byte_input_vm.h" - -ByteInputVM::ByteInputVM() { - byte_input = byte_input_alloc(); -} - -ByteInputVM::~ByteInputVM() { - byte_input_free(byte_input); -} - -View* ByteInputVM::get_view() { - return byte_input_get_view(byte_input); -} - -void ByteInputVM::clean() { - byte_input_set_header_text(byte_input, ""); - byte_input_set_result_callback(byte_input, NULL, NULL, NULL, NULL, 0); -} - -void ByteInputVM::set_result_callback( - ByteInputCallback input_callback, - ByteChangedCallback changed_callback, - void* callback_context, - uint8_t* bytes, - uint8_t bytes_count) { - byte_input_set_result_callback( - byte_input, input_callback, changed_callback, callback_context, bytes, bytes_count); -} - -void ByteInputVM::set_header_text(const char* text) { - byte_input_set_header_text(byte_input, text); -} diff --git a/lib/app-scened-template/view_modules/byte_input_vm.h b/lib/app-scened-template/view_modules/byte_input_vm.h deleted file mode 100644 index 69031fbee6..0000000000 --- a/lib/app-scened-template/view_modules/byte_input_vm.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -#include "generic_view_module.h" -#include - -class ByteInputVM : public GenericViewModule { -public: - ByteInputVM(void); - ~ByteInputVM() final; - View* get_view() final; - void clean() final; - - /** - * @brief Set byte input result callback - * - * @param input_callback input callback fn - * @param changed_callback changed callback fn - * @param callback_context callback context - * @param bytes buffer to use - * @param bytes_count buffer length - */ - void set_result_callback( - ByteInputCallback input_callback, - ByteChangedCallback changed_callback, - void* callback_context, - uint8_t* bytes, - uint8_t bytes_count); - - /** - * @brief Set byte input header text - * - * @param text text to be shown - */ - void set_header_text(const char* text); - -private: - ByteInput* byte_input; -}; diff --git a/lib/app-scened-template/view_modules/dialog_ex_vm.cpp b/lib/app-scened-template/view_modules/dialog_ex_vm.cpp deleted file mode 100644 index 34f4d0336c..0000000000 --- a/lib/app-scened-template/view_modules/dialog_ex_vm.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "dialog_ex_vm.h" - -DialogExVM::DialogExVM() { - dialog_ex = dialog_ex_alloc(); -} - -DialogExVM::~DialogExVM() { - dialog_ex_free(dialog_ex); -} - -View* DialogExVM::get_view() { - return dialog_ex_get_view(dialog_ex); -} - -void DialogExVM::clean() { - set_result_callback(NULL); - set_context(NULL); - set_header(NULL, 0, 0, AlignLeft, AlignBottom); - set_text(NULL, 0, 0, AlignLeft, AlignBottom); - set_icon(0, 0, NULL); - set_left_button_text(NULL); - set_center_button_text(NULL); - set_right_button_text(NULL); -} - -void DialogExVM::set_result_callback(DialogExResultCallback callback) { - dialog_ex_set_result_callback(dialog_ex, callback); -} - -void DialogExVM::set_context(void* context) { - dialog_ex_set_context(dialog_ex, context); -} - -void DialogExVM::set_header( - const char* text, - uint8_t x, - uint8_t y, - Align horizontal, - Align vertical) { - dialog_ex_set_header(dialog_ex, text, x, y, horizontal, vertical); -} - -void DialogExVM::set_text(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical) { - dialog_ex_set_text(dialog_ex, text, x, y, horizontal, vertical); -} - -void DialogExVM::set_icon(uint8_t x, uint8_t y, const Icon* icon) { - dialog_ex_set_icon(dialog_ex, x, y, icon); -} - -void DialogExVM::set_left_button_text(const char* text) { - dialog_ex_set_left_button_text(dialog_ex, text); -} - -void DialogExVM::set_center_button_text(const char* text) { - dialog_ex_set_center_button_text(dialog_ex, text); -} - -void DialogExVM::set_right_button_text(const char* text) { - dialog_ex_set_right_button_text(dialog_ex, text); -} diff --git a/lib/app-scened-template/view_modules/dialog_ex_vm.h b/lib/app-scened-template/view_modules/dialog_ex_vm.h deleted file mode 100644 index cb63ccdbc2..0000000000 --- a/lib/app-scened-template/view_modules/dialog_ex_vm.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once -#include "generic_view_module.h" -#include - -class DialogExVM : public GenericViewModule { -public: - DialogExVM(void); - ~DialogExVM() final; - View* get_view() final; - void clean() final; - - /** - * Set dialog result callback - * @param callback - result callback function - */ - void set_result_callback(DialogExResultCallback callback); - - /** - * Set dialog context - * @param context - context pointer, will be passed to result callback - */ - void set_context(void* context); - - /** - * Set dialog header text - * If text is null, dialog header will not be rendered - * @param text - text to be shown, can be multiline - * @param x, y - text position - * @param horizontal, vertical - text aligment - */ - void set_header(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical); - - /** - * Set dialog text - * If text is null, dialog text will not be rendered - * @param text - text to be shown, can be multiline - * @param x, y - text position - * @param horizontal, vertical - text aligment - */ - void set_text(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical); - - /** - * Set dialog icon - * If x or y is negative, dialog icon will not be rendered - * @param x, y - icon position - * @param name - icon to be shown - */ - void set_icon(uint8_t x, uint8_t y, const Icon* icon); - - /** - * Set left button text - * If text is null, left button will not be rendered and processed - * @param text - text to be shown - */ - void set_left_button_text(const char* text); - - /** - * Set center button text - * If text is null, center button will not be rendered and processed - * @param text - text to be shown - */ - void set_center_button_text(const char* text); - - /** - * Set right button text - * If text is null, right button will not be rendered and processed - * @param text - text to be shown - */ - void set_right_button_text(const char* text); - -private: - DialogEx* dialog_ex; -}; diff --git a/lib/app-scened-template/view_modules/generic_view_module.h b/lib/app-scened-template/view_modules/generic_view_module.h deleted file mode 100644 index f6c56a9110..0000000000 --- a/lib/app-scened-template/view_modules/generic_view_module.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include - -class GenericViewModule { -public: - GenericViewModule() {}; - virtual ~GenericViewModule() {}; - virtual View* get_view() = 0; - virtual void clean() = 0; -}; diff --git a/lib/app-scened-template/view_modules/popup_vm.cpp b/lib/app-scened-template/view_modules/popup_vm.cpp deleted file mode 100644 index 330aa44ca9..0000000000 --- a/lib/app-scened-template/view_modules/popup_vm.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "popup_vm.h" -#include - -PopupVM::PopupVM() { - popup = popup_alloc(); -} - -PopupVM::~PopupVM() { - popup_free(popup); -} - -View* PopupVM::get_view() { - return popup_get_view(popup); -} - -void PopupVM::clean() { - set_callback(NULL); - set_context(NULL); - set_header(NULL, 0, 0, AlignLeft, AlignBottom); - set_text(NULL, 0, 0, AlignLeft, AlignBottom); - set_icon(0, 0, NULL); - disable_timeout(); - set_timeout(1000); -} - -void PopupVM::set_callback(PopupCallback callback) { - popup_set_callback(popup, callback); -} - -void PopupVM::set_context(void* context) { - popup_set_context(popup, context); -} - -void PopupVM::set_header(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical) { - popup_set_header(popup, text, x, y, horizontal, vertical); -} - -void PopupVM::set_text(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical) { - popup_set_text(popup, text, x, y, horizontal, vertical); -} - -void PopupVM::set_icon(int8_t x, int8_t y, const Icon* icon) { - popup_set_icon(popup, x, y, icon); -} - -void PopupVM::set_timeout(uint32_t timeout_in_ms) { - popup_set_timeout(popup, timeout_in_ms); -} - -void PopupVM::enable_timeout() { - popup_enable_timeout(popup); -} - -void PopupVM::disable_timeout() { - popup_disable_timeout(popup); -} diff --git a/lib/app-scened-template/view_modules/popup_vm.h b/lib/app-scened-template/view_modules/popup_vm.h deleted file mode 100644 index 234f337746..0000000000 --- a/lib/app-scened-template/view_modules/popup_vm.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once -#include "generic_view_module.h" -#include - -class PopupVM : public GenericViewModule { -public: - PopupVM(void); - ~PopupVM() final; - View* get_view() final; - void clean() final; - - /** - * Set popup header text - * @param text - text to be shown - */ - void set_callback(PopupCallback callback); - - /** - * Set popup context - * @param context - context pointer, will be passed to result callback - */ - void set_context(void* context); - - /** - * Set popup header text - * If text is null, popup header will not be rendered - * @param text - text to be shown, can be multiline - * @param x, y - text position - * @param horizontal, vertical - text aligment - */ - void set_header(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical); - - /** - * Set popup text - * If text is null, popup text will not be rendered - * @param text - text to be shown, can be multiline - * @param x, y - text position - * @param horizontal, vertical - text aligment - */ - void set_text(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical); - - /** - * Set popup icon - * If icon position is negative, popup icon will not be rendered - * @param x, y - icon position - * @param name - icon to be shown - */ - void set_icon(int8_t x, int8_t y, const Icon* icon); - - /** - * Set popup timeout - * @param timeout_in_ms - popup timeout value in milliseconds - */ - void set_timeout(uint32_t timeout_in_ms); - - /** - * Enable popup timeout - */ - void enable_timeout(void); - - /** - * Disable popup timeout - */ - void disable_timeout(void); - -private: - Popup* popup; -}; diff --git a/lib/app-scened-template/view_modules/submenu_vm.cpp b/lib/app-scened-template/view_modules/submenu_vm.cpp deleted file mode 100644 index 939bb6b1ce..0000000000 --- a/lib/app-scened-template/view_modules/submenu_vm.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "submenu_vm.h" - -SubmenuVM::SubmenuVM() { - submenu = submenu_alloc(); -} - -SubmenuVM::~SubmenuVM() { - submenu_free(submenu); -} - -View* SubmenuVM::get_view() { - return submenu_get_view(submenu); -} - -void SubmenuVM::clean() { - submenu_reset(submenu); -} - -void SubmenuVM::add_item( - const char* label, - uint32_t index, - SubmenuItemCallback callback, - void* callback_context) { - submenu_add_item(submenu, label, index, callback, callback_context); -} - -void SubmenuVM::set_selected_item(uint32_t index) { - submenu_set_selected_item(submenu, index); -} - -void SubmenuVM::set_header(const char* header) { - submenu_set_header(submenu, header); -} diff --git a/lib/app-scened-template/view_modules/submenu_vm.h b/lib/app-scened-template/view_modules/submenu_vm.h deleted file mode 100644 index 223fbd531e..0000000000 --- a/lib/app-scened-template/view_modules/submenu_vm.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include "generic_view_module.h" -#include - -class SubmenuVM : public GenericViewModule { -public: - SubmenuVM(void); - ~SubmenuVM() final; - View* get_view() final; - void clean() final; - - /** - * @brief Add item to submenu - * - * @param label - menu item label - * @param index - menu item index, used for callback, may be the same with other items - * @param callback - menu item callback - * @param callback_context - menu item callback context - */ - void add_item( - const char* label, - uint32_t index, - SubmenuItemCallback callback, - void* callback_context); - - /** - * @brief Set submenu item selector - * - * @param index index of the item to be selected - */ - void set_selected_item(uint32_t index); - - /** - * @brief Set optional header for submenu - * - * @param header header to set - */ - void set_header(const char* header); - -private: - Submenu* submenu; -}; diff --git a/lib/app-scened-template/view_modules/text_input_vm.cpp b/lib/app-scened-template/view_modules/text_input_vm.cpp deleted file mode 100644 index 05e5ed1d69..0000000000 --- a/lib/app-scened-template/view_modules/text_input_vm.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "text_input_vm.h" - -TextInputVM::TextInputVM() { - text_input = text_input_alloc(); -} - -TextInputVM::~TextInputVM() { - text_input_free(text_input); -} - -View* TextInputVM::get_view() { - return text_input_get_view(text_input); -} - -void TextInputVM::clean() { - text_input_reset(text_input); -} - -void TextInputVM::set_result_callback( - TextInputCallback callback, - void* callback_context, - char* text, - uint8_t max_text_length, - bool clear_default_text) { - text_input_set_result_callback( - text_input, callback, callback_context, text, max_text_length, clear_default_text); -} - -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 deleted file mode 100644 index 5c71c4318f..0000000000 --- a/lib/app-scened-template/view_modules/text_input_vm.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once -#include "generic_view_module.h" -#include - -class TextInputVM : public GenericViewModule { -public: - TextInputVM(void); - ~TextInputVM() final; - View* get_view() final; - void clean() final; - - /** - * @brief Set text input result callback - * - * @param callback - callback fn - * @param callback_context - callback context - * @param text - text buffer to use - * @param max_text_length - text buffer length - * @param clear_default_text - clears given buffer on OK event - */ - void set_result_callback( - TextInputCallback callback, - void* callback_context, - char* text, - uint8_t max_text_length, - bool clear_default_text); - - /** - * @brief Set text input header text - * - * @param text - text to be shown - */ - void set_header_text(const char* text); - - void set_validator(TextInputValidatorCallback callback, void* callback_context); - - void* get_validator_callback_context(void); - -private: - TextInput* text_input; -}; diff --git a/lib/appframe.scons b/lib/appframe.scons deleted file mode 100644 index fb268579d6..0000000000 --- a/lib/appframe.scons +++ /dev/null @@ -1,29 +0,0 @@ -Import("env") - -env.Append( - CPPPATH=[ - "#/lib/app-scened-template", - "#/lib/callback-connector", - ], - LINT_SOURCES=[ - Dir("app-scened-template"), - ], -) - - -libenv = env.Clone(FW_LIB_NAME="appframe") -libenv.ApplyLibFlags() - -sources = [] - -recurse_dirs = [ - "app-scened-template", - "callback-connector", -] - -for recurse_dir in recurse_dirs: - sources += libenv.GlobRecursive("*.c*", recurse_dir) - -lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) -libenv.Install("${LIB_DIST_DIR}", lib) -Return("lib") diff --git a/lib/ble_profile/extra_profiles/hid_profile.c b/lib/ble_profile/extra_profiles/hid_profile.c index 85fb101b8c..f559a741a6 100644 --- a/lib/ble_profile/extra_profiles/hid_profile.c +++ b/lib/ble_profile/extra_profiles/hid_profile.c @@ -373,6 +373,12 @@ bool ble_profile_hid_mouse_scroll(FuriHalBleProfileBase* profile, int8_t delta) return state; } +// AN5289: 4.7, in order to use flash controller interval must be at least 25ms + advertisement, which is 30 ms +// Since we don't use flash controller anymore interval can be lowered to 7.5ms +#define CONNECTION_INTERVAL_MIN (0x0006) +// Up to 45 ms +#define CONNECTION_INTERVAL_MAX (0x24) + static GapConfig template_config = { .adv_service_uuid = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, .appearance_char = GAP_APPEARANCE_KEYBOARD, @@ -380,8 +386,8 @@ static GapConfig template_config = { .pairing_method = GapPairingPinCodeVerifyYesNo, .conn_param = { - .conn_int_min = 0x18, // AN5289: 4.7, we need at least 25ms + advertisement, which is 30 ms - .conn_int_max = 0x24, // 45 ms + .conn_int_min = CONNECTION_INTERVAL_MIN, + .conn_int_max = CONNECTION_INTERVAL_MAX, .slave_latency = 0, .supervisor_timeout = 0, }, diff --git a/lib/drivers/bq25896_reg.h b/lib/drivers/bq25896_reg.h index 23d094003a..baadf6df27 100644 --- a/lib/drivers/bq25896_reg.h +++ b/lib/drivers/bq25896_reg.h @@ -3,8 +3,8 @@ #include #include -#if BITS_BIG_ENDIAN == 1 -#error Bit structures defined in this file is not portable to BE +#if defined(BITS_BIG_ENDIAN) && BITS_BIG_ENDIAN == 1 +#error Bit structures defined in this file are not portable to BE #endif #define BQ25896_ADDRESS 0xD6 diff --git a/lib/drivers/lp5562_reg.h b/lib/drivers/lp5562_reg.h index 9103e5395f..a901cbada3 100644 --- a/lib/drivers/lp5562_reg.h +++ b/lib/drivers/lp5562_reg.h @@ -1,7 +1,7 @@ #pragma once -#if BITS_BIG_ENDIAN == 1 -#error Bit structures defined in this file is not portable to BE +#if defined(BITS_BIG_ENDIAN) && BITS_BIG_ENDIAN == 1 +#error Bit structures defined in this file are not portable to BE #endif #define LP5562_ADDRESS 0x60 diff --git a/lib/drivers/st25r3916.c b/lib/drivers/st25r3916.c index 4772612135..f8dc9a5eb3 100644 --- a/lib/drivers/st25r3916.c +++ b/lib/drivers/st25r3916.c @@ -57,9 +57,12 @@ bool st25r3916_read_fifo( do { uint8_t fifo_status[2] = {}; st25r3916_read_burst_regs(handle, ST25R3916_REG_FIFO_STATUS1, fifo_status, 2); - size_t bytes = ((fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >> - ST25R3916_REG_FIFO_STATUS2_fifo_b_shift) | - fifo_status[0]; + + uint16_t fifo_status_b9_b8 = + ((fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >> + ST25R3916_REG_FIFO_STATUS2_fifo_b_shift); + size_t bytes = (fifo_status_b9_b8 << 8) | fifo_status[0]; + uint8_t bits = ((fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask) >> ST25R3916_REG_FIFO_STATUS2_fifo_lb_shift); diff --git a/lib/ibutton/ibutton_protocols.c b/lib/ibutton/ibutton_protocols.c index ecd5f9a0dc..7955b06737 100644 --- a/lib/ibutton/ibutton_protocols.c +++ b/lib/ibutton/ibutton_protocols.c @@ -160,7 +160,7 @@ bool ibutton_protocols_read(iButtonProtocols* protocols, iButtonKey* key) { return id != iButtonProtocolIdInvalid; } -bool ibutton_protocols_write_blank(iButtonProtocols* protocols, iButtonKey* key) { +bool ibutton_protocols_write_id(iButtonProtocols* protocols, iButtonKey* key) { furi_check(protocols); furi_check(key); @@ -168,7 +168,7 @@ bool ibutton_protocols_write_blank(iButtonProtocols* protocols, iButtonKey* key) iButtonProtocolData* data = ibutton_key_get_protocol_data(key); GET_PROTOCOL_GROUP(id); - return GROUP_BASE->write_blank(GROUP_DATA, data, PROTOCOL_ID); + return GROUP_BASE->write_id(GROUP_DATA, data, PROTOCOL_ID); } bool ibutton_protocols_write_copy(iButtonProtocols* protocols, iButtonKey* key) { diff --git a/lib/ibutton/ibutton_protocols.h b/lib/ibutton/ibutton_protocols.h index dd2afbd6ee..b0c542352f 100644 --- a/lib/ibutton/ibutton_protocols.h +++ b/lib/ibutton/ibutton_protocols.h @@ -88,7 +88,7 @@ bool ibutton_protocols_read(iButtonProtocols* protocols, iButtonKey* key); * @param [in] key pointer to the key to be written * @return true on success, false on failure */ -bool ibutton_protocols_write_blank(iButtonProtocols* protocols, iButtonKey* key); +bool ibutton_protocols_write_id(iButtonProtocols* protocols, iButtonKey* key); /** * Write the key to another one of the same type diff --git a/lib/ibutton/ibutton_worker.c b/lib/ibutton/ibutton_worker.c index 2874f120ff..ea6febd125 100644 --- a/lib/ibutton/ibutton_worker.c +++ b/lib/ibutton/ibutton_worker.c @@ -7,7 +7,7 @@ typedef enum { iButtonMessageEnd, iButtonMessageStop, iButtonMessageRead, - iButtonMessageWriteBlank, + iButtonMessageWriteId, iButtonMessageWriteCopy, iButtonMessageEmulate, iButtonMessageNotifyEmulate, @@ -78,11 +78,11 @@ void ibutton_worker_read_start(iButtonWorker* worker, iButtonKey* key) { furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk); } -void ibutton_worker_write_blank_start(iButtonWorker* worker, iButtonKey* key) { +void ibutton_worker_write_id_start(iButtonWorker* worker, iButtonKey* key) { furi_check(worker); furi_check(key); - iButtonMessage message = {.type = iButtonMessageWriteBlank, .data.key = key}; + iButtonMessage message = {.type = iButtonMessageWriteId, .data.key = key}; furi_check( furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk); @@ -185,9 +185,9 @@ static int32_t ibutton_worker_thread(void* thread_context) { ibutton_worker_set_key_p(worker, message.data.key); ibutton_worker_switch_mode(worker, iButtonWorkerModeRead); break; - case iButtonMessageWriteBlank: + case iButtonMessageWriteId: ibutton_worker_set_key_p(worker, message.data.key); - ibutton_worker_switch_mode(worker, iButtonWorkerModeWriteBlank); + ibutton_worker_switch_mode(worker, iButtonWorkerModeWriteId); break; case iButtonMessageWriteCopy: ibutton_worker_set_key_p(worker, message.data.key); diff --git a/lib/ibutton/ibutton_worker.h b/lib/ibutton/ibutton_worker.h index 2a12a3194d..6abacc3b6d 100644 --- a/lib/ibutton/ibutton_worker.h +++ b/lib/ibutton/ibutton_worker.h @@ -84,7 +84,7 @@ void ibutton_worker_write_set_callback( * @param worker * @param key */ -void ibutton_worker_write_blank_start(iButtonWorker* worker, iButtonKey* key); +void ibutton_worker_write_id_start(iButtonWorker* worker, iButtonKey* key); /** * Start write copy mode diff --git a/lib/ibutton/ibutton_worker_i.h b/lib/ibutton/ibutton_worker_i.h index 5f259a38af..2b910bad8e 100644 --- a/lib/ibutton/ibutton_worker_i.h +++ b/lib/ibutton/ibutton_worker_i.h @@ -25,7 +25,7 @@ typedef struct { typedef enum { iButtonWorkerModeIdle, iButtonWorkerModeRead, - iButtonWorkerModeWriteBlank, + iButtonWorkerModeWriteId, iButtonWorkerModeWriteCopy, iButtonWorkerModeEmulate, } iButtonWorkerMode; diff --git a/lib/ibutton/ibutton_worker_modes.c b/lib/ibutton/ibutton_worker_modes.c index 83e207de93..5900b10a27 100644 --- a/lib/ibutton/ibutton_worker_modes.c +++ b/lib/ibutton/ibutton_worker_modes.c @@ -20,7 +20,7 @@ static void ibutton_worker_mode_read_tick(iButtonWorker* worker); static void ibutton_worker_mode_read_stop(iButtonWorker* worker); static void ibutton_worker_mode_write_common_start(iButtonWorker* worker); -static void ibutton_worker_mode_write_blank_tick(iButtonWorker* worker); +static void ibutton_worker_mode_write_id_tick(iButtonWorker* worker); static void ibutton_worker_mode_write_copy_tick(iButtonWorker* worker); static void ibutton_worker_mode_write_common_stop(iButtonWorker* worker); @@ -40,7 +40,7 @@ const iButtonWorkerModeType ibutton_worker_modes[] = { { .quant = 1000, .start = ibutton_worker_mode_write_common_start, - .tick = ibutton_worker_mode_write_blank_tick, + .tick = ibutton_worker_mode_write_id_tick, .stop = ibutton_worker_mode_write_common_stop, }, { @@ -123,10 +123,10 @@ void ibutton_worker_mode_write_common_start(iButtonWorker* worker) { //-V524 furi_hal_power_enable_otg(); } -void ibutton_worker_mode_write_blank_tick(iButtonWorker* worker) { +void ibutton_worker_mode_write_id_tick(iButtonWorker* worker) { furi_assert(worker->key); - const bool success = ibutton_protocols_write_blank(worker->protocols, worker->key); + const bool success = ibutton_protocols_write_id(worker->protocols, worker->key); // TODO FL-3527: pass a proper result to the callback const iButtonWorkerWriteResult result = success ? iButtonWorkerWriteOK : iButtonWorkerWriteNoDetect; diff --git a/lib/ibutton/protocols/dallas/protocol_dallas_base.h b/lib/ibutton/protocols/dallas/protocol_dallas_base.h index 05620329f8..66eb42f155 100644 --- a/lib/ibutton/protocols/dallas/protocol_dallas_base.h +++ b/lib/ibutton/protocols/dallas/protocol_dallas_base.h @@ -25,7 +25,7 @@ typedef struct { const char* name; iButtonProtocolDallasReadWriteFunc read; - iButtonProtocolDallasReadWriteFunc write_blank; + iButtonProtocolDallasReadWriteFunc write_id; iButtonProtocolDallasReadWriteFunc write_copy; iButtonProtocolDallasEmulateFunc emulate; iButtonProtocolDallasSaveFunc save; diff --git a/lib/ibutton/protocols/dallas/protocol_ds1420.c b/lib/ibutton/protocols/dallas/protocol_ds1420.c index 42af9f0b18..54f75fc1f9 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1420.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1420.c @@ -23,7 +23,7 @@ typedef struct { } DS1420ProtocolData; static bool dallas_ds1420_read(OneWireHost*, iButtonProtocolData*); -static bool dallas_ds1420_write_blank(OneWireHost*, iButtonProtocolData*); +static bool dallas_ds1420_write_id(OneWireHost*, iButtonProtocolData*); static void dallas_ds1420_emulate(OneWireSlave*, iButtonProtocolData*); static bool dallas_ds1420_load(FlipperFormat*, uint32_t, iButtonProtocolData*); static bool dallas_ds1420_save(FlipperFormat*, const iButtonProtocolData*); @@ -36,13 +36,13 @@ static void dallas_ds1420_apply_edits(iButtonProtocolData*); const iButtonProtocolDallasBase ibutton_protocol_ds1420 = { .family_code = DS1420_FAMILY_CODE, - .features = iButtonProtocolFeatureWriteBlank, + .features = iButtonProtocolFeatureWriteId, .data_size = sizeof(DS1420ProtocolData), .manufacturer = DALLAS_COMMON_MANUFACTURER_NAME, .name = DS1420_FAMILY_NAME, .read = dallas_ds1420_read, - .write_blank = dallas_ds1420_write_blank, + .write_id = dallas_ds1420_write_id, .write_copy = NULL, /* No data to write a copy */ .emulate = dallas_ds1420_emulate, .save = dallas_ds1420_save, @@ -61,7 +61,7 @@ bool dallas_ds1420_read(OneWireHost* host, iButtonProtocolData* protocol_data) { return onewire_host_reset(host) && dallas_common_read_rom(host, &data->rom_data); } -bool dallas_ds1420_write_blank(OneWireHost* host, iButtonProtocolData* protocol_data) { +bool dallas_ds1420_write_id(OneWireHost* host, iButtonProtocolData* protocol_data) { DS1420ProtocolData* data = protocol_data; return rw1990_write_v1(host, data->rom_data.bytes, sizeof(DallasCommonRomData)) || diff --git a/lib/ibutton/protocols/dallas/protocol_ds1971.c b/lib/ibutton/protocols/dallas/protocol_ds1971.c index 64920f6ace..3a9e986411 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1971.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1971.c @@ -5,6 +5,8 @@ #include "dallas_common.h" +#include "../blanks/tm2004.h" + #define DS1971_FAMILY_CODE 0x14U #define DS1971_FAMILY_NAME "DS1971" @@ -31,6 +33,7 @@ typedef struct { } DS1971ProtocolData; static bool dallas_ds1971_read(OneWireHost*, void*); +static bool dallas_ds1971_write_id(OneWireHost*, iButtonProtocolData*); static bool dallas_ds1971_write_copy(OneWireHost*, iButtonProtocolData*); static void dallas_ds1971_emulate(OneWireSlave*, iButtonProtocolData*); static bool dallas_ds1971_load(FlipperFormat*, uint32_t, iButtonProtocolData*); @@ -48,13 +51,14 @@ static bool ds1971_emulate_read_mem(OneWireSlave* bus, const uint8_t* data, size const iButtonProtocolDallasBase ibutton_protocol_ds1971 = { .family_code = DS1971_FAMILY_CODE, - .features = iButtonProtocolFeatureExtData | iButtonProtocolFeatureWriteCopy, + .features = iButtonProtocolFeatureExtData | iButtonProtocolFeatureWriteId | + iButtonProtocolFeatureWriteCopy, .data_size = sizeof(DS1971ProtocolData), .manufacturer = DALLAS_COMMON_MANUFACTURER_NAME, .name = DS1971_FAMILY_NAME, .read = dallas_ds1971_read, - .write_blank = NULL, // TODO FL-3531: Implement writing to blank + .write_id = dallas_ds1971_write_id, .write_copy = dallas_ds1971_write_copy, .emulate = dallas_ds1971_emulate, .save = dallas_ds1971_save, @@ -74,6 +78,11 @@ bool dallas_ds1971_read(OneWireHost* host, iButtonProtocolData* protocol_data) { dallas_ds1971_read_mem(host, 0, data->eeprom_data, DS1971_EEPROM_DATA_SIZE); } +bool dallas_ds1971_write_id(OneWireHost* host, iButtonProtocolData* protocol_data) { + DS1971ProtocolData* data = protocol_data; + return tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); +} + bool dallas_ds1971_write_copy(OneWireHost* host, iButtonProtocolData* protocol_data) { DS1971ProtocolData* data = protocol_data; diff --git a/lib/ibutton/protocols/dallas/protocol_ds1990.c b/lib/ibutton/protocols/dallas/protocol_ds1990.c index 67e7545f45..5ed2171c63 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1990.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1990.c @@ -23,7 +23,7 @@ typedef struct { } DS1990ProtocolData; static bool dallas_ds1990_read(OneWireHost*, iButtonProtocolData*); -static bool dallas_ds1990_write_blank(OneWireHost*, iButtonProtocolData*); +static bool dallas_ds1990_write_id(OneWireHost*, iButtonProtocolData*); static void dallas_ds1990_emulate(OneWireSlave*, iButtonProtocolData*); static bool dallas_ds1990_load(FlipperFormat*, uint32_t, iButtonProtocolData*); static bool dallas_ds1990_save(FlipperFormat*, const iButtonProtocolData*); @@ -36,13 +36,13 @@ static void dallas_ds1990_apply_edits(iButtonProtocolData*); const iButtonProtocolDallasBase ibutton_protocol_ds1990 = { .family_code = DS1990_FAMILY_CODE, - .features = iButtonProtocolFeatureWriteBlank, + .features = iButtonProtocolFeatureWriteId, .data_size = sizeof(DS1990ProtocolData), .manufacturer = DALLAS_COMMON_MANUFACTURER_NAME, .name = DS1990_FAMILY_NAME, .read = dallas_ds1990_read, - .write_blank = dallas_ds1990_write_blank, + .write_id = dallas_ds1990_write_id, .write_copy = NULL, /* No data to write a copy */ .emulate = dallas_ds1990_emulate, .save = dallas_ds1990_save, @@ -61,7 +61,7 @@ bool dallas_ds1990_read(OneWireHost* host, iButtonProtocolData* protocol_data) { return onewire_host_reset(host) && dallas_common_read_rom(host, &data->rom_data); } -bool dallas_ds1990_write_blank(OneWireHost* host, iButtonProtocolData* protocol_data) { +bool dallas_ds1990_write_id(OneWireHost* host, iButtonProtocolData* protocol_data) { DS1990ProtocolData* data = protocol_data; return rw1990_write_v1(host, data->rom_data.bytes, sizeof(DallasCommonRomData)) || diff --git a/lib/ibutton/protocols/dallas/protocol_ds1992.c b/lib/ibutton/protocols/dallas/protocol_ds1992.c index 0b6cd4fca2..05ea9a15c0 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1992.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1992.c @@ -31,7 +31,7 @@ typedef struct { } DS1992ProtocolData; static bool dallas_ds1992_read(OneWireHost*, void*); -static bool dallas_ds1992_write_blank(OneWireHost*, iButtonProtocolData*); +static bool dallas_ds1992_write_id(OneWireHost*, iButtonProtocolData*); static bool dallas_ds1992_write_copy(OneWireHost*, iButtonProtocolData*); static void dallas_ds1992_emulate(OneWireSlave*, iButtonProtocolData*); static bool dallas_ds1992_load(FlipperFormat*, uint32_t, iButtonProtocolData*); @@ -46,14 +46,14 @@ static void dallas_ds1992_apply_edits(iButtonProtocolData*); const iButtonProtocolDallasBase ibutton_protocol_ds1992 = { .family_code = DS1992_FAMILY_CODE, - .features = iButtonProtocolFeatureExtData | iButtonProtocolFeatureWriteBlank | + .features = iButtonProtocolFeatureExtData | iButtonProtocolFeatureWriteId | iButtonProtocolFeatureWriteCopy, .data_size = sizeof(DS1992ProtocolData), .manufacturer = DALLAS_COMMON_MANUFACTURER_NAME, .name = DS1992_FAMILY_NAME, .read = dallas_ds1992_read, - .write_blank = dallas_ds1992_write_blank, + .write_id = dallas_ds1992_write_id, .write_copy = dallas_ds1992_write_copy, .emulate = dallas_ds1992_emulate, .save = dallas_ds1992_save, @@ -73,10 +73,9 @@ bool dallas_ds1992_read(OneWireHost* host, iButtonProtocolData* protocol_data) { dallas_common_read_mem(host, 0, data->sram_data, DS1992_SRAM_DATA_SIZE); } -bool dallas_ds1992_write_blank(OneWireHost* host, iButtonProtocolData* protocol_data) { +bool dallas_ds1992_write_id(OneWireHost* host, iButtonProtocolData* protocol_data) { DS1992ProtocolData* data = protocol_data; - // TODO FL-3532: Make this work, currently broken - return tm2004_write(host, (uint8_t*)data, sizeof(DallasCommonRomData) + DS1992_SRAM_DATA_SIZE); + return tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); } bool dallas_ds1992_write_copy(OneWireHost* host, iButtonProtocolData* protocol_data) { diff --git a/lib/ibutton/protocols/dallas/protocol_ds1996.c b/lib/ibutton/protocols/dallas/protocol_ds1996.c index d78a303f86..12c91b001d 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds1996.c +++ b/lib/ibutton/protocols/dallas/protocol_ds1996.c @@ -5,6 +5,8 @@ #include "dallas_common.h" +#include "../blanks/tm2004.h" + #define DS1996_FAMILY_CODE 0x0CU #define DS1996_FAMILY_NAME "DS1996" @@ -29,6 +31,7 @@ typedef struct { } DS1996ProtocolData; static bool dallas_ds1996_read(OneWireHost*, void*); +static bool dallas_ds1996_write_id(OneWireHost*, iButtonProtocolData*); static bool dallas_ds1996_write_copy(OneWireHost*, iButtonProtocolData*); static void dallas_ds1996_emulate(OneWireSlave*, iButtonProtocolData*); static bool dallas_ds1996_load(FlipperFormat*, uint32_t, iButtonProtocolData*); @@ -43,13 +46,14 @@ static void dallas_ds1996_apply_edits(iButtonProtocolData*); const iButtonProtocolDallasBase ibutton_protocol_ds1996 = { .family_code = DS1996_FAMILY_CODE, - .features = iButtonProtocolFeatureExtData | iButtonProtocolFeatureWriteCopy, + .features = iButtonProtocolFeatureExtData | iButtonProtocolFeatureWriteId | + iButtonProtocolFeatureWriteCopy, .data_size = sizeof(DS1996ProtocolData), .manufacturer = DALLAS_COMMON_MANUFACTURER_NAME, .name = DS1996_FAMILY_NAME, .read = dallas_ds1996_read, - .write_blank = NULL, /* Data too big for known blanks */ + .write_id = dallas_ds1996_write_id, .write_copy = dallas_ds1996_write_copy, .emulate = dallas_ds1996_emulate, .save = dallas_ds1996_save, @@ -83,6 +87,11 @@ bool dallas_ds1996_read(OneWireHost* host, iButtonProtocolData* protocol_data) { return success; } +bool dallas_ds1996_write_id(OneWireHost* host, iButtonProtocolData* protocol_data) { + DS1996ProtocolData* data = protocol_data; + return tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); +} + bool dallas_ds1996_write_copy(OneWireHost* host, iButtonProtocolData* protocol_data) { DS1996ProtocolData* data = protocol_data; bool success = false; diff --git a/lib/ibutton/protocols/dallas/protocol_ds_generic.c b/lib/ibutton/protocols/dallas/protocol_ds_generic.c index 101db1dbe2..128f20970d 100644 --- a/lib/ibutton/protocols/dallas/protocol_ds_generic.c +++ b/lib/ibutton/protocols/dallas/protocol_ds_generic.c @@ -20,7 +20,7 @@ typedef struct { } DallasGenericProtocolData; static bool ds_generic_read(OneWireHost*, iButtonProtocolData*); -static bool ds_generic_write_blank(OneWireHost*, iButtonProtocolData*); +static bool ds_generic_write_id(OneWireHost*, iButtonProtocolData*); static void ds_generic_emulate(OneWireSlave*, iButtonProtocolData*); static bool ds_generic_load(FlipperFormat*, uint32_t, iButtonProtocolData*); static bool ds_generic_save(FlipperFormat*, const iButtonProtocolData*); @@ -33,13 +33,13 @@ static void ds_generic_apply_edits(iButtonProtocolData*); const iButtonProtocolDallasBase ibutton_protocol_ds_generic = { .family_code = DALLAS_GENERIC_FAMILY_CODE, - .features = iButtonProtocolFeatureWriteBlank, + .features = iButtonProtocolFeatureWriteId, .data_size = sizeof(DallasGenericProtocolData), .manufacturer = DALLAS_COMMON_MANUFACTURER_NAME, .name = DALLAS_GENERIC_FAMILY_NAME, .read = ds_generic_read, - .write_blank = ds_generic_write_blank, + .write_id = ds_generic_write_id, .write_copy = NULL, /* No data to write a copy */ .emulate = ds_generic_emulate, .save = ds_generic_save, @@ -58,7 +58,7 @@ bool ds_generic_read(OneWireHost* host, iButtonProtocolData* protocol_data) { return onewire_host_reset(host) && dallas_common_read_rom(host, &data->rom_data); } -bool ds_generic_write_blank(OneWireHost* host, iButtonProtocolData* protocol_data) { +bool ds_generic_write_id(OneWireHost* host, iButtonProtocolData* protocol_data) { DallasGenericProtocolData* data = protocol_data; return tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData)); } diff --git a/lib/ibutton/protocols/dallas/protocol_group_dallas.c b/lib/ibutton/protocols/dallas/protocol_group_dallas.c index 7dad756690..634c9ab89b 100644 --- a/lib/ibutton/protocols/dallas/protocol_group_dallas.c +++ b/lib/ibutton/protocols/dallas/protocol_group_dallas.c @@ -133,13 +133,13 @@ static bool ibutton_protocol_group_dallas_read( return success; } -static bool ibutton_protocol_group_dallas_write_blank( +static bool ibutton_protocol_group_dallas_write_id( iButtonProtocolGroupDallas* group, iButtonProtocolData* data, iButtonProtocolLocalId id) { furi_assert(id < iButtonProtocolDSMax); const iButtonProtocolDallasBase* protocol = ibutton_protocols_dallas[id]; - furi_assert(protocol->features & iButtonProtocolFeatureWriteBlank); + furi_assert(protocol->features & iButtonProtocolFeatureWriteId); OneWireHost* host = group->host; @@ -148,7 +148,7 @@ static bool ibutton_protocol_group_dallas_write_blank( FURI_CRITICAL_ENTER(); - const bool success = protocol->write_blank(host, data); + const bool success = protocol->write_id(host, data); onewire_host_stop(host); FURI_CRITICAL_EXIT(); @@ -307,7 +307,7 @@ const iButtonProtocolGroupBase ibutton_protocol_group_dallas = { .get_name = (iButtonProtocolGroupGetStringFunc)ibutton_protocol_group_dallas_get_name, .read = (iButtonProtocolGroupReadFunc)ibutton_protocol_group_dallas_read, - .write_blank = (iButtonProtocolGroupWriteFunc)ibutton_protocol_group_dallas_write_blank, + .write_id = (iButtonProtocolGroupWriteFunc)ibutton_protocol_group_dallas_write_id, .write_copy = (iButtonProtocolGroupWriteFunc)ibutton_protocol_group_dallas_write_copy, .emulate_start = (iButtonProtocolGroupApplyFunc)ibutton_protocol_group_dallas_emulate_start, diff --git a/lib/ibutton/protocols/misc/protocol_group_misc.c b/lib/ibutton/protocols/misc/protocol_group_misc.c index ddbbf6bd80..95f34829ab 100644 --- a/lib/ibutton/protocols/misc/protocol_group_misc.c +++ b/lib/ibutton/protocols/misc/protocol_group_misc.c @@ -284,7 +284,7 @@ const iButtonProtocolGroupBase ibutton_protocol_group_misc = { .get_name = (iButtonProtocolGroupGetStringFunc)ibutton_protocol_group_misc_get_name, .read = (iButtonProtocolGroupReadFunc)ibutton_protocol_group_misc_read, - .write_blank = NULL, + .write_id = NULL, .write_copy = NULL, .emulate_start = (iButtonProtocolGroupApplyFunc)ibutton_protocol_group_misc_emulate_start, diff --git a/lib/ibutton/protocols/protocol_common.h b/lib/ibutton/protocols/protocol_common.h index 5383158e46..52fa1589bd 100644 --- a/lib/ibutton/protocols/protocol_common.h +++ b/lib/ibutton/protocols/protocol_common.h @@ -11,7 +11,7 @@ enum { typedef enum { iButtonProtocolFeatureExtData = (1U << 0), - iButtonProtocolFeatureWriteBlank = (1U << 1), + iButtonProtocolFeatureWriteId = (1U << 1), iButtonProtocolFeatureWriteCopy = (1U << 2), } iButtonProtocolFeature; diff --git a/lib/ibutton/protocols/protocol_group_base.h b/lib/ibutton/protocols/protocol_group_base.h index ef57fe0bc0..bbd53e31e9 100644 --- a/lib/ibutton/protocols/protocol_group_base.h +++ b/lib/ibutton/protocols/protocol_group_base.h @@ -84,7 +84,7 @@ typedef struct { iButtonProtocolGroupGetStringFunc get_name; iButtonProtocolGroupReadFunc read; - iButtonProtocolGroupWriteFunc write_blank; + iButtonProtocolGroupWriteFunc write_id; iButtonProtocolGroupWriteFunc write_copy; iButtonProtocolGroupApplyFunc emulate_start; diff --git a/lib/lfrfid/protocols/lfrfid_protocols.c b/lib/lfrfid/protocols/lfrfid_protocols.c index e8d6306682..0e65dc045a 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.c +++ b/lib/lfrfid/protocols/lfrfid_protocols.c @@ -19,6 +19,7 @@ #include "protocol_gallagher.h" #include "protocol_nexwatch.h" #include "protocol_securakey.h" +#include "protocol_gproxii.h" const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolEM4100] = &protocol_em4100, @@ -43,4 +44,5 @@ const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolGallagher] = &protocol_gallagher, [LFRFIDProtocolNexwatch] = &protocol_nexwatch, [LFRFIDProtocolSecurakey] = &protocol_securakey, + [LFRFIDProtocolGProxII] = &protocol_gproxii, }; diff --git a/lib/lfrfid/protocols/lfrfid_protocols.h b/lib/lfrfid/protocols/lfrfid_protocols.h index b9ef5c518f..12ac2dddd9 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.h +++ b/lib/lfrfid/protocols/lfrfid_protocols.h @@ -30,6 +30,7 @@ typedef enum { LFRFIDProtocolGallagher, LFRFIDProtocolNexwatch, LFRFIDProtocolSecurakey, + LFRFIDProtocolGProxII, LFRFIDProtocolMax, } LFRFIDProtocol; diff --git a/lib/lfrfid/protocols/protocol_gproxii.c b/lib/lfrfid/protocols/protocol_gproxii.c new file mode 100644 index 0000000000..73cbe8f39e --- /dev/null +++ b/lib/lfrfid/protocols/protocol_gproxii.c @@ -0,0 +1,261 @@ +#include +#include "toolbox/level_duration.h" +#include "protocol_gproxii.h" +#include +#include +#include "lfrfid_protocols.h" + +#define GPROXII_PREAMBLE_BIT_SIZE (6) +#define GPROXII_ENCODED_BIT_SIZE (90) +#define GPROXII_ENCODED_BYTE_FULL_SIZE \ + (((GPROXII_PREAMBLE_BIT_SIZE + GPROXII_ENCODED_BIT_SIZE) / 8)) + +#define GPROXII_DATA_SIZE (12) + +#define GPROXII_SHORT_TIME (256) +#define GPROXII_LONG_TIME (512) +#define GPROXII_JITTER_TIME (120) + +#define GPROXII_SHORT_TIME_LOW (GPROXII_SHORT_TIME - GPROXII_JITTER_TIME) +#define GPROXII_SHORT_TIME_HIGH (GPROXII_SHORT_TIME + GPROXII_JITTER_TIME) +#define GPROXII_LONG_TIME_LOW (GPROXII_LONG_TIME - GPROXII_JITTER_TIME) +#define GPROXII_LONG_TIME_HIGH (GPROXII_LONG_TIME + GPROXII_JITTER_TIME) + +typedef struct { + bool last_short; + bool last_level; + size_t encoded_index; + uint8_t decoded_data[GPROXII_ENCODED_BYTE_FULL_SIZE]; + uint8_t data[GPROXII_ENCODED_BYTE_FULL_SIZE]; +} ProtocolGProxII; + +ProtocolGProxII* protocol_gproxii_alloc(void) { + ProtocolGProxII* protocol = malloc(sizeof(ProtocolGProxII)); + return protocol; +} + +void protocol_gproxii_free(ProtocolGProxII* protocol) { + free(protocol); +} + +uint8_t* protocol_gproxii_get_data(ProtocolGProxII* proto) { + return proto->data; +} + +void protocol_gproxii_decoder_start(ProtocolGProxII* protocol) { + memset(protocol->data, 0, GPROXII_ENCODED_BYTE_FULL_SIZE); + protocol->last_short = false; +} + +static bool protocol_gproxii_can_be_decoded(ProtocolGProxII* protocol) { + // 96 bit with 5 bit zero parity + // 0 10 20 30 40 50 60 70 80 90 + // | | | | | | | | | | + // 012345 6789 0 1234 5 6789 0 1234 5 6789 0 1234 5 6789 0 1234 5 6789 0 1234 5 6789 0 1234 5 6789 0 1234 5 6789 0 1234 5 6789 0 1234 5 + // ------------------------------------------------------------------------------------------------------------------------------------ + // 111110 0000 0 1001 0 1101 0 1111 0 1000 0 1001 0 0000 0 1001 0 0000 0 1001 0 0000 0 1001 0 0000 0 1001 0 0000 0 1000 0 0000 0 1001 0 + + // Remove header and reverse bytes on the remaining 72 bits + // + // 0 10 20 30 40 50 60 70 + // | | | | | | | | + // 01234567 89012345 67890123 45678901 23456789 01234567 89012345 67890123 45678901 + // -------------------------------------------------------------------------------- + // 00001001 11011111 10001001 00001001 00001001 00001001 00001001 00001000 00001001 - Without parity + // 10010000 11111011 10010001 10010000 10010000 10010000 10010000 00010000 10010000 - Reversed + // 10010000 01101011 00000001 00000000 00000000 00000000 00000000 10000000 00000000 - XOR all bytes from 1 using byte 0 + + // 72 Bit Guardall/Verex/Chubb GProx II 26 bit key with 16 bit profile + // 0 10 20 30 40 50 60 70 + // | | | | | | | | + // 01234567 890123 45 6789012345678901 2 34567890 1234567890123456 7 89012345678901 + // -------------------------------------------------------------------------------- + // XORVALUE LLLLLL DD PPPPPPPPPPPPPPPP E FFFFFFFF CCCCCCCCCCCCCCCC O UUUUUUUUUUUUUU + // 10010000 011010 11 0000000100000000 0 00000000 0000000000000001 0 00000000000000 - Profile: 256 FC: 0 Card: 1 + + // 72 Bit Guardall/Verex/Chubb GProx II 36 bit key with 26 bit profile + // 0 10 20 30 40 50 60 70 + // | | | | | | | | + // 01234567 890123 45 67890123456789012345678901 2 34567890 1234567890123456 7 8901 + // -------------------------------------------------------------------------------- + // XORVALUE LLLLLL DD PPPPPPPPPPPPPPPPPPPPPPPPPP E FFFFFFFF CCCCCCCCCCCCCCCC O UUUU + // 10111000 100100 10 00000001000000000000000000 1 01000000 1000100010111000 1 0000 - Profile: 262144 FC: 64 Card: 35000 + + // X = XOR Key, L = Message length, D = 2 bit check digits, P = Profile, E = Wiegand leading even parity + // F = Faclity code, C = Card number, O = Wiegand trailing odd parity, U = Unused bits + + // Check 6 bits preamble 111110 + if(bit_lib_get_bits(protocol->data, 0, 6) != 0b111110) return false; + + // Check always 0 parity on every 5th bit after preamble + if(bit_lib_test_parity(protocol->data, 5, GPROXII_ENCODED_BIT_SIZE, BitLibParityAlways0, 5)) + return false; + + // Start GProx II decode + bit_lib_copy_bits(protocol->decoded_data, 0, GPROXII_ENCODED_BIT_SIZE, protocol->data, 6); + + // Remove parity + bit_lib_remove_bit_every_nth(protocol->decoded_data, 0, GPROXII_ENCODED_BIT_SIZE, 5); + + // Reverse bytes + for(int i = 0; i < 9; i++) { + protocol->decoded_data[i] = bit_lib_reverse_8_fast(protocol->decoded_data[i]); + } + + // DeXOR from byte 1 using byte 0 + for(int i = 1; i < 9; i++) { + protocol->decoded_data[i] = protocol->decoded_data[0] ^ protocol->decoded_data[i]; + } + + // Check card length is either 26 or 36 + int card_len = bit_lib_get_bits(protocol->decoded_data, 8, 6); + if(card_len == 26 || card_len == 36) { + return true; + } else { + return false; // If we don't get a 26 or 36 it's not a known card type + } +} + +bool protocol_gproxii_decoder_feed(ProtocolGProxII* protocol, bool level, uint32_t duration) { + UNUSED(level); + bool pushed = false; + + // Bi-Phase Manchester decoding inverse. Short = 1, Long = 0 + if(duration >= GPROXII_SHORT_TIME_LOW && duration <= GPROXII_SHORT_TIME_HIGH) { + if(protocol->last_short == false) { + protocol->last_short = true; + } else { + pushed = true; + bit_lib_push_bit(protocol->data, GPROXII_ENCODED_BYTE_FULL_SIZE, true); + protocol->last_short = false; + } + } else if(duration >= GPROXII_LONG_TIME_LOW && duration <= GPROXII_LONG_TIME_HIGH) { + if(protocol->last_short == false) { + pushed = true; + bit_lib_push_bit(protocol->data, GPROXII_ENCODED_BYTE_FULL_SIZE, false); + } else { + // reset + protocol->last_short = false; + } + } else { + // reset + protocol->last_short = false; + } + + if(pushed && protocol_gproxii_can_be_decoded(protocol)) { + return true; + } + + return false; +} + +bool protocol_gproxii_encoder_start(ProtocolGProxII* protocol) { + protocol->encoded_index = 0; + protocol->last_short = false; + protocol->last_level = false; + return true; +} + +LevelDuration protocol_gproxii_encoder_yield(ProtocolGProxII* protocol) { + uint32_t duration; + protocol->last_level = !protocol->last_level; + + bool bit = bit_lib_get_bit(protocol->data, protocol->encoded_index); + + // Bi-Phase Manchester encoder inverted + if(bit) { + // two short pulses for 1 + duration = GPROXII_SHORT_TIME / 8; + if(protocol->last_short) { + bit_lib_increment_index(protocol->encoded_index, 96); + protocol->last_short = false; + } else { + protocol->last_short = true; + } + } else { + // one long pulse for 0 + duration = GPROXII_LONG_TIME / 8; + bit_lib_increment_index(protocol->encoded_index, 96); + } + return level_duration_make(protocol->last_level, duration); +} + +void protocol_gproxii_render_data(ProtocolGProxII* protocol, FuriString* result) { + int xor_code = bit_lib_get_bits(protocol->decoded_data, 0, 8); + int card_len = bit_lib_get_bits(protocol->decoded_data, 8, 6); + int crc_code = bit_lib_get_bits(protocol->decoded_data, 14, 2); + + if(card_len == 26) { // 26 Bit card + // Print FC, Card and Length + furi_string_cat_printf( + result, + "FC: %hhu Card: %hu LEN: %hhu\n", + bit_lib_get_bits(protocol->decoded_data, 33, 8), + bit_lib_get_bits_16(protocol->decoded_data, 41, 16), + card_len); + // XOR Key, CRC and Profile + furi_string_cat_printf( + result, + "XOR: %hhu CRC: %hhu P: %04hX", + xor_code, + crc_code, + bit_lib_get_bits_16(protocol->decoded_data, 16, 16)); + } else if(card_len == 36) { // 36 Bit card + // Print FC, Card and Length + furi_string_cat_printf( + result, + "FC: %hhu Card: %hu LEN: %hhu\n", + bit_lib_get_bits(protocol->decoded_data, 43, 8), + bit_lib_get_bits_16(protocol->decoded_data, 51, 16), + card_len); + // XOR Key, CRC and Profile + furi_string_cat_printf( + result, + "XOR: %hhu CRC: %hhu P: %06lX", + xor_code, + crc_code, + bit_lib_get_bits_32(protocol->decoded_data, 16, 26)); + } else { + furi_string_cat_printf(result, "Read Error\n"); + } +} + +bool protocol_gproxii_write_data(ProtocolGProxII* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_BIPHASE | LFRFID_T5577_BITRATE_RF_64 | + (3 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->data, 64, 32); + request->t5577.blocks_to_write = 4; + result = true; + } + return result; +} + +const ProtocolBase protocol_gproxii = { + .name = "GProxII", + .manufacturer = "Guardall", + .data_size = GPROXII_DATA_SIZE, + .features = LFRFIDFeatureASK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_gproxii_alloc, + .free = (ProtocolFree)protocol_gproxii_free, + .get_data = (ProtocolGetData)protocol_gproxii_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_gproxii_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_gproxii_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_gproxii_encoder_start, + .yield = (ProtocolEncoderYield)protocol_gproxii_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_gproxii_render_data, + .render_brief_data = (ProtocolRenderData)protocol_gproxii_render_data, + .write_data = (ProtocolWriteData)protocol_gproxii_write_data, +}; diff --git a/lib/lfrfid/protocols/protocol_gproxii.h b/lib/lfrfid/protocols/protocol_gproxii.h new file mode 100644 index 0000000000..002c3024fc --- /dev/null +++ b/lib/lfrfid/protocols/protocol_gproxii.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_gproxii; diff --git a/lib/lfs_config.h b/lib/lfs_config.h deleted file mode 100644 index ff8bc4b235..0000000000 --- a/lib/lfs_config.h +++ /dev/null @@ -1,204 +0,0 @@ -#pragma once - -#include - -#ifdef FURI_NDEBUG -#define LFS_NO_ASSERT -#define LFS_ASSERT(x) -#else -#define LFS_ASSERT furi_assert -#endif - -#define LFS_TAG "Lfs" - -#ifdef FURI_LFS_DEBUG -#define LFS_TRACE(...) FURI_LOG_T(LFS_TAG, __VA_ARGS__); - -#define LFS_DEBUG(...) FURI_LOG_D(LFS_TAG, __VA_ARGS__); -#else -#define LFS_TRACE(...) - -#define LFS_DEBUG(...) -#endif // FURI_LFS_DEBUG - -#define LFS_WARN(...) FURI_LOG_W(LFS_TAG, __VA_ARGS__); - -#define LFS_ERROR(...) FURI_LOG_E(LFS_TAG, __VA_ARGS__); - -// Because crc -#undef LFS_CONFIG - -// System includes -#include -#include -#include -#include - -#ifndef LFS_NO_MALLOC -#include -#endif -#ifndef LFS_NO_ASSERT -#include -#endif -#if !defined(LFS_NO_DEBUG) || !defined(LFS_NO_WARN) || !defined(LFS_NO_ERROR) || \ - defined(LFS_YES_TRACE) -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// Builtin functions, these may be replaced by more efficient -// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more -// expensive basic C implementation for debugging purposes - -// Min/max functions for unsigned 32-bit numbers -static inline uint32_t lfs_max(uint32_t a, uint32_t b) { - return (a > b) ? a : b; -} - -static inline uint32_t lfs_min(uint32_t a, uint32_t b) { - return (a < b) ? a : b; -} - -// Align to nearest multiple of a size -static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { - return a - (a % alignment); -} - -static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { - return lfs_aligndown(a + alignment - 1, alignment); -} - -// Find the smallest power of 2 greater than or equal to a -static inline uint32_t lfs_npw2(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) - return 32 - __builtin_clz(a - 1); -#else - uint32_t r = 0; - uint32_t s; - a -= 1; - s = (a > 0xffff) << 4; - a >>= s; - r |= s; - s = (a > 0xff) << 3; - a >>= s; - r |= s; - s = (a > 0xf) << 2; - a >>= s; - r |= s; - s = (a > 0x3) << 1; - a >>= s; - r |= s; - return (r | (a >> 1)) + 1; -#endif -} - -// Count the number of trailing binary zeros in a -// lfs_ctz(0) may be undefined -static inline uint32_t lfs_ctz(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) - return __builtin_ctz(a); -#else - return lfs_npw2((a & -a) + 1) - 1; -#endif -} - -// Count the number of binary ones in a -static inline uint32_t lfs_popc(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) - return __builtin_popcount(a); -#else - a = a - ((a >> 1) & 0x55555555); - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); - return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; -#endif -} - -// Find the sequence comparison of a and b, this is the distance -// between a and b ignoring overflow -static inline int lfs_scmp(uint32_t a, uint32_t b) { - return (int)(unsigned)(a - b); -} - -// Convert between 32-bit little-endian and native order -static inline uint32_t lfs_fromle32(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && \ - ((defined(BYTE_ORDER) && defined(ORDER_LITTLE_ENDIAN) && \ - BYTE_ORDER == ORDER_LITTLE_ENDIAN) || \ - (defined(__BYTE_ORDER) && defined(__ORDER_LITTLE_ENDIAN) && \ - __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ - __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) - return a; -#elif !defined(LFS_NO_INTRINSICS) && \ - ((defined(BYTE_ORDER) && defined(ORDER_BIG_ENDIAN) && BYTE_ORDER == ORDER_BIG_ENDIAN) || \ - (defined(__BYTE_ORDER) && defined(__ORDER_BIG_ENDIAN) && \ - __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ - __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) - return __builtin_bswap32(a); -#else - return (((uint8_t*)&a)[0] << 0) | (((uint8_t*)&a)[1] << 8) | (((uint8_t*)&a)[2] << 16) | - (((uint8_t*)&a)[3] << 24); -#endif -} - -static inline uint32_t lfs_tole32(uint32_t a) { - return lfs_fromle32(a); -} - -// Convert between 32-bit big-endian and native order -static inline uint32_t lfs_frombe32(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && \ - ((defined(BYTE_ORDER) && defined(ORDER_LITTLE_ENDIAN) && \ - BYTE_ORDER == ORDER_LITTLE_ENDIAN) || \ - (defined(__BYTE_ORDER) && defined(__ORDER_LITTLE_ENDIAN) && \ - __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ - __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) - return __builtin_bswap32(a); -#elif !defined(LFS_NO_INTRINSICS) && \ - ((defined(BYTE_ORDER) && defined(ORDER_BIG_ENDIAN) && BYTE_ORDER == ORDER_BIG_ENDIAN) || \ - (defined(__BYTE_ORDER) && defined(__ORDER_BIG_ENDIAN) && \ - __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ - __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) - return a; -#else - return (((uint8_t*)&a)[0] << 24) | (((uint8_t*)&a)[1] << 16) | (((uint8_t*)&a)[2] << 8) | - (((uint8_t*)&a)[3] << 0); -#endif -} - -static inline uint32_t lfs_tobe32(uint32_t a) { - return lfs_frombe32(a); -} - -// Calculate CRC-32 with polynomial = 0x04c11db7 -uint32_t lfs_crc(uint32_t crc, const void* buffer, size_t size); - -// Allocate memory, only used if buffers are not provided to littlefs -// Note, memory must be 64-bit aligned -static inline void* lfs_malloc(size_t size) { -#ifndef LFS_NO_MALLOC - return malloc(size); -#else - (void)size; - return NULL; -#endif -} - -// Deallocate memory, only used if buffers are not provided to littlefs -static inline void lfs_free(void* p) { -#ifndef LFS_NO_MALLOC - free(p); -#else - (void)p; -#endif -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif diff --git a/lib/littlefs b/lib/littlefs deleted file mode 160000 index 611c9b20db..0000000000 --- a/lib/littlefs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 611c9b20db2b99faee261daa7cc9bbe175d3eaca diff --git a/lib/littlefs.scons b/lib/littlefs.scons deleted file mode 100644 index 3d68e07bae..0000000000 --- a/lib/littlefs.scons +++ /dev/null @@ -1,22 +0,0 @@ -Import("env") - -env.Append( - CPPPATH=[ - "#/lib/littlefs", - ], -) - - -libenv = env.Clone(FW_LIB_NAME="littlefs") -libenv.ApplyLibFlags() -libenv.Append( - CPPDEFINES=[ - ("LFS_CONFIG", "lfs_config.h"), - ], -) - -sources = Glob("littlefs/*.c", source=True) - -lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) -libenv.Install("${LIB_DIST_DIR}", lib) -Return("lib") diff --git a/lib/mjs/mjs_array.c b/lib/mjs/mjs_array.c index c74487d65a..9230436e8b 100644 --- a/lib/mjs/mjs_array.c +++ b/lib/mjs/mjs_array.c @@ -19,8 +19,11 @@ static int v_sprintf_s(char* buf, size_t size, const char* fmt, ...) { size_t n; va_list ap; + va_start(ap, fmt); n = c_vsnprintf(buf, size, fmt, ap); + va_end(ap); + if(n > size) { return size; } diff --git a/lib/subghz/devices/registry.c b/lib/subghz/devices/registry.c index cf044c98a3..a3a535c400 100644 --- a/lib/subghz/devices/registry.c +++ b/lib/subghz/devices/registry.c @@ -24,7 +24,8 @@ void subghz_device_registry_init(void) { //TODO FL-3556: fix path to plugins //if(plugin_manager_load_all(subghz_device->manager, APP_DATA_PATH("plugins")) != - if(plugin_manager_load_all(subghz_device->manager, "/ext/apps_data/subghz/plugins") != + // + if(plugin_manager_load_all(subghz_device->manager, EXT_PATH("apps_data/subghz/plugins")) != PluginManagerErrorNone) { FURI_LOG_E(TAG, "Failed to load all libs"); } diff --git a/lib/subghz/protocols/dickert_mahs.c b/lib/subghz/protocols/dickert_mahs.c new file mode 100644 index 0000000000..4691e3423c --- /dev/null +++ b/lib/subghz/protocols/dickert_mahs.c @@ -0,0 +1,385 @@ +#include "dickert_mahs.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#include +#include +#include + +#define TAG "SubGhzProtocolDicketMAHS" + +static const SubGhzBlockConst subghz_protocol_dickert_mahs_const = { + .te_short = 400, + .te_long = 800, + .te_delta = 100, + .min_count_bit_for_found = 36, +}; + +struct SubGhzProtocolDecoderDickertMAHS { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + + uint32_t tmp[2]; + uint8_t tmp_cnt; +}; + +struct SubGhzProtocolEncoderDickertMAHS { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + DickertMAHSDecoderStepReset = 0, + DickertMAHSDecoderStepInitial, + DickertMAHSDecoderStepRecording, +} DickertMAHSDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_dickert_mahs_decoder = { + .alloc = subghz_protocol_decoder_dickert_mahs_alloc, + .free = subghz_protocol_decoder_dickert_mahs_free, + + .feed = subghz_protocol_decoder_dickert_mahs_feed, + .reset = subghz_protocol_decoder_dickert_mahs_reset, + + .get_hash_data = subghz_protocol_decoder_dickert_mahs_get_hash_data, + .serialize = subghz_protocol_decoder_dickert_mahs_serialize, + .deserialize = subghz_protocol_decoder_dickert_mahs_deserialize, + .get_string = subghz_protocol_decoder_dickert_mahs_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_dickert_mahs_encoder = { + .alloc = subghz_protocol_encoder_dickert_mahs_alloc, + .free = subghz_protocol_encoder_dickert_mahs_free, + + .deserialize = subghz_protocol_encoder_dickert_mahs_deserialize, + .stop = subghz_protocol_encoder_dickert_mahs_stop, + .yield = subghz_protocol_encoder_dickert_mahs_yield, +}; + +const SubGhzProtocol subghz_protocol_dickert_mahs = { + .name = SUBGHZ_PROTOCOL_DICKERT_MAHS_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_dickert_mahs_decoder, + .encoder = &subghz_protocol_dickert_mahs_encoder, +}; + +static void subghz_protocol_encoder_dickert_mahs_parse_buffer( + SubGhzProtocolDecoderDickertMAHS* instance, + FuriString* output) { + // We assume we have only decodes < 64 bit! + uint64_t data = instance->generic.data; + uint8_t bits[36] = {}; + + // Convert uint64_t into bit array + for(int i = 35; i >= 0; i--) { + if(data & 1) { + bits[i] = 1; + } + data >>= 1; + } + + // Decode symbols + FuriString* code = furi_string_alloc(); + for(size_t i = 0; i < 35; i += 2) { + uint8_t dip = (bits[i] << 1) + bits[i + 1]; + // PLUS = 3, // 0b11 + // ZERO = 1, // 0b01 + // MINUS = 0, // 0x00 + if(dip == 0x01) { + furi_string_cat(code, "0"); + } else if(dip == 0x00) { + furi_string_cat(code, "-"); + } else if(dip == 0x03) { + furi_string_cat(code, "+"); + } else { + furi_string_cat(code, "?"); + } + } + + FuriString* user_dips = furi_string_alloc(); + FuriString* fact_dips = furi_string_alloc(); + furi_string_set_n(user_dips, code, 0, 10); + furi_string_set_n(fact_dips, code, 10, 8); + + furi_string_cat_printf( + output, + "%s\r\n" + "User-Dips:\t%s\r\n" + "Fac-Code:\t%s\r\n", + instance->generic.protocol_name, + furi_string_get_cstr(user_dips), + furi_string_get_cstr(fact_dips)); + furi_string_free(user_dips); + furi_string_free(fact_dips); + furi_string_free(code); +} + +void* subghz_protocol_encoder_dickert_mahs_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderDickertMAHS* instance = malloc(sizeof(SubGhzProtocolEncoderDickertMAHS)); + + instance->base.protocol = &subghz_protocol_dickert_mahs; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 128; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + return instance; +} + +void subghz_protocol_encoder_dickert_mahs_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderDickertMAHS* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderDickertMAHS instance + * @return true On success + */ +static bool + subghz_protocol_encoder_dickert_mahs_get_upload(SubGhzProtocolEncoderDickertMAHS* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2) + 2; + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_dickert_mahs_const.te_short * 112); + // Send start bit + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_dickert_mahs_const.te_short); + + //Send key data + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_dickert_mahs_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_dickert_mahs_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_dickert_mahs_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_dickert_mahs_const.te_long); + } + } + + return true; +} + +SubGhzProtocolStatus + subghz_protocol_encoder_dickert_mahs_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderDickertMAHS* instance = context; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + do { + ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { + break; + } + + // Allow for longer keys (<) instead of != + if((instance->generic.data_count_bit < + subghz_protocol_dickert_mahs_const.min_count_bit_for_found)) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorValueBitCount; + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + if(!subghz_protocol_encoder_dickert_mahs_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } + instance->encoder.is_running = true; + } while(false); + + return ret; +} + +void subghz_protocol_encoder_dickert_mahs_stop(void* context) { + SubGhzProtocolEncoderDickertMAHS* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_dickert_mahs_yield(void* context) { + SubGhzProtocolEncoderDickertMAHS* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_dickert_mahs_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderDickertMAHS* instance = malloc(sizeof(SubGhzProtocolDecoderDickertMAHS)); + instance->base.protocol = &subghz_protocol_dickert_mahs; + instance->generic.protocol_name = instance->base.protocol->name; + instance->tmp_cnt = 0; + + return instance; +} + +void subghz_protocol_decoder_dickert_mahs_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDickertMAHS* instance = context; + free(instance); +} + +void subghz_protocol_decoder_dickert_mahs_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDickertMAHS* instance = context; + instance->decoder.parser_step = DickertMAHSDecoderStepReset; +} + +void subghz_protocol_decoder_dickert_mahs_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderDickertMAHS* instance = context; + + switch(instance->decoder.parser_step) { + case DickertMAHSDecoderStepReset: + // Check if done + if(instance->decoder.decode_count_bit >= + subghz_protocol_dickert_mahs_const.min_count_bit_for_found) { + instance->generic.serial = 0x0; + instance->generic.btn = 0x0; + + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } + + if((!level) && (duration > 10 * subghz_protocol_dickert_mahs_const.te_short)) { + //Found header DICKERT_MAHS + instance->decoder.parser_step = DickertMAHSDecoderStepInitial; + } + break; + case DickertMAHSDecoderStepInitial: + if(!level) { + break; + } else if( + DURATION_DIFF(duration, subghz_protocol_dickert_mahs_const.te_short) < + subghz_protocol_dickert_mahs_const.te_delta) { + //Found start bit DICKERT_MAHS + instance->decoder.parser_step = DickertMAHSDecoderStepRecording; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } else { + instance->decoder.parser_step = DickertMAHSDecoderStepReset; + } + break; + case DickertMAHSDecoderStepRecording: + if((!level && instance->tmp_cnt == 0) || (level && instance->tmp_cnt == 1)) { + instance->tmp[instance->tmp_cnt] = duration; + + instance->tmp_cnt++; + + if(instance->tmp_cnt == 2) { + if(DURATION_DIFF(instance->tmp[0] + instance->tmp[1], 1200) < + subghz_protocol_dickert_mahs_const.te_delta) { + if(DURATION_DIFF(instance->tmp[0], subghz_protocol_dickert_mahs_const.te_long) < + subghz_protocol_dickert_mahs_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } else if( + DURATION_DIFF( + instance->tmp[0], subghz_protocol_dickert_mahs_const.te_short) < + subghz_protocol_dickert_mahs_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } + + instance->tmp_cnt = 0; + } else { + instance->tmp_cnt = 0; + instance->decoder.parser_step = DickertMAHSDecoderStepReset; + } + } + } else { + instance->tmp_cnt = 0; + instance->decoder.parser_step = DickertMAHSDecoderStepReset; + } + + break; + } +} + +uint8_t subghz_protocol_decoder_dickert_mahs_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDickertMAHS* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +SubGhzProtocolStatus subghz_protocol_decoder_dickert_mahs_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderDickertMAHS* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +SubGhzProtocolStatus + subghz_protocol_decoder_dickert_mahs_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderDickertMAHS* instance = context; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + do { + ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { + break; + } + + // Allow for longer keys (<) instead of != + if((instance->generic.data_count_bit < + subghz_protocol_dickert_mahs_const.min_count_bit_for_found)) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + ret = SubGhzProtocolStatusErrorValueBitCount; + break; + } + } while(false); + return ret; +} + +void subghz_protocol_decoder_dickert_mahs_get_string(void* context, FuriString* output) { + furi_assert(context); + subghz_protocol_encoder_dickert_mahs_parse_buffer(context, output); +} diff --git a/lib/subghz/protocols/dickert_mahs.h b/lib/subghz/protocols/dickert_mahs.h new file mode 100644 index 0000000000..3f682cee09 --- /dev/null +++ b/lib/subghz/protocols/dickert_mahs.h @@ -0,0 +1,120 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_DICKERT_MAHS_NAME "Dickert_MAHS" + +typedef struct SubGhzProtocolDecoderDickertMAHS SubGhzProtocolDecoderDickertMAHS; +typedef struct SubGhzProtocolEncoderDickertMAHS SubGhzProtocolEncoderDickertMAHS; + +extern const SubGhzProtocolDecoder subghz_protocol_dickert_mahs_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_dickert_mahs_encoder; +extern const SubGhzProtocol subghz_protocol_dickert_mahs; + +/** Allocate SubGhzProtocolEncoderDickertMAHS. + * + * @param environment Pointer to a SubGhzEnvironment instance + * + * @return pointer to a SubGhzProtocolEncoderDickertMAHS instance + */ +void* subghz_protocol_encoder_dickert_mahs_alloc(SubGhzEnvironment* environment); + +/** Free SubGhzProtocolEncoderDickertMAHS. + * + * @param context Pointer to a SubGhzProtocolEncoderDickertMAHS instance + */ +void subghz_protocol_encoder_dickert_mahs_free(void* context); + +/** Deserialize and generating an upload to send. + * + * @param context Pointer to a SubGhzProtocolEncoderDickertMAHS + * instance + * @param flipper_format Pointer to a FlipperFormat instance + * + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_encoder_dickert_mahs_deserialize(void* context, FlipperFormat* flipper_format); + +/** Forced transmission stop. + * + * @param context Pointer to a SubGhzProtocolEncoderDickertMAHS instance + */ +void subghz_protocol_encoder_dickert_mahs_stop(void* context); + +/** Getting the level and duration of the upload to be loaded into DMA. + * + * @param context Pointer to a SubGhzProtocolEncoderDickertMAHS instance + * + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_dickert_mahs_yield(void* context); + +/** Allocate SubGhzProtocolDecoderDickertMAHS. + * + * @param environment Pointer to a SubGhzEnvironment instance + * + * @return pointer to a SubGhzProtocolDecoderDickertMAHS instance + */ +void* subghz_protocol_decoder_dickert_mahs_alloc(SubGhzEnvironment* environment); + +/** Free SubGhzProtocolDecoderDickertMAHS. + * + * @param context Pointer to a SubGhzProtocolDecoderDickertMAHS instance + */ +void subghz_protocol_decoder_dickert_mahs_free(void* context); + +/** Reset decoder SubGhzProtocolDecoderDickertMAHS. + * + * @param context Pointer to a SubGhzProtocolDecoderDickertMAHS instance + */ +void subghz_protocol_decoder_dickert_mahs_reset(void* context); + +/** Parse a raw sequence of levels and durations received from the air. + * + * @param context Pointer to a SubGhzProtocolDecoderDickertMAHS instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_dickert_mahs_feed(void* context, bool level, uint32_t duration); + +/** Getting the hash sum of the last randomly received parcel. + * + * @param context Pointer to a SubGhzProtocolDecoderDickertMAHS instance + * + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_dickert_mahs_get_hash_data(void* context); + +/** Serialize data SubGhzProtocolDecoderDickertMAHS. + * + * @param context Pointer to a SubGhzProtocolDecoderDickertMAHS + * instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, + * SubGhzRadioPreset + * + * @return status + */ +SubGhzProtocolStatus subghz_protocol_decoder_dickert_mahs_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** Deserialize data SubGhzProtocolDecoderDickertMAHS. + * + * @param context Pointer to a SubGhzProtocolDecoderDickertMAHS + * instance + * @param flipper_format Pointer to a FlipperFormat instance + * + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_decoder_dickert_mahs_deserialize(void* context, FlipperFormat* flipper_format); + +/** Getting a textual representation of the received data. + * + * @param context Pointer to a SubGhzProtocolDecoderDickertMAHS instance + * @param output Resulting text + */ +void subghz_protocol_decoder_dickert_mahs_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index da1a1e87a4..0e7bed1ea5 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -46,6 +46,7 @@ const SubGhzProtocol* subghz_protocol_registry_items[] = { &subghz_protocol_mastercode, &subghz_protocol_honeywell, &subghz_protocol_legrand, + &subghz_protocol_dickert_mahs, }; const SubGhzProtocolRegistry subghz_protocol_registry = { diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index c0f3be0d6a..7054d24078 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -47,3 +47,4 @@ #include "mastercode.h" #include "honeywell.h" #include "legrand.h" +#include "dickert_mahs.h" diff --git a/lib/toolbox/api_lock.h b/lib/toolbox/api_lock.h index 5902a4922a..a370514dad 100644 --- a/lib/toolbox/api_lock.h +++ b/lib/toolbox/api_lock.h @@ -41,3 +41,7 @@ typedef FuriEventFlag* FuriApiLock; #define api_lock_wait_unlock_and_free(_lock) \ api_lock_wait_unlock(_lock); \ api_lock_free(_lock); + +#define api_lock_is_locked(_lock) (!(furi_event_flag_get(_lock) & API_LOCK_EVENT)) + +#define api_lock_relock(_lock) furi_event_flag_clear(_lock, API_LOCK_EVENT) diff --git a/lib/toolbox/crc32_calc.c b/lib/toolbox/crc32_calc.c index 78295167f3..60d709a364 100644 --- a/lib/toolbox/crc32_calc.c +++ b/lib/toolbox/crc32_calc.c @@ -1,11 +1,37 @@ #include "crc32_calc.h" -#include #define CRC_DATA_BUFFER_MAX_LEN 512 uint32_t crc32_calc_buffer(uint32_t crc, const void* buffer, size_t size) { - // TODO FL-3547: consider removing dependency on LFS - return ~lfs_crc(~crc, buffer, size); + crc = ~crc; + + static const uint32_t rtable[16] = { + 0x00000000, + 0x1db71064, + 0x3b6e20c8, + 0x26d930ac, + 0x76dc4190, + 0x6b6b51f4, + 0x4db26158, + 0x5005713c, + 0xedb88320, + 0xf00f9344, + 0xd6d6a3e8, + 0xcb61b38c, + 0x9b64c2b0, + 0x86d3d2d4, + 0xa00ae278, + 0xbdbdf21c, + }; + + const uint8_t* data = buffer; + + for(size_t i = 0; i < size; i++) { + crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf]; + crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf]; + } + + return ~crc; } uint32_t crc32_calc_file(File* file, const FileCrcProgressCb progress_cb, void* context) { diff --git a/lib/toolbox/stream/file_stream.c b/lib/toolbox/stream/file_stream.c index 80cbb7d5f7..a0dfda3ebe 100644 --- a/lib/toolbox/stream/file_stream.c +++ b/lib/toolbox/stream/file_stream.c @@ -159,8 +159,8 @@ static bool file_stream_delete_and_insert( FuriString* tmp_name; tmp_name = furi_string_alloc(); storage_get_next_filename( - _stream->storage, STORAGE_ANY_PATH_PREFIX, ".scratch", ".pad", tmp_name, 255); - scratch_name = furi_string_alloc_printf(ANY_PATH("%s.pad"), furi_string_get_cstr(tmp_name)); + _stream->storage, STORAGE_EXT_PATH_PREFIX, ".scratch", ".pad", tmp_name, 255); + scratch_name = furi_string_alloc_printf(EXT_PATH("%s.pad"), furi_string_get_cstr(tmp_name)); furi_string_free(tmp_name); do { diff --git a/lib/toolbox/tar/tar_archive.c b/lib/toolbox/tar/tar_archive.c index 80144a0f4f..db1d5177f3 100644 --- a/lib/toolbox/tar/tar_archive.c +++ b/lib/toolbox/tar/tar_archive.c @@ -289,7 +289,7 @@ bool tar_archive_file_finalize(TarArchive* archive) { typedef struct { TarArchive* archive; const char* work_dir; - Storage_name_converter converter; + TarArchiveNameConverter converter; } TarArchiveDirectoryOpParams; static bool archive_extract_current_file(TarArchive* archive, const char* dst_path) { @@ -386,7 +386,7 @@ static int archive_extract_foreach_cb(mtar_t* tar, const mtar_header_t* header, bool tar_archive_unpack_to( TarArchive* archive, const char* destination, - Storage_name_converter converter) { + TarArchiveNameConverter converter) { furi_check(archive); TarArchiveDirectoryOpParams param = { .archive = archive, diff --git a/lib/toolbox/tar/tar_archive.h b/lib/toolbox/tar/tar_archive.h index 3eb97391e8..fd0b28b87f 100644 --- a/lib/toolbox/tar/tar_archive.h +++ b/lib/toolbox/tar/tar_archive.h @@ -54,6 +54,8 @@ bool tar_archive_open(TarArchive* archive, const char* path, TarOpenMode mode); */ void tar_archive_free(TarArchive* archive); +typedef void (*TarArchiveNameConverter)(FuriString*); + /* High-level API - assumes archive is open */ /** Unpack tar archive to destination @@ -67,7 +69,7 @@ void tar_archive_free(TarArchive* archive); bool tar_archive_unpack_to( TarArchive* archive, const char* destination, - Storage_name_converter converter); + TarArchiveNameConverter converter); /** Add file to tar archive * diff --git a/scripts/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py b/scripts/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py index a35f0894f1..4984d2a06a 100644 --- a/scripts/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py +++ b/scripts/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py @@ -102,7 +102,7 @@ def GetQueueType(self): except Exception as exc: # If the TRACE functionality of the RTOS is not enabled, - # then the queue type will not be availabe in the queue + # then the queue type will not be available in the queue # handle - so we return None print("Failed to get Type: %s" % str(exc)) return None diff --git a/scripts/imglint.py b/scripts/imglint.py new file mode 100644 index 0000000000..f25fea4f5e --- /dev/null +++ b/scripts/imglint.py @@ -0,0 +1,97 @@ +import logging +import multiprocessing +import os +from pathlib import Path + +from flipper.app import App +from PIL import Image + +_logger = logging.getLogger(__name__) + + +def _check_image(image, do_fixup=False): + failed_checks = [] + with Image.open(image) as img: + # check that is's pure 1-bit B&W + if img.mode != "1": + failed_checks.append(f"not 1-bit B&W, but {img.mode}") + if do_fixup: + img = img.convert("1") + + # ...and does not have any metadata or ICC profile + if img.info: + failed_checks.append(f"has metadata") + if do_fixup: + img.info = {} + + if do_fixup: + img.save(image) + _logger.info(f"Fixed image {image}") + + if failed_checks: + _logger.warning(f"Image {image} issues: {'; '.join(failed_checks)}") + return len(failed_checks) == 0 + + +class ImageLint(App): + ICONS_SUPPORTED_FORMATS = [".png"] + + def init(self): + self.subparsers = self.parser.add_subparsers(help="sub-command help") + + self.parser_check = self.subparsers.add_parser( + "check", help="Check image format and file names" + ) + self.parser_check.add_argument("input", nargs="+") + self.parser_check.set_defaults(func=self.check) + + self.parser_format = self.subparsers.add_parser( + "format", help="Format image and fix file names" + ) + self.parser_format.add_argument( + "input", + nargs="+", + ) + self.parser_format.set_defaults(func=self.format) + + def _gather_images(self, folders): + images = [] + for folder in folders: + for dirpath, _, filenames in os.walk(folder): + for filename in filenames: + if self.is_file_an_icon(filename): + images.append(os.path.join(dirpath, filename)) + return images + + def is_file_an_icon(self, filename): + extension = Path(filename).suffix.lower() + return extension in self.ICONS_SUPPORTED_FORMATS + + def _process_images(self, images, do_fixup): + with multiprocessing.Pool() as pool: + image_checks = pool.starmap( + _check_image, [(image, do_fixup) for image in images] + ) + return all(image_checks) + + def check(self): + images = self._gather_images(self.args.input) + self.logger.info(f"Found {len(images)} images") + if not self._process_images(images, False): + self.logger.error("Some images are not in the correct format") + return 1 + self.logger.info("All images are in the correct format") + return 0 + + def format(self): + images = self._gather_images(self.args.input) + self.logger.info(f"Found {len(images)} images") + if not self._process_images(images, True): + self.logger.warning("Applied fixes to some images") + else: + self.logger.info("All images were in the correct format") + return 0 + + +if __name__ == "__main__": + ImageLint()() diff --git a/scripts/testops.py b/scripts/testops.py index bf02feaad3..4ae10c7f4a 100644 --- a/scripts/testops.py +++ b/scripts/testops.py @@ -39,7 +39,9 @@ def _get_flipper(self, retry_count: Optional[int] = 1): if port := resolve_port(self.logger, self.args.port): self.logger.info(f"Found flipper at {port}") + time.sleep(1) break + time.sleep(1) if not port: diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index c0a3cd8700..182ba9bb10 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -13,7 +13,7 @@ if not ["%FBT_NOENV%"] == [""] ( exit /b 0 ) -set "FLIPPER_TOOLCHAIN_VERSION=38" +set "FLIPPER_TOOLCHAIN_VERSION=39" if ["%FBT_TOOLCHAIN_PATH%"] == [""] ( set "FBT_TOOLCHAIN_PATH=%FBT_ROOT%" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index ed3d653d58..03df24ffd8 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -4,7 +4,7 @@ # public variables DEFAULT_SCRIPT_PATH="$(pwd -P)"; -FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"38"}"; +FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"39"}"; if [ -z ${FBT_TOOLCHAIN_PATH+x} ] ; then FBT_TOOLCHAIN_PATH_WAS_SET=0; diff --git a/scripts/ufbt/project_template/.vscode/settings.json b/scripts/ufbt/project_template/.vscode/settings.json index b93ad82f1a..d304752a92 100644 --- a/scripts/ufbt/project_template/.vscode/settings.json +++ b/scripts/ufbt/project_template/.vscode/settings.json @@ -19,7 +19,7 @@ "[python]": { "editor.defaultFormatter": "ms-python.black-formatter" }, - // "clangd.path": "@UFBT_TOOLCHAIN_CLANGD@", + "clangd.path": "@UFBT_TOOLCHAIN_CLANGD@", "clangd.arguments": [ "--query-driver=**/arm-none-eabi-*", "--compile-commands-dir=${workspaceFolder}/.vscode", diff --git a/scripts/update.py b/scripts/update.py index e880bced84..47a5eeb27b 100755 --- a/scripts/update.py +++ b/scripts/update.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -import io import math import os import shutil @@ -8,7 +7,6 @@ import zlib from os.path import exists, join -import heatshrink2 from flipper.app import App from flipper.assets.coprobin import CoproBinary, get_stack_type from flipper.assets.heatshrink_stream import HeatshrinkDataStreamHeader @@ -35,7 +33,12 @@ class Main(App): ) FLASH_BASE = 0x8000000 - MIN_LFS_PAGES = 6 + FLASH_PAGE_SIZE = 4 * 1024 + MIN_GAP_PAGES = 2 + + # Update stage file larger than that is not loadable without fix + # https://github.com/flipperdevices/flipperzero-firmware/pull/3676 + UPDATER_SIZE_THRESHOLD = 128 * 1024 HEATSHRINK_WINDOW_SIZE = 13 HEATSHRINK_LOOKAHEAD_SIZE = 6 @@ -117,7 +120,7 @@ def generate(self): self.logger.error( f"You are trying to bundle a non-standard stack type '{self.args.radiotype}'." ) - self.disclaimer() + self.show_disclaimer() return 1 if radio_addr == 0: @@ -130,7 +133,9 @@ def generate(self): if not exists(self.args.directory): os.makedirs(self.args.directory) + updater_stage_size = os.stat(self.args.stage).st_size shutil.copyfile(self.args.stage, join(self.args.directory, stage_basename)) + dfu_size = 0 if self.args.dfu: dfu_size = os.stat(self.args.dfu).st_size @@ -146,10 +151,10 @@ def generate(self): ): return 3 - if not self.layout_check(dfu_size, radio_addr): + if not self.layout_check(updater_stage_size, dfu_size, radio_addr): self.logger.warn("Memory layout looks suspicious") - if not self.args.disclaimer == "yes": - self.disclaimer() + if self.args.disclaimer != "yes": + self.show_disclaimer() return 2 if self.args.splash: @@ -198,22 +203,33 @@ def generate(self): return 0 - def layout_check(self, fw_size, radio_addr): + def layout_check(self, stage_size, fw_size, radio_addr): + if stage_size > self.UPDATER_SIZE_THRESHOLD: + self.logger.warn( + f"Updater size {stage_size}b > {self.UPDATER_SIZE_THRESHOLD}b and is not loadable on older firmwares!" + ) + if fw_size == 0 or radio_addr == 0: self.logger.info("Cannot validate layout for partial package") return True - lfs_span = radio_addr - self.FLASH_BASE - fw_size - self.logger.debug(f"Expected LFS size: {lfs_span}") - lfs_span_pages = lfs_span / (4 * 1024) - if lfs_span_pages < self.MIN_LFS_PAGES: + fw2stack_gap = radio_addr - self.FLASH_BASE - fw_size + self.logger.debug(f"Expected reserved space size: {fw2stack_gap}") + fw2stack_gap_pages = fw2stack_gap / self.FLASH_PAGE_SIZE + if fw2stack_gap_pages < 0: + self.logger.warn( + f"Firmware image overlaps C2 region and is not programmable!" + ) + return False + + elif fw2stack_gap_pages < self.MIN_GAP_PAGES: self.logger.warn( - f"Expected LFS size is too small (~{int(lfs_span_pages)} pages)" + f"Expected reserved flash size is too small (~{int(fw2stack_gap_pages)} page(s), need >={self.MIN_GAP_PAGES} page(s))" ) return False return True - def disclaimer(self): + def show_disclaimer(self): self.logger.error( "You might brick your device into a state in which you'd need an SWD programmer to fix it." ) diff --git a/site_scons/cc.scons b/site_scons/cc.scons index 603ec621c6..c5d99b8965 100644 --- a/site_scons/cc.scons +++ b/site_scons/cc.scons @@ -28,6 +28,7 @@ ENV.AppendUnique( "-Wno-address-of-packed-member", "-Wredundant-decls", "-Wdouble-promotion", + "-Wundef", "-fdata-sections", "-ffunction-sections", "-fsingle-precision-constant", diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 7e254ce401..57cbd1d62e 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,69.0,, +Version,+,72.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, @@ -13,6 +13,7 @@ Header,+,applications/services/gui/icon_i.h,, Header,+,applications/services/gui/modules/button_menu.h,, Header,+,applications/services/gui/modules/button_panel.h,, Header,+,applications/services/gui/modules/byte_input.h,, +Header,+,applications/services/gui/modules/number_input.h,, Header,+,applications/services/gui/modules/dialog_ex.h,, Header,+,applications/services/gui/modules/empty_screen.h,, Header,+,applications/services/gui/modules/file_browser.h,, @@ -687,6 +688,7 @@ Function,+,bt_forget_bonded_devices,void,Bt* Function,+,bt_keys_storage_alloc,BtKeysStorage*,const char* Function,+,bt_keys_storage_delete,_Bool,BtKeysStorage* Function,+,bt_keys_storage_free,void,BtKeysStorage* +Function,+,bt_keys_storage_is_changed,_Bool,BtKeysStorage* Function,+,bt_keys_storage_load,_Bool,BtKeysStorage* Function,+,bt_keys_storage_set_default_path,void,Bt* Function,+,bt_keys_storage_set_file_path,void,"BtKeysStorage*, const char*" @@ -721,6 +723,11 @@ Function,+,byte_input_free,void,ByteInput* Function,+,byte_input_get_view,View*,ByteInput* Function,+,byte_input_set_header_text,void,"ByteInput*, const char*" Function,+,byte_input_set_result_callback,void,"ByteInput*, ByteInputCallback, ByteChangedCallback, void*, uint8_t*, uint8_t" +Function,+,number_input_alloc,NumberInput*, +Function,+,number_input_free,void,NumberInput* +Function,+,number_input_get_view,View*,NumberInput* +Function,+,number_input_set_header_text,void,"NumberInput*, const char*" +Function,+,number_input_set_result_callback,void,"NumberInput*, NumberInputCallback, void*, int32_t, int32_t, int32_t" Function,-,bzero,void,"void*, size_t" Function,+,calloc,void*,"size_t, size_t" Function,+,canvas_clear,void,Canvas* @@ -1107,11 +1114,13 @@ Function,+,furi_event_flag_set,uint32_t,"FuriEventFlag*, uint32_t" Function,+,furi_event_flag_wait,uint32_t,"FuriEventFlag*, uint32_t, uint32_t, uint32_t" Function,+,furi_event_loop_alloc,FuriEventLoop*, Function,+,furi_event_loop_free,void,FuriEventLoop* -Function,+,furi_event_loop_message_queue_subscribe,void,"FuriEventLoop*, FuriMessageQueue*, FuriEventLoopEvent, FuriEventLoopMessageQueueCallback, void*" -Function,+,furi_event_loop_message_queue_unsubscribe,void,"FuriEventLoop*, FuriMessageQueue*" Function,+,furi_event_loop_pend_callback,void,"FuriEventLoop*, FuriEventLoopPendingCallback, void*" Function,+,furi_event_loop_run,void,FuriEventLoop* Function,+,furi_event_loop_stop,void,FuriEventLoop* +Function,+,furi_event_loop_subscribe_message_queue,void,"FuriEventLoop*, FuriMessageQueue*, FuriEventLoopEvent, FuriEventLoopEventCallback, void*" +Function,+,furi_event_loop_subscribe_mutex,void,"FuriEventLoop*, FuriMutex*, FuriEventLoopEvent, FuriEventLoopEventCallback, void*" +Function,+,furi_event_loop_subscribe_semaphore,void,"FuriEventLoop*, FuriSemaphore*, FuriEventLoopEvent, FuriEventLoopEventCallback, void*" +Function,+,furi_event_loop_subscribe_stream_buffer,void,"FuriEventLoop*, FuriStreamBuffer*, FuriEventLoopEvent, FuriEventLoopEventCallback, void*" Function,+,furi_event_loop_tick_set,void,"FuriEventLoop*, uint32_t, FuriEventLoopTickCallback, void*" Function,+,furi_event_loop_timer_alloc,FuriEventLoopTimer*,"FuriEventLoop*, FuriEventLoopTimerCallback, FuriEventLoopTimerType, void*" Function,+,furi_event_loop_timer_free,void,FuriEventLoopTimer* @@ -1121,6 +1130,7 @@ Function,+,furi_event_loop_timer_is_running,_Bool,const FuriEventLoopTimer* Function,+,furi_event_loop_timer_restart,void,FuriEventLoopTimer* Function,+,furi_event_loop_timer_start,void,"FuriEventLoopTimer*, uint32_t" Function,+,furi_event_loop_timer_stop,void,FuriEventLoopTimer* +Function,+,furi_event_loop_unsubscribe,void,"FuriEventLoop*, FuriEventLoopObject*" Function,+,furi_get_tick,uint32_t, Function,+,furi_hal_adc_acquire,FuriHalAdcHandle*, Function,+,furi_hal_adc_configure,void,FuriHalAdcHandle* @@ -1372,6 +1382,7 @@ Function,+,furi_hal_rtc_get_log_baud_rate,FuriHalRtcLogBaudRate, Function,+,furi_hal_rtc_get_log_device,FuriHalRtcLogDevice, Function,+,furi_hal_rtc_get_log_level,uint8_t, Function,+,furi_hal_rtc_get_pin_fails,uint32_t, +Function,-,furi_hal_rtc_get_pin_value,uint32_t, Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister Function,+,furi_hal_rtc_get_timestamp,uint32_t, Function,-,furi_hal_rtc_init,void, @@ -1391,6 +1402,7 @@ Function,+,furi_hal_rtc_set_log_baud_rate,void,FuriHalRtcLogBaudRate Function,+,furi_hal_rtc_set_log_device,void,FuriHalRtcLogDevice Function,+,furi_hal_rtc_set_log_level,void,uint8_t Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t +Function,-,furi_hal_rtc_set_pin_value,void,uint32_t Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" Function,+,furi_hal_rtc_sync_shadow,void, Function,+,furi_hal_sd_get_card_state,FuriStatus, @@ -1541,6 +1553,7 @@ Function,+,furi_semaphore_acquire,FuriStatus,"FuriSemaphore*, uint32_t" Function,+,furi_semaphore_alloc,FuriSemaphore*,"uint32_t, uint32_t" Function,+,furi_semaphore_free,void,FuriSemaphore* Function,+,furi_semaphore_get_count,uint32_t,FuriSemaphore* +Function,+,furi_semaphore_get_space,uint32_t,FuriSemaphore* Function,+,furi_semaphore_release,FuriStatus,FuriSemaphore* Function,+,furi_stream_buffer_alloc,FuriStreamBuffer*,"size_t, size_t" Function,+,furi_stream_buffer_bytes_available,size_t,FuriStreamBuffer* @@ -1569,6 +1582,8 @@ Function,+,furi_string_cmpi_str,int,"const FuriString*, const char[]" Function,+,furi_string_empty,_Bool,const FuriString* Function,+,furi_string_end_with,_Bool,"const FuriString*, const FuriString*" Function,+,furi_string_end_with_str,_Bool,"const FuriString*, const char[]" +Function,+,furi_string_end_withi,_Bool,"const FuriString*, const FuriString*" +Function,+,furi_string_end_withi_str,_Bool,"const FuriString*, const char[]" Function,+,furi_string_equal,_Bool,"const FuriString*, const FuriString*" Function,+,furi_string_equal_str,_Bool,"const FuriString*, const char[]" Function,+,furi_string_free,void,FuriString* @@ -1626,6 +1641,7 @@ Function,+,furi_thread_get_id,FuriThreadId,FuriThread* Function,+,furi_thread_get_name,const char*,FuriThreadId Function,+,furi_thread_get_priority,FuriThreadPriority,FuriThread* Function,+,furi_thread_get_return_code,int32_t,FuriThread* +Function,+,furi_thread_get_signal_callback,FuriThreadSignalCallback,const FuriThread* Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId Function,+,furi_thread_get_state,FuriThreadState,FuriThread* Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback, @@ -2278,7 +2294,7 @@ Function,+,power_get_info,void,"Power*, PowerInfo*" Function,+,power_get_pubsub,FuriPubSub*,Power* Function,+,power_is_battery_healthy,_Bool,Power* Function,+,power_off,void,Power* -Function,+,power_reboot,void,PowerBootMode +Function,+,power_reboot,void,"Power*, PowerBootMode" Function,+,powf,float,"float, float" Function,-,powl,long double,"long double, long double" Function,+,pretty_format_bytes_hex_canonical,void,"FuriString*, size_t, const char*, const uint8_t*, size_t" @@ -2509,7 +2525,7 @@ Function,+,storage_file_write,size_t,"File*, const void*, size_t" Function,+,storage_get_next_filename,void,"Storage*, const char*, const char*, const char*, FuriString*, uint8_t" Function,+,storage_get_pubsub,FuriPubSub*,Storage* Function,+,storage_int_backup,FS_Error,"Storage*, const char*" -Function,+,storage_int_restore,FS_Error,"Storage*, const char*, Storage_name_converter" +Function,+,storage_int_restore,FS_Error,"Storage*, const char*, StorageNameConverter" Function,+,storage_sd_format,FS_Error,Storage* Function,+,storage_sd_info,FS_Error,"Storage*, SDInfo*" Function,+,storage_sd_mount,FS_Error,Storage* @@ -2641,7 +2657,7 @@ Function,+,tar_archive_open,_Bool,"TarArchive*, const char*, TarOpenMode" Function,+,tar_archive_set_file_callback,void,"TarArchive*, tar_unpack_file_cb, void*" Function,+,tar_archive_store_data,_Bool,"TarArchive*, const char*, const uint8_t*, const int32_t" Function,+,tar_archive_unpack_file,_Bool,"TarArchive*, const char*, const char*" -Function,+,tar_archive_unpack_to,_Bool,"TarArchive*, const char*, Storage_name_converter" +Function,+,tar_archive_unpack_to,_Bool,"TarArchive*, const char*, TarArchiveNameConverter" Function,-,tempnam,char*,"const char*, const char*" Function,+,text_box_alloc,TextBox*, Function,+,text_box_free,void,TextBox* @@ -2753,11 +2769,11 @@ Function,+,view_holder_alloc,ViewHolder*, Function,+,view_holder_attach_to_gui,void,"ViewHolder*, Gui*" Function,+,view_holder_free,void,ViewHolder* Function,+,view_holder_get_free_context,void*,ViewHolder* +Function,+,view_holder_send_to_back,void,ViewHolder* +Function,+,view_holder_send_to_front,void,ViewHolder* Function,+,view_holder_set_back_callback,void,"ViewHolder*, BackCallback, void*" Function,+,view_holder_set_free_callback,void,"ViewHolder*, FreeCallback, void*" Function,+,view_holder_set_view,void,"ViewHolder*, View*" -Function,+,view_holder_start,void,ViewHolder* -Function,+,view_holder_stop,void,ViewHolder* Function,+,view_holder_update,void,"View*, void*" Function,+,view_port_alloc,ViewPort*, Function,+,view_port_draw_callback_set,void,"ViewPort*, ViewPortDrawCallback, void*" diff --git a/targets/f18/target.json b/targets/f18/target.json index 229ec0a7ad..3452c6707a 100644 --- a/targets/f18/target.json +++ b/targets/f18/target.json @@ -17,13 +17,11 @@ "stm32wb", "hwdrivers", "fatfs", - "littlefs", "toolbox", "digital_signal", "signal_reader", "microtar", "usb_stm32", - "appframe", "assets", "one_wire", "music_worker", diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 6002ccbee6..0680de4efd 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,69.0,, +Version,+,72.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -20,6 +20,7 @@ Header,+,applications/services/gui/modules/file_browser.h,, Header,+,applications/services/gui/modules/file_browser_worker.h,, Header,+,applications/services/gui/modules/loading.h,, Header,+,applications/services/gui/modules/menu.h,, +Header,+,applications/services/gui/modules/number_input.h,, Header,+,applications/services/gui/modules/popup.h,, Header,+,applications/services/gui/modules/submenu.h,, Header,+,applications/services/gui/modules/text_box.h,, @@ -768,6 +769,7 @@ Function,+,bt_forget_bonded_devices,void,Bt* Function,+,bt_keys_storage_alloc,BtKeysStorage*,const char* Function,+,bt_keys_storage_delete,_Bool,BtKeysStorage* Function,+,bt_keys_storage_free,void,BtKeysStorage* +Function,+,bt_keys_storage_is_changed,_Bool,BtKeysStorage* Function,+,bt_keys_storage_load,_Bool,BtKeysStorage* Function,+,bt_keys_storage_set_default_path,void,Bt* Function,+,bt_keys_storage_set_file_path,void,"BtKeysStorage*, const char*" @@ -1029,7 +1031,6 @@ Function,-,exp2f,float,float Function,-,exp2l,long double,long double Function,+,expansion_disable,void,Expansion* Function,+,expansion_enable,void,Expansion* -Function,+,expansion_is_connected,_Bool,Expansion* Function,+,expansion_set_listen_serial,void,"Expansion*, FuriHalSerialId" Function,-,expf,float,float Function,-,expl,long double,long double @@ -1243,11 +1244,13 @@ Function,+,furi_event_flag_set,uint32_t,"FuriEventFlag*, uint32_t" Function,+,furi_event_flag_wait,uint32_t,"FuriEventFlag*, uint32_t, uint32_t, uint32_t" Function,+,furi_event_loop_alloc,FuriEventLoop*, Function,+,furi_event_loop_free,void,FuriEventLoop* -Function,+,furi_event_loop_message_queue_subscribe,void,"FuriEventLoop*, FuriMessageQueue*, FuriEventLoopEvent, FuriEventLoopMessageQueueCallback, void*" -Function,+,furi_event_loop_message_queue_unsubscribe,void,"FuriEventLoop*, FuriMessageQueue*" Function,+,furi_event_loop_pend_callback,void,"FuriEventLoop*, FuriEventLoopPendingCallback, void*" Function,+,furi_event_loop_run,void,FuriEventLoop* Function,+,furi_event_loop_stop,void,FuriEventLoop* +Function,+,furi_event_loop_subscribe_message_queue,void,"FuriEventLoop*, FuriMessageQueue*, FuriEventLoopEvent, FuriEventLoopEventCallback, void*" +Function,+,furi_event_loop_subscribe_mutex,void,"FuriEventLoop*, FuriMutex*, FuriEventLoopEvent, FuriEventLoopEventCallback, void*" +Function,+,furi_event_loop_subscribe_semaphore,void,"FuriEventLoop*, FuriSemaphore*, FuriEventLoopEvent, FuriEventLoopEventCallback, void*" +Function,+,furi_event_loop_subscribe_stream_buffer,void,"FuriEventLoop*, FuriStreamBuffer*, FuriEventLoopEvent, FuriEventLoopEventCallback, void*" Function,+,furi_event_loop_tick_set,void,"FuriEventLoop*, uint32_t, FuriEventLoopTickCallback, void*" Function,+,furi_event_loop_timer_alloc,FuriEventLoopTimer*,"FuriEventLoop*, FuriEventLoopTimerCallback, FuriEventLoopTimerType, void*" Function,+,furi_event_loop_timer_free,void,FuriEventLoopTimer* @@ -1257,6 +1260,7 @@ Function,+,furi_event_loop_timer_is_running,_Bool,const FuriEventLoopTimer* Function,+,furi_event_loop_timer_restart,void,FuriEventLoopTimer* Function,+,furi_event_loop_timer_start,void,"FuriEventLoopTimer*, uint32_t" Function,+,furi_event_loop_timer_stop,void,FuriEventLoopTimer* +Function,+,furi_event_loop_unsubscribe,void,"FuriEventLoop*, FuriEventLoopObject*" Function,+,furi_get_tick,uint32_t, Function,+,furi_hal_adc_acquire,FuriHalAdcHandle*, Function,+,furi_hal_adc_configure,void,FuriHalAdcHandle* @@ -1589,6 +1593,7 @@ Function,+,furi_hal_rtc_get_log_baud_rate,FuriHalRtcLogBaudRate, Function,+,furi_hal_rtc_get_log_device,FuriHalRtcLogDevice, Function,+,furi_hal_rtc_get_log_level,uint8_t, Function,+,furi_hal_rtc_get_pin_fails,uint32_t, +Function,-,furi_hal_rtc_get_pin_value,uint32_t, Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister Function,+,furi_hal_rtc_get_timestamp,uint32_t, Function,-,furi_hal_rtc_init,void, @@ -1608,6 +1613,7 @@ Function,+,furi_hal_rtc_set_log_baud_rate,void,FuriHalRtcLogBaudRate Function,+,furi_hal_rtc_set_log_device,void,FuriHalRtcLogDevice Function,+,furi_hal_rtc_set_log_level,void,uint8_t Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t +Function,-,furi_hal_rtc_set_pin_value,void,uint32_t Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" Function,+,furi_hal_rtc_sync_shadow,void, Function,+,furi_hal_sd_get_card_state,FuriStatus, @@ -1795,6 +1801,7 @@ Function,+,furi_semaphore_acquire,FuriStatus,"FuriSemaphore*, uint32_t" Function,+,furi_semaphore_alloc,FuriSemaphore*,"uint32_t, uint32_t" Function,+,furi_semaphore_free,void,FuriSemaphore* Function,+,furi_semaphore_get_count,uint32_t,FuriSemaphore* +Function,+,furi_semaphore_get_space,uint32_t,FuriSemaphore* Function,+,furi_semaphore_release,FuriStatus,FuriSemaphore* Function,+,furi_stream_buffer_alloc,FuriStreamBuffer*,"size_t, size_t" Function,+,furi_stream_buffer_bytes_available,size_t,FuriStreamBuffer* @@ -1823,6 +1830,8 @@ Function,+,furi_string_cmpi_str,int,"const FuriString*, const char[]" Function,+,furi_string_empty,_Bool,const FuriString* Function,+,furi_string_end_with,_Bool,"const FuriString*, const FuriString*" Function,+,furi_string_end_with_str,_Bool,"const FuriString*, const char[]" +Function,+,furi_string_end_withi,_Bool,"const FuriString*, const FuriString*" +Function,+,furi_string_end_withi_str,_Bool,"const FuriString*, const char[]" Function,+,furi_string_equal,_Bool,"const FuriString*, const FuriString*" Function,+,furi_string_equal_str,_Bool,"const FuriString*, const char[]" Function,+,furi_string_free,void,FuriString* @@ -1880,6 +1889,7 @@ Function,+,furi_thread_get_id,FuriThreadId,FuriThread* Function,+,furi_thread_get_name,const char*,FuriThreadId Function,+,furi_thread_get_priority,FuriThreadPriority,FuriThread* Function,+,furi_thread_get_return_code,int32_t,FuriThread* +Function,+,furi_thread_get_signal_callback,FuriThreadSignalCallback,const FuriThread* Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId Function,+,furi_thread_get_state,FuriThreadState,FuriThread* Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback, @@ -1991,8 +2001,8 @@ Function,+,ibutton_protocols_render_data,void,"iButtonProtocols*, const iButtonK Function,+,ibutton_protocols_render_error,void,"iButtonProtocols*, const iButtonKey*, FuriString*" Function,+,ibutton_protocols_render_uid,void,"iButtonProtocols*, const iButtonKey*, FuriString*" Function,+,ibutton_protocols_save,_Bool,"iButtonProtocols*, const iButtonKey*, const char*" -Function,+,ibutton_protocols_write_blank,_Bool,"iButtonProtocols*, iButtonKey*" Function,+,ibutton_protocols_write_copy,_Bool,"iButtonProtocols*, iButtonKey*" +Function,+,ibutton_protocols_write_id,_Bool,"iButtonProtocols*, iButtonKey*" Function,+,ibutton_worker_alloc,iButtonWorker*,iButtonProtocols* Function,+,ibutton_worker_emulate_set_callback,void,"iButtonWorker*, iButtonWorkerEmulateCallback, void*" Function,+,ibutton_worker_emulate_start,void,"iButtonWorker*, iButtonKey*" @@ -2002,8 +2012,8 @@ Function,+,ibutton_worker_read_start,void,"iButtonWorker*, iButtonKey*" Function,+,ibutton_worker_start_thread,void,iButtonWorker* Function,+,ibutton_worker_stop,void,iButtonWorker* Function,+,ibutton_worker_stop_thread,void,iButtonWorker* -Function,+,ibutton_worker_write_blank_start,void,"iButtonWorker*, iButtonKey*" Function,+,ibutton_worker_write_copy_start,void,"iButtonWorker*, iButtonKey*" +Function,+,ibutton_worker_write_id_start,void,"iButtonWorker*, iButtonKey*" Function,+,ibutton_worker_write_set_callback,void,"iButtonWorker*, iButtonWorkerWriteCallback, void*" Function,+,icon_animation_alloc,IconAnimation*,const Icon* Function,+,icon_animation_free,void,IconAnimation* @@ -2854,6 +2864,11 @@ Function,+,notification_internal_message_block,void,"NotificationApp*, const Not Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*" Function,-,nrand48,long,unsigned short[3] +Function,+,number_input_alloc,NumberInput*, +Function,+,number_input_free,void,NumberInput* +Function,+,number_input_get_view,View*,NumberInput* +Function,+,number_input_set_header_text,void,"NumberInput*, const char*" +Function,+,number_input_set_result_callback,void,"NumberInput*, NumberInputCallback, void*, int32_t, int32_t, int32_t" Function,-,on_exit,int,"void (*)(int, void*), void*" Function,+,onewire_host_alloc,OneWireHost*,const GpioPin* Function,+,onewire_host_free,void,OneWireHost* @@ -2951,7 +2966,7 @@ Function,+,power_get_info,void,"Power*, PowerInfo*" Function,+,power_get_pubsub,FuriPubSub*,Power* Function,+,power_is_battery_healthy,_Bool,Power* Function,+,power_off,void,Power* -Function,+,power_reboot,void,PowerBootMode +Function,+,power_reboot,void,"Power*, PowerBootMode" Function,-,power_trigger_ui_update,void,Power* Function,+,powf,float,"float, float" Function,-,powl,long double,"long double, long double" @@ -3234,7 +3249,7 @@ Function,+,storage_file_write,size_t,"File*, const void*, size_t" Function,+,storage_get_next_filename,void,"Storage*, const char*, const char*, const char*, FuriString*, uint8_t" Function,+,storage_get_pubsub,FuriPubSub*,Storage* Function,+,storage_int_backup,FS_Error,"Storage*, const char*" -Function,+,storage_int_restore,FS_Error,"Storage*, const char*, Storage_name_converter" +Function,+,storage_int_restore,FS_Error,"Storage*, const char*, StorageNameConverter" Function,+,storage_sd_format,FS_Error,Storage* Function,+,storage_sd_info,FS_Error,"Storage*, SDInfo*" Function,+,storage_sd_mount,FS_Error,Storage* @@ -3550,7 +3565,7 @@ Function,+,tar_archive_open,_Bool,"TarArchive*, const char*, TarOpenMode" Function,+,tar_archive_set_file_callback,void,"TarArchive*, tar_unpack_file_cb, void*" Function,+,tar_archive_store_data,_Bool,"TarArchive*, const char*, const uint8_t*, const int32_t" Function,+,tar_archive_unpack_file,_Bool,"TarArchive*, const char*, const char*" -Function,+,tar_archive_unpack_to,_Bool,"TarArchive*, const char*, Storage_name_converter" +Function,+,tar_archive_unpack_to,_Bool,"TarArchive*, const char*, TarArchiveNameConverter" Function,-,tempnam,char*,"const char*, const char*" Function,+,text_box_alloc,TextBox*, Function,+,text_box_free,void,TextBox* @@ -3668,11 +3683,11 @@ Function,+,view_holder_alloc,ViewHolder*, Function,+,view_holder_attach_to_gui,void,"ViewHolder*, Gui*" Function,+,view_holder_free,void,ViewHolder* Function,+,view_holder_get_free_context,void*,ViewHolder* +Function,+,view_holder_send_to_back,void,ViewHolder* +Function,+,view_holder_send_to_front,void,ViewHolder* Function,+,view_holder_set_back_callback,void,"ViewHolder*, BackCallback, void*" Function,+,view_holder_set_free_callback,void,"ViewHolder*, FreeCallback, void*" Function,+,view_holder_set_view,void,"ViewHolder*, View*" -Function,+,view_holder_start,void,ViewHolder* -Function,+,view_holder_stop,void,ViewHolder* Function,+,view_holder_update,void,"View*, void*" Function,+,view_port_alloc,ViewPort*, Function,+,view_port_draw_callback_set,void,"ViewPort*, ViewPortDrawCallback, void*" diff --git a/targets/f7/ble_glue/app_conf.h b/targets/f7/ble_glue/app_conf.h index 43be8129dc..9ceb747c19 100644 --- a/targets/f7/ble_glue/app_conf.h +++ b/targets/f7/ble_glue/app_conf.h @@ -194,3 +194,7 @@ 255 /**< Set to 255 with the memory manager and the mailbox */ #define TL_BLE_EVENT_FRAME_SIZE (TL_EVT_HDR_SIZE + CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE) + +/* Various defines for compatibility with -Wundef - thanks, ST */ +#define CFG_DEBUG_TRACE_FULL 0 +#define CFG_DEBUG_TRACE_LIGHT 0 diff --git a/targets/f7/ble_glue/ble_conf.h b/targets/f7/ble_glue/ble_conf.h index 4c523a707e..c34c54de66 100644 --- a/targets/f7/ble_glue/ble_conf.h +++ b/targets/f7/ble_glue/ble_conf.h @@ -9,3 +9,15 @@ #define BLE_CFG_SVC_MAX_NBR_CB 0 #define BLE_CFG_CLT_MAX_NBR_CB 0 + +/* Various defines for compatibility with -Wundef - thanks, ST */ +#define BLE_CFG_BLS_INTERMEDIATE_CUFF_PRESSURE 0 +#define BLE_CFG_BLS_TIME_STAMP_FLAG 0 +#define BLE_CFG_BLS_PULSE_RATE_FLAG 0 +#define BLE_CFG_BLS_USER_ID_FLAG 0 +#define BLE_CFG_BLS_MEASUREMENT_STATUS_FLAG 0 +#define BLE_CFG_HRS_ENERGY_EXPENDED_INFO_FLAG 0 +#define BLE_CFG_HRS_ENERGY_RR_INTERVAL_FLAG 0 +#define BLE_CFG_HTS_MEASUREMENT_INTERVAL 0 +#define BLE_CFG_HTS_TIME_STAMP_FLAG 0 +#define BLE_CFG_HTS_TEMPERATURE_TYPE_VALUE_STATIC 0 diff --git a/targets/f7/ble_glue/extra_beacon.c b/targets/f7/ble_glue/extra_beacon.c index 0fd452a5a6..f9b9b13ef6 100644 --- a/targets/f7/ble_glue/extra_beacon.c +++ b/targets/f7/ble_glue/extra_beacon.c @@ -8,9 +8,9 @@ #define GAP_MS_TO_SCAN_INTERVAL(x) ((uint16_t)((x) / 0.625)) -// Also used as an indicator of whether the beacon had ever been configured -// AN5289: 4.7, we need at least 25ms + advertisement, which is 30 ms -#define GAP_MIN_ADV_INTERVAL_MS (30u) +// AN5289: 4.7, in order to use flash controller interval must be at least 25ms + advertisement, which is 30 ms +// Since we don't use flash controller anymore interval can be lowered to 20ms +#define GAP_MIN_ADV_INTERVAL_MS (20U) typedef struct { GapExtraBeaconConfig last_config; diff --git a/targets/f7/ble_glue/hw_ipcc.c b/targets/f7/ble_glue/hw_ipcc.c index 4daaa7e49d..43785a1b4b 100644 --- a/targets/f7/ble_glue/hw_ipcc.c +++ b/targets/f7/ble_glue/hw_ipcc.c @@ -15,6 +15,8 @@ (LL_C2_IPCC_IsActiveFlag_CHx(IPCC, channel) && \ LL_C1_IPCC_IsEnabledReceiveChannel(IPCC, channel)) +#define IPCC_SEND_CMD_TIMEOUT_US (33UL * 1000UL * 1000UL) + static void (*FreeBufCb)(void); static void HW_IPCC_BLE_EvtHandler(void); @@ -113,7 +115,7 @@ void HW_IPCC_SYS_Init(void) { void HW_IPCC_SYS_SendCmd(void) { LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL); - FuriHalCortexTimer timer = furi_hal_cortex_timer_get(33000000); + FuriHalCortexTimer timer = furi_hal_cortex_timer_get(IPCC_SEND_CMD_TIMEOUT_US); while(LL_C1_IPCC_IsActiveFlag_CHx(IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL)) { furi_check(!furi_hal_cortex_timer_is_expired(timer), "HW_IPCC_SYS_SendCmd timeout"); diff --git a/targets/f7/ble_glue/profiles/serial_profile.c b/targets/f7/ble_glue/profiles/serial_profile.c index 118a76e8c3..1d414889f8 100644 --- a/targets/f7/ble_glue/profiles/serial_profile.c +++ b/targets/f7/ble_glue/profiles/serial_profile.c @@ -40,14 +40,20 @@ static void ble_profile_serial_stop(FuriHalBleProfileBase* profile) { ble_svc_serial_stop(serial_profile->serial_svc); } +// AN5289: 4.7, in order to use flash controller interval must be at least 25ms + advertisement, which is 30 ms +// Since we don't use flash controller anymore interval can be lowered to 7.5ms +#define CONNECTION_INTERVAL_MIN (0x06) +// Up to 45 ms +#define CONNECTION_INTERVAL_MAX (0x24) + static GapConfig serial_template_config = { .adv_service_uuid = 0x3080, .appearance_char = 0x8600, .bonding_mode = true, .pairing_method = GapPairingPinCodeShow, .conn_param = { - .conn_int_min = 0x18, // AN5289: 4.7, we need at least 25ms + advertisement, which is 30 ms - .conn_int_max = 0x24, // 45 ms + .conn_int_min = CONNECTION_INTERVAL_MIN, + .conn_int_max = CONNECTION_INTERVAL_MAX, .slave_latency = 0, .supervisor_timeout = 0, }}; diff --git a/targets/f7/furi_hal/furi_hal_bt.c b/targets/f7/furi_hal/furi_hal_bt.c index 30a4ee7ede..05a066630d 100644 --- a/targets/f7/furi_hal/furi_hal_bt.c +++ b/targets/f7/furi_hal/furi_hal_bt.c @@ -87,10 +87,9 @@ static bool furi_hal_bt_radio_stack_is_supported(const BleGlueC2Info* info) { } bool furi_hal_bt_start_radio_stack(void) { - bool res = false; - furi_check(furi_hal_bt.core2_mtx); + furi_hal_bt_lock_core2(); - furi_mutex_acquire(furi_hal_bt.core2_mtx, FuriWaitForever); + bool res = false; // Explicitly tell that we are in charge of CLK48 domain furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0); @@ -123,7 +122,8 @@ bool furi_hal_bt_start_radio_stack(void) { } res = true; } while(false); - furi_mutex_release(furi_hal_bt.core2_mtx); + + furi_hal_bt_unlock_core2(); gap_extra_beacon_init(); return res; @@ -198,6 +198,8 @@ FuriHalBleProfileBase* furi_hal_bt_start_app( } void furi_hal_bt_reinit(void) { + furi_hal_bt_lock_core2(); + furi_hal_power_insomnia_enter(); FURI_LOG_I(TAG, "Disconnect and stop advertising"); furi_hal_bt_stop_advertising(); @@ -229,6 +231,7 @@ void furi_hal_bt_reinit(void) { furi_hal_bus_disable(FuriHalBusCRC); furi_hal_bt_init(); + furi_hal_bt_unlock_core2(); furi_hal_bt_start_radio_stack(); furi_hal_power_insomnia_exit(); } diff --git a/targets/f7/furi_hal/furi_hal_crypto.c b/targets/f7/furi_hal/furi_hal_crypto.c index 1879eb2cae..4deda293a2 100644 --- a/targets/f7/furi_hal/furi_hal_crypto.c +++ b/targets/f7/furi_hal/furi_hal_crypto.c @@ -262,36 +262,54 @@ bool furi_hal_crypto_enclave_load_key(uint8_t slot, const uint8_t* iv) { furi_hal_bus_enable(FuriHalBusAES1); - if(!furi_hal_bt_is_alive()) { - return false; - } + bool success = false; - furi_hal_crypto_mode_init_done = false; - crypto_key_init(NULL, (uint32_t*)iv); + furi_hal_bt_lock_core2(); - if(SHCI_C2_FUS_LoadUsrKey(slot) == SHCI_Success) { - return true; - } else { - CLEAR_BIT(AES1->CR, AES_CR_EN); - furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk); - return false; - } + do { + if(!furi_hal_bt_is_alive()) { + break; + } + + furi_hal_crypto_mode_init_done = false; + crypto_key_init(NULL, (uint32_t*)iv); + + if(SHCI_C2_FUS_LoadUsrKey(slot) == SHCI_Success) { + success = true; + } else { + CLEAR_BIT(AES1->CR, AES_CR_EN); + furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk); + } + + } while(false); + + furi_hal_bt_unlock_core2(); + return success; } bool furi_hal_crypto_enclave_unload_key(uint8_t slot) { - if(!furi_hal_bt_is_alive()) { - return false; - } + furi_hal_bt_lock_core2(); - CLEAR_BIT(AES1->CR, AES_CR_EN); + bool success = false; + + do { + if(!furi_hal_bt_is_alive()) { + break; + } - SHCI_CmdStatus_t shci_state = SHCI_C2_FUS_UnloadUsrKey(slot); + CLEAR_BIT(AES1->CR, AES_CR_EN); - furi_hal_bus_disable(FuriHalBusAES1); + SHCI_CmdStatus_t shci_state = SHCI_C2_FUS_UnloadUsrKey(slot); - furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk); + furi_hal_bus_disable(FuriHalBusAES1); - return shci_state == SHCI_Success; + furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk); + + success = (shci_state == SHCI_Success); + } while(false); + + furi_hal_bt_unlock_core2(); + return success; } bool furi_hal_crypto_load_key(const uint8_t* key, const uint8_t* iv) { diff --git a/targets/f7/furi_hal/furi_hal_infrared.c b/targets/f7/furi_hal/furi_hal_infrared.c index 029d103cb5..a1169391d6 100644 --- a/targets/f7/furi_hal/furi_hal_infrared.c +++ b/targets/f7/furi_hal/furi_hal_infrared.c @@ -54,6 +54,7 @@ typedef struct { typedef struct { float cycle_duration; + float cycle_remainder; FuriHalInfraredTxGetDataISRCallback data_callback; FuriHalInfraredTxSignalSentISRCallback signal_sent_callback; void* data_context; @@ -512,7 +513,11 @@ static void furi_hal_infrared_tx_fill_buffer(uint8_t buf_num, uint8_t polarity_s status = infrared_tim_tx.data_callback(infrared_tim_tx.data_context, &duration, &level); - uint32_t num_of_impulses = roundf(duration / infrared_tim_tx.cycle_duration); + const float num_of_impulses_f = + duration / infrared_tim_tx.cycle_duration + infrared_tim_tx.cycle_remainder; + const uint32_t num_of_impulses = roundf(num_of_impulses_f); + // Save the remainder (in carrier periods) for later use + infrared_tim_tx.cycle_remainder = num_of_impulses_f - num_of_impulses; if(num_of_impulses == 0) { if((*size == 0) && (status == FuriHalInfraredTxGetDataStateDone)) { @@ -521,7 +526,7 @@ static void furi_hal_infrared_tx_fill_buffer(uint8_t buf_num, uint8_t polarity_s */ status = FuriHalInfraredTxGetDataStateOk; } - } else if((num_of_impulses - 1) > 0xFFFF) { + } else if((num_of_impulses - 1) > UINT16_MAX) { infrared_tim_tx.tx_timing_rest_duration = num_of_impulses - 1; infrared_tim_tx.tx_timing_rest_status = status; infrared_tim_tx.tx_timing_rest_level = level; @@ -632,6 +637,7 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { infrared_tim_tx.stop_semaphore = furi_semaphore_alloc(1, 0); infrared_tim_tx.cycle_duration = 1000000.0 / freq; infrared_tim_tx.tx_timing_rest_duration = 0; + infrared_tim_tx.cycle_remainder = 0; furi_hal_infrared_tx_fill_buffer(0, INFRARED_POLARITY_SHIFT); @@ -655,7 +661,7 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { const GpioPin* tx_gpio = infrared_tx_pins[infrared_tx_output]; LL_GPIO_ResetOutputPin(tx_gpio->port, tx_gpio->pin); /* when disable it prevents false pulse */ furi_hal_gpio_init_ex( - tx_gpio, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedHigh, GpioAltFn1TIM1); + tx_gpio, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedHigh, GpioAltFn1TIM1); FURI_CRITICAL_ENTER(); LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* TIMx_RCR -> Repetition counter */ diff --git a/targets/f7/furi_hal/furi_hal_interrupt.c b/targets/f7/furi_hal/furi_hal_interrupt.c index 35c40c2595..cf10c8d33d 100644 --- a/targets/f7/furi_hal/furi_hal_interrupt.c +++ b/targets/f7/furi_hal/furi_hal_interrupt.c @@ -120,6 +120,7 @@ void furi_hal_interrupt_init(void) { TAMP_STAMP_LSECSS_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0)); NVIC_EnableIRQ(TAMP_STAMP_LSECSS_IRQn); + NVIC_SetPriority(SVCall_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0)); NVIC_SetPriority(PendSV_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0)); NVIC_SetPriority(FPU_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0)); diff --git a/targets/f7/furi_hal/furi_hal_rtc.c b/targets/f7/furi_hal/furi_hal_rtc.c index f5f7bdf2d2..d5cda74767 100644 --- a/targets/f7/furi_hal/furi_hal_rtc.c +++ b/targets/f7/furi_hal/furi_hal_rtc.c @@ -411,6 +411,14 @@ uint32_t furi_hal_rtc_get_pin_fails(void) { return furi_hal_rtc_get_register(FuriHalRtcRegisterPinFails); } +void furi_hal_rtc_set_pin_value(uint32_t value) { + furi_hal_rtc_set_register(FuriHalRtcRegisterPinValue, value); +} + +uint32_t furi_hal_rtc_get_pin_value(void) { + return furi_hal_rtc_get_register(FuriHalRtcRegisterPinValue); +} + uint32_t furi_hal_rtc_get_timestamp(void) { DateTime datetime = {0}; furi_hal_rtc_get_datetime(&datetime); diff --git a/targets/f7/furi_hal/furi_hal_rtc.h b/targets/f7/furi_hal/furi_hal_rtc.h index 3bdbb0c729..030b464cf7 100644 --- a/targets/f7/furi_hal/furi_hal_rtc.h +++ b/targets/f7/furi_hal/furi_hal_rtc.h @@ -46,9 +46,10 @@ typedef enum { FuriHalRtcRegisterVersion, /**< Pointer to Version */ FuriHalRtcRegisterLfsFingerprint, /**< LFS geometry fingerprint */ FuriHalRtcRegisterFaultData, /**< Pointer to last fault message */ - FuriHalRtcRegisterPinFails, /**< Failed pins count */ + FuriHalRtcRegisterPinFails, /**< Failed PINs count */ /* Index of FS directory entry corresponding to FW update to be applied */ FuriHalRtcRegisterUpdateFolderFSIndex, + FuriHalRtcRegisterPinValue, /**< Encoded value of the currently set PIN */ FuriHalRtcRegisterMAX, /**< Service value, do not use */ } FuriHalRtcRegister; @@ -257,18 +258,29 @@ void furi_hal_rtc_set_fault_data(uint32_t value); */ uint32_t furi_hal_rtc_get_fault_data(void); -/** Set Pin Fails count +/** Set PIN Fails count * - * @param[in] value The Pin Fails count + * @param[in] value The PIN Fails count */ void furi_hal_rtc_set_pin_fails(uint32_t value); -/** Get Pin Fails count +/** Get PIN Fails count * - * @return Pin Fails Count + * @return PIN Fails Count */ uint32_t furi_hal_rtc_get_pin_fails(void); +/** Set encoded PIN value + * + * @param[in] value new PIN code value to be set + */ +void furi_hal_rtc_set_pin_value(uint32_t value); + +/** Get the current PIN encoded value + * + */ +uint32_t furi_hal_rtc_get_pin_value(void); + /** Get UNIX Timestamp * * @return Unix Timestamp in seconds from UNIX epoch start diff --git a/targets/f7/inc/FreeRTOSConfig.h b/targets/f7/inc/FreeRTOSConfig.h index 62310511d2..2948faef93 100644 --- a/targets/f7/inc/FreeRTOSConfig.h +++ b/targets/f7/inc/FreeRTOSConfig.h @@ -17,11 +17,13 @@ #define configUSE_PREEMPTION 1 #define configSUPPORT_STATIC_ALLOCATION 1 #define configSUPPORT_DYNAMIC_ALLOCATION 0 +#define configUSE_MALLOC_FAILED_HOOK 0 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCPU_CLOCK_HZ (SystemCoreClock) #define configTICK_RATE_HZ_RAW 1000 #define configTICK_RATE_HZ ((TickType_t)configTICK_RATE_HZ_RAW) +#define configUSE_16_BIT_TICKS 0 #define configMAX_PRIORITIES (32) #define configMINIMAL_STACK_SIZE ((uint16_t)128) @@ -34,7 +36,6 @@ #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() #define configUSE_TRACE_FACILITY 1 -#define configUSE_16_BIT_TICKS 0 #define configUSE_MUTEXES 1 #define configQUEUE_REGISTRY_SIZE 0 #define configCHECK_FOR_STACK_OVERFLOW 0 diff --git a/targets/f7/target.json b/targets/f7/target.json index 665864d7d9..f5b3cf3b6b 100644 --- a/targets/f7/target.json +++ b/targets/f7/target.json @@ -25,7 +25,6 @@ "stm32wb", "hwdrivers", "fatfs", - "littlefs", "subghz", "toolbox", "nfc", @@ -35,7 +34,6 @@ "microtar", "usb_stm32", "infrared", - "appframe", "assets", "one_wire", "ibutton", diff --git a/targets/furi_hal_include/furi_hal_region.h b/targets/furi_hal_include/furi_hal_region.h index b6a6d425e6..f370596494 100644 --- a/targets/furi_hal_include/furi_hal_region.h +++ b/targets/furi_hal_include/furi_hal_region.h @@ -2,7 +2,6 @@ #include #include -#include #ifdef __cplusplus extern "C" {