diff --git a/.ci_files/rgb.patch b/.ci_files/rgb.patch index 710890109..51a305aec 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 a31ef8e75..1fdc58bc6 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 df5bf648f..c9373c093 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 8606eef15..4040dcb91 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 da2ef41a1..0ae007b34 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 5e0da6897..5e5b5dcf4 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 c0b9e8867..681544c32 100644 --- a/.vscode/example/tasks.json +++ b/.vscode/example/tasks.json @@ -75,48 +75,42 @@ "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", "type": "shell", "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb" }, + { + "label": "[Debug] Flash (USB, w/o resources)", + "group": "build", + "type": "shell", + "command": "./fbt FORCE=1 flash_usb" + }, { "label": "[Debug:unit_tests] Flash (USB)", "group": "build", "type": "shell", "command": "./fbt FIRMWARE_APP_SET=unit_tests FORCE=1 flash_usb_full" }, - { - "label": "[Debug] Flash (USB, with resources)", - "group": "build", - "type": "shell", - "command": "./fbt FORCE=1 flash_usb_full" - }, { "label": "[Release] Flash (USB, with resources)", "group": "build", "type": "shell", "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb_full" }, + { + "label": "[Debug] Flash (USB, with resources)", + "group": "build", + "type": "shell", + "command": "./fbt FORCE=1 flash_usb_full" + }, { "label": "[Debug] Create PVS-Studio report", "group": "build", "type": "shell", "command": "./fbt firmware_pvs" }, - { - "label": "[Debug] Build FAPs", - "group": "build", - "type": "shell", - "command": "./fbt fap_dist" - }, { "label": "[Release] Build FAPs", "group": "build", @@ -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", @@ -156,18 +156,18 @@ "Serial Console" ] }, - { - "label": "[Debug] Build and upload all FAPs to Flipper over USB", - "group": "build", - "type": "shell", - "command": "./fbt fap_deploy" - }, { "label": "[Release] Build and upload all FAPs to Flipper over USB", "group": "build", "type": "shell", "command": "./fbt COMPACT=1 DEBUG=0 fap_deploy" }, + { + "label": "[Debug] Build and upload all FAPs to Flipper over USB", + "group": "build", + "type": "shell", + "command": "./fbt fap_deploy" + }, { // Press Ctrl+] to quit "label": "Serial Console", @@ -192,4 +192,4 @@ } } ] -} \ No newline at end of file +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bd2bf251..b51403f7c 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 7eb98aeed..b2911d14d 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 48baaa95e..298954fd6 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 955c0b286..aeb90c297 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)); + + // set back callback + view_holder_set_back_callback(view_holder, callback, NULL); gui = static_cast(furi_record_open(RECORD_GUI)); - view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); - - // 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); + 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 66e54e41c..c0a12cbe8 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 @@ public: enum class ViewType : uint8_t { Submenu, Popup, - Tune, }; FuriMessageQueue* event_queue; @@ -27,11 +26,10 @@ public: 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 5f9934e77..363c8f4d5 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 109feee60..56c67e3e6 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 46a1237f9..abb8ad3dd 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 000000000..1daaa70c3 --- /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 000000000..ca3275aec --- /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 000000000..97214d1b2 --- /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 000000000..d67118ce6 --- /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 3de5555f4..216f2582f 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 50eb476a9..a21dfbafc 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 6c1bb106a..000000000 --- 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 6b408c7f5..000000000 --- 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 ae0074fe1..2b2be13d6 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 3028a13b9..3b742906d 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 5c7e0ce55..7f00e63f2 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 c3e7c898b..a502a8a90 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 037474aa3..2b5a3bf97 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 9eb26944f..0ff6303bf 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 000000000..bfd7cd5d4 --- /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 000000000..0187bd49d --- /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 13c0b299f..962afd1c3 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 1ca077db1..51d45a6b0 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 5e53c221e..1536b8918 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 089aaed83..9cdc2e448 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 10dac0eca..77dc6d382 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 6eba864f6..dccdac213 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 7bbcb285b..4d63e3779 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 8e1884e9a..bf38ba4c2 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 000000000..9737b71a6 --- /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 000000000..544fc7a1d --- /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 4eeecb2b8..291181c77 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 63ea706ed..5d26bdb30 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 3e93ac4c3..abbcbd2b0 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 1adec4db2..50524e5b7 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 ddec9d9b0..a71ac3c6e 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 faa3feb91..16979543c 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 7060e893d..c6aff4189 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 4cf4d19c5..8ca6d664d 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 000000000..a37ffb1a0 --- /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 000000000..ebfb00911 --- /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 000000000..d043f3f89 --- /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 000000000..65dbd83cf --- /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 000000000..e255f6b61 --- /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 6b3f8aa59..26c21e235 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 000000000..9d5a0a9e5 --- /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 000000000..58cff4496 --- /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 000000000..19d787ef5 --- /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 000000000..8d944e6fd --- /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 000000000..bdb494fcd 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 000000000..caf77fa8c --- /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 bdeb4a843..49fcd256f 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 000000000..71acbda52 --- /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 000000000..7478f58a7 --- /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 000000000..ad7656232 --- /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 000000000..d9b1fd52f --- /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 000000000..2afdaf5c1 --- /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 3d527f306..bc42d190c 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 000000000..f7b743bcf --- /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 000000000..71d29edfd --- /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 000000000..19ad8d2ac --- /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 000000000..24907dbc2 --- /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 2345d3f7d..7c23ee315 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 43befc055..7aca29364 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 bd9b00745..96518cd7a 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 1e1cdc881..bdfeba035 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 64ffcdd7b..75070c44d 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 3684fe643..868fa8a11 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 0f10d60d8..2d2d4be86 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 037474aa3..2b5a3bf97 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 217423ecc..234cc793a 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 4a6eccf05..7b54bb5cb 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 b6e8a20cf..765d53612 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 12e237e8a..dcac8f963 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 d355a4ea5..fc2324c63 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 2fdaf123a..f73af065f 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 890e0a284..94ad4b69e 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 668b79ae3..6727c5458 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 0fc073fda..4525eae7b 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 22c986180..36c214f3b 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 d860aa3b2..db178fb42 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 d353b2503..75d4e230d 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 ce01284a2..fd3947ff3 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 a405c0f85..b51a0da26 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 f949e73e6..913b7358b 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 70b111472..7f60d339e 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 000000000..339d4ddc2 --- /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 000000000..2ab46add3 --- /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 063e0ece3..c56b55390 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 6bc027111..e998d291e 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 ce444982d..9f855f9e9 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 9a9c81004..1c174986e 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 11b60d6fa..36f745697 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 2f92030d9..dc87d3072 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 3ef153657..7ef3f9d87 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 4df8a6289..a0b6986d1 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 af644035e..f2c92b631 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 e8774b4aa..53857b849 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 5a25fdf4e..70940ad77 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 2a0b5e498..9e5289c54 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 01b46d248..1a0063418 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 2f8a1f03f..4675afaeb 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 7a5fad74c..30480054e 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 43bb25ab8..43ba9c644 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 1bb2f044f..fde3a1f61 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 6ba386c09..b63137679 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 fcd87a2ef..6f46b0e78 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 6a37769a8..0143eb245 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 68966390a..58af40e7b 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 36e7446fb..db058ce42 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"); - } + 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); - // Start radio stack - if(!furi_hal_bt_start_radio_stack()) { - FURI_LOG_E(TAG, "Radio stack start failed"); - } - - 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 f0e792d42..39b9a099d 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 eb9428388..58a60e275 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 6392c2d67..57742e8e2 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; } +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 is_changed = false; + uint8_t* data_buffer = NULL; + + do { + 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; + } + + 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(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 - 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"); + size_t payload_size; + 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"); - break; - } - - if(payload_size > instance->nvm_sram_buff_size) { - FURI_LOG_E(TAG, "Saved data doesn't fit ram buffer"); + } 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 587dd570d..b7a127035 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 000000000..441295893 --- /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 3602cf497..abdc97f7e 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 a4e76a12c..c63220abb 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 1604f4389..8fe5643af 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 8e04e7894..858efb9fe 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 53e2d29c8..e57e1eb00 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 "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 +#include + +#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); - furi_semaphore_release(desktop->animation_semaphore); - return true; - case DesktopGlobalAfterAppFinished: - animation_manager_load_and_continue_animation(desktop->animation_manager); - DESKTOP_SETTINGS_LOAD(&desktop->settings); - 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) { + desktop_auto_lock_inhibit(desktop); + desktop->app_running = true; + + furi_semaphore_release(desktop->animation_semaphore); + + } else if(event == DesktopGlobalAfterAppFinished) { + animation_manager_load_and_continue_animation(desktop->animation_manager); + desktop_auto_lock_arm(desktop); + desktop->app_running = false; + + } 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) { + const bool clock_enabled = gui_active_view_port_count(desktop->gui, GuiLayerStatusBarLeft) < 6; + + if(clock_enabled) { 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); - - if(desktop->settings.pin_code.length) { - 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, 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); - - if(desktop->settings.pin_code.length) { - 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) { +static void desktop_apply_settings(Desktop* desktop) { 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_clock_reconfigure(desktop); + + 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); + + if(!desktop->app_running && !desktop->locked) { + desktop_auto_lock_arm(desktop); + } + 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 4eab24fcc..e83bc3ee4 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 4bcbb6585..1dc7c7d21 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 000000000..828ec5f0d --- /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 4c848117a..ba5a78840 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 0b1149d6c..000000000 --- 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 23d16b0aa..000000000 --- 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 000000000..d1a37ed24 --- /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 000000000..848c915b6 --- /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 f481733ac..000000000 --- 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 5951a8e4e..5ca95c4c5 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 846b2b541..e7eeebca6 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 000000000..7d5b6b7bc --- /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 5cc2033c3..4fdcc3400 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 6f5bfe8cb..449dd97f1 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 012aff751..759924116 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 c22b19acc..ba91a30cc 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 74b020f45..2fb89b27e 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 965b5cceb..c89a143c8 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 c430aff9f..4605b6ff1 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 2811ba7d2..d7e5507a7 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 b1558f1e9..12a7439e6 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 a71f403c5..9dc9ff9cb 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 95982f1af..501e37c3c 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 d4add808a..6a6b3dfd8 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 5216b961d..5cbc51145 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)); - dolphin_state->dirty = true; - } + FURI_LOG_W(TAG, "Reset Dolphin state"); + memset(dolphin_state, 0, sizeof(DolphinState)); - return success; + dolphin_state->dirty = true; + dolphin_state_save(dolphin_state); + } } 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 a8d8406be..bdbd98d47 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 9b0b31cf7..219bf0641 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 1b0879b1e..e169b3c15 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 13a496252..000000000 --- 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 c00b8fe24..274ac7430 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; - } - return true; -} -bool expansion_settings_save(const ExpansionSettings* settings) { - furi_assert(settings); - return saved_struct_save( + 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); + } +} + +void expansion_settings_save(const ExpansionSettings* settings) { + furi_assert(settings); + + 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 38e9f8d02..4594918e3 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 edc1d09cc..449d02cff 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 faab2887f..761f79c1d 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 b7dd18baa..b24f5bbb6 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 7092e15da..78a438ebb 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 000000000..317f22f54 --- /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 000000000..80e631e9b --- /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 b4c534932..63878fc19 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 905c60975..9fbf89791 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 46a4ac7fa..c6c8dc665 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 ca2f9b04e..7d8b5e17c 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 90ce82b37..78dbfda0e 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,26 +101,27 @@ void view_holder_set_back_callback( void view_holder_attach_to_gui(ViewHolder* view_holder, Gui* gui); /** - * @brief Enable view processing - * - * @param view_holder - */ -void view_holder_start(ViewHolder* view_holder); - -/** - * @brief Disable view processing - * - * @param view_holder - */ -void view_holder_stop(ViewHolder* view_holder); - -/** View Update Handler + * @brief View Update Handler * - * @param view View Instance - * @param context ViewHolder instance + * @param view View Instance + * @param context ViewHolder instance */ void view_holder_update(View* view, void* context); +/** + * @brief Send ViewPort of this ViewHolder instance to front + * + * @param view_holder ViewHolder instance + */ +void view_holder_send_to_front(ViewHolder* view_holder); + +/** + * @brief Send ViewPort of this ViewHolder instance to back + * + * @param view_holder ViewHolder instance + */ +void view_holder_send_to_back(ViewHolder* view_holder); + #ifdef __cplusplus } #endif diff --git a/applications/services/loader/loader_applications.c b/applications/services/loader/loader_applications.c index 232e5314e..5399ba26f 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 0ee3cada2..ad4a4c7d5 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 d4c5b91c8..35d2fe675 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 434773f2e..e19546574 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 6e1e34e67..93d0f232a 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 636a2bc98..2773e9fe8 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)); +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), + }; - // 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; + 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); } + + } 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); } -} -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); - - 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,16 +350,133 @@ 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); } +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"); +} + +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_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(); + } + + 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); + power->displayBatteryPercentage = settings->displayBatteryPercentage; + free(settings); + // Gui + Gui* gui = furi_record_open(RECORD_GUI); + + power->view_holder = view_holder_alloc(); + power->view_power_off = power_off_alloc(); + power->view_power_unplug_usb = power_unplug_usb_alloc(); + + 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); + + return power; +} + int32_t power_srv(void* p) { UNUSED(p); @@ -400,40 +489,9 @@ int32_t power_srv(void* p) { Power* power = power_alloc(); power_update_info(power); + furi_record_create(RECORD_POWER, power); - - DesktopSettings* settings = malloc(sizeof(DesktopSettings)); - DESKTOP_SETTINGS_LOAD(settings); - power->displayBatteryPercentage = settings->displayBatteryPercentage; - free(settings); - - while(1) { - // Update data from gauge and charger - 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(); - } - - furi_delay_ms(1000); - } - - furi_crash("That was unexpected"); + 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 e43651ea2..34d58353a 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 1bb482bf5..6f7515f5e 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(); - } +void power_reboot(Power* power, PowerBootMode mode) { + PowerMessage msg = { + .type = PowerMessageTypeReboot, + .boot_mode = mode, + }; - furi_hal_power_reset(); + 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 a09a6f072..d75071f8f 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 4da374b31..dbc233dde 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 000000000..a4cdc94ea --- /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 000000000..dffcc6b2d --- /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 c2aa3e27c..d5cef52f0 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 0b9fd33f9..1cc0f90eb 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 21f8789ce..bfe2a08b2 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 a4dffe633..6dbeb0d36 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 918e796ce..a18b28940 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 4cbce7546..defab966c 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 000000000..889bdc497 --- /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 9e96765b6..8d86dd385 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 93e06f663..a945f1cd5 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 324ce6328..000000000 --- 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 456d72408..000000000 --- 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 a4c2e5b9e..d9fbca87a 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 d86c9df64..174d0bcbb 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 b79e36951..5255945ff 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 1d72a9e6f..a76740bd1 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 35ee2a3f1..30d80514a 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) { - DesktopSettingsApp* app = desktop_settings_app_alloc(); - DESKTOP_SETTINGS_LOAD(&app->settings); + UNUSED(p); - 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); - } + DesktopSettingsApp* app = desktop_settings_app_alloc(); + Desktop* desktop = furi_record_open(RECORD_DESKTOP); + + 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 48adb9cfb..2ce57c118 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 ee6af0bd9..ec970a315 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 5af25cd61..1e6416531 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 f31a96894..abcce66da 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 1ba3c1b2d..711683c3f 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 7375edd3f..e0c66cb28 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 93012330a..08f5fcb3f 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 170e6bca5..aa3d2214e 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 52e776959..fec783a35 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 fe0e3ca2c..639f7f23d 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 a404f9c1a..a43bf853f 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 7576dcf3c..2462b32bd 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 d2eaec0a5..57df1344f 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 62e06de92..25e7b2bc4 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 2d977176a..0f8e1aa96 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 b7620b6e8..5a367afce 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 0508e8e0f..354632890 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 29fe0cd48..1c2654c5e 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 095ca1ab2..c5f81defa 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 78529ca07..54c4557ba 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 46a21a2e8..bd1adf606 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 d4034efc4..dc97d3abc 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 28b4236a2..4e199c7d0 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 64dab9b53..1301399da 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 bd54646d8..f926ce212 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 2954bb6a6..0cda838e0 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 d1a7a04f0..a817cce36 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 7e177358e..9ebe40150 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 50d2a7dc6..a50b16ca3 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 7394d2710..53a30974b 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 9d922a385..df28654a5 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 95c2dd4f4..a36cd56b9 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 602466f4b..535195859 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 d73b54052..918017f5a 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 c50748257..1009799a5 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 396c98f51..a6c44ddd8 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 6304d7fb8..a789a0f36 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 148e69580..222b2e151 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 0b4655d43..7c43f3b04 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 8e1c74c1c..31de21c0e 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 1be79328b..48d0f9f01 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 30a5b4fab..2334dd8be 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 b29da07b7..68b3be606 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 9d31b4eb3..9f9cdea99 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 05be3292e..c70dd2c16 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 6fade6dd7..c16df04ee 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 95cbf7d5b..3fd55e92f 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 594d62d52..881aaa8d2 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 d41b8feff..1b07df2cf 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 83a6f225f..bd7e3cb96 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 9a1539da2..ceff4e8a8 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 9687397af..dc97d3abc 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 fb4ded78f..9b6ccb51f 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 97648d176..b79bca2e3 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 a91a6fd5e..4e199c7d0 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 3bafabd14..64b25db5a 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 823926b84..d0e2c3a37 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 ffa1e9aca..ebf0a7777 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 1ec9ce11e..1dbb762f9 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 1cd97076e..696e7e9ee 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 e29f50ae9..7d2116ad5 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 b60ae5097..eb417f674 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 4d8471483..0be2d938c 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 4dbde3bab..6748d1f49 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 d7a82a2df..d6d7e286a 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 4b7ec66d6..66477bc7b 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 0f54f0e2b..a4b2cab8e 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 6cac74a57..e579e113e 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 caf92807b..80e91c3c2 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 17cb1b740..a4acbf0db 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 1e5955a03..0d2b8942c 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 a61db48f3..56eb69043 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 bf6b927f1..8df2c19ce 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 8fe8afe34..4d3232af2 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 bddc7aace..0a3974f64 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 ce12dcbf1..72190605b 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 e96d29ddc..9fabcd26c 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 60871320f..b877b9106 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 0983db129..ea50cd657 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 48f9c77e4..bd18bbfad 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 eb000cba5..7ab5cdbab 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 586d198a9..e297e0738 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 d4d30afe0..27355f8db 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 77ac76337..48210a049 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 24cb54589..20c4ce733 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 65373db78..53f48d01d 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 058b32fd0..5ab9bef77 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 33798b296..b90dbc153 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 0d6aeb1db..6c8e79b2e 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 52d9fa7e0..3ace2de40 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 de47de055..000000000 --- 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 011bf47df..000000000 --- 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 1d7b2d25b..000000000 --- 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 08c9e2d7f..000000000 --- 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 7aa951bd8..000000000 --- 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 44e73c689..000000000 --- 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 135f3e9b0..000000000 --- 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 4c7fd29e9..15d7dd3a9 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 0eae0eaf5..8f051ff77 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 848cc5494..e7e1bbbed 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 5f7f5fa42..d948c55bd 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 db9bf227b..5730f1889 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 5394851f5..aa1061b94 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 d16966fb4..cdcdda356 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 759007623..ee52444d8 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 c9810b61e..a65475899 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 e4d381b0a..4469a5cad 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 b48aef978..c7668019d 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 f9a7e073a..6b6ddb123 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 147561f0a..dffda3010 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 6ebbc1111..89af52e69 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 5f7a5d2a5..7417b7ed9 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 a3450ae05..3e7d95af3 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 1e52f1513..78dc1e809 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 387c85ea2..e95d7c3a4 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 9975ca3f0..d614498e6 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 84241c3f1..e1e676d9d 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 c44b171bf..928c1a78d 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 36c1bbd49..bef9d522d 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 1950347a6..4d476beed 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 65a0154d4..ca01a68d1 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 f7c086431..f767fe332 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 e3bfd179d..701b70c43 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 0094ab5ae..01d8b8c9a 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 b36fd051f..18da66c10 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 33607328a..529ae406e 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 e115834ef..d7c015212 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 8e5fa20d8..95068c50f 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 6a658e0e2..87069ea8e 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 cba72f16f..48e607096 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 9f4cc1fb9..72febfa30 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 457fa7a00..4b4c5b14c 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 727511100..ec6168e31 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 213e05771..c90432ebe 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 5d3571db8..b49348856 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 e54d47e29..b5ea1a21c 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 26c944d16..9da0a4cc6 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 2972318cd..e7838e39f 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 397face78..b1ae3ee6c 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 6ca246f57..3b12a422d 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 8bcc83a1d..b4a35158e 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 7a1d2b36e..9afce23c9 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 9f477f8d7..870255497 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 4f2deb5c5..68249a4d5 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 4f59f9955..5eb2b770b 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 1adf3d351..795b88fb4 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 5ffc55f75..cd9673d56 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 9a101f0aa..7a2154c4b 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 ea42d75d6..55f3b66a6 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 c347d3035..6b5666677 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 07a7c70c0..f16295ffd 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 275f2a357..e28db7832 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 1feb3e875..e44453afa 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 e0ba8250f..aed5833f3 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 b6b2c75b8..59d3ef3fa 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 347d71cc2..ecbd27419 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 51a7fd236..7c5f0b6cc 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 7004e10c3..aee654cc8 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 556cb8948..eef11402b 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 fd6170340..cf2299b28 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 34839517c..853d85fb7 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 b2636f005..58ceddd8f 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 e73499e94..df0abf137 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 16005a990..17b991809 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 02e833dec..e0c975bea 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 3f7dff4db..4e2e80240 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 385106787..0a3285397 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 7871674db..4bc351b8d 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 5865e91e1..f1f78883f 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 396ec251a..120855f61 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 2a497f85a..a9346b8da 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 d33f1e416..d4ab0e356 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 e5ee82f70..2d98d57ab 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 f3059dde7..95d09d14b 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 5d1ff45be..c385a5ec4 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 d46f62e89..25b4ec565 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 ec11dbd03..d9ef6edbb 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 720e95f9e..d68243826 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 7debe764f..1a94e80b6 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 d3674a02b..54615c613 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 ba4435157..ca7cb9dbc 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 c0ee41623..5a18e3cbe 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 ecda81274..909c6106c 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 e8662b2eb..582e2b19f 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 29cadd14e..d1e4f0af4 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 18e793b58..120855f61 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 34b2e4001..521a8ec43 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 d192f2e34..77d0198d0 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 8b8dc80bc..ed6f4a71f 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 956de6170..f2dba5e87 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 93fdaa076..bd6291f99 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 a4e194825..e4a6d1639 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 9cbcbd070..fc62957e2 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 a745cdb03..ef2875aef 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 768f471ec..e56f7c6c4 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 2f50fb8c9..1bb46d54a 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 fc7b76696..76ebd1f39 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 013e2008a..7a6339638 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 795120e77..172ee4d9c 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 52061a5a2..afd4c496f 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 10afed391..5f3fe2804 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 52f87f3a8..287800454 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 9696e0b5c..50ef42181 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 d23ee492b..ebab212e2 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 9d368900c..55d2e5695 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 daf0788ad..df78c0887 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 b40333654..9d71ca41b 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 9d499f23d..ea66720dd 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 0291dfb58..0ee0b2135 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 54a889d81..02b31050b 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 ba79b3b88..c00255748 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 bedf366c6..9cac27897 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 0731760df..8d9176c4c 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 898efdc4b..d73a65583 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 39f5db8a0..c97abe79b 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 bee4cff08..20299c04d 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 969b91193..bf89e9d7b 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 a72cf1823..40440a0e1 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 9a13e7c67..627a02ef2 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 da3ee77f3..7cb901f41 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 93da7f4f9..6b46de609 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 7510931b4..a2946bff3 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 f99454b16..314e716ed 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 a17a14044..5cb229d26 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 f763540c9..048d4dfeb 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 97a829e9b..6ec37e4a6 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 7eadf7518..efb7389df 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 5241195d3..80a09122d 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 2a3ea8e23..232a5c63a 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 f4b263b19..3d2b6a87b 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 1563ff39b..90a5aa5d6 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 394bb53df..934c098b3 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 3f84ad47e..54ad31fb4 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 8ea650ad0..148851185 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 2c8cf3f5d..542ff45cb 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 caf6a90ef..cf612c74e 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 a42e97fc4..cd0f0bfb4 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 90152d2b3..3b326e584 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 93df45f84..d8a2623b4 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 a86b5e744..d4ab7525c 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 8ca6f6319..ef5fc0e7f 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 ef1a75b90..0f0528f50 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 7e148697b..1c06ae08f 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 ca19b669f..24a9b853a 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 c7751a1d4..011570b2c 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 20b3a7104..6ee8edd66 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 ef2ed21d6..c25a72534 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 0d2610a11..420ee0ef5 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 1edc93480..fef1b5d50 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 5752d80e6..64103f1db 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 f62078f84..a05fdf825 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 021e05822..569fc7779 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 d7e88112a..d8ab4235c 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 142ebbca0..c927e7928 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 26af84948..898ecd842 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 d307e7a27..da93d6f14 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 0d28a8615..edf48b0f0 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 04aa17ac0..c1046f9e1 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 d93b1f588..24c08c043 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 47185499d..324adab8c 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 d90fd3d5b..5cbb23ec5 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 15ded2672..e9562ab71 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 13ee0450e..449235a1e 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 32c0a1b9b..c94fbaf16 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 93593594e..eb23cfe0c 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 d6ca9b82d..1db181127 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 0421d8f6f..107d82779 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 17930e075..6c2fa6ecb 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 d4115d240..fb13a48b0 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 570c8b0c4..9cf7366e4 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 2b6b6e57c..27e3dc369 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 220908495..e185204ee 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 9123906fb..69bff228b 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 e90ad5e90..d09cc03a0 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 031c0ad81..78ca6798f 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 856e068fd..bfe678880 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 a0366b2cf..ad29e872d 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 24fd557ab..94ef0e680 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 3bf1d3ed2..5f3e54d95 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 f0b44898f..7bd404a93 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 c98c70c91..f10d328f9 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 4f7b7ae82..05cdb7be8 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 b3ad6700c..c7e290ff9 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 c4aac4b91..bba9f165e 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 ea2eae4d7..76f900792 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 00a7a6e99..a0c56bb31 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 137d5ddf6..bd8464e4e 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 89690fc03..4074e0983 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 53d7b07a5..2aa0c42e0 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 2838804e5..776f1a73d 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 2af49cf17..4df95f375 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 7dc44d061..3ee650af3 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 87df75ff7..406d965ea 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 2fdb9d736..1a46e8b01 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 1b0e77426..ea3f7c006 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 785f19fd0..f3ca77191 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 36310f705..13917efdd 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 92db8f024..f4d0972d8 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 768030b3c..27e17fba6 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 12f22abdb..d8fb6fa4a 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 9fca976de..0ac3ecf94 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 4b2ab5863..b856989ed 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 69c709adc..753deefee 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 13caae7ca..61e2dbac5 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 b1d1e8bfe..4952ff527 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 45e47de12..2260541b4 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 acf000827..6bce5ee40 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 b6c6fbb19..010ba0efa 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 7d2dcda5d..1197601e3 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 461270ba4..c7ac5c446 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 b018a94c1..a10c37020 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 fa2b303cc..47cce6619 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 ed38122f5..f9e3ec5f4 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 38610bb4b..2e87539b4 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 7f6b4b29a..ad22352cb 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 7c293b485..0162f0da0 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 e72e7a30e..5a3b35046 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 5c840d6f6..344f02fd1 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 f689f190c..0d029c93e 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 628394e57..713c4449e 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 bf07d03d6..4706786b7 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 4402654c7..e81a3eae7 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 10dabe4c5..0bc0462a7 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 878712fe2..0b2a3e97b 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 19fc985ac..d01bb39f5 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 39172f26f..2f4cb5987 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 9a3a84fff..c8b3def2a 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 2472c2729..e545002bd 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 4940aef67..8e906e4f4 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 fd910ce5a..56765ecb8 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 ed33f18a7..1deb8d82f 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 d602a01d5..ac288ba8a 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 b680b4ae0..007419dec 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 2dfa931f2..cd9d06d2c 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 272064d90..20a22b06e 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 35d0149ad..0f3dbd46a 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 83d02ef88..f47a3d597 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 f3ac44178..6ca6b4017 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 832c2bde9..1c768c19a 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 3836a3b01..06cd12d2c 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 ff621b73e..17a20f544 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 94e05f94d..2f9f7106e 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 1ce384b16..dffa2d7c5 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 a5056eb4b..314efc632 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 8d42b8b48..52b8d35f0 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 ac926d7be..6c282c0af 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 35070eb6b..1d1f631b0 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 a6c973f67..4376fe29f 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 3f9407f38..d431b9090 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 6059e00d5..e4ce5da4d 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 d2cd0c970..f9d8b6ebf 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 e60fd08de..18080af54 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 70e56b168..b9271ca8d 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 450b4d4f6..cc3b2c5e3 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 2d9f4e963..4b7361a42 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 369200345..ac0c42834 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 e0f882268..18fa9c0a1 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 a8a23536a..86a79df74 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 6a402b350..d71c76f05 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 f425bcc17..9e9ed92f5 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 b0ea1a7e7..70da80e9b 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 3113ff2e6..ef0cd69bd 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 87403c610..d4e5ccfe2 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 2734e2fcd..30848e939 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 df2255949..94ee5d154 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 4c00552ea..34233f5bb 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 970380940..f21b4f406 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 86e41e913..1f574da94 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 4334eefaf..5e75e2dff 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 b2f9bc775..154a85ffb 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 02ac533ce..e52dfd628 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 ae3148c32..39389a64f 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 89d003d07..e6ea79c37 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 8bfe6b33c..302d5be61 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 1c6fc2144..6227c4089 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 d39cddea1..8d76d9d0d 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 4f21a268a..5e562ce05 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 3f492eab5..9284cbef9 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 336cffcb4..8212e629c 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 a44a7315d..f13bf906c 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 7cd425291..65c881627 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 fbf265286..240fc15d5 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 be9c5dc15..7037de7ba 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 eb8075ecb..627edfaa4 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 0f1fd5c52..babab2e47 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 dd2d918af..1a3f38e48 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 bfcc7bcd2..5f864b0d8 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 eabe9def3..aded14709 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 3ff0aee0c..9540789e7 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 ce663f75f..2d87b962c 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 ed0f030b8..e1361d632 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 f3b3f8a97..0b549c648 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 a474c2147..e45ac86be 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 cf654afb2..487e5ea4b 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 f61e59efd..2901debc4 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 87e297b2a..c0e2388b7 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 62428a405..c81f90539 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 93953024a..22006b552 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 942f082b8..aecd99f1a 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 84ce00d23..c7b305372 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 f6f45552b..6fac0a661 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 dcd3aa0b9..448266cd2 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 71e85fe8f..36e5de4c9 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 31ab932b9..f487ffdb7 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 da8f13680..15a5d5379 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 9c87945b5..e66b473f7 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 52ecb01c1..3f11cc90e 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 165b0635a..41abfcc61 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 3ad1f1c2d..93b0dfd43 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 dace07e83..64780d71b 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 2f2321888..6372d943a 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 ea67b3645..a61ef2ab8 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 e4526da94..52c250fe5 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 b6e3de1ac..39ce84076 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 a76a00022..4ec651e93 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 b33656867..4cfcf5282 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 6048810f0..0b04296e3 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 657788f2b..5b8635a51 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 852e778bf..9d7af682b 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 d8497ee6a..324311a33 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 d647aae1b..eaea2d87e 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 83bc94316..75eae29c7 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 9f4e0ce7b..2c0de95be 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 894394ab3..f6a0c6e69 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 63babe793..de18082e5 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 630f42f2e..05bb61c0b 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 d062254d9..95def778c 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 01ebecda7..5c12231bd 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 a66d6a42d..0524f50fa 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 e80a66743..52af71e8b 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 cea25e209..4cebede66 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 56e05f8f9..8558d74f7 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 8e72a7c39..3f13b3c16 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 9f20081e5..f4fc155be 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 39e620954..2c2968c9f 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 febe3bf0b..2326527f3 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 7377c6080..711f8f7a9 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 2540fd383..a0aca8d5d 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 63106c87a..1d8c4257d 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 21038b47a..42d9a0d02 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 09309607c..8d1a63ce4 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 2d4b51225..9d5904cfd 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 0501b735a..b858fd89a 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 1edca6aed..63af06f99 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 467fe93e0..98f147ce9 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 fb2c54aa9..0ba0ccf90 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 74cd345fa..3b89c00a5 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 70ed4f559..2da816601 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 32221d347..94d6d3087 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 a81457ddc..626692b0b 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 3fc75d870..261c424e2 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 2e4528c73..fd893efb9 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 abab31964..08f645570 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 dfa5312f5..8c6d81c0f 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 59a194b14..301d61d37 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 d142a38db..e4893fd0c 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 d6a66da8b..52f0ed99f 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 4ab56d31e..95542d4a2 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 7d4f0684e..a28e22e4f 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 0cb8722e3..5b311fbe6 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 7da7d1adf..ef4d9db7e 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 1bfd8d303..c6d519fb4 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 0ff0f5a3f..4e363367e 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 698776737..53a4652de 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 606272119..24d0fc41c 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 ed37723ac..7390c84e8 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 ad708ee43..bf14f9319 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 e385018bf..db0766f66 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 553a979be..92ad6d095 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 9f8ca7e9b..02b5c78ff 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 a996443fe..b8537f4bf 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 628d58b93..3e51ddea0 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 cc8431ade..a86e54c3f 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 3ec372798..230ae8d89 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 11b247eca..e92acac9c 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 bb1504133..47b716ef7 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 f953c8ef1..9e084150a 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 36c3b4abe..337bc2dd3 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 d683b9f62..2caed65c6 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 66cbfe1d8..4a7cfb5f8 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 dd241d24a..21a721994 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 944bdc74e..fd5d53b27 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 3f445593a..7e7d008bc 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 ea7823bd7..5f1ea16ef 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 0b378fbcc..e753eadf9 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 66eec542a..e815ead02 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 1e232ba91..24e579be1 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 e2767bd65..8edea2b08 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 9a3c13f66..c610eddcf 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 36d1212be..00edcb7f2 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 037bdc8ed..3d2d5d6f7 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 91ce18869..819ae205e 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 e3e7799db..0e43a4987 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 a28aac4e0..53c2ce75c 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 04f8c1a7f..d6b2f16d8 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 d065b77a1..966e60681 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 7a111afd0..838f46432 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 318c7eca0..f5e811188 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 b56b995dc..aabcd529e 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 6c4b87570..4c18a154c 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 00b02330e..577207e5c 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 851f1d01d..69d0d671e 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 89b40b36f..c29188dc4 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 70ad96dde..20f3709d2 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 03b2f529a..ba0ce672f 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 adad4f413..aabae9cae 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 462824be2..4adada4f3 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 a5a728849..84b2453ba 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 4f454a743..cccfabec1 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 e34e79690..7f1c84c26 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 cc6032ad3..4b8a3e252 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 a28a21225..ee9424ee5 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 3d94c8910..7400b90eb 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 74e0b962c..c8779d6b4 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 3269169e4..87b19aa30 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 42f844d3d..7209b545f 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 861b16c65..b7725b350 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 2f4b3b839..82b1feae0 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 7cba6f795..b92a8c2d1 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 0b8fe650e..3114dc599 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 e3c50e308..9c79cd16b 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 c259b5a5a..df558a704 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 ae6e76532..96a1c159b 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 e97affd7e..e832983f3 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 b5c615924..fcb5f4430 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 ef4876275..df827d72a 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 4dfe3a029..688fb69af 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 1f9d6ac54..9ee574396 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 379e29b50..2c3fe6987 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 16210a792..3253a415f 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 7685c3bc3..2152f449e 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 5f114a479..2286f7936 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 3f5c523ac..65b126e6c 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 645ffa669..d67714a89 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 a086ba60c..c2371bc4d 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 4fdc011d1..43c995266 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 f9789d8b8..41ff0cced 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 e13f825fa..05ae0f146 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 05f9639b9..61bd92f5f 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 a968fd015..6924299da 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 8393e3ce8..72e71368d 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 5e6c32499..2fe57d02d 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 7ca97b4a7..8a7e28ebc 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 11253dd62..87b339fcf 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 a1ac9f6f3..b471cf949 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 c33f03e92..7126105ef 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 dc51592c7..47c4fa671 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 ff83fe771..600c1d773 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 a5488fcb1..248b26b36 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 86630e83a..e6da05bd1 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 a9147ae3c..d4988a819 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 f5b4529e4..3d631e3fe 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 1f27241b7..247bf9844 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 f5656a750..a8a57bee6 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 1545c0ee7..c9aaa31fa 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 1ff2a8874..37cd3d893 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 3608e114f..0ece627b4 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 f109b562b..aa5b3112c 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 a91b863c7..55574b441 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 052196298..f909bd9f8 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 b8a8c6512..8711624f9 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 44f5bf6d2..855375c08 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 f7c1e8023..753aa478e 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 61efe9f45..846266c12 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 d0bfc886c..3d6b98dd2 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 f99662e70..119d8d346 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 950152b73..89ce15403 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 4e430d5c5..ed02b62a3 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 cf09a7842..bc407b6ff 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 d12fa6aba..7935a7755 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 ace68d642..99072fae9 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 95f72f901..18a5e83f6 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 32e13541d..efd0fcfaf 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 3cce11f99..1e33265d6 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 eca4a1296..956d31d02 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 5f92e47fd..a99135d7b 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 1b1017ce2..3c5ff7b33 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 2cf408c97..79e28e916 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 9b796498c..69d233ab5 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 c1545500c..a3766106a 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 80863f0b6..f606afb4b 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 b4527bc83..392b12e25 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 f1531da4e..fba62faae 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 391cfe1e1..85c5008be 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 f63904f29..c80e59d07 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 076448fa9..c3768e27b 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 8651f12f8..f5fe6855f 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 d2d8e7e51..f404dafc3 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 6080e7aa3..b5c59f09c 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 ec483addf..7495a0169 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 90fc3b138..601015748 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 39ddf46ab..48e08cf62 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 f433c969c..a48aa0927 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 263ffe15a..1eae636a5 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 40d1314c9..4772c9217 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 27c297e8d..631240dd0 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 f2aefbfae..5dcfb355d 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 852c24233..9021fdca1 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 665ac5eaf..e5467bcfb 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 81f133ac5..e12c77c8a 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 c828207d3..335f819d8 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 fc923b402..39ce84076 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 d372ff643..57a9dd944 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 5b52f9517..c6f556fbf 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 8a1e84a11..4a6f97d20 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 1fddffaa4..cf626fdae 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 14ef1aded..40facba15 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 05de5d5c6..12a3e590d 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 43b26283e..37d3e1ecd 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 fecba5ad5..93ff00a84 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 3c15e7ccf..d4ab0e356 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 0f293281f..2d98d57ab 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 733962d3a..95d09d14b 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 4b7ed184f..c385a5ec4 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 1efff0f21..25b4ec565 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 f2d76409d..2e7a73bce 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 125fb98fa..29e39b5c1 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 3a4a5f5a1..74bbee98e 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 13dd34859..2a9e4884d 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 ef3150fd8..a24187a1b 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 537ab523e..16f36b3c4 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 873570126..eaa20698e 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 dbbeb1fe1..272d99f74 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 d18085027..705272470 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 24f9333fe..37d3e1ecd 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 30b97cdf5..e2433ea58 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 7ceead056..be1afd958 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 d303aef08..4c91dd60b 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 45aeb57b5..88849fc6b 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 a4508f14b..c2e190203 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 350002167..cb5868d3f 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 7addbf932..4b1f6a2aa 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 8f29d5e2c..72cb959f0 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 f0756ff85..c973f205b 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 03d95e2af..63a84b876 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 e4cf6ea8d..d7c9bce75 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 6a7fe1bbb..488958005 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 38171c273..74c418e36 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 3eb9a1f63..50b8299e2 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 624407488..8fb3240d7 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 f1306c2eb..b59622a7a 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 ed8d96bab..0f6ec25dd 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 e1df3ea49..45fd14e8e 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 d231a6561..3fdc37116 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 e2a864c76..1ba48033e 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 ddf9d4931..3b2292c9c 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 0d407de64..904d2931f 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 f53ee0588..4e0235770 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 83be68d84..18b103c40 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 ae61e5831..9cae5887c 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 a2608a0e1..c44defec7 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 6602e3f57..8adee40b9 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 e82d7fcd1..b2521cee3 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 b16dda91d..5a5043ec5 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 cf91009bf..04bb206bc 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 8bfdcabda..2054724f9 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 080748498..44eec1f24 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 d4dfbce33..fa18ea345 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 c9c169f2e..13bc7f178 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 0e939aa2d..6cb3f7c8b 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 d0f3a5383..0b0d3e5b5 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 2e3a3c64f..ab2515fec 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 4b34fe377..5dcd576da 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 4935b75a6..a28bd7bd9 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 ccf5bdf09..ec5731155 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 d276c2123..dba19aeeb 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 354a96b6c..84acd2bda 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 873386a57..de8a4e7de 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 529f6cdd4..f614ecd7d 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 15168cd11..4bd13c36f 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 16196a706..bc9c6dc21 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 06fb27905..8e271e10a 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 5a2221cb9..026064c5a 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 7db77e935..eac19b8cd 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 a6d5407ad..4dbb14ce9 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 c6a17fda8..a6efbbdcf 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 0e6845ac2..58993db8b 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 45decf285..8654008fd 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 aa121a538..bcebe86cd 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 38184aa75..4d732c392 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 1259a591a..b2a87c442 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 cd916c404..713e66f22 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 d28bb5454..da9f67db4 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 3621243f7..567ac58ac 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 4d3d53716..979863437 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 bd20ae843..db6877259 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 b9453d056..0ff99dc58 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 0519e851d..a6d4d2f25 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 514241266..c0adab346 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 ba7ad99ae..27808c97b 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 ca696e4cf..324938865 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 aa7fc8ea0..43cb2a283 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 85d1e30c9..29d09c423 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 5ef6820f9..b2730636c 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 12bed1b4a..f74c6415d 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 46f9fd378..3f4d80b04 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 912090032..f85f1df6b 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 0b99a32ff..6b614c773 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 9da72ac1d..3e7749145 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 8d54da6c6..a90b2f6c0 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 84046a46c..69605e7a2 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 3e1c9c329..9ff3e4dde 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 f4f6ccd66..741e4b58f 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 5dc1a6525..c725d6a71 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 bec472921..4bc14bdc9 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 82e5176c8..4e4fa0e52 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 3b5e60dfd..f7302372b 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 5f76c7d23..d1d99f489 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 84d6aaf35..ffc82fd6f 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 2f8394fd5..99dbc3e08 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 48adde113..f13628011 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 5889835b7..5a0c613c9 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 7f980f57f..61e2d1981 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 497136000..1c6402cec 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 03d67134a..37ea651ab 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 9f523cace..5fdf6365d 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 5a565b1af..9979896e4 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 7d42cb57d..c727bd3f0 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 25b4609c3..38e775d81 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 575df3b9f..81be06a77 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 2cfc582ef..808dd08fb 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 4aa135cd6..214455e57 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 aae2827e8..d69939385 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 a66867a32..cf333a85e 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 7ec1216e3..173de44e8 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 2632103d6..be5e5fc3f 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 f50cd0b88..9857478f8 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 b5a85de1d..233f6aed6 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 d9a29def6..c02f58c52 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 ca4bf322b..61880587f 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 fe95a716c..e9fd6041f 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 6a40d4148..db36ad5fa 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 67189811d..72a78cde2 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 b770f3208..2a042e23e 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 4a899faf2..f26aece8c 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 c12a583f5..e7bec7eed 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 f62f6495e..85b4e2ee9 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 37218c396..ea3a6adf8 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 a28511c91..96328c9b2 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 f18f8798d..9334a3e83 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 93e694375..1705c1f90 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 64cf58580..67d6c1234 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 2502b3f21..9cf2edd6f 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 417419f85..1737a82cf 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 5c7906075..a7a0ed870 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 26dfe5391..3ef1e8f61 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 b6d507057..4f009f28c 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 7bd425e1d..414041750 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 7edea62a1..5432c2e0d 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 7b51b6a34..2ad368010 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 30b6bd67e..6f8b4f0ca 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 ff0b1fb28..8ee956c4b 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 d413cf0ed..24de01dab 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 277077265..beac49ed8 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 baf3c7c79..2a095979a 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 b4cb1179f..32e35f4ba 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 09dfc28e8..4dfef4ff6 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 94b26fe06..de4d7cacc 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 28f47d714..bb5719795 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 a9cc34ca2..8aaceac98 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 cc9a89dad..11e017674 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 ef68cf866..c667c9f81 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 b0367a603..e7de890b4 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 a44a566c7..d3305472c 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 ba00473dd..3d7005fb6 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 8045749ac..a7db03a33 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 18337cd63..f443ae5c3 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 10be0ad16..a32249641 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 fd8269bb4..da7a84aea 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 300cbd9ec..7d0b0732a 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 56f37fbd8..645953060 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 0e4fb27a6..4be5ea9ac 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 641d06f39..8cf252c9f 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 5bcf7e588..9cc334e0a 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 3b82285e6..87d1fc9d2 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 7af08829b..67d77257f 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 0ef6d471d..7bca8d134 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 e6f397eb8..be63ef5c4 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 9221fb156..95d09d14b 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 e43b1edb8..c385a5ec4 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 64da8d8f9..25b4ec565 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 96b196696..228c29482 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 620dbca29..49e01f317 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 49aa979d7..f5871e49c 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 7739e294a..d2a276eea 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 c36e54b2f..c5e8a2a5b 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 dce96b74c..6849b5011 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 2c096689a..41575e79f 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 792719974..f7965d9f7 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 689e7dd79..3288f6ab9 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 7b468ab83..87d1fc9d2 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 e9246c0b7..2cd571dff 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 c2e164c51..e2f84bac5 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 6fb7de66c..0c47516c2 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 eaf39cff4..dd02ff2e9 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 1e3890a7b..60556a9dd 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 fc8aef13a..a0b7ea6c8 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 8174af0d1..6faa6fd5b 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 b5e75921a..d92aeb984 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 6a239a1b6..a4da82eab 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 8cec74395..c5ba8af0e 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 d034b0a53..23166c1a6 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 472241e56..7cd73e35b 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 db53a0bb4..fe9a996a1 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 f2015a77d..06e38fddc 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 39b8d5f8f..7240e048b 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 8b5e6f5ee..c074f6881 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 b937cc086..3b179a0d4 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 a3b494dda..bba17279d 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 b8163164b..5016136e5 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 e685ff86a..95c1a8a32 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 10a52400b..fd0a6c625 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 9cdea5002..4f4a2623c 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 590d0bf89..4d27df289 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 97cf05dd0..e6be08847 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 e2bae209f..779de319e 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 63db9fa0e..b9e89ebd0 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 ad66f34ef..255818b91 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 213fb7636..23e10f553 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 81174f7fa..d0426c0fc 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 7f4ce3bac..e80dee320 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 dc90311fe..64b38cbff 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 cda17cb60..52793ffae 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 7a048dbae..fefe0d834 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 c5a80a925..0e46efde1 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 e80fdfb00..69b8e9d5a 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 b3955ac8a..d93dc9aa7 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 4b003d034..c7f848cb7 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 df2008d93..adcae64da 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 c0afacdfa..05dd84317 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 97c138235..d8155c7e2 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 6f693de4f..9b60bc189 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 c971b2178..19ae6d56f 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 856c84557..dcc5cfdde 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 7e99a4a82..6548ece20 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 949d845d4..266021370 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 ee7be1409..c44b65adc 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 ae6fca1cd..28aa1539c 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 2567cf087..95ac16500 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 b3d0c7acf..796df31f4 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 dd98cfcbd..320de262d 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 0f81cd5dc..bf55efc7d 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 8e55dd9ed..4af4b80a6 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 459f0c8e6..707dc05bb 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 3c0955993..19de275d9 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 32d4eb4f1..95e61d24f 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 11bd640ae..376b23ee9 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 27af626e8..5e2b91f0b 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 cfc81bd3f..b19f70c54 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 f9480b1e3..1d6afe6ff 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 6793a3df6..38e8bc329 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 6b58a0fa7..f22a84b66 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 cb62bb7b3..7c0c0539d 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 8b5ab6a9b..a08a141db 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 9a2c6b150..3f631fe4e 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 f7da1b587..043481281 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 d8e390bb5..cb8d0f15f 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 8dfe5defe..66179fcd1 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 fae299733..0c25fab74 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 2d111a7a1..15034fad3 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 4c8a9d2e5..d5d30c8ed 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 aa0d1e6a7..dab8497c8 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 9f2d03b7e..e445ae752 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 c85bb77c4..3d170012c 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 dedff6024..2c4b10234 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 1a53ab75d..02a91f9ba 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 1768d50dd..12e545419 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 2beb237d9..489c53035 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 c46dc3bab..daa7667cc 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 01f07c68d..34650daa6 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 148fe4640..7da00632d 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 0d402b0db..9a5d688cf 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 6853e1d61..697b307cb 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 9a92ba8d8..daa7667cc 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 910ae5852..91fd1cbaf 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 0f681e6ab..7fc99ca89 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 0f391b75e..6b237672e 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 7d3f3dcdf..4977401e1 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 98c2979cf..ef1f17fcc 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 9a48d15f7..0ba376d65 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 b58936d81..4764b4888 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 5b474fff2..554fe0156 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 952f968fb..692a584a3 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 2bb43b306..9efdaf23a 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 d7f8c6402..657cbf815 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 acc24df00..f225aa993 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 b0ead7994..81f12ca09 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 c1541b2dd..ce0d85411 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 1e13b0951..40bf13a4d 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 7d87fa2f8..13d3074c9 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 282f43059..b11e81b8d 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 8516cbe75..52fdba463 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 42196cab1..d2834c6ed 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 bf97f8d6e..d0d8bc82f 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 39c910d3a..1429d994e 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 4975adf86..4b3bf5f83 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 5a05529c5..188a38bbf 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 e6c88df92..3d9711731 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 e7bae4d6c..639d7fc17 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 489bce368..4227e1784 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 32e864e98..d59622993 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 c692f4895..23b9a9bd0 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 fb1c8bb90..1fdedbc19 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 3b0205a48..79e0b1543 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 77b531076..0bf23b5c5 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 b53437265..b9990b406 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 9623af7d8..a57641e44 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 f18269019..deeff97c5 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 677a3367e..4b7367a37 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 fb58fed1e..a033448f7 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 b2cbd699b..5389124dc 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 4f3dfc8c4..cd4324f0d 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 3a5a28805..fea362808 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 76267a2a8..fd4a3de1d 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 bda1bf44c..fae535997 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 ce01284a2..fd3947ff3 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 6bc027111..e998d291e 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 f9c615a99..b7ffd4efb 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 037474aa3..2b5a3bf97 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 a4cdf453e..1b64022c2 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 2fdaf123a..f73af065f 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 22c986180..36c214f3b 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 77ac76337..48210a049 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 74a10e6db..dc3e3cee2 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 4f626b3d5..a6065b6c0 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 d41eb0db8..98fed6d92 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 5a25fdf4e..70940ad77 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 fcd87a2ef..6f46b0e78 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 18d31c67c..2d2668e85 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 5a97651c4..94c96769f 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 64dab9b53..1301399da 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 0858bb93f..f926ce212 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 30a5b4fab..2334dd8be 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 6a16ebf7b..bf72412f5 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 c533d8572..5bd2d395f 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 9a1539da2..ceff4e8a8 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 6b46ba3a8..ced2369b4 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 823926b84..d0e2c3a37 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 446d7176c..1da29ee43 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 b60ae5097..eb417f674 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 d7a82a2df..d6d7e286a 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 4b7ec66d6..66477bc7b 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 34068c300..97800403f 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 ab06d008e..71ba0274f 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 16a5a74d9..28de03da8 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 987af3258..1ba168c61 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 7e28c9f01..0318d425a 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 d39d21733..82fc0f330 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 15ca088fd..7209d3581 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 677911fd4..97b304f1a 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 d2aae0dc3..c0ff50c0b 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 cc41b5b9a..33ce1bf5a 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 1d7686ddd..c5ebb8352 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 a66461b22..e1e015ab5 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 2954bb6a6..0cda838e0 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 51411acaf..0fb7fb313 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 0b4655d43..7c43f3b04 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 b9d5f87db..c25ba7261 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 8e1c74c1c..31de21c0e 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 1be79328b..48d0f9f01 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 951cdc198..256a61b6b 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 93fb147be..6ede005dd 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 9c49dcad1..7fafe05ca 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 93a59fe68..8684b4f34 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 7bb66fca0..01c99c56e 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 adefde921..15019fbc6 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 80bf88e96..c144a72ed 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 b768a7875..fe66f11c6 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 190d2edf3..a7843a35b 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 85025d9f0..bbfdae047 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 a5dc239d8..b8db2a4b5 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 162d8a8f4..aa0f22a4c 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 5483e4734..cba466ef6 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 ce2fbbd47..4e90ed650 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 8b786c029..ed319f764 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 5f7e02dd8..f307436f5 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 da66350bd..244b022a5 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 4a1d5be85..ccaf88b6e 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 594d62d52..881aaa8d2 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 1bbbec84a..4d47ed5b1 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 46f559f65..1380d2dd7 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 e8704295c..4d8195b80 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 80caeb203..1dc514db6 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 bdf8171b8..b906916d2 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 2ba54afce..a2554eaa6 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 d766ffbb4..310be0f70 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 92ca5f91c..847146b78 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 261c6d89e..01209712e 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 fa35eb2f8..2c6dfd9cc 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 2ac7bcdbe..086fa43fb 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 4c9a16b3f..1be28a53a 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 783ad0877..cd71a69db 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 64d7a1db1..9a6c30c75 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 0488b40f5..f5eb3f4bd 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 8c3f81c3d..a3803c745 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 9b840f9ce..5320c82a7 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 30e0f584c..88f5c3890 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 fa4074d12..356d124f6 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 944a973f4..bef0ab0cc 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 38a8014bd..5dd42782d 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 c689c0675..aab1e650f 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 5b7196ae2..5cd1a2814 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 7696e1fc8..49e2d4ab5 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 d6f55e806..df6ce92cf 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 db922c557..9a1f73a08 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 aca27c7c8..f702816d6 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 a382d84e2..ce627b002 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 b4cc7b462..ef048a7bd 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 d2c3709f7..918bd79d8 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 e7be1e995..dccaf46cd 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 49eee2f53..7ed58a5b4 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 90e1d4b4e..f3a3ed308 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 e68c744f0..1383bbbb9 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 d4163a65f..b7836abbf 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 65f97b0ce..f3e87a581 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 410e88ac2..d767e2f9c 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 e9a5b3510..cf899b883 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 fa2d042a6..62183e5ac 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 512b68745..6d48639b8 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 c84bfdb90..006b92a09 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 74d53171f..8146e688d 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 6d68d7e6e..8c97c072e 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 fddd3f917..98c384838 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 500adbf27..7ee27fc7a 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 99196d23b..f3fda0fc4 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 33e7d8eb2..465c150a9 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 72c7b0403..fd991be3b 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 880e977d2..cb1d4ad80 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 4c837a144..35ab01448 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 c5f067bcf..375f8155e 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 12b927973..eef764158 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 3a41249ff..c8e30cafa 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 88fff8e33..8f2fda83a 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 8d17cec57..69ac3bccb 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 be9dce700..51f5779f0 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 473b89745..115887bbe 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 068266d62..2286627c8 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 caef54c25..166cbdce6 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 a80c59594..d6f8d2f32 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 6bc57c70e..b9ac48b4e 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 688552751..ebc3f3e42 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 5d790e796..1d35173d1 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 5df87ba3c..6f795c5e0 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 0cc1e65e6..01abc3865 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 1912e5d24..e795d6708 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 5c5252b16..0cda838e0 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 9c6242078..4a4dc8a77 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 886369abc..48d0f9f01 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 7cc0759a8..1df3f7fc9 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 9946232d9..895124807 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 000000000..fe570a10c 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 000000000..d67b294ad 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 eeb3569d3..abfced776 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 e7dba987a..f97838d95 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 000000000..23ec2a9c4 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 000000000..f31e9e0fa 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 7ffdf761d..f8a43d892 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 e00b1cb3b..94fab160f 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 bb28c29ab..83b12af0a 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 40d9f9b9e..503652196 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 c606f9a33..b639ba5d8 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 0f46d4262..d00392a1b 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 13c252b14..6ffd7fe16 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 cdc882e7e..afd20d347 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 bdbc7adf5..cf93c63f8 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 162753d8a..b2fb1d653 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 50e12f8ba..4060dc72f 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 5dafb2597..6b720f8a9 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 6ca08f842..f1931ef5e 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 a3b06a0e7..8e32911da 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 7d8f43653..47e0a7a39 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 a3b06a0e7..8e32911da 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 6ca08f842..f1931ef5e 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 5dafb2597..6b720f8a9 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 50e12f8ba..4060dc72f 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 162753d8a..b2fb1d653 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 59b61fea8..0f0cdad8c 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 93b4f950e..31a43bd69 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 cf55953c8..a77b9de08 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 5f89c2e1b..74c7e7fe8 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 3403ec8a6..aaf107ae2 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 53cbfc541..c6faf6c29 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 af4313708..fa7b04e78 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 edeed16d5..d2909d00b 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 71e4f76a0..bdf66a9b6 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 fd5e95020..49181b3c4 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 71e4f76a0..bdf66a9b6 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 edeed16d5..d2909d00b 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 af4313708..fa7b04e78 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 53cbfc541..c6faf6c29 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 23e27d59c..97c2ccaf2 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 aa171cfaf..7e227af42 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 42fef0327..e2d7a420e 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 52ac41fb8..e801c88f5 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 30a259371..ebdc1382a 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 be19567f3..5ebb0953f 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 2f7a42368..7138b727d 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 aa4ad384d..a753127a8 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 63256dfff..b9ea5b6f9 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 b31366d60..172c2eba7 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 aed6b807c..8b6667b5b 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 df7829408..bf2e55641 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 bc1229a25..8a08e093c 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 711390213..50590d6bb 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 84b79da13..e96d0293c 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 d8da3d730..7ba638842 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 d33251fbf..442dde8ca 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 568151d7d..6a0b8acb9 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 a3e192b83..bc7cc779a 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 f025f2309..c914a3e9f 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 f82dd553a..47a1473ff 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 bc22d3b00..0230d16a7 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 ddbe5f700..951816148 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 3ce0f8aca..affe37cfa 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 91a1125de..0ccf3f271 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 c302db0ab..360cae32c 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 2be305721..15c2e0a8e 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 aad9e3558..1f8f45ee1 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 124ffde21..8127986f3 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 e4d72fe6f..0479bef21 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 fec89bb85..192df5fdb 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 fadaebc9f..5aaa83010 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 5b7b6423b..89082d7e2 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 6301512e8..424e68a08 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 ce0611e34..347b760e9 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 11e93da37..64794e7ee 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 aad9e3558..1f8f45ee1 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 52dc4ad21..ba1b89f9f 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 2dff1c031..c34b691bc 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 c1e438b01..420e568ce 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 169fb6147..c40eee7b2 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 79b2bc972..08a6a6194 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 8fce0c44d..291fa8ace 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 6903a28b8..0dc3edfab 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 e4bba739d..21dc5fa7d 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 4c903182c..d516bf7f6 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 e4bba739d..21dc5fa7d 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 d9f10748e..6e7398d86 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 cf3422c03..531364566 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 1b0ed62e0..31354eeff 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 0caa9956b..78bc56178 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 79f217b96..82dbaedeb 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 eabb2b190..5d7163d54 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 3a30aa7fb..3020c8105 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 3a0c6dd0c..0f4d3e1b2 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 9aaa1c555..71c56f60c 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 d15850b5b..773f388d5 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 feb07e280..7059260ea 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 b1f15432d..28250ca9c 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 b19c0f30c..aac13396a 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 ff4af9ff0..981c17236 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 ad5646d16..ef57f73c4 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 787c0bcfe..6a7f75499 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 187a90345..bd487fdb5 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 0e84cfa07..ddc7d3721 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 a91a6fd5e..4e199c7d0 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 984db9cc7..65a2670a0 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 3bafabd14..64b25db5a 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 edf3d41bb..4a4dc8a77 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 42fdea86e..3ab57222d 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 9b0e7c74e..94bce9c4b 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 d11682ab8..890941257 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 e39e6629d..ae21ac9ee 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 691ed8b4a..26d2fb53b 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 56ea000cd..4e58303cd 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 f64e770e5..ba66d94fc 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 7aef17674..9f5e84571 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 17d3ad265..8e9d00b13 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 198ba5436..94b9dbf74 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 34fd3767b..62f39ba21 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 e65da5b0e..d81f78819 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 1fe568346..7f32403da 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 49af3c225..d59b884fa 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 106ededbf..7ee7f7414 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 dcd2e3c67..0f07c8725 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 f3da0c8ca..df9028d44 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 52d78c086..84e5d031f 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 af343c520..8ef39f64a 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 aade43882..7add41383 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 35d73ba76..18fd7bf9c 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 bafa2c494..e9b697104 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 94e796872..4484e3af7 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 e1f5f9f80..06deb0a27 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 380a970d9..65dff8241 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 257ab1d85..a07a98e4b 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 9c49dcad1..7fafe05ca 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 351a849b0..1ebb69e3e 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 c5f9df119..908821b6b 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 d03f107ef..fe82828f6 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 137d4c4d0..225a56ee3 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 e8480287c..9f955de83 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 78ef029ae..b2fe0bb97 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 5fc1b0cd6..a9fea1309 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 c77bc1494..667c6d892 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 dc4a8733c..8d7b05ca0 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 c2eaa47d0..0e4629ff5 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 d44a32ae0..9c0cc455c 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 a5f096682..fc136087b 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 49f2e25bf..88f1a87c1 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 d6fc2b326..7fce0d5f6 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 fee4e09f5..8d35be7fa 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 f643a82aa..75ab10b4b 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 876cfa229..cad9c4fcc 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 68bc61921..3a3227adb 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 f7c9ca2c7..df07af6b8 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 b99554956..2dae11a7e 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 6825247fb..95b4a7907 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 9d82b4daf..da11e49cb 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 40f094ac9..0c22865b2 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 68c48c0e6..d7def86b0 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 eeaf660b1..ee415989d 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 6f7b9c834..b910c7920 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 bb280e751..c8b3b7a30 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 d8f7654b8..ed1507323 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 0a85465cc..0d8263c5e 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 db895ec52..d3bf6e20f 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 67f23bd31..b464e0c55 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 5ac995c39..5687e44df 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 adff6af66..f9d1fafb7 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 bd6ae73f7..c8fc8e1b0 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 59f62dcc7..942eded49 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 3682c6d0c..2df80976a 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 98a38ffd8..493c9253b 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 f2b5b2213..0f429fda1 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 5b93cf8b1..f980c42f0 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 8f912c517..67581999e 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) -**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! +## 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? + +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? -You must close qFlipper (or other flipper lab web pages) before attempting to connect your flipper 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.
+ +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) -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 +## How Can I Unlock / Remove SubGHz restriction? + +> [!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 + +## 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 - -### Unknown Card/Fob +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. -If you have exhausted all options of scanning via NFC/RFID/PICOPASS then take a photo of: +T5577s are multi-emulator chips that the Flipper Zero can program to be other tags + +### Unknown Card / Fob + +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 12c5a70ec..7077e3abf 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 ddf759f1b..eec2e632a 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 f6a81d97b..0df5c1f7d 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 04fa9d358..a679ccb11 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 e9fc0e2ca..41461b1cd 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). +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) - -*** +![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 8e083349f..4009822f8 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. -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`. +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. + +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 1bac3c4aa..0b8381c1e 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 +Some Media/Consumer Control keys can be pressed with `MEDIA` command -| Command | Parameters | Notes | -| ------- | ------------------------- | ----- | -| MEDIA | Media key, see list below | | +| 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 | + +| 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` +```text +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. +> [!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 2463195e4..6bad4a3c0 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 26401c84b..2a6cd51d3 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; - } - - if(item->callback(item->object, item->callback_context)) { + } 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 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) { + 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, + 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 9ae9f6c4d..af5987101 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); -/** Unsubscribe from message queue +/** 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 message_queue The message queue + * @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_message_queue_unsubscribe( +void furi_event_loop_subscribe_stream_buffer( FuriEventLoop* instance, - FuriMessageQueue* message_queue); + 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); + +/** 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 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_subscribe_mutex( + FuriEventLoop* instance, + 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 cd1014867..15efa8f86 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 5c0b144a1..992ca6555 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 3521ceb30..bd0cec021 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 a88d04131..000000000 --- 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 f59ae83ad..f9848e1ba 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 6413eb65f..850169ad6 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 c6b9a1176..47a77ed55 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 ef8869dea..f35abec64 100644 --- a/furi/core/stream_buffer.c +++ b/furi/core/stream_buffer.c @@ -1,13 +1,19 @@ #include "stream_buffer.h" -#include "check.h" -#include "common_defines.h" - #include #include +#include "check.h" +#include "common_defines.h" + +#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 f3e40fe5e..804445e22 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 bcdf9336c..84b8c6a24 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 c47df55e4..69c6b0f04 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 be09e040e..e8cdeaeaf 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 dca674da5..f4e64ee09 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 80ee30457..d75debe98 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 64da39e35..4656f187b 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 f331198a4..fb0473f8d 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 580346c8c..000000000 --- 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 3453c12f3..000000000 --- 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 eb4310958..000000000 --- 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 c81a2c4e7..000000000 --- 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 3fe58ed1d..000000000 --- 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 579a0189d..000000000 --- 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 ccd3c0fd3..000000000 --- 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 754de9111..000000000 --- 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 69031fbee..000000000 --- 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 34f4d0336..000000000 --- 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 cb63ccdbc..000000000 --- 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 f6c56a911..000000000 --- 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 330aa44ca..000000000 --- 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 234f33774..000000000 --- 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 939bb6b1c..000000000 --- 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 223fbd531..000000000 --- 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 05e5ed1d6..000000000 --- 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 5c71c4318..000000000 --- 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 fb268579d..000000000 --- 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 85fb101b8..f559a741a 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 23d094003..baadf6df2 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 9103e5395..a901cbada 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 477261213..f8dc9a5eb 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 ecd5f9a0d..7955b0673 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 dd2afbd6e..b0c542352 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 2874f120f..ea6febd12 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 2a12a3194..6abacc3b6 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 5f259a38a..2b910bad8 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 83e207de9..5900b10a2 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 05620329f..66eb42f15 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 42af9f0b1..54f75fc1f 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 64920f6ac..3a9e98641 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 67e7545f4..5ed2171c6 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 0b6cd4fca..05ea9a15c 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 d78a303f8..12c91b001 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 101db1dbe..128f20970 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 7dad75669..634c9ab89 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 ddbbf6bd8..95f34829a 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 5383158e4..52fa1589b 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 ef57fe0bc..bbd53e31e 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 e8d630668..0e65dc045 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 b9ef5c518..12ac2dddd 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 000000000..73cbe8f39 --- /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 000000000..002c3024f --- /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 ff8bc4b23..000000000 --- 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 611c9b20d..000000000 --- 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 3d68e07ba..000000000 --- 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 c74487d65..9230436e8 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 cf044c98a..a3a535c40 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 000000000..4691e3423 --- /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 000000000..3f682cee0 --- /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 da1a1e87a..0e7bed1ea 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 c0f3be0d6..7054d2407 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 5902a4922..a370514da 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 78295167f..60d709a36 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 80cbb7d5f..a0dfda3eb 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 80144a0f4..db1d5177f 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 3eb97391e..fd0b28b87 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 a35f0894f..4984d2a06 100644 --- a/scripts/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py +++ b/scripts/debug/FreeRTOS/FreeRTOSgdb/QueueTools.py @@ -102,7 +102,7 @@ class QueueInspector: 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 000000000..f25fea4f5 --- /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 bf02feaad..4ae10c7f4 100644 --- a/scripts/testops.py +++ b/scripts/testops.py @@ -39,7 +39,9 @@ class Main(App): 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 c0a3cd870..182ba9bb1 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 ed3d653d5..03df24ffd 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 b93ad82f1..d304752a9 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 e880bced8..47a5eeb27 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 tarfile 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 @@ class Main(App): 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 @@ class Main(App): 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 @@ class Main(App): ): 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 @@ class Main(App): 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"Expected LFS size is too small (~{int(lfs_span_pages)} pages)" + 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 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 603ec621c..c5d99b896 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 7e254ce40..57cbd1d62 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 229ec0a7a..3452c6707 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 6002ccbee..0680de4ef 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 43be8129d..9ceb747c1 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 4c523a707..c34c54de6 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 0fd452a5a..f9b9b13ef 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 4daaa7e49..43785a1b4 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 118a76e8c..1d414889f 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 30a4ee7ed..05a066630 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 1879eb2ca..4deda293a 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; - SHCI_CmdStatus_t shci_state = SHCI_C2_FUS_UnloadUsrKey(slot); + do { + if(!furi_hal_bt_is_alive()) { + break; + } - furi_hal_bus_disable(FuriHalBusAES1); + CLEAR_BIT(AES1->CR, AES_CR_EN); - furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk); + SHCI_CmdStatus_t shci_state = SHCI_C2_FUS_UnloadUsrKey(slot); - return shci_state == SHCI_Success; + furi_hal_bus_disable(FuriHalBusAES1); + + 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 029d103cb..a1169391d 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 35c40c259..cf10c8d33 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 f5f7bdf2d..d5cda7476 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 3bdbb0c72..030b464cf 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 62310511d..2948faef9 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 665864d7d..f5b3cf3b6 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 b6a6d425e..f37059649 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" {