Просмотр исходного кода

Squashed commit of the following:

commit 1d50a5981e818e6033512fb6bd633a181aef9539
Author: hedger <hedger@users.noreply.github.com>
Date:   Tue Aug 9 18:57:11 2022 +0300

    [FL-2059] Storage fixes for handling empty files (#1563)

    * storage: fixed handling of zero-length files
    * docs: added ReadMe.md for vscode workspace
    * rpc: storage: improved empty file & error handling in write handler
    * docs: markdown fix
    * docs: typo fixes

    Co-authored-by: SG <who.just.the.doctor@gmail.com>
    Co-authored-by: あく <alleteam@gmail.com>

commit 01eb92db0695fe73f8866580af36cc03362d297c
Author: Astra <93453568+Astrrra@users.noreply.github.com>
Date:   Tue Aug 9 18:45:52 2022 +0300

    Mifare Classic emulation fixes (#1566)

    * Add fix for field
    * More small bugfixes
    * Clean up

commit ca23d0c207a2ac2f52885686e61f893d332c515f
Author: MX <10697207+xMasterX@users.noreply.github.com>
Date:   Tue Aug 9 15:16:09 2022 +0300

    fix building updater package (#1564)

commit a7316e7822900f1c4adb806b7b73b36f01937aa6
Author: Oleg K <mastahh@gmail.com>
Date:   Sun Aug 7 19:08:00 2022 +0300

    Added support for Samsung TVs using address 07. (#1509)

    * Added support for Samsung TVs using address 07. Samsung QEXX, UEXX
    * Recompile assets and update manifest

    Co-authored-by: あく <alleteam@gmail.com>

commit 416cce9ffc9819422940978cbc66476150aec900
Author: Skorpionm <85568270+Skorpionm@users.noreply.github.com>
Date:   Sun Aug 7 19:56:45 2022 +0400

    [FL-2718,  FL-2719] SubGhz: add protocol BERNER / ELKA / TEDSEN / TELETASTER / Doitrand / Marantec / Phoenix V2 (static mode) / Phox (static mode), fix Princeton (#1516)

    * SubGhz: add protocol marantec
    * SubGhz: add protocol BERNER / ELKA / TEDSEN / TELETASTER
    * SubGhz: add protocol Doitrand
    * SubGhz: delete debug
    * SubGhz: add protocol Phoenix V2 (static mode)
    * SubGhz: fix serial decode Phoenix V2
    * SubGhz: fix Princeton, display serial number and button on boot
    * SubGhz: fix Bett decoder and fix unit_test
    * SubGhz: update test_random_raw for unit_test

    Co-authored-by: あく <alleteam@gmail.com>

commit 81b404aafa3ead93c1496de696bef5c99b21d6fa
Author: Mayco <tristan.jansen@mailbox.org>
Date:   Sun Aug 7 17:40:09 2022 +0200

    Add ability to type a space with the input keyboard by long-pressing "_" (#1550)

    Co-authored-by: Mayco <tristan@polymerprints.nl>
    Co-authored-by: あく <alleteam@gmail.com>

commit 173c94156d4c6644046ea782eb6ac7e1b18033a4
Author: gornekich <n.gorbadey@gmail.com>
Date:   Sun Aug 7 18:33:14 2022 +0300

    NFC: Add Skylanders support (#1553)

    * nfc: add skylanders support
    * nfc: format sources

    Co-authored-by: あく <alleteam@gmail.com>

commit f3d7d7dba085f4e676c1d901122fb021a3553644
Author: Peter Seprus <ppseprus@users.noreply.github.com>
Date:   Sun Aug 7 17:28:04 2022 +0200

    Extend random name generator (#1551)

    * Extend random name generator
    * Format sources

    Co-authored-by: あく <alleteam@gmail.com>

commit 67a9753f78d95d1158cbb09aa8548c82069dcf5b
Author: Astra <93453568+Astrrra@users.noreply.github.com>
Date:   Sun Aug 7 18:18:39 2022 +0300

    Add a Mifare Classic info screen to parser output (#1504)

    * Add the info screen
    * Oops, don't dupe the points!
    * Show ATQA and SAK, remove the back label
    * And the dolphin doesn't need to be imported anymore
    * Correct UX to the approved one

    Co-authored-by: gornekich <n.gorbadey@gmail.com>

commit 9ffcc52ada215be47a1921875ada955d3420e0be
Author: Vitaliya Chumakova <vichuma9@gmail.com>
Date:   Sun Aug 7 18:09:00 2022 +0300

    Mifare Ultralight authentication (#1365)

    * mifare ultralight auth prototype
    * it works!
    * Reference source
    * use countof
    * rework everything
    * oops forgot scenes
    * build: revert changes in manifest, stack size
    * build: fix buid, format sources
    * nfc: update unlock ultralight GUI
    * nfc: fix byte input header
    * nfc: add new scenes for locked ultralight
    * nfc: add data read to ultralights
    * nfc: add unlock option in mf ultralight menu
    * nfc: add data read init in ultralight generation
    * nfc: lin sources, fix unlocked save
    * nfc: format python sources
    * nfc: clean up

    Co-authored-by: gornekich <n.gorbadey@gmail.com>

commit d147190d6173f427bbedce988cb28eff22ca692e
Author: Georgii Surkov <37121527+gsurkov@users.noreply.github.com>
Date:   Fri Aug 5 18:38:20 2022 +0300

    [FL-2717] Fix unexpected behaviour when opening a remote from outside (#1538)

    * Fix unexpected behaviour when opening remote from outside
    * Same fix for editing button name
    * Exit application correctly if remote was deleted
    * Remove duplicate function from ibutton
    * Use COUNT_OF macro

    Co-authored-by: あく <alleteam@gmail.com>

commit 55b4ff8e0c23ba64a3c82b8f7736b20d2022f295
Author: Mewa <ms1997sokol@gmail.com>
Date:   Fri Aug 5 17:12:13 2022 +0200

    Documentation: fixed outdated naming (#1518)

    * Documentation: fixed outdated naming: changed outdated naming in assets/dolphin/ReadMe. `essential -> blocking`
    * Updated naming convencion in assets/ReadMe file and assets/dolphin/ReadMe file

    Co-authored-by: あく <alleteam@gmail.com>

commit 040558c8f989aa36a50f86276f847dfb73cfa8e2
Author: TQMatvey <77576395+TQMatvey@users.noreply.github.com>
Date:   Thu Aug 4 19:18:34 2022 +0700

    PicoPass: Fix Card Detection Visuals (#1511)

    Co-authored-by: あく <alleteam@gmail.com>

commit 8a370d70dc15ee90892d55232e9a3709c39cf8b6
Author: Georgii Surkov <37121527+gsurkov@users.noreply.github.com>
Date:   Thu Aug 4 15:11:01 2022 +0300

    [FL-2700] Fix IR hangup with short signals (#1535)

    * Do not use infrared worker callback for notifications
    * Remove tx callback
    * Port Infrared notifications to hardware blinker
    * Move all blink message definitions to notification_messages.h
    * Fix potential hangup after leaving debug scene

commit 4460010e76fba3626e0ef2c7e3e5c8149dda25c3
Author: SG <who.just.the.doctor@gmail.com>
Date:   Thu Aug 4 14:34:04 2022 +1000

    Archive: fix null dereference #1531 (#1532)

commit 4c499d9045d0cda866b1820c731c63df3fb47092
Author: HexPandaa <47880094+HexPandaa@users.noreply.github.com>
Date:   Wed Aug 3 19:13:06 2022 +0200

    Fix directory name in lib readme (#1528)

    Co-authored-by: あく <alleteam@gmail.com>

commit 3ee93e1a820fa0401b4de49de0e1050b83e53399
Author: Fedor Indutny <238531+indutny@users.noreply.github.com>
Date:   Wed Aug 3 10:07:35 2022 -0700

    nfc: make dict attack more interactive (#1462)

    * nfc: deduplify dict attack worker code
    * nfc: make dict attack more interactive

    Co-authored-by: gornekich <n.gorbadey@gmail.com>
    Co-authored-by: あく <alleteam@gmail.com>

commit 284c56718bf808f8346a2e48fd26a9d8ee865e9d
Author: Ryan Murphy <57873842+fork-bombed@users.noreply.github.com>
Date:   Wed Aug 3 18:00:17 2022 +0100

    NFC: Edit UID feature (#1513)

    * Added option to edit UID in saved NFC files
    * Fixed bug with saved filename
    * Only show for data that can't be read

    Co-authored-by: あく <alleteam@gmail.com>

commit 135fbd294bcc9e67eda18230df7547c1ef347645
Author: Georgii Surkov <37121527+gsurkov@users.noreply.github.com>
Date:   Wed Aug 3 19:43:14 2022 +0300

    [FL-2693] RW buffered streams (#1523)

    * Add write methods for stream cache
    * Fix logical error
    * Implement write cache for buffered file streams
    * Minor code refactoring
    * Less ugly code
    * Better read() implementation
    * Intermediate implementation
    * Fix logical error
    * Code cleanup
    * Update FFF comments
    * Fix logical error
    * Github: rsync with delete

    Co-authored-by: あく <alleteam@gmail.com>

commit 6499597586c9e5aff76bf4d58f8389c4d2fca0ee
Author: hedger <hedger@users.noreply.github.com>
Date:   Wed Aug 3 19:32:31 2022 +0300

    vscode: initial development configuration (#1520)

    * vscode: initial development configuration; fbt: `vscode_dist` target for deploying vscode config
    * vscode: fixed fbt blackmagic command

    Co-authored-by: あく <alleteam@gmail.com>

commit 51f5641c5efa9a00f491d57574a4e7254add22a7
Author: Žiga Deisinger <41201503+zigad@users.noreply.github.com>
Date:   Wed Aug 3 18:18:48 2022 +0200

    FIX: Fixed inconsistencies between texts (#1496)

    * FIX: Fixed inconsistencies between texts: I have changed inconsistencies. Sometimes there was a missing capital letter and sometimes there was dot instead of exclamation mark and so on. No other changes were made. I have made the correction based on how other text looks on Fliper and for headers most texts use Pascal Case.

    * FIX: Fixed inconsistencies between texts: Found 2 more texts with inconsistencies.

    Co-authored-by: あく <alleteam@gmail.com>

commit bc34689ed6e6a8c2c757be2da01984814468537a
Author: SG <who.just.the.doctor@gmail.com>
Date:   Thu Aug 4 02:00:17 2022 +1000

    Make printf great again (#1438)

    * Printf lib: wrap *printf* functions
    * Printf lib, FW: drop sprintf. Dolphin: dump timestamp as is, wo asctime.
    * FW: remove sniprintf, wrap assert functions
    * Printf lib: wrap putc, puts, putchar
    * Printf: a working but not thread-safe concept.
    * Poorly wrap fflush
    * stdglue: buffers
    * Core: thread local buffers
    * Core: move stdglue to thread api, add ability to get FuriThread instance of current thread.
    * RPC tests: replace sprintf with snprintf
    * Applications: use new stdout api
    * Printf lib: wrap more printf-like and stdout functions
    * Documentation
    * Apps: snprintf size fixes

    Co-authored-by: あく <alleteam@gmail.com>

commit eed4296890f7bb24c0b7f7627e9fcbcc695dd10a
Author: SG <who.just.the.doctor@gmail.com>
Date:   Thu Aug 4 01:47:10 2022 +1000

    MPU Hal (#1492)

    * Furi HAL: memory protection unit
    * Core: prohibit NULL dereferencing, even for reads.
    * Applications: fix NULL dereference
    * Core: stack protection by MPU
    * MPU: stack region alignment
    * Apps: fix null pointer dereferences
    * Threads: fix non-null arg check
    * Desktop settings: fix null pointer dereference
    * Core: documented null-check hack
    * Fix null dereference issues
    * Apps: args check
    * Core: naming fixes
    * format code
    * Core: remove NONNULL specifier
    * FurHal: move MPU initialization to begining, fix enum naming

    Co-authored-by: あく <alleteam@gmail.com>

commit 4a6477aaa87ed35388d27ffbedb8f3d19a032461
Author: SG <who.just.the.doctor@gmail.com>
Date:   Wed Aug 3 22:01:38 2022 +1000

    Core, logs: removed tag concatenation (#1524)

    * Core, logs: removed tag concatenation
    * Logs: remove unused fn
    * Logs: remove allocation

commit 93a4b9c4a9ee35372e95eae7f96fffd42a2a809e
Author: Max Andreev <drunkbatya.js@gmail.com>
Date:   Tue Aug 2 17:05:31 2022 +0300

    [FL-2649] Drop Docker in CI/CD (#1412)

    * enable sparseCheckout, moving github actions from docker to raw shell
    * fix missing known_hosts while setting ssh priv key
    * fix build.yml
    * add ssh key to upload just in time
    * fixing rsync syntax
    * fix build.yml
    * try to fix build.yml again
    * testing rsync
    * test rsync again
    * add linters
    * add Black Python linter to submodules
    * add Black submodule
    * add working python linter target, dirty file list
    * up toolchain to version 4
    * up toolchain to ver 5
    * up toolchain version to 6
    * fbt: using black 22.6.0
    * remove Black submodule, up toolchain to ver 7
    * fbt: added lint_py, format_py targets
    * add pvs_studio workflow
    * fix pvs_studio segfault
    * fix pvs_studio command
    * fix pvs_studio command 2
    * show env before run pvs_studio
    * try to debug pvs_studio
    * try to strace pvs_studio..
    * Add FBT_TOOLCHAIN_PATH, MacOS Rosseta check, and ignore non-x86_64 linux architectures
    * prevent redownloading toolchain on github-runners
    * fix toolchain download exitcode
    * add strace to debug pvs_studio segfault
    * disable strace to catch full code dump
    * Add './fbt cli' target to access Flipper CLI via PySerial
    * remove pvs_studio from this PR
    * removing clang-format from toolchain due errors
    * make source easy, and fix some mistakes found by @hedger
    * Add check_submodules workflow, some fixes
    * fixing mistakes

    Co-authored-by: hedger <hedger@nanode.su>
    Co-authored-by: hedger <hedger@users.noreply.github.com>

commit a1637e9216e98396938debd7ccb4e15cbcb41eb1
Author: hedger <hedger@users.noreply.github.com>
Date:   Tue Aug 2 16:46:43 2022 +0300

    fbt fixes & improvements (#1490)

    * fbt: minimal USB flash mode; scripts: faster storage.py with larger chunks
    * fbt: fixed creation of temporary file nodes confusing scons
    * docs: removed refs to --with-updater
    * fbt: removed splashscreen from minimal update package
    * fbt: renamed dist arguments for consistency
    * docs: fixed updater_debug target
    * fbt: separate target for generating compilation_database.json without building the code.
    * fbt: added `jflash` target for programming over JLink probe; refactored usb flashing targets
    * fbt: building updater_app in unit_tests configuration
    * fbt: fixed reset behavior after flashing with J-Link
    * fbt: generating .map file for firmware binary & external apps
    * fbt/core: moved library contents before apps code

    Co-authored-by: あく <alleteam@gmail.com>

commit 1e732830ec23be2a9acff42c240609d53bed275a
Author: hedger <hedger@users.noreply.github.com>
Date:   Tue Aug 2 16:29:16 2022 +0300

    ci: check for uncommited changes after build (#1461)

    * ci: check for uncommited changes after build
    * assets: updated Manifest to match sources
    * ci: simplified uncommited files check
    * resources: Updated Manifest
    * fbt: always rebuild manifest

    Co-authored-by: あく <alleteam@gmail.com>

commit 01afb289c0dd968193ec6f8abf6282a327fa4e7e
Author: Georgii Surkov <37121527+gsurkov@users.noreply.github.com>
Date:   Tue Aug 2 16:17:37 2022 +0300

    [FL-2713] Buffered file streams fix (#1515)

    * Fix incorrect buffered stream behaviour
    * Add specific tests
    * Make the test fail on wrong behaviour
    * Better names

    Co-authored-by: あく <alleteam@gmail.com>

commit f9745b4141570e6dbc919ac5a63ed98acb9483c7
Author: あく <alleteam@gmail.com>
Date:   Tue Aug 2 21:54:12 2022 +0900

    [FL-2705] App RPC Bug Fixes and redesign  (#1491)

    * Rpc: remove callback timer
    * Rpc: simplify rpc event callback
    * Rpc: migrate to new confirmation schema
    * Rpc: migrate to new confirmation schema part2: finalize ibutton and rfid
    * Rpc: migrate to new confirmation schema part3: finallize nfc and fix id in load
    * Rpc: hardened sequencing check
    * Rpc: migrate to new confirmation schema part4: finalize subghz
    * iButton: properly handle exit
    * Nfc: correct sequence for rpc exit send
    * Rpc: fix review issues and nfc exit message
    * Rpc: more logging and condition race fix in confirmation
    * Rpc: migrate to new confirmation schema part5: finalize infrared
    * Rpc: more logging

commit f9386b2649c022fde75572046ceb51198a4a5317
Author: SG <who.just.the.doctor@gmail.com>
Date:   Tue Aug 2 21:24:42 2022 +1000

    Assets: unused assets removed (#1514)

commit 4da6eba395652de8266ecd6a2bb63012517efd85
Author: Skorpionm <85568270+Skorpionm@users.noreply.github.com>
Date:   Mon Aug 1 16:24:21 2022 +0400

    [FL-2706, FL-2709] SubGhz: checking saved key files for length (#1485)

    * [FL-2706] SubGhz: checking saved key files for length
    * SubGhz: fix RAW file upload error
    * [FL-2709] GubGhz: RAW screen fix

    Co-authored-by: あく <alleteam@gmail.com>

commit 84550d58784637fb46d91c8087a635350e84db5b
Author: hedger <hedger@users.noreply.github.com>
Date:   Sun Jul 31 02:48:55 2022 +0300

    [FL-2654] Updater: retrying pre-boot SD card mount multiple times (#1402)

    * Updater: retrying pre-boot SD card mount multiple times
    * Updater: added delay before retrying SD card mount on early boot

    Co-authored-by: あく <alleteam@gmail.com>

commit 712a48b5db166a401cae9f6ca986d5aaeca7a1a5
Author: MX <10697207+xMasterX@users.noreply.github.com>
Date:   Sun Jul 31 02:34:38 2022 +0300

    Fix typo in subghz (#1467)

    * fix typo across subghz

    Co-authored-by: あく <alleteam@gmail.com>
    Co-authored-by: Aleksandr Kutuzov <aku@plooks.com>

commit 4c39dcbe0c40c89f92df93d8b572799e39e603e1
Author: Anna Prosvetova <anna@prosvetova.me>
Date:   Sun Jul 31 01:14:16 2022 +0200

    ☦️ Rpc: fix backup commands responses (#1502)

commit c40e8811d68e9f4b8f603ae5d5826b814521014d
Author: gornekich <n.gorbadey@gmail.com>
Date:   Thu Jul 28 15:34:28 2022 +0300

    [FL-2701], [FL-2702], [FL-2699] NFC fixes (#1478)

    * nfc: change read scene views
    * nfc: rework return after save success
    * nfc: add fallback to read UID of unrecognized iso14443-3
    * nfc: show mifare desfire on read success
    * nfc: add restore original confirm scene
    * nfc: fix icon name
    * nfc: clear 6 bit in SAK to emulate 14443-4 uids
    * nfc: don't change original sak

commit b6e52e979d07dbd17de80614df6fa224fcb9af33
Author: TQMatvey <77576395+TQMatvey@users.noreply.github.com>
Date:   Thu Jul 28 16:48:45 2022 +0700

    Infrared.c: Dont Close GUI 2 times (#1477)

    GUI was being closed 2 times upon exit, this PR fixes that by removing 1 of those cases

commit c7772060657afc8ee5a160ea3ed62246d989c136
Author: gornekich <n.gorbadey@gmail.com>
Date:   Tue Jul 26 20:28:37 2022 +0300

    NFC: fix navigation from menu scenes #1459

commit 80a7de80783150b6f1aae7a7426ed982b5221d43
Author: hedger <hedger@users.noreply.github.com>
Date:   Tue Jul 26 20:13:09 2022 +0300

    updater: fixed dolphin level not being migrated (#1458)

commit 9c59bcd7763cbe9b0132b0f2698543e2dfb11623
Author: gornekich <n.gorbadey@gmail.com>
Date:   Tue Jul 26 18:30:49 2022 +0300

    [FL-2605] NFC new design (#1364)

    * nfc: add new read scene

    * lib: refactore nfc library

    * mifare desfire: add read card fuction

    * lib nfc: add auto read worker

    * nfc: add supported cards

    * nfc: add mifare classic read success scene

    * nfc: add troyka support

    * submodule: update protobuf

    * nfc: mifare classic keys cache

    * nfc: rework mifare classic key cache

    * Correct spelling

    * nfc: add user dictionary

    * nfc: introduce block read map in fff

    * nfc: rework dict attack

    * nfc: improve dict attack

    * nfc: rework mifare classic format

    * nfc: rework MFC read with Reader

    * nfc: add gui for MFC read success scene

    * nfc: fix dict attack view gui

    * nfc: add retry and exit confirm scenes

    * nfc: add retry and exit scenes navigation

    * nfc: check user dictionary

    * nfc: remove unused scenes

    * nfc: rename functions in nfc worker

    * nfc: rename mf_classic_dict_attack -> dict_attack

    * nfc: change scenes names
    * nfc: remove scene tick events
    * nfc: rework dict calls with buffer streams
    * nfc: fix notifications
    * nfc: fix mf desfire navigation
    * nfc: remove notification from mf classic read success
    * nfc: fix read sectors calculation
    * nfc: add fallback for unknown card
    * nfc: show file name while emulating
    * nfc: fix build
    * nfc: fix memory leak
    * nfc: fix desfire read
    * nfc: add no dict found navigation
    * nfc: add read views
    * nfc: update card fix
    * nfc: fix access bytes save
    * nfc: add exit and retry confirm to mf ultralight read success
    * nfc: introduce detect reader
    * nfc: change record open arg to macros
    * nfc: fix start from archive

    Co-authored-by: Astra <astra@astrra.space>
    Co-authored-by: あく <alleteam@gmail.com>

commit ec19c11dbe4a81147947cc3a8dd2d182374ed67a
Author: Skorpionm <85568270+Skorpionm@users.noreply.github.com>
Date:   Tue Jul 26 18:16:59 2022 +0400

    [FL-2669] SubGhz: add support for loading custom presets (#1398)

    * SubGhz: load custom -preset
    * SubGhz: fix error prt=0
    * SubGhz: load custom preset
    * SubGhz: code refactoring to support custom preset
    * SubGhz: add custom presert refactoring
    * SubGhz: fix alloc history alloc preset
    * SubGhz: fix error load file
    * SubGhz: fix start custom preset
    * SubGhz: fix delete custom preset
    * SubGhz: add description Custom_preset_data for CC1101
    * SubGhz: debug logging and buffer size rounding

    Co-authored-by: あく <alleteam@gmail.com>
    Co-authored-by: Aleksandr Kutuzov <aku@plooks.com>

commit ed7db336c1ce537ee86af5df6b9512299e323db8
Author: Skorpionm <85568270+Skorpionm@users.noreply.github.com>
Date:   Tue Jul 26 16:58:07 2022 +0400

    [FL-2684, FL-2685] bugfix subghz (#1446)

    * [FL-2684] SubGhz: fix incorrect CAME TWICE protocol definition
    * [FL-2685] SubGhz: fix the recorded RAW signal is deleted when trying to transmit on a prohibited frequency

    Co-authored-by: あく <alleteam@gmail.com>

commit 3fa5e18c5a2c17fc666c2b767d90187bb5f30c3a
Author: hedger <hedger@users.noreply.github.com>
Date:   Tue Jul 26 15:44:03 2022 +0300

    [FL-2692, FL-2604, FL-2632] New first start sequence (#1456)

    * desktop: restored automatic power off & manual power off on slideshow view; assets: added frames for new first start sequence; docs: added info on slideshow compilation
    * desktop: restarting long timer on OK button release

    Co-authored-by: あく <alleteam@gmail.com>

commit 056446dfed68931b9997cd3d7600f655809243c4
Author: hedger <hedger@users.noreply.github.com>
Date:   Tue Jul 26 15:21:51 2022 +0300

    [FL-2675] /int space reservation (#1448)

    * storage: added global #defines for /int, /ext & /any
    * storage: introduced PATH_EXT, PATH_INT& PATH_ANY macros
    * core apps: moved hardcoded config files names to separate headers; prefixed them with "."; updater: added file name migration to new naming convention on backup extraction
    * storage: fixed storage_merge_recursive handling of complex directory structures; storage_move_to_sd: changed data migration logic to all non-dot files & all folders
    * core: added macro aliases for core record names
    * Bumped protobuf commit pointer
    * storage: reserved 5 pages in /int; denying write&creation of non-dot files when running out of free space

    Co-authored-by: あく <alleteam@gmail.com>

commit 52a83fc929f125d24136e017661c671d21caac17
Author: Georgii Surkov <37121527+gsurkov@users.noreply.github.com>
Date:   Tue Jul 26 14:46:14 2022 +0300

     [FL-2688] Fix incorrect remote renaming behaviour #1455

commit 05b816429c6a1801e26d74467be65da81d44428d
Author: TijnMertens <110020473+TijnMertens@users.noreply.github.com>
Date:   Tue Jul 26 11:13:04 2022 +0200

    Minor grammar and typo fix (#1454)

commit e03b102af220d7cd0697e57838b8370b1fb60155
Author: MX <10697207+xMasterX@users.noreply.github.com>
Date:   Tue Jul 26 02:09:04 2022 +0300

    Fix git submodules update called anyways (#1450)

    Ignoring FBT_NO_SYNC

commit 27b698f081ecbda04e9337ba5b9ee7abae8cdb4e
Author: Szymon Lisowiec <szymonlisowiec@gmail.com>
Date:   Mon Jul 25 23:31:34 2022 +0200

    fbt: Fixed build for users with space in username (#1437)

    Co-authored-by: あく <alleteam@gmail.com>
    Co-authored-by: hedger <hedger@users.noreply.github.com>

commit d085af31c3ed9155058d6b5ea49f279d73eab541
Author: AlexeyOplachko <45398541+AlexeyOplachko@users.noreply.github.com>
Date:   Mon Jul 25 23:34:49 2022 +0300

    Fixing a typo in Bug Report Issue Template (#1449)

commit cd77b93f26fd05996dc0a2381eaf23c37ef5e394
Author: Eric Betts <bettse@fastmail.fm>
Date:   Mon Jul 25 08:36:38 2022 -0700

    Picopass: dump full card, extract some details (#1408)

    * Dump entire picopass card
    * Capture more iClass details
    * facility code bugfix

    Co-authored-by: あく <alleteam@gmail.com>

commit f8e0ec42c53b7b0710d17f5efcd264c8b4c94927
Author: Yukai Li <GMMan@users.noreply.github.com>
Date:   Mon Jul 25 09:21:05 2022 -0600

    nfc: NTAG203 support (#1383)

    * nfc: Fix original MFUL feature flags
    * nfc: Add NTAG203 read support
    * nfc: Update emulation lock byte handling for NTAG203
    * nfc: Add NTAG203 counter emulation support
    * nfc: Add NTAG203 tag generator
    * nfc: Fix NTAG203 emulating GET_VERSION
    * nfc: Fix MFUL version reading
    * nfc: Complete NTAG203 counter emulation behavior
    * nfc: Complete NTAG203 emulation
    * nfc: Remove unnecessary init in MFUL emulation
    * nfc: Add notes about MFUL type enum

    Co-authored-by: gornekich <n.gorbadey@gmail.com>
    Co-authored-by: あく <alleteam@gmail.com>

commit 30820b83b5d6738c0867b11860ccbf92f8530183
Author: Nikolay Minaylov <nm29719@gmail.com>
Date:   Mon Jul 25 17:46:42 2022 +0300

    [FL-2464, FL-2466] RFID, ibutton text fix #1413

    Co-authored-by: あく <alleteam@gmail.com>

commit ac60d1808a055be65ca42ad64f89d3c721de8772
Author: Wyatt Neal <wyattearp@users.noreply.github.com>
Date:   Mon Jul 25 10:35:02 2022 -0400

    fixing typos, satus -> status (#1422)

    Co-authored-by: あく <alleteam@gmail.com>

commit d80edba8916210248cb2f0107f872cddc1dceb95
Author: Nikolay Minaylov <nm29719@gmail.com>
Date:   Mon Jul 25 17:16:45 2022 +0300

    RPC App: state message and GUI update (#1423)

    * RPC App: state message and GUI update
    * Protobuf submodule update

    Co-authored-by: SG <who.just.the.doctor@gmail.com>
    Co-authored-by: あく <alleteam@gmail.com>

commit f1cb95655cdb6cb6ca7ea9251f85d79cbc4b1e94
Author: Kowlin <10947836+Kowlin@users.noreply.github.com>
Date:   Mon Jul 25 15:11:24 2022 +0200

    Port over Issue templates to new YML format (#1433)

    * WIP Push
    * Add feature request label to template
    * Punctuation helps
    * rename feature request and add in enhancement
    * wording
    * Add in extra markdown explanations

    Co-authored-by: SG <who.just.the.doctor@gmail.com>
    Co-authored-by: あく <alleteam@gmail.com>

commit f5d6a8084b2ff90608cf9fee65185b31f2080993
Author: Nikolay Minaylov <nm29719@gmail.com>
Date:   Mon Jul 25 15:11:34 2022 +0300

     [FL-2668] GUI message screens update #1428

    Co-authored-by: SG <who.just.the.doctor@gmail.com>
    Co-authored-by: あく <alleteam@gmail.com>

commit 3ee592cae724ca2823c96be4070cbc8ae0001e4f
Author: Ruben van Baarle <rubnvb@xs4all.nl>
Date:   Mon Jul 25 13:48:06 2022 +0200

    Fix SubGHz chat immediately closing #1440

    It's just an if condition which should've been inverted

    Co-authored-by: あく <alleteam@gmail.com>

commit c22d66590e86ba27f99b79332f0ea1fd46e8ec83
Author: Georgii Surkov <37121527+gsurkov@users.noreply.github.com>
Date:   Mon Jul 25 14:23:47 2022 +0300

     [FL-2682] Allow spaces in file names #1444

commit 7c49f604f986f13790051822c72ae7de1730827c
Author: Zoë Prosvetova <109866245+ZoeMeetAgain@users.noreply.github.com>
Date:   Sat Jul 23 18:33:39 2022 +0200

    Fix toolchain typos (#1435)

commit 253b98c8f014e4fa91a129eaba3a986f91ac5b12
Author: ESurge <s_marcelino@hotmail.com>
Date:   Fri Jul 22 20:35:14 2022 -0700

    Added condition to cli "log" command to end if serial terminal is disconnected. (#1425)

    * Added condition to cli "log" command. If USB is disconnected while "log" command is running, it will end the command.
    * Reverted change on cli_commands.c
      Added condition in cli.c for cli_cmd_interrupt_received function to react appropriately when serial terminal is disconnected.
      Added condition in subghz_cli.c for subghz chat cmd to exit gracefully when serial terminal is disconnected.
    * Formatting

    Co-authored-by: あく <alleteam@gmail.com>

commit 16e598b2c08bf3156370f15fef5b5dd002780f68
Author: Georgii Surkov <37121527+gsurkov@users.noreply.github.com>
Date:   Fri Jul 22 19:00:25 2022 +0300

    [FL-2655, FL-2650] Buffered file streams (#1424)

    * Initial buffered file stream implementation
    * Fix logical errors
    * Fix more logical errors
    * Minimally working implementation
    * Adapt infrared unit tests for buffered streams
    * Increase read buffer size from 512 to 1K
    * Correct naming and formatting
    * More code improvements
    * Allow passing access and open modes for buffered streams
    * Implement tests for buffered streams
    * Better file and method names
    * Add comments and correct formatting
    * Use buffered streams in Infrared
    * Fix compilation error

commit ec57dd310a6ad9657c08d143bd82a66da532dc78
Author: adisbladis <adisbladis@gmail.com>
Date:   Wed Jul 20 20:48:10 2022 +0800

    fbt: Respect SOURCE_DATE_EPOCH when setting build date (#1421)

    * fbt: using SOURCE_DATE_EPOCH from environment for build timestamp (if set)

    Co-authored-by: hedger <hedger@users.noreply.github.com>

commit e3c7201a2065677ad3c96f0bb1f47f7b58cdb819
Author: あく <alleteam@gmail.com>
Date:   Wed Jul 20 13:56:33 2022 +0300

    Furi: core refactoring and CMSIS removal part 2  (#1410)

    * Furi: rename and move core
    * Furi: drop CMSIS_OS header and unused api, partially refactor and cleanup the rest
    * Furi: CMSIS_OS drop and refactoring.
    * Furi: refactoring, remove cmsis legacy
    * Furi: fix incorrect assert on queue deallocation, cleanup timer
    * Furi: improve delay api, get rid of floats
    * hal: dropped furi_hal_crc
    * Furi: move DWT based delay to cortex HAL
    * Furi: update core documentation

    Co-authored-by: hedger <hedger@nanode.su>

commit f9c2287ea7dabb0e8275d9a635c4b941516f59bc
Author: Dom <FroggMaster@users.noreply.github.com>
Date:   Sun Jul 17 03:09:47 2022 -0700

    Update ReadMe.md (#1409)

    - Minor correction in grammar for ReadMe.

    Co-authored-by: あく <alleteam@gmail.com>

commit 73711c75e630badf275eb0f11cfc4391ac3d2566
Author: t0m1o1 <94725994+t0m1o1@users.noreply.github.com>
Date:   Sun Jul 17 10:56:47 2022 +0100

    Update bad_usb_script.c to fix incorrect ALT key const #1406

    Co-authored-by: あく <alleteam@gmail.com>

commit e7c3da1da9bbbd454b1a863e336dce3fbd5e6553
Author: Skorpionm <85568270+Skorpionm@users.noreply.github.com>
Date:   Sun Jul 17 13:45:21 2022 +0400

    [FL-2658, FL-2657] SubGhz: add new protocol (IronLogic, Comunello, Sommer(fsk476), Normstahl, KEY, EcoStar, Gibidi, Mutancode) (#1404)

    * Subghz: fix cli  no load keeloq_mfcodes_user
    * SubGhz: add new protocol (IronLogic, Comunello, Sommer(fsk476), Normstahl, KEY, EcoStar, Gibidi, Mutancode)
    * SubGhz: fix syntax
    * SubGhz: fix error build

    Co-authored-by: あく <alleteam@gmail.com>

commit 7741a19244ce3af206c6434fc922f1340a96e547
Author: SG <who.just.the.doctor@gmail.com>
Date:   Sun Jul 17 12:34:13 2022 +0300

    Better crash handling (#1397)

    * Core: correct ISR flag check on crash, dump heap and stack info on crash
    * Core: crash, show task name
    * Core crash: optimization

    Co-authored-by: あく <alleteam@gmail.com>

commit 80629de01ecc6cee5a811ba647479117f17b8374
Author: Georgii Surkov <37121527+gsurkov@users.noreply.github.com>
Date:   Sun Jul 17 12:21:56 2022 +0300

    [FL-2601] Move Infrared unit test data to assets (#1396)

    * Move samsung raw data to assets
    * Add more assets and fix bugs
    * Clean up code
    * Implement all raw data as assets
    * Remove input data from old test files
    * Better signal names
    * Better file opening logic
    * Implement loading parsed data from files
    * Move most of RC5 tests into assets
    * Add more test cases
    * Add more test cases
    * Eliminate RUN_DECODER macro
    * Better code structure
    * Implement run_encoder function
    * More encoder tests
    * Move all encoder tests to assets
    * Move all test data to assets
    * Normalise function names
    * Rename code files
    * Uncomment other tests
    * Swich test order to avoid weird memory leaks
    * UnitTests: cleanup output and redirect it into stdout
    * UnitTests: selectable tests and better reporting

    Co-authored-by: あく <alleteam@gmail.com>

commit 877c5c812236337756bd8dba8694ac0ccf53da66
Author: Nikolay Minaylov <nm29719@gmail.com>
Date:   Sun Jul 17 10:41:16 2022 +0300

    [FL-1962, FL-2464, FL-2465, FL-2466, FL-2560, FL-2637, FL-2595] Ibutton, Infrared, LfRFID GUI fixes (#1392)

    * Ibutton, Infrared, LfRFID GUI fixes
    * Loading screens update

    Co-authored-by: あく <alleteam@gmail.com>

commit edc6ca0c8f3cd66ccfa2a8b0bf102bb1828d388e
Author: Eric Betts <bettse@fastmail.fm>
Date:   Sat Jul 16 23:13:51 2022 -0700

    Log MFC nonces for use with mfkey32v2 (#1390)

    Co-authored-by: あく <alleteam@gmail.com>

commit c29ab50016655d57304e9ffd358a2923cc85faa1
Author: Eric Betts <bettse@fastmail.fm>
Date:   Sat Jul 16 23:01:19 2022 -0700

    Calculate picopass CRC dynamically (#1389)

    Co-authored-by: あく <alleteam@gmail.com>
0xchocolate 3 лет назад
Родитель
Сommit
bc519747d9
100 измененных файлов с 946 добавлено и 572 удалено
  1. 1 1
      .github/CODEOWNERS
  2. 46 0
      .github/ISSUE_TEMPLATE/01_bug_report.yml
  3. 21 0
      .github/ISSUE_TEMPLATE/02_enhancements.yml
  4. 24 0
      .github/ISSUE_TEMPLATE/03_feature_request.yml
  5. 0 30
      .github/ISSUE_TEMPLATE/bug_report.md
  6. 5 0
      .github/ISSUE_TEMPLATE/config.yml
  7. 0 12
      .github/ISSUE_TEMPLATE/discuss-issue.md
  8. 0 20
      .github/ISSUE_TEMPLATE/feature_request.md
  9. 0 10
      .github/ISSUE_TEMPLATE/in-progress.md
  10. 0 10
      .github/ISSUE_TEMPLATE/need-help.md
  11. 46 69
      .github/workflows/build.yml
  12. 0 46
      .github/workflows/build_toolchain.yml
  13. 41 11
      .github/workflows/check_submodules.yml
  14. 4 20
      .github/workflows/lint_c.yml
  15. 4 10
      .github/workflows/lint_python.yml
  16. 3 4
      .github/workflows/reindex.yml
  17. 4 0
      .vscode/.gitignore
  18. 17 0
      .vscode/ReadMe.md
  19. 32 0
      .vscode/example/c_cpp_properties.json
  20. 87 0
      .vscode/example/launch.json
  21. 22 0
      .vscode/example/settings.json
  22. 103 0
      .vscode/example/tasks.json
  23. 15 0
      .vscode/extensions.json
  24. 2 2
      ReadMe.md
  25. 91 23
      SConstruct
  26. 8 8
      applications/about/about.c
  27. 2 2
      applications/archive/archive.c
  28. 9 8
      applications/archive/helpers/archive_apps.c
  29. 3 3
      applications/archive/helpers/archive_browser.c
  30. 8 7
      applications/archive/helpers/archive_browser.h
  31. 14 14
      applications/archive/helpers/archive_favorites.c
  32. 2 2
      applications/archive/helpers/archive_favorites.h
  33. 4 4
      applications/archive/helpers/archive_files.c
  34. 14 15
      applications/archive/scenes/archive_scene_browser.c
  35. 3 3
      applications/archive/scenes/archive_scene_rename.c
  36. 7 8
      applications/bad_usb/bad_usb_app.c
  37. 1 2
      applications/bad_usb/bad_usb_app_i.h
  38. 1 1
      applications/bad_usb/bad_usb_script.c
  39. 9 7
      applications/bad_usb/scenes/bad_usb_scene_error.c
  40. 13 13
      applications/bt/bt_cli.c
  41. 3 3
      applications/bt/bt_debug_app/bt_debug_app.c
  42. 8 8
      applications/bt/bt_hid_app/bt_hid.c
  43. 9 8
      applications/bt/bt_service/bt.c
  44. 2 0
      applications/bt/bt_service/bt.h
  45. 3 0
      applications/bt/bt_service/bt_keys_filename.h
  46. 2 1
      applications/bt/bt_service/bt_keys_storage.c
  47. 1 0
      applications/bt/bt_service/bt_keys_storage.h
  48. 2 1
      applications/bt/bt_settings.c
  49. 2 0
      applications/bt/bt_settings.h
  50. 4 4
      applications/bt/bt_settings_app/bt_settings_app.c
  51. 2 2
      applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c
  52. 3 0
      applications/bt/bt_settings_filename.h
  53. 8 8
      applications/cli/cli.c
  54. 2 0
      applications/cli/cli.h
  55. 6 6
      applications/cli/cli_commands.c
  56. 1 1
      applications/cli/cli_i.h
  57. 1 2
      applications/cli/cli_vcp.c
  58. 2 2
      applications/crypto/crypto_cli.c
  59. 4 4
      applications/debug_tools/blink_test.c
  60. 2 2
      applications/debug_tools/display_test/display_test.c
  61. 5 5
      applications/debug_tools/file_browser_test/file_browser_app.c
  62. 5 3
      applications/debug_tools/file_browser_test/scenes/file_browser_scene_start.c
  63. 7 7
      applications/debug_tools/keypad_test.c
  64. 2 2
      applications/debug_tools/text_box_test.c
  65. 4 4
      applications/debug_tools/uart_echo.c
  66. 1 1
      applications/debug_tools/usb_mouse.c
  67. 2 2
      applications/debug_tools/usb_test.c
  68. 4 4
      applications/debug_tools/vibro_test.c
  69. 27 27
      applications/desktop/animations/animation_manager.c
  70. 6 6
      applications/desktop/animations/animation_storage.c
  71. 15 10
      applications/desktop/animations/views/bubble_animation_view.c
  72. 14 13
      applications/desktop/desktop.c
  73. 5 1
      applications/desktop/desktop_settings/desktop_settings.h
  74. 3 3
      applications/desktop/desktop_settings/desktop_settings_app.c
  75. 3 0
      applications/desktop/desktop_settings/desktop_settings_filename.h
  76. 2 2
      applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c
  77. 8 8
      applications/desktop/helpers/pin_lock.c
  78. 2 2
      applications/desktop/helpers/slideshow.c
  79. 3 0
      applications/desktop/helpers/slideshow_filename.h
  80. 2 2
      applications/desktop/scenes/desktop_scene_debug.c
  81. 2 2
      applications/desktop/scenes/desktop_scene_locked.c
  82. 2 2
      applications/desktop/scenes/desktop_scene_pin_input.c
  83. 11 3
      applications/desktop/scenes/desktop_scene_slideshow.c
  84. 1 0
      applications/desktop/views/desktop_events.h
  85. 10 9
      applications/desktop/views/desktop_view_debug.c
  86. 1 1
      applications/desktop/views/desktop_view_lock_menu.c
  87. 29 2
      applications/desktop/views/desktop_view_slideshow.c
  88. 3 0
      applications/desktop/views/desktop_view_slideshow.h
  89. 1 1
      applications/dialogs/dialogs.c
  90. 2 0
      applications/dialogs/dialogs.h
  91. 2 2
      applications/dialogs/dialogs_module_file_browser.c
  92. 2 2
      applications/dialogs/dialogs_module_message.c
  93. 1 1
      applications/dolphin/dolphin.c
  94. 2 0
      applications/dolphin/dolphin.h
  95. 4 1
      applications/dolphin/helpers/dolphin_state.c
  96. 3 0
      applications/dolphin/helpers/dolphin_state_filename.h
  97. 4 4
      applications/dolphin/passport/passport.c
  98. 2 0
      applications/extapps.scons
  99. 4 4
      applications/gpio/gpio_app.c
  100. 7 19
      applications/gpio/scenes/gpio_scene_usb_uart_close_rpc.c

+ 1 - 1
.github/CODEOWNERS

@@ -76,7 +76,7 @@
 /lib/microtar/ @skotopes @DrZlo13 @hedger
 /lib/microtar/ @skotopes @DrZlo13 @hedger
 /lib/mlib/ @skotopes @DrZlo13 @hedger
 /lib/mlib/ @skotopes @DrZlo13 @hedger
 /lib/nanopb/ @skotopes @DrZlo13 @hedger
 /lib/nanopb/ @skotopes @DrZlo13 @hedger
-/lib/nfc_protocols/ @skotopes @DrZlo13 @hedger @gornekich
+/lib/nfc/ @skotopes @DrZlo13 @hedger @gornekich
 /lib/one_wire/ @skotopes @DrZlo13 @hedger
 /lib/one_wire/ @skotopes @DrZlo13 @hedger
 /lib/qrcode/ @skotopes @DrZlo13 @hedger
 /lib/qrcode/ @skotopes @DrZlo13 @hedger
 /lib/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm
 /lib/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm

+ 46 - 0
.github/ISSUE_TEMPLATE/01_bug_report.yml

@@ -0,0 +1,46 @@
+name: Bug report
+description: File a bug reports regarding the firmware.
+labels: ['bug']
+body:
+- type: markdown
+  attributes:
+    value: |
+      Thank you for taking the time to fill out an issue, this template is meant for any issues related to the Flipper Zero firmware.
+      If you require help with the Flipper zero and its firmware, we ask that you join [our forum](https://forum.flipperzero.one)
+- type: textarea
+  id: description
+  attributes:
+    label: Describe the bug.
+    description: "A clear and concise description of what the bug is."
+  validations:
+    required: true
+- type: textarea
+  id: repro
+  attributes: 
+    label: Reproduction
+    description: "How can this bug be reproduced?"
+    placeholder: |
+      1. Switch on...
+      2. Press button '....'
+      3. Wait for the moon phase
+      4. It burns
+  validations:
+    required: true
+- type: input
+  id: target
+  attributes:
+    label: Target
+    description: Specify the target
+    # Target seems to be largely ignored by outside sources.
+- type: textarea
+  id: logs
+  attributes:
+    label: Logs
+    description: Attach your debug logs here
+    render: Text
+    # Avoid rendering as Markdown here.
+- type: textarea
+  id: anything-else
+  attributes:
+    label: Anything else?
+    description: Let us know if you have anything else to share.

+ 21 - 0
.github/ISSUE_TEMPLATE/02_enhancements.yml

@@ -0,0 +1,21 @@
+name: Enhancements
+description: Suggest improvements for any existing functionality within the firmware.
+body:
+- type: markdown
+  attributes:
+    value: |
+      Thank you for taking the time to fill out an issue. This template is meant for feature requests and improvements to already existing functionality.
+      If you require help with the Flipper zero and its firmware, we ask that you join [our forum](https://forum.flipperzero.one)
+- type: textarea
+  id: proposal
+  attributes:
+    label: "Describe the enhancement you're suggesting."
+    description: |
+      Feel free to describe in as much detail as you wish.
+  validations:
+    required: true
+- type: textarea
+  id: anything-else
+  attributes:
+    label: Anything else?
+    description: Let us know if you have anything else to share.

+ 24 - 0
.github/ISSUE_TEMPLATE/03_feature_request.yml

@@ -0,0 +1,24 @@
+name: Feature Request
+description: For feature requests regarding the firmware.
+labels: ['feature request']
+body:
+- type: markdown
+  attributes:
+    value: |
+      Thank you for taking the time to fill out an issue, this template is meant for any feature suggestions.
+      If you require help with the Flipper zero and its firmware, we ask that you join [our forum](https://forum.flipperzero.one)
+- type: textarea
+  id: proposal
+  attributes:
+    label: "Description of the feature you're suggesting."
+    description: |
+      Please describe your feature request in as many details as possible.
+        - Describe what it should do.
+        - Note whetever it is to extend existing functionality or introduce new functionality.
+  validations:
+    required: true
+- type: textarea
+  id: anything-else
+  attributes:
+    label: Anything else?
+    description: Let us know if you have anything else to share.

+ 0 - 30
.github/ISSUE_TEMPLATE/bug_report.md

@@ -1,30 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: ''
-labels: bug
-assignees: ''
-
----
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-Steps to reproduce the behavior:
-1. Switch on...
-2. Press button '....'
-3. Wait for the moon phase
-4. It burns
-
-**Expected behavior**
-A clear and concise description of what you expected to happen.
-
-**Logs**
-Add debug logs
-
-**Target**
-Specify the target
-
-**Additional context**
-Add any other context about the problem here.

+ 5 - 0
.github/ISSUE_TEMPLATE/config.yml

@@ -0,0 +1,5 @@
+blank_issues_enabled: true
+contact_links:
+  - name: Need help?
+    url: https://forum.flipperzero.one
+    about: For any question regarding on how to use the Flipper Zero and its firmware.

+ 0 - 12
.github/ISSUE_TEMPLATE/discuss-issue.md

@@ -1,12 +0,0 @@
----
-name: Discuss issue
-about: Start discussion about improvements
-title: ''
-labels: discussion
-assignees: ''
-
----
-
-# What are you want to add or change
-
-# What questions do you have

+ 0 - 20
.github/ISSUE_TEMPLATE/feature_request.md

@@ -1,20 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: ''
-labels: feature request
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here.

+ 0 - 10
.github/ISSUE_TEMPLATE/in-progress.md

@@ -1,10 +0,0 @@
----
-name: In progress
-about: When you start doing your big deal
-title: ''
-labels: in progress
-assignees: ''
-
----
-
-Shortly (or not) describe what are you will do

+ 0 - 10
.github/ISSUE_TEMPLATE/need-help.md

@@ -1,10 +0,0 @@
----
-name: Need help
-about: Ask the community for help if you confused and can't figure out something
-title: ''
-labels: need help
-assignees: ''
-
----
-
-# Describe you problem here

+ 46 - 69
.github/workflows/build.yml

@@ -15,11 +15,8 @@ env:
 
 
 jobs:
 jobs:
   main:
   main:
-    runs-on: [self-hosted,FlipperZero]
+    runs-on: [self-hosted,FlipperZeroShell]
     steps:
     steps:
-      - name: 'Cleanup workspace'
-        uses: AutoModality/action-clean@v1
-
       - name: 'Decontaminate previous build leftovers'
       - name: 'Decontaminate previous build leftovers'
         run: |
         run: |
           if [ -d .git ]
           if [ -d .git ]
@@ -32,12 +29,8 @@ jobs:
         uses: actions/checkout@v2
         uses: actions/checkout@v2
         with:
         with:
           fetch-depth: 0
           fetch-depth: 0
-          submodules: true
           ref: ${{ github.event.pull_request.head.sha }}
           ref: ${{ github.event.pull_request.head.sha }}
 
 
-      - name: 'Build docker image'
-        uses: ./.github/actions/docker
-
       - name: 'Make artifacts directory'
       - name: 'Make artifacts directory'
         run: |
         run: |
           test -d artifacts && rm -rf artifacts || true
           test -d artifacts && rm -rf artifacts || true
@@ -71,40 +64,38 @@ jobs:
         run: |
         run: |
           tar czpf artifacts/flipper-z-any-scripts-${{steps.names.outputs.suffix}}.tgz scripts
           tar czpf artifacts/flipper-z-any-scripts-${{steps.names.outputs.suffix}}.tgz scripts
 
 
-      - name: 'Build the firmware in docker'
-        uses: ./.github/actions/docker
-        with:
-          run: |
-            set -e
-            for TARGET in ${TARGETS}
-            do
-              ./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` --with-updater updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }}
-            done
+      - name: 'Build the firmware'
+        run: |
+          set -e
+          for TARGET in ${TARGETS}
+          do
+            FBT_TOOLCHAIN_PATH=/opt ./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }}
+          done
 
 
       - name: 'Move upload files'
       - name: 'Move upload files'
         if: ${{ !github.event.pull_request.head.repo.fork }}
         if: ${{ !github.event.pull_request.head.repo.fork }}
-        uses: ./.github/actions/docker
-        with:
-          run: |
-            set -e
-            for TARGET in ${TARGETS}
-            do
-              mv dist/${TARGET}-*/* artifacts/
-            done
+        run: |
+          set -e
+          for TARGET in ${TARGETS}
+          do
+            mv dist/${TARGET}-*/* artifacts/
+          done
 
 
       - name: 'Bundle self-update package'
       - name: 'Bundle self-update package'
         if: ${{ !github.event.pull_request.head.repo.fork }}
         if: ${{ !github.event.pull_request.head.repo.fork }}
-        uses: ./.github/actions/docker
-        with:
-          run: |
-            set -e
-            for UPDATEBUNDLE in artifacts/*/
-            do
-              BUNDLE_NAME=`echo $UPDATEBUNDLE | cut -d'/' -f2`
-              echo Packaging ${BUNDLE_NAME}
-              tar czpf artifacts/flipper-z-${BUNDLE_NAME}.tgz -C artifacts ${BUNDLE_NAME}
-              rm -rf artifacts/${BUNDLE_NAME}
-            done
+        run: |
+          set -e
+          for UPDATEBUNDLE in artifacts/*/
+          do
+            BUNDLE_NAME=`echo $UPDATEBUNDLE | cut -d'/' -f2`
+            echo Packaging ${BUNDLE_NAME}
+            tar czpf artifacts/flipper-z-${BUNDLE_NAME}.tgz -C artifacts ${BUNDLE_NAME}
+            rm -rf artifacts/${BUNDLE_NAME}
+          done
+
+      - name: "Check for uncommited changes"
+        run: |
+          git diff --exit-code
 
 
       - name: 'Bundle resources'
       - name: 'Bundle resources'
         if: ${{ !github.event.pull_request.head.repo.fork }}
         if: ${{ !github.event.pull_request.head.repo.fork }}
@@ -113,29 +104,23 @@ jobs:
 
 
       - name: 'Bundle core2 firmware'
       - name: 'Bundle core2 firmware'
         if: ${{ !github.event.pull_request.head.repo.fork }}
         if: ${{ !github.event.pull_request.head.repo.fork }}
-        uses: ./.github/actions/docker
-        with:
-          run: |
-            ./fbt copro_dist
-            tar czpf artifacts/flipper-z-any-core2_firmware-${{steps.names.outputs.suffix}}.tgz -C assets core2_firmware
+        run: |
+          FBT_TOOLCHAIN_PATH=/opt ./fbt copro_dist
+          tar czpf artifacts/flipper-z-any-core2_firmware-${{steps.names.outputs.suffix}}.tgz -C assets core2_firmware
 
 
       - name: 'Upload artifacts to update server'
       - name: 'Upload artifacts to update server'
         if: ${{ !github.event.pull_request.head.repo.fork }}
         if: ${{ !github.event.pull_request.head.repo.fork }}
-        uses: burnett01/rsync-deployments@5.1
-        with:
-          switches: -avzP --delete --mkpath
-          path: artifacts/
-          remote_path: "${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${{steps.names.outputs.artifacts-path}}/"
-          remote_host: ${{ secrets.RSYNC_DEPLOY_HOST }}
-          remote_port: ${{ secrets.RSYNC_DEPLOY_PORT }}
-          remote_user: ${{ secrets.RSYNC_DEPLOY_USER }}
-          remote_key: ${{ secrets.RSYNC_DEPLOY_KEY }}
+        run: |
+          echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key;
+          chmod 600 ./deploy_key;
+          rsync -avzP --delete --mkpath \
+              -e 'ssh -p ${{ secrets.RSYNC_DEPLOY_PORT }} -i ./deploy_key' \
+              artifacts/ ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:"${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${{steps.names.outputs.artifacts-path}}/";
+          rm ./deploy_key;
 
 
       - name: 'Trigger update server reindex'
       - name: 'Trigger update server reindex'
         if: ${{ !github.event.pull_request.head.repo.fork }}
         if: ${{ !github.event.pull_request.head.repo.fork }}
-        uses: wei/curl@master
-        with:
-          args: -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }}
+        run: curl -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }}
 
 
       - name: 'Find Previous Comment'
       - name: 'Find Previous Comment'
         if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request }}
         if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request }}
@@ -161,11 +146,8 @@ jobs:
 
 
   compact:
   compact:
     if: ${{ !startsWith(github.ref, 'refs/tags') }}
     if: ${{ !startsWith(github.ref, 'refs/tags') }}
-    runs-on: [self-hosted,FlipperZero]
+    runs-on: [self-hosted,FlipperZeroShell]
     steps:
     steps:
-      - name: 'Cleanup workspace'
-        uses: AutoModality/action-clean@v1
-
       - name: 'Decontaminate previous build leftovers'
       - name: 'Decontaminate previous build leftovers'
         run: |
         run: |
           if [ -d .git ]
           if [ -d .git ]
@@ -181,9 +163,6 @@ jobs:
           submodules: true
           submodules: true
           ref: ${{ github.event.pull_request.head.sha }}
           ref: ${{ github.event.pull_request.head.sha }}
 
 
-      - name: 'Build docker image'
-        uses: ./.github/actions/docker
-
       - name: 'Generate suffix and folder name'
       - name: 'Generate suffix and folder name'
         id: names
         id: names
         run: |
         run: |
@@ -203,12 +182,10 @@ jobs:
           echo "WORKFLOW_BRANCH_OR_TAG=${BRANCH_OR_TAG}" >> $GITHUB_ENV
           echo "WORKFLOW_BRANCH_OR_TAG=${BRANCH_OR_TAG}" >> $GITHUB_ENV
           echo "DIST_SUFFIX=${SUFFIX}" >> $GITHUB_ENV
           echo "DIST_SUFFIX=${SUFFIX}" >> $GITHUB_ENV
 
 
-      - name: 'Build the firmware in docker'
-        uses: ./.github/actions/docker
-        with:
-          run: |
-            set -e
-            for TARGET in ${TARGETS}
-            do
-              ./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` --with-updater updater_package DEBUG=0 COMPACT=1
-            done
+      - name: 'Build the firmware'
+        run: |
+          set -e
+          for TARGET in ${TARGETS}
+          do
+            FBT_TOOLCHAIN_PATH=/opt ./fbt TARGET_HW=`echo ${TARGET} | sed 's/f//'` updater_package DEBUG=0 COMPACT=1
+          done

+ 0 - 46
.github/workflows/build_toolchain.yml

@@ -1,46 +0,0 @@
-name: 'Build toolchain Docker image'
-
-on:
-  push:
-    branches:
-      - dev
-    tags:
-      - '*'
-
-jobs:
-  build:
-    runs-on: ubuntu-latest
-    steps:
-      - name: Checkout code
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
-      - name: Docker meta
-        id: meta
-        uses: docker/metadata-action@v3
-        with:
-          images: flipperdevices/flipperzero-toolchain
-          flavor: latest=${{ startsWith(github.ref, 'refs/tags/') && !endsWith(github.ref, 'rc')}}
-          tags: |
-            type=ref,event=branch
-            type=ref,event=tag
-      - name: Set up QEMU
-        uses: docker/setup-qemu-action@v1
-      - name: Set up Docker Buildx
-        uses: docker/setup-buildx-action@v1
-      - name: Login to DockerHub
-        uses: docker/login-action@v1
-        with:
-          username: ${{ secrets.DOCKERHUB_USERNAME }}
-          password: ${{ secrets.DOCKERHUB_TOKEN }}
-      - name: Build and push
-        id: docker_build
-        uses: docker/build-push-action@v2
-        with:
-          context: docker/
-          push: true
-          tags: ${{ steps.meta.outputs.tags }}
-          labels: ${{ steps.meta.outputs.labels }}
-          platforms: linux/amd64,linux/arm64
-          cache-from: type=registry,ref=flipperdevices/flipperzero-toolchain:buildcache
-          cache-to: type=registry,ref=flipperdevices/flipperzero-toolchain:buildcache,mode=max

+ 41 - 11
.github/workflows/check_submodules.yml

@@ -1,17 +1,47 @@
-name: 'Check submodules'
+name: 'Check submodules branch'
 
 
 on:
 on:
+  push:
+    branches:
+      - dev
+      - "release*"
+    tags:
+      - '*'
   pull_request:
   pull_request:
 
 
 jobs:
 jobs:
-  protobuf:
-    runs-on: ubuntu-latest
+  check_protobuf:
+    runs-on: [self-hosted, FlipperZeroShell]
     steps:
     steps:
-    - name: 'Checkout code'
-      uses: actions/checkout@v2
-    - name: 'Check submodule commit branch'
-      uses: jtmullen/submodule-branch-check-action@v1
-      with:
-        path: assets/protobuf
-        branch: dev
-        fetch_depth: 50
+      - name: 'Decontaminate previous build leftovers'
+        run: |
+          if [ -d .git ]
+          then
+            git submodule status \
+              || git checkout `git rev-list --max-parents=0 HEAD | tail -n 1`
+          fi
+
+      - name: 'Checkout code'
+        uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+
+      - name: 'Check protobuf branch'
+        run: |
+          SUB_PATH="assets/protobuf";
+          SUB_BRANCH="dev";
+          SUB_COMMITS_MIN=40;
+          cd "$SUB_PATH";
+          SUBMODULE_HASH="$(git rev-parse HEAD)";
+          BRANCHES=$(git branch -r --contains "$SUBMODULE_HASH");
+          COMMITS_IN_BRANCH="$(git rev-list --count dev)";
+          if [ $COMMITS_IN_BRANCH -lt $SUB_COMMITS_MIN ]; then
+            echo "::set-output name=fails::error";
+            echo "::error::Error: Too low commits in $SUB_BRANCH of submodule $SUB_PATH: $COMMITS_IN_BRANCH(expected $SUB_COMMITS_MIN+)";
+            exit 1;
+          fi
+          if ! grep -q "/$SUB_BRANCH" <<< "$BRANCHES"; then
+            echo "::set-output name=fails::error";
+            echo "::error::Error: Submodule $SUB_PATH is not on branch $SUB_BRANCH";
+            exit 1;
+          fi

+ 4 - 20
.github/workflows/lint_c.yml

@@ -1,6 +1,6 @@
 name: 'Lint C/C++ with clang-format'
 name: 'Lint C/C++ with clang-format'
 
 
-on: 
+on:
   push:
   push:
     branches:
     branches:
       - dev
       - dev
@@ -14,11 +14,8 @@ env:
 
 
 jobs:
 jobs:
   lint_c_cpp:
   lint_c_cpp:
-    runs-on: [self-hosted,FlipperZero]
+    runs-on: [self-hosted,FlipperZeroShell]
     steps:
     steps:
-      - name: 'Cleanup workspace'
-        uses: AutoModality/action-clean@v1
-
       - name: 'Decontaminate previous build leftovers'
       - name: 'Decontaminate previous build leftovers'
         run: |
         run: |
           if [ -d .git ]
           if [ -d .git ]
@@ -31,23 +28,10 @@ jobs:
         uses: actions/checkout@v2
         uses: actions/checkout@v2
         with:
         with:
           fetch-depth: 0
           fetch-depth: 0
-          submodules: true
-
-      - name: 'Docker cache'
-        uses: satackey/action-docker-layer-caching@v0.0.11
-        continue-on-error: true
-        with:
-          key: docker-cache-${{ hashFiles('docker/**') }}-{hash}
-          restore-keys: docker-cache-${{ hashFiles('docker/**') }}-
-
-      - name: 'Build docker image'
-        uses: ./.github/actions/docker
 
 
       - name: 'Check code formatting'
       - name: 'Check code formatting'
         id: syntax_check
         id: syntax_check
-        uses: ./.github/actions/docker
-        with:
-          run: SET_GH_OUTPUT=1 ./fbt lint
+        run: SET_GH_OUTPUT=1 FBT_TOOLCHAIN_PATH=/opt ./fbt lint
 
 
       - name: Report code formatting errors
       - name: Report code formatting errors
         if: failure() && steps.syntax_check.outputs.errors && github.event.pull_request
         if: failure() && steps.syntax_check.outputs.errors && github.event.pull_request
@@ -59,4 +43,4 @@ jobs:
             ```
             ```
             ${{ steps.syntax_check.outputs.errors }}
             ${{ steps.syntax_check.outputs.errors }}
             ```
             ```
-            You might want to run `docker compose exec dev make format` for an auto-fix.
+            You might want to run `./fbt format` for an auto-fix.

+ 4 - 10
.github/workflows/lint_python.yml

@@ -1,6 +1,6 @@
 name: 'Python Lint'
 name: 'Python Lint'
 
 
-on: 
+on:
   push:
   push:
     branches:
     branches:
       - dev
       - dev
@@ -11,11 +11,8 @@ on:
 
 
 jobs:
 jobs:
   lint_python:
   lint_python:
-    runs-on: ubuntu-latest
+    runs-on: [self-hosted,FlipperZeroShell]
     steps:
     steps:
-      - name: 'Cleanup workspace'
-        uses: AutoModality/action-clean@v1
-
       - name: 'Decontaminate previous build leftovers'
       - name: 'Decontaminate previous build leftovers'
         run: |
         run: |
           if [ -d .git ]
           if [ -d .git ]
@@ -29,8 +26,5 @@ jobs:
         with:
         with:
           fetch-depth: 0
           fetch-depth: 0
 
 
-      - name: 'Setup python'
-        uses: actions/setup-python@v2
-
-      - name: 'Check python code with black'
-        uses: psf/black@20.8b1
+      - name: 'Check code formatting'
+        run: SET_GH_OUTPUT=1 FBT_TOOLCHAIN_PATH=/opt ./fbt lint_py

+ 3 - 4
.github/workflows/reindex.yml

@@ -7,9 +7,8 @@ on:
 jobs:
 jobs:
   reindex:
   reindex:
     name: 'Reindex updates'
     name: 'Reindex updates'
-    runs-on: [self-hosted,FlipperZero]
+    runs-on: [self-hosted,FlipperZeroShell]
     steps:
     steps:
       - name: Trigger reindex
       - name: Trigger reindex
-        uses: wei/curl@master
-        with:
-          args: -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }}
+        run: |
+          curl -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }}

+ 4 - 0
.vscode/.gitignore

@@ -0,0 +1,4 @@
+./c_cpp_properties.json
+./launch.json
+./settings.json
+./tasks.json

+ 17 - 0
.vscode/ReadMe.md

@@ -0,0 +1,17 @@
+# Visual Studio Code workspace for Flipper Zero
+
+## Setup
+
+ * To start developing with VSCode, run `./fbt vscode_dist` in project root. _That should only be done once_
+ * After that, open firmware folder in VSCode: "File" > "Open folder"
+
+ For more details on fbt, see [fbt docs](../documentation/fbt.md).
+
+
+## Workflow
+
+Commands for building firmware are invoked through Build menu: Ctrl+Shift+B.
+
+To attach a debugging session, first build and flash firmware, then choose your debug probe in Debug menu (Ctrl+Shift+D).
+
+Note that you have to detach debugging session before rebuilding and re-flashing firmware.

+ 32 - 0
.vscode/example/c_cpp_properties.json

@@ -0,0 +1,32 @@
+{
+    "configurations": [
+        {
+            "name": "Win32",
+            "compilerPath": "${workspaceFolder}/toolchain/i686-windows/bin/arm-none-eabi-gcc.exe",
+            "intelliSenseMode": "gcc-arm",
+            "compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
+            "configurationProvider": "ms-vscode.cpptools",
+            "cStandard": "gnu17",
+            "cppStandard": "c++17"
+        },
+        {
+            "name": "Linux",
+            "compilerPath": "${workspaceFolder}/toolchain/x86_64-linux/bin/arm-none-eabi-gcc",
+            "intelliSenseMode": "gcc-arm",
+            "compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
+            "configurationProvider": "ms-vscode.cpptools",
+            "cStandard": "gnu17",
+            "cppStandard": "c++17"
+        },
+        {
+            "name": "Mac",
+            "compilerPath": "${workspaceFolder}/toolchain/x86_64-darwin/bin/arm-none-eabi-gcc",
+            "intelliSenseMode": "gcc-arm",
+            "compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
+            "configurationProvider": "ms-vscode.cpptools",
+            "cStandard": "gnu17",
+            "cppStandard": "c++17"
+        }
+    ],
+    "version": 4
+}

+ 87 - 0
.vscode/example/launch.json

@@ -0,0 +1,87 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "inputs": [
+        {
+            "id": "BLACKMAGIC",
+            "type": "command",
+            "command": "shellCommand.execute",
+            "args": {
+                "command": "./fbt get_blackmagic",
+                "description": "Get Blackmagic device",
+            }
+        }
+    ],
+    "configurations": [
+        {
+            "name": "Attach FW (ST-Link)",
+            "cwd": "${workspaceFolder}",
+            "executable": "./build/latest/firmware.elf",
+            "request": "attach",
+            "type": "cortex-debug",
+            "servertype": "openocd",
+            "device": "stlink",
+            "svdFile": "./debug/STM32WB55_CM4.svd",
+            "rtos": "FreeRTOS",
+            "configFiles": [
+                "interface/stlink.cfg",
+                "./debug/stm32wbx.cfg",
+            ],
+            "postAttachCommands": [
+                // "attach 1",
+                "compare-sections",
+            ]
+            // "showDevDebugOutput": "raw",
+        },
+        {
+            "name": "Attach FW (blackmagic)",
+            "cwd": "${workspaceFolder}",
+            "executable": "./build/latest/firmware.elf",
+            "request": "attach",
+            "type": "cortex-debug",
+            "servertype": "external",
+            "gdbTarget": "${input:BLACKMAGIC}",
+            "svdFile": "./debug/STM32WB55_CM4.svd",
+            "rtos": "FreeRTOS",
+            "postAttachCommands": [
+                "monitor swdp_scan",
+                "attach 1",
+                "set confirm off",
+                "set mem inaccessible-by-default off",
+                "compare-sections",
+            ]
+            // "showDevDebugOutput": "raw",
+        },
+        {
+            "name": "Attach FW (JLink)",
+            "cwd": "${workspaceFolder}",
+            "executable": "./build/latest/firmware.elf",
+            "request": "attach",
+            "type": "cortex-debug",
+            "servertype": "jlink",
+            "interface": "swd",
+            "device": "STM32WB55RG",
+            "svdFile": "./debug/STM32WB55_CM4.svd",
+            "rtos": "FreeRTOS",
+            // "showDevDebugOutput": "raw",
+        },
+        {
+            "name": "fbt debug",
+            "type": "python",
+            "request": "launch",
+            "program": "./lib/scons/scripts/scons.py",
+            "args": [
+                "sdk"
+            ]
+        },
+        {
+            "name": "python debug",
+            "type": "python",
+            "request": "launch",
+            "program": "${file}",
+            "args": []
+        }
+    ]
+}

+ 22 - 0
.vscode/example/settings.json

@@ -0,0 +1,22 @@
+{
+    "C_Cpp.default.cStandard": "gnu17",
+    "C_Cpp.default.cppStandard": "c++17",
+    "python.formatting.provider": "black",
+    "workbench.tree.indent": 12,
+    "cortex-debug.enableTelemetry": false,
+    "cortex-debug.variableUseNaturalFormat": true,
+    "cortex-debug.showRTOS": true,
+    "cortex-debug.armToolchainPath.windows": "${workspaceFolder}/toolchain/i686-windows/bin",
+    "cortex-debug.armToolchainPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/bin",
+    "cortex-debug.armToolchainPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/bin",
+    "cortex-debug.openocdPath.windows": "${workspaceFolder}/toolchain/i686-windows/openocd/bin/openocd.exe",
+    "cortex-debug.openocdPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/openocd/bin/openocd",
+    "cortex-debug.openocdPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/openocd/bin/openocd",
+    "editor.formatOnSave": true,
+    "files.associations": {
+        "*.scons": "python",
+        "SConscript": "python",
+        "SConstruct": "python",
+        "*.fam": "python",
+    }
+}

+ 103 - 0
.vscode/example/tasks.json

@@ -0,0 +1,103 @@
+{
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "[Release] Build",
+            "group": "build",
+            "type": "shell",
+            "command": "./fbt COMPACT=1 DEBUG=0"
+        },
+        {
+            "label": "[Debug] Build",
+            "group": "build",
+            "type": "shell",
+            "command": "./fbt"
+        },
+        {
+            "label": "[Release] Flash (ST-Link)",
+            "group": "build",
+            "type": "shell",
+            "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash"
+        },
+        {
+            "label": "[Debug] Flash (ST-Link)",
+            "group": "build",
+            "type": "shell",
+            "command": "./fbt FORCE=1 flash"
+        },
+        {
+            "label": "[Release] Flash (blackmagic)",
+            "group": "build",
+            "type": "shell",
+            "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_blackmagic"
+        },
+        {
+            "label": "[Debug] Flash (blackmagic)",
+            "group": "build",
+            "type": "shell",
+            "command": "./fbt FORCE=1 flash_blackmagic"
+        },
+        {
+            "label": "[Release] Flash (JLink)",
+            "group": "build",
+            "type": "shell",
+            "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 jflash"
+        },
+        {
+            "label": "[Debug] Flash (JLink)",
+            "group": "build",
+            "type": "shell",
+            "command": "./fbt FORCE=1 jflash"
+        },
+        {
+            "label": "[Release] Build update bundle",
+            "group": "build",
+            "type": "shell",
+            "command": "./fbt updater_package COMPACT=1 DEBUG=0"
+        },
+        {
+            "label": "[Debug] Build update bundle",
+            "group": "build",
+            "type": "shell",
+            "command": "./fbt updater_package"
+        },
+        {
+            "label": "[Release] Build updater",
+            "group": "build",
+            "type": "shell",
+            "command": "./fbt updater_all COMPACT=1 DEBUG=0"
+        },
+        {
+            "label": "[Debug] Build updater",
+            "group": "build",
+            "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:unit_tests] Flash (USB)",
+            "group": "build",
+            "type": "shell",
+            "command": "./fbt FIRMWARE_APP_SET=unit_tests FORCE=1 flash_usb"
+        },
+        {
+            "label": "[Release] Flash (USB, with resources)",
+            "group": "build",
+            "type": "shell",
+            "command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb_full"
+        },
+    ]
+}

+ 15 - 0
.vscode/extensions.json

@@ -0,0 +1,15 @@
+{
+	// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
+	// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
+	// List of extensions which should be recommended for users of this workspace.
+	"recommendations": [
+		"ms-python.black-formatter",
+		"ms-vscode.cpptools",
+		"amiralizadeh9480.cpp-helper",
+		"marus25.cortex-debug",
+		"zxh404.vscode-proto3",
+		"augustocdias.tasks-shell-input"
+	],
+	// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
+	"unwantedRecommendations": []
+}

+ 2 - 2
ReadMe.md

@@ -29,11 +29,11 @@ They both must be flashed in the order described.
 
 
 With Flipper attached over USB:
 With Flipper attached over USB:
 
 
-`./fbt --with-updater flash_usb`
+`./fbt flash_usb`
 
 
 Just building the package:
 Just building the package:
 
 
-`./fbt --with-updater updater_package`
+`./fbt updater_package`
 
 
 To update, copy the resulting directory to Flipper's SD card and navigate to `update.fuf` file in Archive app. 
 To update, copy the resulting directory to Flipper's SD card and navigate to `update.fuf` file in Archive app. 
 
 

+ 91 - 23
SConstruct

@@ -7,6 +7,7 @@
 # construction of certain targets behind command-line options.
 # construction of certain targets behind command-line options.
 
 
 import os
 import os
+import subprocess
 
 
 EnsurePythonVersion(3, 8)
 EnsurePythonVersion(3, 8)
 
 
@@ -33,8 +34,10 @@ coreenv["ROOT_DIR"] = Dir(".")
 
 
 # Create a separate "dist" environment and add construction envs to it
 # Create a separate "dist" environment and add construction envs to it
 distenv = coreenv.Clone(
 distenv = coreenv.Clone(
-    tools=["fbt_dist", "openocd", "blackmagic"],
-    OPENOCD_GDB_PIPE=["|openocd -c 'gdb_port pipe; log_output debug/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"],
+    tools=["fbt_dist", "openocd", "blackmagic", "jflash"],
+    OPENOCD_GDB_PIPE=[
+        "|openocd -c 'gdb_port pipe; log_output debug/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"
+    ],
     GDBOPTS_BASE=[
     GDBOPTS_BASE=[
         "-ex",
         "-ex",
         "target extended-remote ${GDBREMOTE}",
         "target extended-remote ${GDBREMOTE}",
@@ -61,6 +64,7 @@ distenv = coreenv.Clone(
         "-ex",
         "-ex",
         "compare-sections",
         "compare-sections",
     ],
     ],
+    JFLASHPROJECT="${ROOT_DIR.abspath}/debug/fw.jflash",
     ENV=os.environ,
     ENV=os.environ,
 )
 )
 
 
@@ -71,7 +75,9 @@ firmware_env = distenv.AddFwProject(
 )
 )
 
 
 # If enabled, initialize updater-related targets
 # If enabled, initialize updater-related targets
-if GetOption("fullenv"):
+if GetOption("fullenv") or any(
+    filter(lambda target: "updater" in target or "flash_usb" in target, BUILD_TARGETS)
+):
     updater_env = distenv.AddFwProject(
     updater_env = distenv.AddFwProject(
         base_env=coreenv,
         base_env=coreenv,
         fw_type="updater",
         fw_type="updater",
@@ -79,11 +85,11 @@ if GetOption("fullenv"):
     )
     )
 
 
     # Target for self-update package
     # Target for self-update package
-    dist_arguments = [
-        "-r",
-        '"${ROOT_DIR.abspath}/assets/resources"',
+    dist_basic_arguments = [
         "--bundlever",
         "--bundlever",
         '"${UPDATE_VERSION_STRING}"',
         '"${UPDATE_VERSION_STRING}"',
+    ]
+    dist_radio_arguments = [
         "--radio",
         "--radio",
         '"${ROOT_DIR.abspath}/${COPRO_STACK_BIN_DIR}/${COPRO_STACK_BIN}"',
         '"${ROOT_DIR.abspath}/${COPRO_STACK_BIN_DIR}/${COPRO_STACK_BIN}"',
         "--radiotype",
         "--radiotype",
@@ -92,16 +98,34 @@ if GetOption("fullenv"):
         "--obdata",
         "--obdata",
         '"${ROOT_DIR.abspath}/${COPRO_OB_DATA}"',
         '"${ROOT_DIR.abspath}/${COPRO_OB_DATA}"',
     ]
     ]
-    if distenv["UPDATE_SPLASH"]:
-        dist_arguments += [
+    dist_resource_arguments = [
+        "-r",
+        '"${ROOT_DIR.abspath}/assets/resources"',
+    ]
+    dist_splash_arguments = (
+        [
             "--splash",
             "--splash",
             distenv.subst("assets/slideshow/$UPDATE_SPLASH"),
             distenv.subst("assets/slideshow/$UPDATE_SPLASH"),
         ]
         ]
+        if distenv["UPDATE_SPLASH"]
+        else []
+    )
 
 
     selfupdate_dist = distenv.DistCommand(
     selfupdate_dist = distenv.DistCommand(
         "updater_package",
         "updater_package",
         (distenv["DIST_DEPENDS"], firmware_env["FW_RESOURCES"]),
         (distenv["DIST_DEPENDS"], firmware_env["FW_RESOURCES"]),
-        DIST_EXTRA=dist_arguments,
+        DIST_EXTRA=[
+            *dist_basic_arguments,
+            *dist_radio_arguments,
+            *dist_resource_arguments,
+            *dist_splash_arguments,
+        ],
+    )
+
+    selfupdate_min_dist = distenv.DistCommand(
+        "updater_minpackage",
+        distenv["DIST_DEPENDS"],
+        DIST_EXTRA=dist_basic_arguments,
     )
     )
 
 
     # Updater debug
     # Updater debug
@@ -121,18 +145,16 @@ if GetOption("fullenv"):
     )
     )
 
 
     # Installation over USB & CLI
     # Installation over USB & CLI
-    usb_update_package = distenv.UsbInstall(
-        "#build/usbinstall.flag",
-        (
-            distenv["DIST_DEPENDS"],
-            firmware_env["FW_RESOURCES"],
-            selfupdate_dist,
-        ),
+    usb_update_package = distenv.AddUsbFlashTarget(
+        "#build/usbinstall.flag", (firmware_env["FW_RESOURCES"], selfupdate_dist)
+    )
+    distenv.Alias("flash_usb_full", usb_update_package)
+
+    usb_minupdate_package = distenv.AddUsbFlashTarget(
+        "#build/minusbinstall.flag", (selfupdate_min_dist,)
     )
     )
-    if distenv["FORCE"]:
-        distenv.AlwaysBuild(usb_update_package)
-    distenv.Depends(usb_update_package, selfupdate_dist)
-    distenv.Alias("flash_usb", usb_update_package)
+    distenv.Alias("flash_usb", usb_minupdate_package)
+
 
 
 # Target for copying & renaming binaries to dist folder
 # Target for copying & renaming binaries to dist folder
 basic_dist = distenv.DistCommand("fw_dist", distenv["DIST_DEPENDS"])
 basic_dist = distenv.DistCommand("fw_dist", distenv["DIST_DEPENDS"])
@@ -147,8 +169,9 @@ distenv.Alias("copro_dist", copro_dist)
 
 
 firmware_flash = distenv.AddOpenOCDFlashTarget(firmware_env)
 firmware_flash = distenv.AddOpenOCDFlashTarget(firmware_env)
 distenv.Alias("flash", firmware_flash)
 distenv.Alias("flash", firmware_flash)
-if distenv["FORCE"]:
-    distenv.AlwaysBuild(firmware_flash)
+
+firmware_jflash = distenv.AddJFlashTarget(firmware_env)
+distenv.Alias("jflash", firmware_jflash)
 
 
 firmware_bm_flash = distenv.PhonyTarget(
 firmware_bm_flash = distenv.PhonyTarget(
     "flash_blackmagic",
     "flash_blackmagic",
@@ -209,10 +232,55 @@ distenv.PhonyTarget(
     LINT_SOURCES=firmware_env["LINT_SOURCES"],
     LINT_SOURCES=firmware_env["LINT_SOURCES"],
 )
 )
 
 
+# PY_LINT_SOURCES contains recursively-built modules' SConscript files + application manifests
+# Here we add additional Python files residing in repo root
+firmware_env.Append(
+    PY_LINT_SOURCES=[
+        # Py code folders
+        "site_scons",
+        "scripts",
+        # Extra files
+        "applications/extapps.scons",
+        "SConstruct",
+        "firmware.scons",
+        "fbt_options.py",
+    ]
+)
 
 
-# Find blackmagic probe
+
+black_commandline = "@${PYTHON3} -m black ${PY_BLACK_ARGS} ${PY_LINT_SOURCES}"
+black_base_args = ["--include", '"\\.scons|\\.py|SConscript|SConstruct"']
+
+distenv.PhonyTarget(
+    "lint_py",
+    black_commandline,
+    PY_BLACK_ARGS=[
+        "--check",
+        "--diff",
+        *black_base_args,
+    ],
+    PY_LINT_SOURCES=firmware_env["PY_LINT_SOURCES"],
+)
 
 
+distenv.PhonyTarget(
+    "format_py",
+    black_commandline,
+    PY_BLACK_ARGS=black_base_args,
+    PY_LINT_SOURCES=firmware_env["PY_LINT_SOURCES"],
+)
+
+# Start Flipper CLI via PySerial's miniterm
+distenv.PhonyTarget("cli", "${PYTHON3} scripts/serial_cli.py")
+
+
+# Find blackmagic probe
 distenv.PhonyTarget(
 distenv.PhonyTarget(
     "get_blackmagic",
     "get_blackmagic",
     "@echo $( ${BLACKMAGIC_ADDR} $)",
     "@echo $( ${BLACKMAGIC_ADDR} $)",
 )
 )
+
+# Prepare vscode environment
+vscode_dist = distenv.Install("#.vscode", distenv.Glob("#.vscode/example/*"))
+distenv.Precious(vscode_dist)
+distenv.NoClean(vscode_dist)
+distenv.Alias("vscode_dist", vscode_dist)

+ 8 - 8
applications/about/about.c

@@ -45,7 +45,7 @@ static DialogMessageButton compliance_screen(DialogsApp* dialogs, DialogMessage*
     DialogMessageButton result;
     DialogMessageButton result;
 
 
     const char* screen_text = "For all compliance\n"
     const char* screen_text = "For all compliance\n"
-                              "certificates please visit\n"
+                              "certificates please visit:\n"
                               "www.flipp.dev/compliance";
                               "www.flipp.dev/compliance";
 
 
     dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop);
     dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop);
@@ -91,13 +91,13 @@ static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage*
         furi_hal_version_get_hw_region_name(),
         furi_hal_version_get_hw_region_name(),
         my_name ? my_name : "Unknown");
         my_name ? my_name : "Unknown");
 
 
-    string_cat_printf(buffer, "Serial number:\n");
+    string_cat_printf(buffer, "Serial Number:\n");
     const uint8_t* uid = furi_hal_version_uid();
     const uint8_t* uid = furi_hal_version_uid();
     for(size_t i = 0; i < furi_hal_version_uid_size(); i++) {
     for(size_t i = 0; i < furi_hal_version_uid_size(); i++) {
         string_cat_printf(buffer, "%02X", uid[i]);
         string_cat_printf(buffer, "%02X", uid[i]);
     }
     }
 
 
-    dialog_message_set_header(message, "HW Version info:", 0, 0, AlignLeft, AlignTop);
+    dialog_message_set_header(message, "HW Version Info:", 0, 0, AlignLeft, AlignTop);
     dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop);
     dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop);
     result = dialog_message_show(dialogs, message);
     result = dialog_message_show(dialogs, message);
     dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
     dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
@@ -133,7 +133,7 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage*
             version_get_gitbranch(ver));
             version_get_gitbranch(ver));
     }
     }
 
 
-    dialog_message_set_header(message, "FW Version info:", 0, 0, AlignLeft, AlignTop);
+    dialog_message_set_header(message, "FW Version Info:", 0, 0, AlignLeft, AlignTop);
     dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop);
     dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop);
     result = dialog_message_show(dialogs, message);
     result = dialog_message_show(dialogs, message);
     dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
     dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
@@ -156,10 +156,10 @@ const size_t about_screens_count = sizeof(about_screens) / sizeof(AboutDialogScr
 
 
 int32_t about_settings_app(void* p) {
 int32_t about_settings_app(void* p) {
     UNUSED(p);
     UNUSED(p);
-    DialogsApp* dialogs = furi_record_open("dialogs");
+    DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
     DialogMessage* message = dialog_message_alloc();
     DialogMessage* message = dialog_message_alloc();
 
 
-    Gui* gui = furi_record_open("gui");
+    Gui* gui = furi_record_open(RECORD_GUI);
     ViewDispatcher* view_dispatcher = view_dispatcher_alloc();
     ViewDispatcher* view_dispatcher = view_dispatcher_alloc();
     EmptyScreen* empty_screen = empty_screen_alloc();
     EmptyScreen* empty_screen = empty_screen_alloc();
     const uint32_t empty_screen_index = 0;
     const uint32_t empty_screen_index = 0;
@@ -198,12 +198,12 @@ int32_t about_settings_app(void* p) {
     }
     }
 
 
     dialog_message_free(message);
     dialog_message_free(message);
-    furi_record_close("dialogs");
+    furi_record_close(RECORD_DIALOGS);
 
 
     view_dispatcher_remove_view(view_dispatcher, empty_screen_index);
     view_dispatcher_remove_view(view_dispatcher, empty_screen_index);
     view_dispatcher_free(view_dispatcher);
     view_dispatcher_free(view_dispatcher);
     empty_screen_free(empty_screen);
     empty_screen_free(empty_screen);
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
 
 
     return 0;
     return 0;
 }
 }

+ 2 - 2
applications/archive/archive.c

@@ -16,7 +16,7 @@ bool archive_back_event_callback(void* context) {
 ArchiveApp* archive_alloc() {
 ArchiveApp* archive_alloc() {
     ArchiveApp* archive = malloc(sizeof(ArchiveApp));
     ArchiveApp* archive = malloc(sizeof(ArchiveApp));
 
 
-    archive->gui = furi_record_open("gui");
+    archive->gui = furi_record_open(RECORD_GUI);
     archive->text_input = text_input_alloc();
     archive->text_input = text_input_alloc();
     string_init(archive->fav_move_str);
     string_init(archive->fav_move_str);
 
 
@@ -62,7 +62,7 @@ void archive_free(ArchiveApp* archive) {
 
 
     text_input_free(archive->text_input);
     text_input_free(archive->text_input);
 
 
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
     archive->gui = NULL;
     archive->gui = NULL;
 
 
     free(archive);
     free(archive);

+ 9 - 8
applications/archive/helpers/archive_apps.c

@@ -29,21 +29,22 @@ bool archive_app_is_available(void* context, const char* path) {
 
 
     if(app == ArchiveAppTypeU2f) {
     if(app == ArchiveAppTypeU2f) {
         bool file_exists = false;
         bool file_exists = false;
-        Storage* fs_api = furi_record_open("storage");
+        Storage* fs_api = furi_record_open(RECORD_STORAGE);
         File* file = storage_file_alloc(fs_api);
         File* file = storage_file_alloc(fs_api);
 
 
-        file_exists = storage_file_open(file, "/any/u2f/key.u2f", FSAM_READ, FSOM_OPEN_EXISTING);
+        file_exists =
+            storage_file_open(file, ANY_PATH("u2f/key.u2f"), FSAM_READ, FSOM_OPEN_EXISTING);
         if(file_exists) {
         if(file_exists) {
             storage_file_close(file);
             storage_file_close(file);
             file_exists =
             file_exists =
-                storage_file_open(file, "/any/u2f/cnt.u2f", FSAM_READ, FSOM_OPEN_EXISTING);
+                storage_file_open(file, ANY_PATH("u2f/cnt.u2f"), FSAM_READ, FSOM_OPEN_EXISTING);
             if(file_exists) {
             if(file_exists) {
                 storage_file_close(file);
                 storage_file_close(file);
             }
             }
         }
         }
 
 
         storage_file_free(file);
         storage_file_free(file);
-        furi_record_close("storage");
+        furi_record_close(RECORD_STORAGE);
 
 
         return file_exists;
         return file_exists;
     } else {
     } else {
@@ -77,10 +78,10 @@ void archive_app_delete_file(void* context, const char* path) {
     bool res = false;
     bool res = false;
 
 
     if(app == ArchiveAppTypeU2f) {
     if(app == ArchiveAppTypeU2f) {
-        Storage* fs_api = furi_record_open("storage");
-        res = (storage_common_remove(fs_api, "/any/u2f/key.u2f") == FSE_OK);
-        res |= (storage_common_remove(fs_api, "/any/u2f/cnt.u2f") == FSE_OK);
-        furi_record_close("storage");
+        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);
+        furi_record_close(RECORD_STORAGE);
 
 
         if(archive_is_favorite("/app:u2f/U2F Token")) {
         if(archive_is_favorite("/app:u2f/U2F Token")) {
             archive_favorites_delete("/app:u2f/U2F Token");
             archive_favorites_delete("/app:u2f/U2F Token");

+ 3 - 3
applications/archive/helpers/archive_browser.c

@@ -391,18 +391,18 @@ void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) {
 }
 }
 
 
 static bool archive_is_dir_exists(string_t path) {
 static bool archive_is_dir_exists(string_t path) {
-    if(string_equal_str_p(path, "/any")) {
+    if(string_equal_str_p(path, STORAGE_ANY_PATH_PREFIX)) {
         return true;
         return true;
     }
     }
     bool state = false;
     bool state = false;
     FileInfo file_info;
     FileInfo file_info;
-    Storage* storage = furi_record_open("storage");
+    Storage* storage = furi_record_open(RECORD_STORAGE);
     if(storage_common_stat(storage, string_get_cstr(path), &file_info) == FSE_OK) {
     if(storage_common_stat(storage, string_get_cstr(path), &file_info) == FSE_OK) {
         if(file_info.flags & FSF_DIRECTORY) {
         if(file_info.flags & FSF_DIRECTORY) {
             state = true;
             state = true;
         }
         }
     }
     }
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
     return state;
     return state;
 }
 }
 
 

+ 8 - 7
applications/archive/helpers/archive_browser.h

@@ -1,6 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "../archive_i.h"
 #include "../archive_i.h"
+#include <storage/storage.h>
 
 
 #define TAB_RIGHT InputKeyRight // Default tab swith direction
 #define TAB_RIGHT InputKeyRight // Default tab swith direction
 #define TAB_DEFAULT ArchiveTabFavorites // Start tab
 #define TAB_DEFAULT ArchiveTabFavorites // Start tab
@@ -8,14 +9,14 @@
 
 
 static const char* tab_default_paths[] = {
 static const char* tab_default_paths[] = {
     [ArchiveTabFavorites] = "/app:favorites",
     [ArchiveTabFavorites] = "/app:favorites",
-    [ArchiveTabIButton] = "/any/ibutton",
-    [ArchiveTabNFC] = "/any/nfc",
-    [ArchiveTabSubGhz] = "/any/subghz",
-    [ArchiveTabLFRFID] = "/any/lfrfid",
-    [ArchiveTabInfrared] = "/any/infrared",
-    [ArchiveTabBadUsb] = "/any/badusb",
+    [ArchiveTabIButton] = ANY_PATH("ibutton"),
+    [ArchiveTabNFC] = ANY_PATH("nfc"),
+    [ArchiveTabSubGhz] = ANY_PATH("subghz"),
+    [ArchiveTabLFRFID] = ANY_PATH("lfrfid"),
+    [ArchiveTabInfrared] = ANY_PATH("infrared"),
+    [ArchiveTabBadUsb] = ANY_PATH("badusb"),
     [ArchiveTabU2f] = "/app:u2f",
     [ArchiveTabU2f] = "/app:u2f",
-    [ArchiveTabBrowser] = "/any",
+    [ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX,
 };
 };
 
 
 static const char* known_ext[] = {
 static const char* known_ext[] = {

+ 14 - 14
applications/archive/helpers/archive_favorites.c

@@ -49,7 +49,7 @@ static bool archive_favorites_read_line(File* file, string_t str_result) {
 uint16_t archive_favorites_count(void* context) {
 uint16_t archive_favorites_count(void* context) {
     furi_assert(context);
     furi_assert(context);
 
 
-    Storage* fs_api = furi_record_open("storage");
+    Storage* fs_api = furi_record_open(RECORD_STORAGE);
     File* file = storage_file_alloc(fs_api);
     File* file = storage_file_alloc(fs_api);
 
 
     string_t buffer;
     string_t buffer;
@@ -74,7 +74,7 @@ uint16_t archive_favorites_count(void* context) {
 
 
     string_clear(buffer);
     string_clear(buffer);
     storage_file_free(file);
     storage_file_free(file);
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 
 
     return lines;
     return lines;
 }
 }
@@ -82,7 +82,7 @@ uint16_t archive_favorites_count(void* context) {
 static bool archive_favourites_rescan() {
 static bool archive_favourites_rescan() {
     string_t buffer;
     string_t buffer;
     string_init(buffer);
     string_init(buffer);
-    Storage* fs_api = furi_record_open("storage");
+    Storage* fs_api = furi_record_open(RECORD_STORAGE);
     File* file = storage_file_alloc(fs_api);
     File* file = storage_file_alloc(fs_api);
     File* fav_item_file = storage_file_alloc(fs_api);
     File* fav_item_file = storage_file_alloc(fs_api);
 
 
@@ -122,7 +122,7 @@ static bool archive_favourites_rescan() {
 
 
     storage_file_free(file);
     storage_file_free(file);
     storage_file_free(fav_item_file);
     storage_file_free(fav_item_file);
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 
 
     return result;
     return result;
 }
 }
@@ -131,7 +131,7 @@ bool archive_favorites_read(void* context) {
     furi_assert(context);
     furi_assert(context);
 
 
     ArchiveBrowserView* browser = context;
     ArchiveBrowserView* browser = context;
-    Storage* fs_api = furi_record_open("storage");
+    Storage* fs_api = furi_record_open(RECORD_STORAGE);
     File* file = storage_file_alloc(fs_api);
     File* file = storage_file_alloc(fs_api);
     File* fav_item_file = storage_file_alloc(fs_api);
     File* fav_item_file = storage_file_alloc(fs_api);
 
 
@@ -184,7 +184,7 @@ bool archive_favorites_read(void* context) {
     string_clear(buffer);
     string_clear(buffer);
     storage_file_free(file);
     storage_file_free(file);
     storage_file_free(fav_item_file);
     storage_file_free(fav_item_file);
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 
 
     archive_set_item_count(browser, file_count);
     archive_set_item_count(browser, file_count);
 
 
@@ -204,7 +204,7 @@ bool archive_favorites_delete(const char* format, ...) {
     va_end(args);
     va_end(args);
 
 
     string_init(buffer);
     string_init(buffer);
-    Storage* fs_api = furi_record_open("storage");
+    Storage* fs_api = furi_record_open(RECORD_STORAGE);
     File* file = storage_file_alloc(fs_api);
     File* file = storage_file_alloc(fs_api);
 
 
     bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
     bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
@@ -233,7 +233,7 @@ bool archive_favorites_delete(const char* format, ...) {
     storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH);
     storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH);
 
 
     storage_file_free(file);
     storage_file_free(file);
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 
 
     return result;
     return result;
 }
 }
@@ -247,7 +247,7 @@ bool archive_is_favorite(const char* format, ...) {
     va_end(args);
     va_end(args);
 
 
     string_init(buffer);
     string_init(buffer);
-    Storage* fs_api = furi_record_open("storage");
+    Storage* fs_api = furi_record_open(RECORD_STORAGE);
     File* file = storage_file_alloc(fs_api);
     File* file = storage_file_alloc(fs_api);
 
 
     bool found = false;
     bool found = false;
@@ -272,7 +272,7 @@ bool archive_is_favorite(const char* format, ...) {
     string_clear(buffer);
     string_clear(buffer);
     string_clear(filename);
     string_clear(filename);
     storage_file_free(file);
     storage_file_free(file);
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 
 
     return found;
     return found;
 }
 }
@@ -281,7 +281,7 @@ bool archive_favorites_rename(const char* src, const char* dst) {
     furi_assert(src);
     furi_assert(src);
     furi_assert(dst);
     furi_assert(dst);
 
 
-    Storage* fs_api = furi_record_open("storage");
+    Storage* fs_api = furi_record_open(RECORD_STORAGE);
     File* file = storage_file_alloc(fs_api);
     File* file = storage_file_alloc(fs_api);
 
 
     string_t path;
     string_t path;
@@ -318,7 +318,7 @@ bool archive_favorites_rename(const char* src, const char* dst) {
     storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH);
     storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH);
 
 
     storage_file_free(file);
     storage_file_free(file);
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 
 
     return result;
     return result;
 }
 }
@@ -333,7 +333,7 @@ void archive_favorites_save(void* context) {
     furi_assert(context);
     furi_assert(context);
 
 
     ArchiveBrowserView* browser = context;
     ArchiveBrowserView* browser = context;
-    Storage* fs_api = furi_record_open("storage");
+    Storage* fs_api = furi_record_open(RECORD_STORAGE);
     File* file = storage_file_alloc(fs_api);
     File* file = storage_file_alloc(fs_api);
 
 
     for(size_t i = 0; i < archive_file_get_array_size(browser); i++) {
     for(size_t i = 0; i < archive_file_get_array_size(browser); i++) {
@@ -346,5 +346,5 @@ void archive_favorites_save(void* context) {
     storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH);
     storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH);
 
 
     storage_file_free(file);
     storage_file_free(file);
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 }
 }

+ 2 - 2
applications/archive/helpers/archive_favorites.h

@@ -2,8 +2,8 @@
 
 
 #include <storage/storage.h>
 #include <storage/storage.h>
 
 
-#define ARCHIVE_FAV_PATH "/any/favorites.txt"
-#define ARCHIVE_FAV_TEMP_PATH "/any/favorites.tmp"
+#define ARCHIVE_FAV_PATH ANY_PATH("favorites.txt")
+#define ARCHIVE_FAV_TEMP_PATH ANY_PATH("favorites.tmp")
 
 
 uint16_t archive_favorites_count(void* context);
 uint16_t archive_favorites_count(void* context);
 bool archive_favorites_read(void* context);
 bool archive_favorites_read(void* context);

+ 4 - 4
applications/archive/helpers/archive_files.c

@@ -60,7 +60,7 @@ void archive_file_append(const char* path, const char* format, ...) {
     string_init_vprintf(string, format, args);
     string_init_vprintf(string, format, args);
     va_end(args);
     va_end(args);
 
 
-    Storage* fs_api = furi_record_open("storage");
+    Storage* fs_api = furi_record_open(RECORD_STORAGE);
     File* file = storage_file_alloc(fs_api);
     File* file = storage_file_alloc(fs_api);
 
 
     bool res = storage_file_open(file, path, FSAM_WRITE, FSOM_OPEN_APPEND);
     bool res = storage_file_open(file, path, FSAM_WRITE, FSOM_OPEN_APPEND);
@@ -71,7 +71,7 @@ void archive_file_append(const char* path, const char* format, ...) {
 
 
     storage_file_close(file);
     storage_file_close(file);
     storage_file_free(file);
     storage_file_free(file);
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 }
 }
 
 
 void archive_delete_file(void* context, const char* format, ...) {
 void archive_delete_file(void* context, const char* format, ...) {
@@ -84,7 +84,7 @@ void archive_delete_file(void* context, const char* format, ...) {
     va_end(args);
     va_end(args);
 
 
     ArchiveBrowserView* browser = context;
     ArchiveBrowserView* browser = context;
-    Storage* fs_api = furi_record_open("storage");
+    Storage* fs_api = furi_record_open(RECORD_STORAGE);
 
 
     FileInfo fileinfo;
     FileInfo fileinfo;
     storage_common_stat(fs_api, string_get_cstr(filename), &fileinfo);
     storage_common_stat(fs_api, string_get_cstr(filename), &fileinfo);
@@ -97,7 +97,7 @@ void archive_delete_file(void* context, const char* format, ...) {
         res = (storage_common_remove(fs_api, string_get_cstr(filename)) == FSE_OK);
         res = (storage_common_remove(fs_api, string_get_cstr(filename)) == FSE_OK);
     }
     }
 
 
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 
 
     if(archive_is_favorite("%s", string_get_cstr(filename))) {
     if(archive_is_favorite("%s", string_get_cstr(filename))) {
         archive_favorites_delete("%s", string_get_cstr(filename));
         archive_favorites_delete("%s", string_get_cstr(filename));

+ 14 - 15
applications/archive/scenes/archive_scene_browser.c

@@ -36,7 +36,7 @@ static void archive_loader_callback(const void* message, void* context) {
 
 
 static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selected) {
 static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selected) {
     UNUSED(browser);
     UNUSED(browser);
-    Loader* loader = furi_record_open("loader");
+    Loader* loader = furi_record_open(RECORD_LOADER);
 
 
     LoaderStatus status;
     LoaderStatus status;
     if(selected->is_app) {
     if(selected->is_app) {
@@ -54,7 +54,7 @@ static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selec
         FURI_LOG_E(TAG, "loader_start failed: %d", status);
         FURI_LOG_E(TAG, "loader_start failed: %d", status);
     }
     }
 
 
-    furi_record_close("loader");
+    furi_record_close(RECORD_LOADER);
 }
 }
 
 
 void archive_scene_browser_callback(ArchiveBrowserEvent event, void* context) {
 void archive_scene_browser_callback(ArchiveBrowserEvent event, void* context) {
@@ -71,10 +71,10 @@ void archive_scene_browser_on_enter(void* context) {
     archive_update_focus(browser, archive->text_store);
     archive_update_focus(browser, archive->text_store);
     view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewBrowser);
     view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewBrowser);
 
 
-    Loader* loader = furi_record_open("loader");
+    Loader* loader = furi_record_open(RECORD_LOADER);
     archive->loader_stop_subscription =
     archive->loader_stop_subscription =
         furi_pubsub_subscribe(loader_get_pubsub(loader), archive_loader_callback, archive);
         furi_pubsub_subscribe(loader_get_pubsub(loader), archive_loader_callback, archive);
-    furi_record_close("loader");
+    furi_record_close(RECORD_LOADER);
 
 
     uint32_t state = scene_manager_get_scene_state(archive->scene_manager, ArchiveAppSceneBrowser);
     uint32_t state = scene_manager_get_scene_state(archive->scene_manager, ArchiveAppSceneBrowser);
 
 
@@ -92,8 +92,6 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
     ArchiveBrowserView* browser = archive->browser;
     ArchiveBrowserView* browser = archive->browser;
     ArchiveFile_t* selected = archive_get_current_file(browser);
     ArchiveFile_t* selected = archive_get_current_file(browser);
 
 
-    const char* name = archive_get_name(browser);
-    bool known_app = archive_is_known_app(selected->type);
     bool favorites = archive_get_tab(browser) == ArchiveTabFavorites;
     bool favorites = archive_get_tab(browser) == ArchiveTabFavorites;
     bool consumed = false;
     bool consumed = false;
 
 
@@ -108,18 +106,19 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
             consumed = true;
             consumed = true;
             break;
             break;
         case ArchiveBrowserEventFileMenuRun:
         case ArchiveBrowserEventFileMenuRun:
-            if(known_app) {
+            if(archive_is_known_app(selected->type)) {
                 archive_run_in_app(browser, selected);
                 archive_run_in_app(browser, selected);
                 archive_show_file_menu(browser, false);
                 archive_show_file_menu(browser, false);
             }
             }
             consumed = true;
             consumed = true;
             break;
             break;
-        case ArchiveBrowserEventFileMenuPin:
+        case ArchiveBrowserEventFileMenuPin: {
+            const char* name = archive_get_name(browser);
             if(favorites) {
             if(favorites) {
                 archive_favorites_delete(name);
                 archive_favorites_delete(name);
                 archive_file_array_rm_selected(browser);
                 archive_file_array_rm_selected(browser);
                 archive_show_file_menu(browser, false);
                 archive_show_file_menu(browser, false);
-            } else if(known_app) {
+            } else if(archive_is_known_app(selected->type)) {
                 if(archive_is_favorite("%s", name)) {
                 if(archive_is_favorite("%s", name)) {
                     archive_favorites_delete("%s", name);
                     archive_favorites_delete("%s", name);
                 } else {
                 } else {
@@ -128,12 +127,12 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
                 archive_show_file_menu(browser, false);
                 archive_show_file_menu(browser, false);
             }
             }
             consumed = true;
             consumed = true;
-            break;
+        } break;
 
 
         case ArchiveBrowserEventFileMenuRename:
         case ArchiveBrowserEventFileMenuRename:
             if(favorites) {
             if(favorites) {
                 browser->callback(ArchiveBrowserEventEnterFavMove, browser->context);
                 browser->callback(ArchiveBrowserEventEnterFavMove, browser->context);
-            } else if((known_app) && (selected->is_app == false)) {
+            } else if((archive_is_known_app(selected->type)) && (selected->is_app == false)) {
                 archive_show_file_menu(browser, false);
                 archive_show_file_menu(browser, false);
                 scene_manager_set_scene_state(
                 scene_manager_set_scene_state(
                     archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH);
                     archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH);
@@ -196,10 +195,10 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
             if(!archive_is_home(browser)) {
             if(!archive_is_home(browser)) {
                 archive_leave_dir(browser);
                 archive_leave_dir(browser);
             } else {
             } else {
-                Loader* loader = furi_record_open("loader");
+                Loader* loader = furi_record_open(RECORD_LOADER);
                 furi_pubsub_unsubscribe(
                 furi_pubsub_unsubscribe(
                     loader_get_pubsub(loader), archive->loader_stop_subscription);
                     loader_get_pubsub(loader), archive->loader_stop_subscription);
-                furi_record_close("loader");
+                furi_record_close(RECORD_LOADER);
 
 
                 view_dispatcher_stop(archive->view_dispatcher);
                 view_dispatcher_stop(archive->view_dispatcher);
             }
             }
@@ -216,7 +215,7 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
 void archive_scene_browser_on_exit(void* context) {
 void archive_scene_browser_on_exit(void* context) {
     ArchiveApp* archive = (ArchiveApp*)context;
     ArchiveApp* archive = (ArchiveApp*)context;
 
 
-    Loader* loader = furi_record_open("loader");
+    Loader* loader = furi_record_open(RECORD_LOADER);
     furi_pubsub_unsubscribe(loader_get_pubsub(loader), archive->loader_stop_subscription);
     furi_pubsub_unsubscribe(loader_get_pubsub(loader), archive->loader_stop_subscription);
-    furi_record_close("loader");
+    furi_record_close(RECORD_LOADER);
 }
 }

+ 3 - 3
applications/archive/scenes/archive_scene_rename.c

@@ -37,7 +37,7 @@ void archive_scene_rename_on_enter(void* context) {
         false);
         false);
 
 
     ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
     ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
-        string_get_cstr(archive->browser->path), archive->file_extension, NULL);
+        string_get_cstr(archive->browser->path), archive->file_extension, "");
     text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
     text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
 
 
     string_clear(filename);
     string_clear(filename);
@@ -51,7 +51,7 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) {
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SCENE_RENAME_CUSTOM_EVENT) {
         if(event.event == SCENE_RENAME_CUSTOM_EVENT) {
-            Storage* fs_api = furi_record_open("storage");
+            Storage* fs_api = furi_record_open(RECORD_STORAGE);
 
 
             const char* path_src = archive_get_name(archive->browser);
             const char* path_src = archive_get_name(archive->browser);
             ArchiveFile_t* file = archive_get_current_file(archive->browser);
             ArchiveFile_t* file = archive_get_current_file(archive->browser);
@@ -62,7 +62,7 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) {
             string_cat_printf(path_dst, "/%s%s", archive->text_store, known_ext[file->type]);
             string_cat_printf(path_dst, "/%s%s", archive->text_store, known_ext[file->type]);
 
 
             storage_common_rename(fs_api, path_src, string_get_cstr(path_dst));
             storage_common_rename(fs_api, path_src, string_get_cstr(path_dst));
-            furi_record_close("storage");
+            furi_record_close(RECORD_STORAGE);
 
 
             if(file->fav) {
             if(file->fav) {
                 archive_favorites_rename(path_src, string_get_cstr(path_dst));
                 archive_favorites_rename(path_src, string_get_cstr(path_dst));

+ 7 - 8
applications/bad_usb/bad_usb_app.c

@@ -28,13 +28,13 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
 
 
     string_init(app->file_path);
     string_init(app->file_path);
 
 
-    if(arg != NULL) {
+    if(arg && strlen(arg)) {
         string_set_str(app->file_path, arg);
         string_set_str(app->file_path, arg);
     }
     }
 
 
-    app->gui = furi_record_open("gui");
-    app->notifications = furi_record_open("notification");
-    app->dialogs = furi_record_open("dialogs");
+    app->gui = furi_record_open(RECORD_GUI);
+    app->notifications = furi_record_open(RECORD_NOTIFICATION);
+    app->dialogs = furi_record_open(RECORD_DIALOGS);
 
 
     app->view_dispatcher = view_dispatcher_alloc();
     app->view_dispatcher = view_dispatcher_alloc();
     view_dispatcher_enable_queue(app->view_dispatcher);
     view_dispatcher_enable_queue(app->view_dispatcher);
@@ -79,7 +79,6 @@ void bad_usb_app_free(BadUsbApp* app) {
     furi_assert(app);
     furi_assert(app);
 
 
     // Views
     // Views
-    view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewFileSelect);
     view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork);
     view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork);
     bad_usb_free(app->bad_usb_view);
     bad_usb_free(app->bad_usb_view);
 
 
@@ -92,9 +91,9 @@ void bad_usb_app_free(BadUsbApp* app) {
     scene_manager_free(app->scene_manager);
     scene_manager_free(app->scene_manager);
 
 
     // Close records
     // Close records
-    furi_record_close("gui");
-    furi_record_close("notification");
-    furi_record_close("dialogs");
+    furi_record_close(RECORD_GUI);
+    furi_record_close(RECORD_NOTIFICATION);
+    furi_record_close(RECORD_DIALOGS);
 
 
     string_clear(app->file_path);
     string_clear(app->file_path);
 
 

+ 1 - 2
applications/bad_usb/bad_usb_app_i.h

@@ -14,7 +14,7 @@
 #include <gui/modules/widget.h>
 #include <gui/modules/widget.h>
 #include "views/bad_usb_view.h"
 #include "views/bad_usb_view.h"
 
 
-#define BAD_USB_APP_PATH_FOLDER "/any/badusb"
+#define BAD_USB_APP_PATH_FOLDER ANY_PATH("badusb")
 #define BAD_USB_APP_EXTENSION ".txt"
 #define BAD_USB_APP_EXTENSION ".txt"
 
 
 typedef enum {
 typedef enum {
@@ -38,6 +38,5 @@ struct BadUsbApp {
 
 
 typedef enum {
 typedef enum {
     BadUsbAppViewError,
     BadUsbAppViewError,
-    BadUsbAppViewFileSelect,
     BadUsbAppViewWork,
     BadUsbAppViewWork,
 } BadUsbAppView;
 } BadUsbAppView;

+ 1 - 1
applications/bad_usb/bad_usb_script.c

@@ -455,7 +455,7 @@ static int32_t bad_usb_worker(void* context) {
     FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
     FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
 
 
     FURI_LOG_I(WORKER_TAG, "Init");
     FURI_LOG_I(WORKER_TAG, "Init");
-    File* script_file = storage_file_alloc(furi_record_open("storage"));
+    File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
     string_init(bad_usb->line);
     string_init(bad_usb->line);
     string_init(bad_usb->line_prev);
     string_init(bad_usb->line_prev);
 
 

+ 9 - 7
applications/bad_usb/scenes/bad_usb_scene_error.c

@@ -27,20 +27,22 @@ void bad_usb_scene_error_on_enter(void* context) {
             AlignTop,
             AlignTop,
             FontSecondary,
             FontSecondary,
             "No SD card or\napp data found.\nThis app will not\nwork without\nrequired files.");
             "No SD card or\napp data found.\nThis app will not\nwork without\nrequired files.");
+        widget_add_button_element(
+            app->widget, GuiButtonTypeLeft, "Back", bad_usb_scene_error_event_callback, app);
     } else if(app->error == BadUsbAppErrorCloseRpc) {
     } else if(app->error == BadUsbAppErrorCloseRpc) {
+        widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
+        widget_add_string_multiline_element(
+            app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nis active!");
         widget_add_string_multiline_element(
         widget_add_string_multiline_element(
             app->widget,
             app->widget,
-            63,
-            10,
-            AlignCenter,
+            3,
+            30,
+            AlignLeft,
             AlignTop,
             AlignTop,
             FontSecondary,
             FontSecondary,
-            "Disconnect from\ncompanion app\nto use this function");
+            "Disconnect from\nPC or phone to\nuse this function.");
     }
     }
 
 
-    widget_add_button_element(
-        app->widget, GuiButtonTypeLeft, "Back", bad_usb_scene_error_event_callback, app);
-
     view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewError);
     view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewError);
 }
 }
 
 

+ 13 - 13
applications/bt/bt_cli.c

@@ -33,7 +33,7 @@ static void bt_cli_command_carrier_tx(Cli* cli, string_t args, void* context) {
             break;
             break;
         }
         }
 
 
-        Bt* bt = furi_record_open("bt");
+        Bt* bt = furi_record_open(RECORD_BT);
         bt_disconnect(bt);
         bt_disconnect(bt);
         furi_hal_bt_reinit();
         furi_hal_bt_reinit();
         printf("Transmitting carrier at %d channel at %d dB power\r\n", channel, power);
         printf("Transmitting carrier at %d channel at %d dB power\r\n", channel, power);
@@ -46,7 +46,7 @@ static void bt_cli_command_carrier_tx(Cli* cli, string_t args, void* context) {
         furi_hal_bt_stop_tone_tx();
         furi_hal_bt_stop_tone_tx();
 
 
         bt_set_profile(bt, BtProfileSerial);
         bt_set_profile(bt, BtProfileSerial);
-        furi_record_close("bt");
+        furi_record_close(RECORD_BT);
     } while(false);
     } while(false);
 }
 }
 
 
@@ -60,7 +60,7 @@ static void bt_cli_command_carrier_rx(Cli* cli, string_t args, void* context) {
             break;
             break;
         }
         }
 
 
-        Bt* bt = furi_record_open("bt");
+        Bt* bt = furi_record_open(RECORD_BT);
         bt_disconnect(bt);
         bt_disconnect(bt);
         furi_hal_bt_reinit();
         furi_hal_bt_reinit();
         printf("Receiving carrier at %d channel\r\n", channel);
         printf("Receiving carrier at %d channel\r\n", channel);
@@ -77,7 +77,7 @@ static void bt_cli_command_carrier_rx(Cli* cli, string_t args, void* context) {
         furi_hal_bt_stop_packet_test();
         furi_hal_bt_stop_packet_test();
 
 
         bt_set_profile(bt, BtProfileSerial);
         bt_set_profile(bt, BtProfileSerial);
-        furi_record_close("bt");
+        furi_record_close(RECORD_BT);
     } while(false);
     } while(false);
 }
 }
 
 
@@ -107,7 +107,7 @@ static void bt_cli_command_packet_tx(Cli* cli, string_t args, void* context) {
             break;
             break;
         }
         }
 
 
-        Bt* bt = furi_record_open("bt");
+        Bt* bt = furi_record_open(RECORD_BT);
         bt_disconnect(bt);
         bt_disconnect(bt);
         furi_hal_bt_reinit();
         furi_hal_bt_reinit();
         printf(
         printf(
@@ -125,7 +125,7 @@ static void bt_cli_command_packet_tx(Cli* cli, string_t args, void* context) {
         printf("Transmitted %lu packets", furi_hal_bt_get_transmitted_packets());
         printf("Transmitted %lu packets", furi_hal_bt_get_transmitted_packets());
 
 
         bt_set_profile(bt, BtProfileSerial);
         bt_set_profile(bt, BtProfileSerial);
-        furi_record_close("bt");
+        furi_record_close(RECORD_BT);
     } while(false);
     } while(false);
 }
 }
 
 
@@ -144,7 +144,7 @@ static void bt_cli_command_packet_rx(Cli* cli, string_t args, void* context) {
             break;
             break;
         }
         }
 
 
-        Bt* bt = furi_record_open("bt");
+        Bt* bt = furi_record_open(RECORD_BT);
         bt_disconnect(bt);
         bt_disconnect(bt);
         furi_hal_bt_reinit();
         furi_hal_bt_reinit();
         printf("Receiving packets at %d channel at %d M datarate\r\n", channel, datarate);
         printf("Receiving packets at %d channel at %d M datarate\r\n", channel, datarate);
@@ -160,7 +160,7 @@ static void bt_cli_command_packet_rx(Cli* cli, string_t args, void* context) {
         printf("Received %hu packets", packets_received);
         printf("Received %hu packets", packets_received);
 
 
         bt_set_profile(bt, BtProfileSerial);
         bt_set_profile(bt, BtProfileSerial);
-        furi_record_close("bt");
+        furi_record_close(RECORD_BT);
     } while(false);
     } while(false);
 }
 }
 
 
@@ -180,7 +180,7 @@ static void bt_cli_print_usage() {
 
 
 static void bt_cli(Cli* cli, string_t args, void* context) {
 static void bt_cli(Cli* cli, string_t args, void* context) {
     UNUSED(context);
     UNUSED(context);
-    furi_record_open("bt");
+    furi_record_open(RECORD_BT);
 
 
     string_t cmd;
     string_t cmd;
     string_init(cmd);
     string_init(cmd);
@@ -223,14 +223,14 @@ static void bt_cli(Cli* cli, string_t args, void* context) {
     }
     }
 
 
     string_clear(cmd);
     string_clear(cmd);
-    furi_record_close("bt");
+    furi_record_close(RECORD_BT);
 }
 }
 
 
 void bt_on_system_start() {
 void bt_on_system_start() {
 #ifdef SRV_CLI
 #ifdef SRV_CLI
-    Cli* cli = furi_record_open("cli");
-    cli_add_command(cli, "bt", CliCommandFlagDefault, bt_cli, NULL);
-    furi_record_close("cli");
+    Cli* cli = furi_record_open(RECORD_CLI);
+    cli_add_command(cli, RECORD_BT, CliCommandFlagDefault, bt_cli, NULL);
+    furi_record_close(RECORD_CLI);
 #else
 #else
     UNUSED(bt_cli);
     UNUSED(bt_cli);
 #endif
 #endif

+ 3 - 3
applications/bt/bt_debug_app/bt_debug_app.c

@@ -35,7 +35,7 @@ BtDebugApp* bt_debug_app_alloc() {
     bt_settings_load(&app->settings);
     bt_settings_load(&app->settings);
 
 
     // Gui
     // Gui
-    app->gui = furi_record_open("gui");
+    app->gui = furi_record_open(RECORD_GUI);
 
 
     // View dispatcher
     // View dispatcher
     app->view_dispatcher = view_dispatcher_alloc();
     app->view_dispatcher = view_dispatcher_alloc();
@@ -88,7 +88,7 @@ void bt_debug_app_free(BtDebugApp* app) {
     view_dispatcher_free(app->view_dispatcher);
     view_dispatcher_free(app->view_dispatcher);
 
 
     // Close gui record
     // Close gui record
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
     app->gui = NULL;
     app->gui = NULL;
 
 
     // Free rest
     // Free rest
@@ -99,7 +99,7 @@ int32_t bt_debug_app(void* p) {
     UNUSED(p);
     UNUSED(p);
     if(!furi_hal_bt_is_testing_supported()) {
     if(!furi_hal_bt_is_testing_supported()) {
         FURI_LOG_E(TAG, "Incorrect radio stack: radio testing fetures are absent.");
         FURI_LOG_E(TAG, "Incorrect radio stack: radio testing fetures are absent.");
-        DialogsApp* dialogs = furi_record_open("dialogs");
+        DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
         dialog_message_show_storage_error(dialogs, "Incorrect\nRadioStack");
         dialog_message_show_storage_error(dialogs, "Incorrect\nRadioStack");
         return 255;
         return 255;
     }
     }

+ 8 - 8
applications/bt/bt_hid_app/bt_hid.c

@@ -70,13 +70,13 @@ BtHid* bt_hid_app_alloc() {
     BtHid* app = malloc(sizeof(BtHid));
     BtHid* app = malloc(sizeof(BtHid));
 
 
     // Gui
     // Gui
-    app->gui = furi_record_open("gui");
+    app->gui = furi_record_open(RECORD_GUI);
 
 
     // Bt
     // Bt
-    app->bt = furi_record_open("bt");
+    app->bt = furi_record_open(RECORD_BT);
 
 
     // Notifications
     // Notifications
-    app->notifications = furi_record_open("notification");
+    app->notifications = furi_record_open(RECORD_NOTIFICATION);
 
 
     // View dispatcher
     // View dispatcher
     app->view_dispatcher = view_dispatcher_alloc();
     app->view_dispatcher = view_dispatcher_alloc();
@@ -90,7 +90,7 @@ BtHid* bt_hid_app_alloc() {
     submenu_add_item(
     submenu_add_item(
         app->submenu, "Keyboard", BtHidSubmenuIndexKeyboard, bt_hid_submenu_callback, app);
         app->submenu, "Keyboard", BtHidSubmenuIndexKeyboard, bt_hid_submenu_callback, app);
     submenu_add_item(
     submenu_add_item(
-        app->submenu, "Media player", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app);
+        app->submenu, "Media Player", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app);
     submenu_add_item(app->submenu, "Mouse", BtHidSubmenuIndexMouse, bt_hid_submenu_callback, app);
     submenu_add_item(app->submenu, "Mouse", BtHidSubmenuIndexMouse, bt_hid_submenu_callback, app);
     view_set_previous_callback(submenu_get_view(app->submenu), bt_hid_exit);
     view_set_previous_callback(submenu_get_view(app->submenu), bt_hid_exit);
     view_dispatcher_add_view(
     view_dispatcher_add_view(
@@ -103,7 +103,7 @@ BtHid* bt_hid_app_alloc() {
     dialog_ex_set_left_button_text(app->dialog, "Exit");
     dialog_ex_set_left_button_text(app->dialog, "Exit");
     dialog_ex_set_right_button_text(app->dialog, "Stay");
     dialog_ex_set_right_button_text(app->dialog, "Stay");
     dialog_ex_set_center_button_text(app->dialog, "Menu");
     dialog_ex_set_center_button_text(app->dialog, "Menu");
-    dialog_ex_set_header(app->dialog, "Close current app?", 16, 12, AlignLeft, AlignTop);
+    dialog_ex_set_header(app->dialog, "Close Current App?", 16, 12, AlignLeft, AlignTop);
     view_dispatcher_add_view(
     view_dispatcher_add_view(
         app->view_dispatcher, BtHidViewExitConfirm, dialog_ex_get_view(app->dialog));
         app->view_dispatcher, BtHidViewExitConfirm, dialog_ex_get_view(app->dialog));
 
 
@@ -161,11 +161,11 @@ void bt_hid_app_free(BtHid* app) {
     view_dispatcher_free(app->view_dispatcher);
     view_dispatcher_free(app->view_dispatcher);
 
 
     // Close records
     // Close records
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
     app->gui = NULL;
     app->gui = NULL;
-    furi_record_close("notification");
+    furi_record_close(RECORD_NOTIFICATION);
     app->notifications = NULL;
     app->notifications = NULL;
-    furi_record_close("bt");
+    furi_record_close(RECORD_BT);
     app->bt = NULL;
     app->bt = NULL;
 
 
     // Free rest
     // Free rest

+ 9 - 8
applications/bt/bt_service/bt.c

@@ -124,23 +124,23 @@ Bt* bt_alloc() {
     // Pin code view port
     // Pin code view port
     bt->pin_code_view_port = bt_pin_code_view_port_alloc(bt);
     bt->pin_code_view_port = bt_pin_code_view_port_alloc(bt);
     // Notification
     // Notification
-    bt->notification = furi_record_open("notification");
+    bt->notification = furi_record_open(RECORD_NOTIFICATION);
     // Gui
     // Gui
-    bt->gui = furi_record_open("gui");
+    bt->gui = furi_record_open(RECORD_GUI);
     gui_add_view_port(bt->gui, bt->statusbar_view_port, GuiLayerStatusBarLeft);
     gui_add_view_port(bt->gui, bt->statusbar_view_port, GuiLayerStatusBarLeft);
     gui_add_view_port(bt->gui, bt->pin_code_view_port, GuiLayerFullscreen);
     gui_add_view_port(bt->gui, bt->pin_code_view_port, GuiLayerFullscreen);
 
 
     // Dialogs
     // Dialogs
-    bt->dialogs = furi_record_open("dialogs");
+    bt->dialogs = furi_record_open(RECORD_DIALOGS);
     bt->dialog_message = dialog_message_alloc();
     bt->dialog_message = dialog_message_alloc();
 
 
     // Power
     // Power
-    bt->power = furi_record_open("power");
+    bt->power = furi_record_open(RECORD_POWER);
     FuriPubSub* power_pubsub = power_get_pubsub(bt->power);
     FuriPubSub* power_pubsub = power_get_pubsub(bt->power);
     furi_pubsub_subscribe(power_pubsub, bt_battery_level_changed_callback, bt);
     furi_pubsub_subscribe(power_pubsub, bt_battery_level_changed_callback, bt);
 
 
     // RPC
     // RPC
-    bt->rpc = furi_record_open("rpc");
+    bt->rpc = furi_record_open(RECORD_RPC);
     bt->rpc_event = furi_event_flag_alloc();
     bt->rpc_event = furi_event_flag_alloc();
 
 
     // API evnent
     // API evnent
@@ -347,13 +347,14 @@ static void bt_close_connection(Bt* bt) {
     furi_event_flag_set(bt->api_event, BT_API_UNLOCK_EVENT);
     furi_event_flag_set(bt->api_event, BT_API_UNLOCK_EVENT);
 }
 }
 
 
-int32_t bt_srv() {
+int32_t bt_srv(void* p) {
+    UNUSED(p);
     Bt* bt = bt_alloc();
     Bt* bt = bt_alloc();
 
 
     if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) {
     if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) {
         FURI_LOG_W(TAG, "Skipped BT init: device in special startup mode");
         FURI_LOG_W(TAG, "Skipped BT init: device in special startup mode");
         ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT);
         ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT);
-        furi_record_create("bt", bt);
+        furi_record_create(RECORD_BT, bt);
         return 0;
         return 0;
     }
     }
 
 
@@ -381,7 +382,7 @@ int32_t bt_srv() {
         bt->status = BtStatusUnavailable;
         bt->status = BtStatusUnavailable;
     }
     }
 
 
-    furi_record_create("bt", bt);
+    furi_record_create(RECORD_BT, bt);
 
 
     BtMessage message;
     BtMessage message;
     while(1) {
     while(1) {

+ 2 - 0
applications/bt/bt_service/bt.h

@@ -7,6 +7,8 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
+#define RECORD_BT "bt"
+
 typedef struct Bt Bt;
 typedef struct Bt Bt;
 
 
 typedef enum {
 typedef enum {

+ 3 - 0
applications/bt/bt_service/bt_keys_filename.h

@@ -0,0 +1,3 @@
+#pragma once
+
+#define BT_KEYS_STORAGE_FILE_NAME ".bt.keys"

+ 2 - 1
applications/bt/bt_service/bt_keys_storage.c

@@ -2,8 +2,9 @@
 
 
 #include <furi.h>
 #include <furi.h>
 #include <lib/toolbox/saved_struct.h>
 #include <lib/toolbox/saved_struct.h>
+#include <storage/storage.h>
 
 
-#define BT_KEYS_STORAGE_PATH "/int/bt.keys"
+#define BT_KEYS_STORAGE_PATH INT_PATH(BT_KEYS_STORAGE_FILE_NAME)
 #define BT_KEYS_STORAGE_VERSION (0)
 #define BT_KEYS_STORAGE_VERSION (0)
 #define BT_KEYS_STORAGE_MAGIC (0x18)
 #define BT_KEYS_STORAGE_MAGIC (0x18)
 
 

+ 1 - 0
applications/bt/bt_service/bt_keys_storage.h

@@ -1,6 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "bt_i.h"
 #include "bt_i.h"
+#include "bt_keys_filename.h"
 
 
 bool bt_keys_storage_load(Bt* bt);
 bool bt_keys_storage_load(Bt* bt);
 
 

+ 2 - 1
applications/bt/bt_settings.c

@@ -2,8 +2,9 @@
 
 
 #include <furi.h>
 #include <furi.h>
 #include <lib/toolbox/saved_struct.h>
 #include <lib/toolbox/saved_struct.h>
+#include <storage/storage.h>
 
 
-#define BT_SETTINGS_PATH "/int/bt.settings"
+#define BT_SETTINGS_PATH INT_PATH(BT_SETTINGS_FILE_NAME)
 #define BT_SETTINGS_VERSION (0)
 #define BT_SETTINGS_VERSION (0)
 #define BT_SETTINGS_MAGIC (0x19)
 #define BT_SETTINGS_MAGIC (0x19)
 
 

+ 2 - 0
applications/bt/bt_settings.h

@@ -1,5 +1,7 @@
 #pragma once
 #pragma once
 
 
+#include "bt_settings_filename.h"
+
 #include <stdint.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdbool.h>
 
 

+ 4 - 4
applications/bt/bt_settings_app/bt_settings_app.c

@@ -17,8 +17,8 @@ BtSettingsApp* bt_settings_app_alloc() {
 
 
     // Load settings
     // Load settings
     bt_settings_load(&app->settings);
     bt_settings_load(&app->settings);
-    app->gui = furi_record_open("gui");
-    app->bt = furi_record_open("bt");
+    app->gui = furi_record_open(RECORD_GUI);
+    app->bt = furi_record_open(RECORD_BT);
 
 
     // View Dispatcher and Scene Manager
     // View Dispatcher and Scene Manager
     app->view_dispatcher = view_dispatcher_alloc();
     app->view_dispatcher = view_dispatcher_alloc();
@@ -70,8 +70,8 @@ void bt_settings_app_free(BtSettingsApp* app) {
     scene_manager_free(app->scene_manager);
     scene_manager_free(app->scene_manager);
 
 
     // Records
     // Records
-    furi_record_close("gui");
-    furi_record_close("bt");
+    furi_record_close(RECORD_GUI);
+    furi_record_close(RECORD_BT);
     free(app);
     free(app);
 }
 }
 
 

+ 2 - 2
applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c

@@ -10,9 +10,9 @@ void bt_settings_scene_forget_dev_confirm_dialog_callback(DialogExResult result,
 void bt_settings_scene_forget_dev_confirm_on_enter(void* context) {
 void bt_settings_scene_forget_dev_confirm_on_enter(void* context) {
     BtSettingsApp* app = context;
     BtSettingsApp* app = context;
     DialogEx* dialog = app->dialog;
     DialogEx* dialog = app->dialog;
-    dialog_ex_set_header(dialog, "Unpair all devices?", 64, 3, AlignCenter, AlignTop);
+    dialog_ex_set_header(dialog, "Unpair All Devices?", 64, 3, AlignCenter, AlignTop);
     dialog_ex_set_text(
     dialog_ex_set_text(
-        dialog, "All previous pairings\nwill be lost.", 64, 22, AlignCenter, AlignTop);
+        dialog, "All previous pairings\nwill be lost!", 64, 22, AlignCenter, AlignTop);
     dialog_ex_set_left_button_text(dialog, "Back");
     dialog_ex_set_left_button_text(dialog, "Back");
     dialog_ex_set_right_button_text(dialog, "Unpair");
     dialog_ex_set_right_button_text(dialog, "Unpair");
     dialog_ex_set_context(dialog, app);
     dialog_ex_set_context(dialog, app);

+ 3 - 0
applications/bt/bt_settings_filename.h

@@ -0,0 +1,3 @@
+#pragma once
+
+#define BT_SETTINGS_FILE_NAME ".bt.settings"

+ 8 - 8
applications/cli/cli.c

@@ -185,7 +185,7 @@ static void cli_execute_command(Cli* cli, CliCommand* command, string_t args) {
 
 
     // Ensure that we running alone
     // Ensure that we running alone
     if(!(command->flags & CliCommandFlagParallelSafe)) {
     if(!(command->flags & CliCommandFlagParallelSafe)) {
-        Loader* loader = furi_record_open("loader");
+        Loader* loader = furi_record_open(RECORD_LOADER);
         bool safety_lock = loader_lock(loader);
         bool safety_lock = loader_lock(loader);
         if(safety_lock) {
         if(safety_lock) {
             // Execute command
             // Execute command
@@ -194,7 +194,7 @@ static void cli_execute_command(Cli* cli, CliCommand* command, string_t args) {
         } else {
         } else {
             printf("Other application is running, close it first");
             printf("Other application is running, close it first");
         }
         }
-        furi_record_close("loader");
+        furi_record_close(RECORD_LOADER);
     } else {
     } else {
         // Execute command
         // Execute command
         command->callback(cli, args, command->context);
         command->callback(cli, args, command->context);
@@ -439,9 +439,9 @@ void cli_session_open(Cli* cli, void* session) {
     cli->session = session;
     cli->session = session;
     if(cli->session != NULL) {
     if(cli->session != NULL) {
         cli->session->init();
         cli->session->init();
-        furi_stdglue_set_thread_stdout_callback(cli->session->tx_stdout);
+        furi_thread_set_stdout_callback(cli->session->tx_stdout);
     } else {
     } else {
-        furi_stdglue_set_thread_stdout_callback(NULL);
+        furi_thread_set_stdout_callback(NULL);
     }
     }
     furi_semaphore_release(cli->idle_sem);
     furi_semaphore_release(cli->idle_sem);
     furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
     furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
@@ -455,7 +455,7 @@ void cli_session_close(Cli* cli) {
         cli->session->deinit();
         cli->session->deinit();
     }
     }
     cli->session = NULL;
     cli->session = NULL;
-    furi_stdglue_set_thread_stdout_callback(NULL);
+    furi_thread_set_stdout_callback(NULL);
     furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
     furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
 }
 }
 
 
@@ -466,12 +466,12 @@ int32_t cli_srv(void* p) {
     // Init basic cli commands
     // Init basic cli commands
     cli_commands_init(cli);
     cli_commands_init(cli);
 
 
-    furi_record_create("cli", cli);
+    furi_record_create(RECORD_CLI, cli);
 
 
     if(cli->session != NULL) {
     if(cli->session != NULL) {
-        furi_stdglue_set_thread_stdout_callback(cli->session->tx_stdout);
+        furi_thread_set_stdout_callback(cli->session->tx_stdout);
     } else {
     } else {
-        furi_stdglue_set_thread_stdout_callback(NULL);
+        furi_thread_set_stdout_callback(NULL);
     }
     }
 
 
     if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) {
     if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) {

+ 2 - 0
applications/cli/cli.h

@@ -33,6 +33,8 @@ typedef enum {
     CliCommandFlagInsomniaSafe = (1 << 1), /**< Safe to run with insomnia mode on */
     CliCommandFlagInsomniaSafe = (1 << 1), /**< Safe to run with insomnia mode on */
 } CliCommandFlag;
 } CliCommandFlag;
 
 
+#define RECORD_CLI "cli"
+
 /** Cli type anonymous structure */
 /** Cli type anonymous structure */
 typedef struct Cli Cli;
 typedef struct Cli Cli;
 
 

+ 6 - 6
applications/cli/cli_commands.c

@@ -166,13 +166,13 @@ void cli_command_vibro(Cli* cli, string_t args, void* context) {
     UNUSED(cli);
     UNUSED(cli);
     UNUSED(context);
     UNUSED(context);
     if(!string_cmp(args, "0")) {
     if(!string_cmp(args, "0")) {
-        NotificationApp* notification = furi_record_open("notification");
+        NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
         notification_message_block(notification, &sequence_reset_vibro);
         notification_message_block(notification, &sequence_reset_vibro);
-        furi_record_close("notification");
+        furi_record_close(RECORD_NOTIFICATION);
     } else if(!string_cmp(args, "1")) {
     } else if(!string_cmp(args, "1")) {
-        NotificationApp* notification = furi_record_open("notification");
+        NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
         notification_message_block(notification, &sequence_set_vibro_on);
         notification_message_block(notification, &sequence_set_vibro_on);
-        furi_record_close("notification");
+        furi_record_close(RECORD_NOTIFICATION);
     } else {
     } else {
         cli_print_usage("vibro", "<1|0>", string_get_cstr(args));
         cli_print_usage("vibro", "<1|0>", string_get_cstr(args));
     }
     }
@@ -244,9 +244,9 @@ void cli_command_led(Cli* cli, string_t args, void* context) {
     };
     };
 
 
     // Send notification
     // Send notification
-    NotificationApp* notification = furi_record_open("notification");
+    NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
     notification_internal_message_block(notification, &notification_sequence);
     notification_internal_message_block(notification, &notification_sequence);
-    furi_record_close("notification");
+    furi_record_close(RECORD_NOTIFICATION);
 }
 }
 
 
 void cli_command_ps(Cli* cli, string_t args, void* context) {
 void cli_command_ps(Cli* cli, string_t args, void* context) {

+ 1 - 1
applications/cli/cli_i.h

@@ -25,7 +25,7 @@ struct CliSession {
     void (*deinit)(void);
     void (*deinit)(void);
     size_t (*rx)(uint8_t* buffer, size_t size, uint32_t timeout);
     size_t (*rx)(uint8_t* buffer, size_t size, uint32_t timeout);
     void (*tx)(const uint8_t* buffer, size_t size);
     void (*tx)(const uint8_t* buffer, size_t size);
-    void (*tx_stdout)(void* _cookie, const char* data, size_t size);
+    void (*tx_stdout)(const char* data, size_t size);
     bool (*is_connected)(void);
     bool (*is_connected)(void);
 };
 };
 
 

+ 1 - 2
applications/cli/cli_vcp.c

@@ -277,8 +277,7 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) {
 #endif
 #endif
 }
 }
 
 
-static void cli_vcp_tx_stdout(void* _cookie, const char* data, size_t size) {
-    UNUSED(_cookie);
+static void cli_vcp_tx_stdout(const char* data, size_t size) {
     cli_vcp_tx((const uint8_t*)data, size);
     cli_vcp_tx((const uint8_t*)data, size);
 }
 }
 
 

+ 2 - 2
applications/crypto/crypto_cli.c

@@ -317,9 +317,9 @@ static void crypto_cli(Cli* cli, string_t args, void* context) {
 
 
 void crypto_on_system_start() {
 void crypto_on_system_start() {
 #ifdef SRV_CLI
 #ifdef SRV_CLI
-    Cli* cli = furi_record_open("cli");
+    Cli* cli = furi_record_open(RECORD_CLI);
     cli_add_command(cli, "crypto", CliCommandFlagDefault, crypto_cli, NULL);
     cli_add_command(cli, "crypto", CliCommandFlagDefault, crypto_cli, NULL);
-    furi_record_close("cli");
+    furi_record_close(RECORD_CLI);
 #else
 #else
     UNUSED(crypto_cli);
     UNUSED(crypto_cli);
 #endif
 #endif

+ 4 - 4
applications/debug_tools/blink_test.c

@@ -88,10 +88,10 @@ int32_t blink_test_app(void* p) {
     furi_timer_start(timer, furi_kernel_get_tick_frequency());
     furi_timer_start(timer, furi_kernel_get_tick_frequency());
 
 
     // Register view port in GUI
     // Register view port in GUI
-    Gui* gui = furi_record_open("gui");
+    Gui* gui = furi_record_open(RECORD_GUI);
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
 
 
-    NotificationApp* notifications = furi_record_open("notification");
+    NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
 
 
     uint8_t state = 0;
     uint8_t state = 0;
     BlinkEvent event;
     BlinkEvent event;
@@ -119,8 +119,8 @@ int32_t blink_test_app(void* p) {
     view_port_free(view_port);
     view_port_free(view_port);
     furi_message_queue_free(event_queue);
     furi_message_queue_free(event_queue);
 
 
-    furi_record_close("notification");
-    furi_record_close("gui");
+    furi_record_close(RECORD_NOTIFICATION);
+    furi_record_close(RECORD_GUI);
 
 
     return 0;
     return 0;
 }
 }

+ 2 - 2
applications/debug_tools/display_test/display_test.c

@@ -127,7 +127,7 @@ DisplayTest* display_test_alloc() {
 
 
     View* view = NULL;
     View* view = NULL;
 
 
-    instance->gui = furi_record_open("gui");
+    instance->gui = furi_record_open(RECORD_GUI);
     instance->view_dispatcher = view_dispatcher_alloc();
     instance->view_dispatcher = view_dispatcher_alloc();
     view_dispatcher_enable_queue(instance->view_dispatcher);
     view_dispatcher_enable_queue(instance->view_dispatcher);
     view_dispatcher_attach_to_gui(
     view_dispatcher_attach_to_gui(
@@ -206,7 +206,7 @@ void display_test_free(DisplayTest* instance) {
     view_display_test_free(instance->view_display_test);
     view_display_test_free(instance->view_display_test);
 
 
     view_dispatcher_free(instance->view_dispatcher);
     view_dispatcher_free(instance->view_dispatcher);
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
 
 
     free(instance);
     free(instance);
 }
 }

+ 5 - 5
applications/debug_tools/file_browser_test/file_browser_app.c

@@ -29,8 +29,8 @@ FileBrowserApp* file_browser_app_alloc(char* arg) {
     UNUSED(arg);
     UNUSED(arg);
     FileBrowserApp* app = malloc(sizeof(FileBrowserApp));
     FileBrowserApp* app = malloc(sizeof(FileBrowserApp));
 
 
-    app->gui = furi_record_open("gui");
-    app->dialogs = furi_record_open("dialogs");
+    app->gui = furi_record_open(RECORD_GUI);
+    app->dialogs = furi_record_open(RECORD_DIALOGS);
 
 
     app->view_dispatcher = view_dispatcher_alloc();
     app->view_dispatcher = view_dispatcher_alloc();
     view_dispatcher_enable_queue(app->view_dispatcher);
     view_dispatcher_enable_queue(app->view_dispatcher);
@@ -80,9 +80,9 @@ void file_browser_app_free(FileBrowserApp* app) {
     scene_manager_free(app->scene_manager);
     scene_manager_free(app->scene_manager);
 
 
     // Close records
     // Close records
-    furi_record_close("gui");
-    furi_record_close("notification");
-    furi_record_close("dialogs");
+    furi_record_close(RECORD_GUI);
+    furi_record_close(RECORD_NOTIFICATION);
+    furi_record_close(RECORD_DIALOGS);
 
 
     string_clear(app->file_path);
     string_clear(app->file_path);
 
 

+ 5 - 3
applications/debug_tools/file_browser_test/scenes/file_browser_scene_start.c

@@ -1,6 +1,8 @@
 #include "../file_browser_app_i.h"
 #include "../file_browser_app_i.h"
-#include "furi_hal.h"
-#include "gui/modules/widget_elements/widget_element_i.h"
+
+#include <furi_hal.h>
+#include <gui/modules/widget_elements/widget_element_i.h>
+#include <storage/storage.h>
 
 
 static void
 static void
     file_browser_scene_start_ok_callback(GuiButtonType result, InputType type, void* context) {
     file_browser_scene_start_ok_callback(GuiButtonType result, InputType type, void* context) {
@@ -17,7 +19,7 @@ bool file_browser_scene_start_on_event(void* context, SceneManagerEvent event) {
     bool consumed = false;
     bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
-        string_set_str(app->file_path, "/any/badusb/demo_windows.txt");
+        string_set_str(app->file_path, ANY_PATH("badusb/demo_windows.txt"));
         scene_manager_next_scene(app->scene_manager, FileBrowserSceneBrowser);
         scene_manager_next_scene(app->scene_manager, FileBrowserSceneBrowser);
         consumed = true;
         consumed = true;
     } else if(event.type == SceneManagerEventTypeTick) {
     } else if(event.type == SceneManagerEventTypeTick) {

+ 7 - 7
applications/debug_tools/keypad_test.c

@@ -26,11 +26,11 @@ static void keypad_test_render_callback(Canvas* canvas, void* ctx) {
     canvas_clear(canvas);
     canvas_clear(canvas);
     char strings[5][20];
     char strings[5][20];
 
 
-    sprintf(strings[0], "Ok: %d", state->ok);
-    sprintf(strings[1], "L: %d", state->left);
-    sprintf(strings[2], "R: %d", state->right);
-    sprintf(strings[3], "U: %d", state->up);
-    sprintf(strings[4], "D: %d", state->down);
+    snprintf(strings[0], 20, "Ok: %d", state->ok);
+    snprintf(strings[1], 20, "L: %d", state->left);
+    snprintf(strings[2], 20, "R: %d", state->right);
+    snprintf(strings[3], 20, "U: %d", state->up);
+    snprintf(strings[4], 20, "D: %d", state->down);
 
 
     canvas_set_font(canvas, FontPrimary);
     canvas_set_font(canvas, FontPrimary);
     canvas_draw_str(canvas, 0, 10, "Keypad test");
     canvas_draw_str(canvas, 0, 10, "Keypad test");
@@ -78,7 +78,7 @@ int32_t keypad_test_app(void* p) {
     view_port_input_callback_set(view_port, keypad_test_input_callback, event_queue);
     view_port_input_callback_set(view_port, keypad_test_input_callback, event_queue);
 
 
     // Open GUI and register view_port
     // Open GUI and register view_port
-    Gui* gui = furi_record_open("gui");
+    Gui* gui = furi_record_open(RECORD_GUI);
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
 
 
     InputEvent event;
     InputEvent event;
@@ -149,7 +149,7 @@ int32_t keypad_test_app(void* p) {
     furi_message_queue_free(event_queue);
     furi_message_queue_free(event_queue);
     delete_mutex(&state_mutex);
     delete_mutex(&state_mutex);
 
 
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
 
 
     return 0;
     return 0;
 }
 }

+ 2 - 2
applications/debug_tools/text_box_test.c

@@ -88,7 +88,7 @@ int32_t text_box_test_app(void* p) {
     view_port_input_callback_set(view_port, text_box_test_input_callback, event_queue);
     view_port_input_callback_set(view_port, text_box_test_input_callback, event_queue);
 
 
     // Open GUI and register view_port
     // Open GUI and register view_port
-    Gui* gui = furi_record_open("gui");
+    Gui* gui = furi_record_open(RECORD_GUI);
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
 
 
     uint32_t test_renders_num = COUNT_OF(text_box_test_render);
     uint32_t test_renders_num = COUNT_OF(text_box_test_render);
@@ -121,7 +121,7 @@ int32_t text_box_test_app(void* p) {
     furi_message_queue_free(event_queue);
     furi_message_queue_free(event_queue);
     delete_mutex(&state_mutex);
     delete_mutex(&state_mutex);
 
 
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
 
 
     return 0;
     return 0;
 }
 }

+ 4 - 4
applications/debug_tools/uart_echo.c

@@ -189,8 +189,8 @@ static UartEchoApp* uart_echo_app_alloc() {
     app->rx_stream = xStreamBufferCreate(2048, 1);
     app->rx_stream = xStreamBufferCreate(2048, 1);
 
 
     // Gui
     // Gui
-    app->gui = furi_record_open("gui");
-    app->notification = furi_record_open("notification");
+    app->gui = furi_record_open(RECORD_GUI);
+    app->notification = furi_record_open(RECORD_NOTIFICATION);
 
 
     // View dispatcher
     // View dispatcher
     app->view_dispatcher = view_dispatcher_alloc();
     app->view_dispatcher = view_dispatcher_alloc();
@@ -256,8 +256,8 @@ static void uart_echo_app_free(UartEchoApp* app) {
     view_dispatcher_free(app->view_dispatcher);
     view_dispatcher_free(app->view_dispatcher);
 
 
     // Close gui record
     // Close gui record
-    furi_record_close("gui");
-    furi_record_close("notification");
+    furi_record_close(RECORD_GUI);
+    furi_record_close(RECORD_NOTIFICATION);
     app->gui = NULL;
     app->gui = NULL;
 
 
     vStreamBufferDelete(app->rx_stream);
     vStreamBufferDelete(app->rx_stream);

+ 1 - 1
applications/debug_tools/usb_mouse.c

@@ -51,7 +51,7 @@ int32_t usb_mouse_app(void* p) {
     view_port_input_callback_set(view_port, usb_mouse_input_callback, event_queue);
     view_port_input_callback_set(view_port, usb_mouse_input_callback, event_queue);
 
 
     // Open GUI and register view_port
     // Open GUI and register view_port
-    Gui* gui = furi_record_open("gui");
+    Gui* gui = furi_record_open(RECORD_GUI);
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
 
 
     UsbMouseEvent event;
     UsbMouseEvent event;

+ 2 - 2
applications/debug_tools/usb_test.c

@@ -59,7 +59,7 @@ UsbTestApp* usb_test_app_alloc() {
     UsbTestApp* app = malloc(sizeof(UsbTestApp));
     UsbTestApp* app = malloc(sizeof(UsbTestApp));
 
 
     // Gui
     // Gui
-    app->gui = furi_record_open("gui");
+    app->gui = furi_record_open(RECORD_GUI);
 
 
     // View dispatcher
     // View dispatcher
     app->view_dispatcher = view_dispatcher_alloc();
     app->view_dispatcher = view_dispatcher_alloc();
@@ -106,7 +106,7 @@ void usb_test_app_free(UsbTestApp* app) {
     view_dispatcher_free(app->view_dispatcher);
     view_dispatcher_free(app->view_dispatcher);
 
 
     // Close gui record
     // Close gui record
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
     app->gui = NULL;
     app->gui = NULL;
 
 
     // Free rest
     // Free rest

+ 4 - 4
applications/debug_tools/vibro_test.c

@@ -32,10 +32,10 @@ int32_t vibro_test_app(void* p) {
     view_port_input_callback_set(view_port, vibro_test_input_callback, event_queue);
     view_port_input_callback_set(view_port, vibro_test_input_callback, event_queue);
 
 
     // Register view port in GUI
     // Register view port in GUI
-    Gui* gui = furi_record_open("gui");
+    Gui* gui = furi_record_open(RECORD_GUI);
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
 
 
-    NotificationApp* notification = furi_record_open("notification");
+    NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
 
 
     InputEvent event;
     InputEvent event;
 
 
@@ -60,8 +60,8 @@ int32_t vibro_test_app(void* p) {
     view_port_free(view_port);
     view_port_free(view_port);
     furi_message_queue_free(event_queue);
     furi_message_queue_free(event_queue);
 
 
-    furi_record_close("notification");
-    furi_record_close("gui");
+    furi_record_close(RECORD_NOTIFICATION);
+    furi_record_close(RECORD_GUI);
 
 
     return 0;
     return 0;
 }
 }

+ 27 - 27
applications/desktop/animations/animation_manager.c

@@ -137,9 +137,9 @@ void animation_manager_check_blocking_process(AnimationManager* animation_manage
         bool blocked = animation_manager_check_blocking(animation_manager);
         bool blocked = animation_manager_check_blocking(animation_manager);
 
 
         if(!blocked) {
         if(!blocked) {
-            Dolphin* dolphin = furi_record_open("dolphin");
+            Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
             DolphinStats stats = dolphin_stats(dolphin);
             DolphinStats stats = dolphin_stats(dolphin);
-            furi_record_close("dolphin");
+            furi_record_close(RECORD_DOLPHIN);
 
 
             const StorageAnimationManifestInfo* manifest_info =
             const StorageAnimationManifestInfo* manifest_info =
                 animation_storage_get_meta(animation_manager->current_animation);
                 animation_storage_get_meta(animation_manager->current_animation);
@@ -170,9 +170,9 @@ bool animation_manager_interact_process(AnimationManager* animation_manager) {
         animation_manager->levelup_pending = false;
         animation_manager->levelup_pending = false;
         animation_manager->levelup_active = true;
         animation_manager->levelup_active = true;
         animation_manager_switch_to_one_shot_view(animation_manager);
         animation_manager_switch_to_one_shot_view(animation_manager);
-        Dolphin* dolphin = furi_record_open("dolphin");
+        Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
         dolphin_upgrade_level(dolphin);
         dolphin_upgrade_level(dolphin);
-        furi_record_close("dolphin");
+        furi_record_close(RECORD_DOLPHIN);
     } else if(animation_manager->levelup_active) {
     } else if(animation_manager->levelup_active) {
         animation_manager->levelup_active = false;
         animation_manager->levelup_active = false;
         animation_manager_start_new_idle(animation_manager);
         animation_manager_start_new_idle(animation_manager);
@@ -205,7 +205,7 @@ static bool animation_manager_check_blocking(AnimationManager* animation_manager
     furi_assert(animation_manager);
     furi_assert(animation_manager);
 
 
     StorageAnimation* blocking_animation = NULL;
     StorageAnimation* blocking_animation = NULL;
-    Storage* storage = furi_record_open("storage");
+    Storage* storage = furi_record_open(RECORD_STORAGE);
     FS_Error sd_status = storage_sd_status(storage);
     FS_Error sd_status = storage_sd_status(storage);
 
 
     if(sd_status == FSE_INTERNAL) {
     if(sd_status == FSE_INTERNAL) {
@@ -220,7 +220,7 @@ static bool animation_manager_check_blocking(AnimationManager* animation_manager
             furi_assert(blocking_animation);
             furi_assert(blocking_animation);
             animation_manager->sd_shown_sd_ok = true;
             animation_manager->sd_shown_sd_ok = true;
         } else if(!animation_manager->sd_shown_no_db) {
         } else if(!animation_manager->sd_shown_no_db) {
-            bool db_exists = storage_common_stat(storage, "/ext/Manifest", NULL) == FSE_OK;
+            bool db_exists = storage_common_stat(storage, EXT_PATH("Manifest"), NULL) == FSE_OK;
             if(!db_exists) {
             if(!db_exists) {
                 blocking_animation = animation_storage_find_animation(NO_DB_ANIMATION_NAME);
                 blocking_animation = animation_storage_find_animation(NO_DB_ANIMATION_NAME);
                 furi_assert(blocking_animation);
                 furi_assert(blocking_animation);
@@ -234,9 +234,9 @@ static bool animation_manager_check_blocking(AnimationManager* animation_manager
         }
         }
     }
     }
 
 
-    Dolphin* dolphin = furi_record_open("dolphin");
+    Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
     DolphinStats stats = dolphin_stats(dolphin);
     DolphinStats stats = dolphin_stats(dolphin);
-    furi_record_close("dolphin");
+    furi_record_close(RECORD_DOLPHIN);
     if(!blocking_animation && stats.level_up_is_pending) {
     if(!blocking_animation && stats.level_up_is_pending) {
         blocking_animation = animation_storage_find_animation(NEW_MAIL_ANIMATION_NAME);
         blocking_animation = animation_storage_find_animation(NEW_MAIL_ANIMATION_NAME);
         furi_assert(blocking_animation);
         furi_assert(blocking_animation);
@@ -252,7 +252,7 @@ static bool animation_manager_check_blocking(AnimationManager* animation_manager
         animation_manager->state = AnimationManagerStateBlocked;
         animation_manager->state = AnimationManagerStateBlocked;
     }
     }
 
 
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 
 
     return !!blocking_animation;
     return !!blocking_animation;
 }
 }
@@ -287,15 +287,15 @@ AnimationManager* animation_manager_alloc(void) {
     bubble_animation_view_set_interact_callback(
     bubble_animation_view_set_interact_callback(
         animation_manager->animation_view, animation_manager_interact_callback, animation_manager);
         animation_manager->animation_view, animation_manager_interact_callback, animation_manager);
 
 
-    Storage* storage = furi_record_open("storage");
+    Storage* storage = furi_record_open(RECORD_STORAGE);
     animation_manager->pubsub_subscription_storage = furi_pubsub_subscribe(
     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_check_blocking_callback, animation_manager);
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 
 
-    Dolphin* dolphin = furi_record_open("dolphin");
+    Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
     animation_manager->pubsub_subscription_dolphin = furi_pubsub_subscribe(
     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_check_blocking_callback, animation_manager);
-    furi_record_close("dolphin");
+    furi_record_close(RECORD_DOLPHIN);
 
 
     animation_manager->sd_shown_sd_ok = true;
     animation_manager->sd_shown_sd_ok = true;
     if(!animation_manager_check_blocking(animation_manager)) {
     if(!animation_manager_check_blocking(animation_manager)) {
@@ -308,15 +308,15 @@ AnimationManager* animation_manager_alloc(void) {
 void animation_manager_free(AnimationManager* animation_manager) {
 void animation_manager_free(AnimationManager* animation_manager) {
     furi_assert(animation_manager);
     furi_assert(animation_manager);
 
 
-    Dolphin* dolphin = furi_record_open("dolphin");
+    Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
     furi_pubsub_unsubscribe(
     furi_pubsub_unsubscribe(
         dolphin_get_pubsub(dolphin), animation_manager->pubsub_subscription_dolphin);
         dolphin_get_pubsub(dolphin), animation_manager->pubsub_subscription_dolphin);
-    furi_record_close("dolphin");
+    furi_record_close(RECORD_DOLPHIN);
 
 
-    Storage* storage = furi_record_open("storage");
+    Storage* storage = furi_record_open(RECORD_STORAGE);
     furi_pubsub_unsubscribe(
     furi_pubsub_unsubscribe(
         storage_get_pubsub(storage), animation_manager->pubsub_subscription_storage);
         storage_get_pubsub(storage), animation_manager->pubsub_subscription_storage);
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 
 
     string_clear(animation_manager->freezed_animation_name);
     string_clear(animation_manager->freezed_animation_name);
     View* animation_view = bubble_animation_get_view(animation_manager->animation_view);
     View* animation_view = bubble_animation_get_view(animation_manager->animation_view);
@@ -340,16 +340,16 @@ static bool animation_manager_is_valid_idle_animation(
     bool result = true;
     bool result = true;
 
 
     if(!strcmp(info->name, BAD_BATTERY_ANIMATION_NAME)) {
     if(!strcmp(info->name, BAD_BATTERY_ANIMATION_NAME)) {
-        Power* power = furi_record_open("power");
+        Power* power = furi_record_open(RECORD_POWER);
         bool battery_is_well = power_is_battery_healthy(power);
         bool battery_is_well = power_is_battery_healthy(power);
-        furi_record_close("power");
+        furi_record_close(RECORD_POWER);
 
 
         result = !battery_is_well;
         result = !battery_is_well;
     }
     }
     if(!strcmp(info->name, NO_SD_ANIMATION_NAME)) {
     if(!strcmp(info->name, NO_SD_ANIMATION_NAME)) {
-        Storage* storage = furi_record_open("storage");
+        Storage* storage = furi_record_open(RECORD_STORAGE);
         FS_Error sd_status = storage_sd_status(storage);
         FS_Error sd_status = storage_sd_status(storage);
-        furi_record_close("storage");
+        furi_record_close(RECORD_STORAGE);
 
 
         result = (sd_status == FSE_NOT_READY);
         result = (sd_status == FSE_NOT_READY);
     }
     }
@@ -370,9 +370,9 @@ static StorageAnimation*
     StorageAnimationList_init(animation_list);
     StorageAnimationList_init(animation_list);
     animation_storage_fill_animation_list(&animation_list);
     animation_storage_fill_animation_list(&animation_list);
 
 
-    Dolphin* dolphin = furi_record_open("dolphin");
+    Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
     DolphinStats stats = dolphin_stats(dolphin);
     DolphinStats stats = dolphin_stats(dolphin);
-    furi_record_close("dolphin");
+    furi_record_close(RECORD_DOLPHIN);
     uint32_t whole_weight = 0;
     uint32_t whole_weight = 0;
 
 
     StorageAnimationList_it_t it;
     StorageAnimationList_it_t it;
@@ -492,9 +492,9 @@ void animation_manager_load_and_continue_animation(AnimationManager* animation_m
             StorageAnimation* restore_animation = animation_storage_find_animation(
             StorageAnimation* restore_animation = animation_storage_find_animation(
                 string_get_cstr(animation_manager->freezed_animation_name));
                 string_get_cstr(animation_manager->freezed_animation_name));
             if(restore_animation) {
             if(restore_animation) {
-                Dolphin* dolphin = furi_record_open("dolphin");
+                Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
                 DolphinStats stats = dolphin_stats(dolphin);
                 DolphinStats stats = dolphin_stats(dolphin);
-                furi_record_close("dolphin");
+                furi_record_close(RECORD_DOLPHIN);
                 const StorageAnimationManifestInfo* manifest_info =
                 const StorageAnimationManifestInfo* manifest_info =
                     animation_storage_get_meta(restore_animation);
                     animation_storage_get_meta(restore_animation);
                 bool valid = animation_manager_is_valid_idle_animation(manifest_info, &stats);
                 bool valid = animation_manager_is_valid_idle_animation(manifest_info, &stats);
@@ -543,9 +543,9 @@ void animation_manager_load_and_continue_animation(AnimationManager* animation_m
 static void animation_manager_switch_to_one_shot_view(AnimationManager* animation_manager) {
 static void animation_manager_switch_to_one_shot_view(AnimationManager* animation_manager) {
     furi_assert(animation_manager);
     furi_assert(animation_manager);
     furi_assert(!animation_manager->one_shot_view);
     furi_assert(!animation_manager->one_shot_view);
-    Dolphin* dolphin = furi_record_open("dolphin");
+    Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
     DolphinStats stats = dolphin_stats(dolphin);
     DolphinStats stats = dolphin_stats(dolphin);
-    furi_record_close("dolphin");
+    furi_record_close(RECORD_DOLPHIN);
 
 
     animation_manager->one_shot_view = one_shot_view_alloc();
     animation_manager->one_shot_view = one_shot_view_alloc();
     one_shot_view_set_interact_callback(
     one_shot_view_set_interact_callback(

+ 6 - 6
applications/desktop/animations/animation_storage.c

@@ -14,7 +14,7 @@
 #include <assets_dolphin_blocking.h>
 #include <assets_dolphin_blocking.h>
 
 
 #define ANIMATION_META_FILE "meta.txt"
 #define ANIMATION_META_FILE "meta.txt"
-#define ANIMATION_DIR "/ext/dolphin"
+#define ANIMATION_DIR EXT_PATH("dolphin")
 #define ANIMATION_MANIFEST_FILE ANIMATION_DIR "/manifest.txt"
 #define ANIMATION_MANIFEST_FILE ANIMATION_DIR "/manifest.txt"
 #define TAG "AnimationStorage"
 #define TAG "AnimationStorage"
 
 
@@ -29,7 +29,7 @@ static bool animation_storage_load_single_manifest_info(
     furi_assert(manifest_info);
     furi_assert(manifest_info);
 
 
     bool result = false;
     bool result = false;
-    Storage* storage = furi_record_open("storage");
+    Storage* storage = furi_record_open(RECORD_STORAGE);
     FlipperFormat* file = flipper_format_file_alloc(storage);
     FlipperFormat* file = flipper_format_file_alloc(storage);
     flipper_format_set_strict_mode(file, true);
     flipper_format_set_strict_mode(file, true);
     string_t read_string;
     string_t read_string;
@@ -75,7 +75,7 @@ static bool animation_storage_load_single_manifest_info(
     string_clear(read_string);
     string_clear(read_string);
     flipper_format_free(file);
     flipper_format_free(file);
 
 
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 
 
     return result;
     return result;
 }
 }
@@ -84,7 +84,7 @@ void animation_storage_fill_animation_list(StorageAnimationList_t* animation_lis
     furi_assert(sizeof(StorageAnimationList_t) == sizeof(void*));
     furi_assert(sizeof(StorageAnimationList_t) == sizeof(void*));
     furi_assert(!StorageAnimationList_size(*animation_list));
     furi_assert(!StorageAnimationList_size(*animation_list));
 
 
-    Storage* storage = furi_record_open("storage");
+    Storage* storage = furi_record_open(RECORD_STORAGE);
     FlipperFormat* file = flipper_format_file_alloc(storage);
     FlipperFormat* file = flipper_format_file_alloc(storage);
     /* Forbid skipping fields */
     /* Forbid skipping fields */
     flipper_format_set_strict_mode(file, true);
     flipper_format_set_strict_mode(file, true);
@@ -134,7 +134,7 @@ void animation_storage_fill_animation_list(StorageAnimationList_t* animation_lis
         StorageAnimationList_push_back(*animation_list, (StorageAnimation*)&dolphin_internal[i]);
         StorageAnimationList_push_back(*animation_list, (StorageAnimation*)&dolphin_internal[i]);
     }
     }
 
 
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 }
 }
 
 
 StorageAnimation* animation_storage_find_animation(const char* name) {
 StorageAnimation* animation_storage_find_animation(const char* name) {
@@ -434,7 +434,7 @@ static BubbleAnimation* animation_storage_load_animation(const char* name) {
     uint32_t height = 0;
     uint32_t height = 0;
     uint32_t width = 0;
     uint32_t width = 0;
     uint32_t* u32array = NULL;
     uint32_t* u32array = NULL;
-    Storage* storage = furi_record_open("storage");
+    Storage* storage = furi_record_open(RECORD_STORAGE);
     FlipperFormat* ff = flipper_format_file_alloc(storage);
     FlipperFormat* ff = flipper_format_file_alloc(storage);
     /* Forbid skipping fields */
     /* Forbid skipping fields */
     flipper_format_set_strict_mode(ff, true);
     flipper_format_set_strict_mode(ff, true);

+ 15 - 10
applications/desktop/animations/views/bubble_animation_view.c

@@ -143,7 +143,7 @@ static void bubble_animation_activate(BubbleAnimationView* view, bool force) {
     furi_assert(view);
     furi_assert(view);
     bool activate = true;
     bool activate = true;
     BubbleAnimationViewModel* model = view_get_model(view->view);
     BubbleAnimationViewModel* model = view_get_model(view->view);
-    if(!model->current) {
+    if(model->current == NULL) {
         activate = false;
         activate = false;
     } else if(model->freeze_frame) {
     } else if(model->freeze_frame) {
         activate = false;
         activate = false;
@@ -151,14 +151,16 @@ static void bubble_animation_activate(BubbleAnimationView* view, bool force) {
         activate = false;
         activate = false;
     }
     }
 
 
-    if(!force) {
-        if((model->active_ended_at + model->current->active_cooldown * 1000) >
-           xTaskGetTickCount()) {
-            activate = false;
-        } else if(model->active_shift) {
-            activate = false;
-        } else if(model->current_frame >= model->current->passive_frames) {
-            activate = false;
+    if(model->current != NULL) {
+        if(!force) {
+            if((model->active_ended_at + model->current->active_cooldown * 1000) >
+               xTaskGetTickCount()) {
+                activate = false;
+            } else if(model->active_shift) {
+                activate = false;
+            } else if(model->current_frame >= model->current->passive_frames) {
+                activate = false;
+            }
         }
         }
     }
     }
     view_commit_model(view->view, false);
     view_commit_model(view->view, false);
@@ -288,7 +290,10 @@ static void bubble_animation_enter(void* context) {
     bubble_animation_activate(view, false);
     bubble_animation_activate(view, false);
 
 
     BubbleAnimationViewModel* model = view_get_model(view->view);
     BubbleAnimationViewModel* model = view_get_model(view->view);
-    uint8_t frame_rate = model->current->icon_animation.frame_rate;
+    uint8_t frame_rate = 0;
+    if(model->current != NULL) {
+        frame_rate = model->current->icon_animation.frame_rate;
+    }
     view_commit_model(view->view, false);
     view_commit_model(view->view, false);
 
 
     if(frame_rate) {
     if(frame_rate) {

+ 14 - 13
applications/desktop/desktop.c

@@ -15,6 +15,7 @@
 #include "desktop/views/desktop_view_pin_timeout.h"
 #include "desktop/views/desktop_view_pin_timeout.h"
 #include "desktop_i.h"
 #include "desktop_i.h"
 #include "helpers/pin_lock.h"
 #include "helpers/pin_lock.h"
+#include "helpers/slideshow_filename.h"
 
 
 static void desktop_auto_lock_arm(Desktop*);
 static void desktop_auto_lock_arm(Desktop*);
 static void desktop_auto_lock_inhibit(Desktop*);
 static void desktop_auto_lock_inhibit(Desktop*);
@@ -127,9 +128,9 @@ void desktop_lock(Desktop* desktop) {
 
 
 void desktop_unlock(Desktop* desktop) {
 void desktop_unlock(Desktop* desktop) {
     view_port_enabled_set(desktop->lock_viewport, false);
     view_port_enabled_set(desktop->lock_viewport, false);
-    Gui* gui = furi_record_open("gui");
+    Gui* gui = furi_record_open(RECORD_GUI);
     gui_set_lockdown(gui, false);
     gui_set_lockdown(gui, false);
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
     desktop_view_locked_unlock(desktop->locked_view);
     desktop_view_locked_unlock(desktop->locked_view);
     scene_manager_search_and_switch_to_previous_scene(desktop->scene_manager, DesktopSceneMain);
     scene_manager_search_and_switch_to_previous_scene(desktop->scene_manager, DesktopSceneMain);
     desktop_auto_lock_arm(desktop);
     desktop_auto_lock_arm(desktop);
@@ -139,7 +140,7 @@ Desktop* desktop_alloc() {
     Desktop* desktop = malloc(sizeof(Desktop));
     Desktop* desktop = malloc(sizeof(Desktop));
 
 
     desktop->animation_manager = animation_manager_alloc();
     desktop->animation_manager = animation_manager_alloc();
-    desktop->gui = furi_record_open("gui");
+    desktop->gui = furi_record_open(RECORD_GUI);
     desktop->scene_thread = furi_thread_alloc();
     desktop->scene_thread = furi_thread_alloc();
     desktop->view_dispatcher = view_dispatcher_alloc();
     desktop->view_dispatcher = view_dispatcher_alloc();
     desktop->scene_manager = scene_manager_alloc(&desktop_scene_handlers, desktop);
     desktop->scene_manager = scene_manager_alloc(&desktop_scene_handlers, desktop);
@@ -218,17 +219,17 @@ Desktop* desktop_alloc() {
     gui_add_view_port(desktop->gui, desktop->lock_viewport, GuiLayerStatusBarLeft);
     gui_add_view_port(desktop->gui, desktop->lock_viewport, GuiLayerStatusBarLeft);
 
 
     // Special case: autostart application is already running
     // Special case: autostart application is already running
-    desktop->loader = furi_record_open("loader");
+    desktop->loader = furi_record_open(RECORD_LOADER);
     if(loader_is_locked(desktop->loader) &&
     if(loader_is_locked(desktop->loader) &&
        animation_manager_is_animation_loaded(desktop->animation_manager)) {
        animation_manager_is_animation_loaded(desktop->animation_manager)) {
         animation_manager_unload_and_stall_animation(desktop->animation_manager);
         animation_manager_unload_and_stall_animation(desktop->animation_manager);
     }
     }
 
 
-    desktop->notification = furi_record_open("notification");
+    desktop->notification = furi_record_open(RECORD_NOTIFICATION);
     desktop->app_start_stop_subscription = furi_pubsub_subscribe(
     desktop->app_start_stop_subscription = furi_pubsub_subscribe(
         loader_get_pubsub(desktop->loader), desktop_loader_callback, desktop);
         loader_get_pubsub(desktop->loader), desktop_loader_callback, desktop);
 
 
-    desktop->input_events_pubsub = furi_record_open("input_events");
+    desktop->input_events_pubsub = furi_record_open(RECORD_INPUT_EVENTS);
     desktop->input_events_subscription = NULL;
     desktop->input_events_subscription = NULL;
 
 
     desktop->auto_lock_timer =
     desktop->auto_lock_timer =
@@ -250,9 +251,9 @@ void desktop_free(Desktop* desktop) {
 
 
     desktop->loader = NULL;
     desktop->loader = NULL;
     desktop->input_events_pubsub = NULL;
     desktop->input_events_pubsub = NULL;
-    furi_record_close("loader");
-    furi_record_close("notification");
-    furi_record_close("input_events");
+    furi_record_close(RECORD_LOADER);
+    furi_record_close(RECORD_NOTIFICATION);
+    furi_record_close(RECORD_INPUT_EVENTS);
 
 
     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdMain);
     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdMain);
     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu);
     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu);
@@ -276,7 +277,7 @@ void desktop_free(Desktop* desktop) {
     popup_free(desktop->hw_mismatch_popup);
     popup_free(desktop->hw_mismatch_popup);
     desktop_view_pin_timeout_free(desktop->pin_timeout_view);
     desktop_view_pin_timeout_free(desktop->pin_timeout_view);
 
 
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
     desktop->gui = NULL;
     desktop->gui = NULL;
 
 
     furi_thread_free(desktop->scene_thread);
     furi_thread_free(desktop->scene_thread);
@@ -289,9 +290,9 @@ void desktop_free(Desktop* desktop) {
 }
 }
 
 
 static bool desktop_check_file_flag(const char* flag_path) {
 static bool desktop_check_file_flag(const char* flag_path) {
-    Storage* storage = furi_record_open("storage");
+    Storage* storage = furi_record_open(RECORD_STORAGE);
     bool exists = storage_common_stat(storage, flag_path, NULL) == FSE_OK;
     bool exists = storage_common_stat(storage, flag_path, NULL) == FSE_OK;
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
 
 
     return exists;
     return exists;
 }
 }
@@ -318,7 +319,7 @@ int32_t desktop_srv(void* p) {
         desktop_lock(desktop);
         desktop_lock(desktop);
     }
     }
 
 
-    if(desktop_check_file_flag("/int/slideshow")) {
+    if(desktop_check_file_flag(SLIDESHOW_FS_PATH)) {
         scene_manager_next_scene(desktop->scene_manager, DesktopSceneSlideshow);
         scene_manager_next_scene(desktop->scene_manager, DesktopSceneSlideshow);
     }
     }
 
 

+ 5 - 1
applications/desktop/desktop_settings/desktop_settings.h

@@ -1,12 +1,16 @@
 #pragma once
 #pragma once
 
 
+#include "desktop_settings_filename.h"
+
 #include <furi_hal.h>
 #include <furi_hal.h>
 #include <stdint.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdbool.h>
 #include <toolbox/saved_struct.h>
 #include <toolbox/saved_struct.h>
+#include <storage/storage.h>
 
 
 #define DESKTOP_SETTINGS_VER (4)
 #define DESKTOP_SETTINGS_VER (4)
-#define DESKTOP_SETTINGS_PATH "/int/desktop.settings"
+
+#define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME)
 #define DESKTOP_SETTINGS_MAGIC (0x17)
 #define DESKTOP_SETTINGS_MAGIC (0x17)
 #define PIN_MAX_LENGTH 12
 #define PIN_MAX_LENGTH 12
 
 

+ 3 - 3
applications/desktop/desktop_settings/desktop_settings_app.c

@@ -21,7 +21,7 @@ static bool desktop_settings_back_event_callback(void* context) {
 DesktopSettingsApp* desktop_settings_app_alloc() {
 DesktopSettingsApp* desktop_settings_app_alloc() {
     DesktopSettingsApp* app = malloc(sizeof(DesktopSettingsApp));
     DesktopSettingsApp* app = malloc(sizeof(DesktopSettingsApp));
 
 
-    app->gui = furi_record_open("gui");
+    app->gui = furi_record_open(RECORD_GUI);
     app->view_dispatcher = view_dispatcher_alloc();
     app->view_dispatcher = view_dispatcher_alloc();
     app->scene_manager = scene_manager_alloc(&desktop_settings_scene_handlers, app);
     app->scene_manager = scene_manager_alloc(&desktop_settings_scene_handlers, app);
     view_dispatcher_enable_queue(app->view_dispatcher);
     view_dispatcher_enable_queue(app->view_dispatcher);
@@ -83,14 +83,14 @@ void desktop_settings_app_free(DesktopSettingsApp* app) {
     view_dispatcher_free(app->view_dispatcher);
     view_dispatcher_free(app->view_dispatcher);
     scene_manager_free(app->scene_manager);
     scene_manager_free(app->scene_manager);
     // Records
     // Records
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
     free(app);
     free(app);
 }
 }
 
 
 extern int32_t desktop_settings_app(void* p) {
 extern int32_t desktop_settings_app(void* p) {
     DesktopSettingsApp* app = desktop_settings_app_alloc();
     DesktopSettingsApp* app = desktop_settings_app_alloc();
     LOAD_DESKTOP_SETTINGS(&app->settings);
     LOAD_DESKTOP_SETTINGS(&app->settings);
-    if(!strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG)) {
+    if(p && (strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG) == 0)) {
         scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto);
         scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto);
     } else {
     } else {
         scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart);
         scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart);

+ 3 - 0
applications/desktop/desktop_settings/desktop_settings_filename.h

@@ -0,0 +1,3 @@
+#pragma once
+
+#define DESKTOP_SETTINGS_FILE_NAME ".desktop.settings"

+ 2 - 2
applications/desktop/desktop_settings/scenes/desktop_settings_scene_pin_setup_done.c

@@ -25,9 +25,9 @@ void desktop_settings_scene_pin_setup_done_on_enter(void* context) {
 
 
     app->settings.pin_code = app->pincode_buffer;
     app->settings.pin_code = app->pincode_buffer;
     SAVE_DESKTOP_SETTINGS(&app->settings);
     SAVE_DESKTOP_SETTINGS(&app->settings);
-    NotificationApp* notification = furi_record_open("notification");
+    NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
     notification_message(notification, &sequence_single_vibro);
     notification_message(notification, &sequence_single_vibro);
-    furi_record_close("notification");
+    furi_record_close(RECORD_NOTIFICATION);
 
 
     desktop_view_pin_input_set_context(app->pin_input_view, app);
     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_back_callback(app->pin_input_view, NULL);

+ 8 - 8
applications/desktop/helpers/pin_lock.c

@@ -44,9 +44,9 @@ static const uint8_t desktop_helpers_fails_timeout[] = {
 };
 };
 
 
 void desktop_pin_lock_error_notify() {
 void desktop_pin_lock_error_notify() {
-    NotificationApp* notification = furi_record_open("notification");
+    NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
     notification_message(notification, &sequence_pin_fail);
     notification_message(notification, &sequence_pin_fail);
-    furi_record_close("notification");
+    furi_record_close(RECORD_NOTIFICATION);
 }
 }
 
 
 uint32_t desktop_pin_lock_get_fail_timeout() {
 uint32_t desktop_pin_lock_get_fail_timeout() {
@@ -67,9 +67,9 @@ void desktop_pin_lock(DesktopSettings* settings) {
 
 
     furi_hal_rtc_set_pin_fails(0);
     furi_hal_rtc_set_pin_fails(0);
     furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
     furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
-    Cli* cli = furi_record_open("cli");
+    Cli* cli = furi_record_open(RECORD_CLI);
     cli_session_close(cli);
     cli_session_close(cli);
-    furi_record_close("cli");
+    furi_record_close(RECORD_CLI);
     settings->is_locked = 1;
     settings->is_locked = 1;
     SAVE_DESKTOP_SETTINGS(settings);
     SAVE_DESKTOP_SETTINGS(settings);
 }
 }
@@ -78,9 +78,9 @@ void desktop_pin_unlock(DesktopSettings* settings) {
     furi_assert(settings);
     furi_assert(settings);
 
 
     furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
     furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
-    Cli* cli = furi_record_open("cli");
+    Cli* cli = furi_record_open(RECORD_CLI);
     cli_session_open(cli, &cli_vcp);
     cli_session_open(cli, &cli_vcp);
-    furi_record_close("cli");
+    furi_record_close(RECORD_CLI);
     settings->is_locked = 0;
     settings->is_locked = 0;
     SAVE_DESKTOP_SETTINGS(settings);
     SAVE_DESKTOP_SETTINGS(settings);
 }
 }
@@ -103,9 +103,9 @@ void desktop_pin_lock_init(DesktopSettings* settings) {
     }
     }
 
 
     if(desktop_pin_lock_is_locked()) {
     if(desktop_pin_lock_is_locked()) {
-        Cli* cli = furi_record_open("cli");
+        Cli* cli = furi_record_open(RECORD_CLI);
         cli_session_close(cli);
         cli_session_close(cli);
-        furi_record_close("cli");
+        furi_record_close(RECORD_CLI);
     }
     }
 }
 }
 
 

+ 2 - 2
applications/desktop/helpers/slideshow.c

@@ -52,7 +52,7 @@ void slideshow_free(Slideshow* slideshow) {
 }
 }
 
 
 bool slideshow_load(Slideshow* slideshow, const char* fspath) {
 bool slideshow_load(Slideshow* slideshow, const char* fspath) {
-    Storage* storage = furi_record_open("storage");
+    Storage* storage = furi_record_open(RECORD_STORAGE);
     File* slideshow_file = storage_file_alloc(storage);
     File* slideshow_file = storage_file_alloc(storage);
     slideshow->loaded = false;
     slideshow->loaded = false;
     do {
     do {
@@ -86,7 +86,7 @@ bool slideshow_load(Slideshow* slideshow, const char* fspath) {
         }
         }
     } while(false);
     } while(false);
     storage_file_free(slideshow_file);
     storage_file_free(slideshow_file);
-    furi_record_close("storage");
+    furi_record_close(RECORD_STORAGE);
     return slideshow->loaded;
     return slideshow->loaded;
 }
 }
 
 

+ 3 - 0
applications/desktop/helpers/slideshow_filename.h

@@ -0,0 +1,3 @@
+#pragma once
+
+#define SLIDESHOW_FILE_NAME ".slideshow"

+ 2 - 2
applications/desktop/scenes/desktop_scene_debug.c

@@ -22,7 +22,7 @@ void desktop_scene_debug_on_enter(void* context) {
 
 
 bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) {
 bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) {
     Desktop* desktop = (Desktop*)context;
     Desktop* desktop = (Desktop*)context;
-    Dolphin* dolphin = furi_record_open("dolphin");
+    Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
     bool consumed = false;
     bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
@@ -55,7 +55,7 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) {
         }
         }
     }
     }
 
 
-    furi_record_close("dolphin");
+    furi_record_close(RECORD_DOLPHIN);
     return consumed;
     return consumed;
 }
 }
 
 

+ 2 - 2
applications/desktop/scenes/desktop_scene_locked.c

@@ -47,9 +47,9 @@ void desktop_scene_locked_on_enter(void* context) {
     if(state == SCENE_LOCKED_FIRST_ENTER) {
     if(state == SCENE_LOCKED_FIRST_ENTER) {
         bool pin_locked = desktop_pin_lock_is_locked();
         bool pin_locked = desktop_pin_lock_is_locked();
         view_port_enabled_set(desktop->lock_viewport, true);
         view_port_enabled_set(desktop->lock_viewport, true);
-        Gui* gui = furi_record_open("gui");
+        Gui* gui = furi_record_open(RECORD_GUI);
         gui_set_lockdown(gui, true);
         gui_set_lockdown(gui, true);
-        furi_record_close("gui");
+        furi_record_close(RECORD_GUI);
 
 
         if(pin_locked) {
         if(pin_locked) {
             LOAD_DESKTOP_SETTINGS(&desktop->settings);
             LOAD_DESKTOP_SETTINGS(&desktop->settings);

+ 2 - 2
applications/desktop/scenes/desktop_scene_pin_input.c

@@ -24,13 +24,13 @@ typedef struct {
 } DesktopScenePinInputState;
 } DesktopScenePinInputState;
 
 
 static void desktop_scene_locked_light_red(bool value) {
 static void desktop_scene_locked_light_red(bool value) {
-    NotificationApp* app = furi_record_open("notification");
+    NotificationApp* app = furi_record_open(RECORD_NOTIFICATION);
     if(value) {
     if(value) {
         notification_message(app, &sequence_set_only_red_255);
         notification_message(app, &sequence_set_only_red_255);
     } else {
     } else {
         notification_message(app, &sequence_reset_red);
         notification_message(app, &sequence_reset_red);
     }
     }
-    furi_record_close("notification");
+    furi_record_close(RECORD_NOTIFICATION);
 }
 }
 
 
 static void
 static void

+ 11 - 3
applications/desktop/scenes/desktop_scene_slideshow.c

@@ -3,6 +3,7 @@
 #include "../desktop_i.h"
 #include "../desktop_i.h"
 #include "../views/desktop_view_slideshow.h"
 #include "../views/desktop_view_slideshow.h"
 #include "../views/desktop_events.h"
 #include "../views/desktop_events.h"
+#include <power/power_service/power.h>
 
 
 void desktop_scene_slideshow_callback(DesktopEvent event, void* context) {
 void desktop_scene_slideshow_callback(DesktopEvent event, void* context) {
     Desktop* desktop = (Desktop*)context;
     Desktop* desktop = (Desktop*)context;
@@ -22,16 +23,23 @@ bool desktop_scene_slideshow_on_event(void* context, SceneManagerEvent event) {
     Desktop* desktop = (Desktop*)context;
     Desktop* desktop = (Desktop*)context;
     bool consumed = false;
     bool consumed = false;
     Storage* storage = NULL;
     Storage* storage = NULL;
+    Power* power = NULL;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         switch(event.event) {
         switch(event.event) {
         case DesktopSlideshowCompleted:
         case DesktopSlideshowCompleted:
-            storage = furi_record_open("storage");
-            storage_common_remove(storage, "/int/slideshow");
-            furi_record_close("storage");
+            storage = furi_record_open(RECORD_STORAGE);
+            storage_common_remove(storage, SLIDESHOW_FS_PATH);
+            furi_record_close(RECORD_STORAGE);
             scene_manager_previous_scene(desktop->scene_manager);
             scene_manager_previous_scene(desktop->scene_manager);
             consumed = true;
             consumed = true;
             break;
             break;
+        case DesktopSlideshowPoweroff:
+            power = furi_record_open(RECORD_POWER);
+            power_off(power);
+            furi_record_close(RECORD_POWER);
+            consumed = true;
+            break;
 
 
         default:
         default:
             break;
             break;

+ 1 - 0
applications/desktop/views/desktop_events.h

@@ -35,6 +35,7 @@ typedef enum {
     DesktopAnimationEventInteractAnimation,
     DesktopAnimationEventInteractAnimation,
 
 
     DesktopSlideshowCompleted,
     DesktopSlideshowCompleted,
+    DesktopSlideshowPoweroff,
 
 
     // Global events
     // Global events
     DesktopGlobalBeforeAppStarted,
     DesktopGlobalBeforeAppStarted,

+ 10 - 9
applications/desktop/views/desktop_view_debug.c

@@ -23,7 +23,7 @@ void desktop_debug_render(Canvas* canvas, void* model) {
     const Version* ver;
     const Version* ver;
     char buffer[64];
     char buffer[64];
 
 
-    static const char* headers[] = {"FW Version info:", "Dolphin info:"};
+    static const char* headers[] = {"FW Version Info:", "Dolphin Info:"};
 
 
     canvas_set_color(canvas, ColorBlack);
     canvas_set_color(canvas, ColorBlack);
     canvas_set_font(canvas, FontPrimary);
     canvas_set_font(canvas, FontPrimary);
@@ -78,27 +78,28 @@ void desktop_debug_render(Canvas* canvas, void* model) {
         canvas_draw_str(canvas, 5, 50 + STATUS_BAR_Y_SHIFT, buffer);
         canvas_draw_str(canvas, 5, 50 + STATUS_BAR_Y_SHIFT, buffer);
 
 
     } else {
     } else {
-        char buffer[64];
-        Dolphin* dolphin = furi_record_open("dolphin");
+        Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
         DolphinStats stats = dolphin_stats(dolphin);
         DolphinStats stats = dolphin_stats(dolphin);
-        furi_record_close("dolphin");
+        furi_record_close(RECORD_DOLPHIN);
 
 
         uint32_t current_lvl = stats.level;
         uint32_t current_lvl = stats.level;
         uint32_t remaining = dolphin_state_xp_to_levelup(m->icounter);
         uint32_t remaining = dolphin_state_xp_to_levelup(m->icounter);
 
 
         canvas_set_font(canvas, FontSecondary);
         canvas_set_font(canvas, FontSecondary);
-        snprintf(buffer, 64, "Icounter: %ld  Butthurt %ld", m->icounter, m->butthurt);
+        snprintf(buffer, sizeof(buffer), "Icounter: %ld  Butthurt %ld", m->icounter, m->butthurt);
         canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer);
         canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer);
 
 
         snprintf(
         snprintf(
             buffer,
             buffer,
-            64,
+            sizeof(buffer),
             "Level: %ld  To level up: %ld",
             "Level: %ld  To level up: %ld",
             current_lvl,
             current_lvl,
             (remaining == (uint32_t)(-1) ? remaining : 0));
             (remaining == (uint32_t)(-1) ? remaining : 0));
         canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, buffer);
         canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, buffer);
 
 
-        snprintf(buffer, 64, "%s", asctime(localtime((const time_t*)&m->timestamp)));
+        // even if timestamp is uint64_t, it's safe to cast it to uint32_t, because furi_hal_rtc_datetime_to_timestamp only returns uint32_t
+        snprintf(buffer, sizeof(buffer), "%ld", (uint32_t)m->timestamp);
+
         canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer);
         canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer);
         canvas_draw_str(canvas, 0, 49 + STATUS_BAR_Y_SHIFT, "[< >] icounter value   [ok] save");
         canvas_draw_str(canvas, 0, 49 + STATUS_BAR_Y_SHIFT, "[< >] icounter value   [ok] save");
     }
     }
@@ -175,7 +176,7 @@ void desktop_debug_free(DesktopDebugView* debug_view) {
 }
 }
 
 
 void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view) {
 void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view) {
-    Dolphin* dolphin = furi_record_open("dolphin");
+    Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
     DolphinStats stats = dolphin_stats(dolphin);
     DolphinStats stats = dolphin_stats(dolphin);
     with_view_model(
     with_view_model(
         debug_view->view, (DesktopDebugViewModel * model) {
         debug_view->view, (DesktopDebugViewModel * model) {
@@ -185,7 +186,7 @@ void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view) {
             return true;
             return true;
         });
         });
 
 
-    furi_record_close("dolphin");
+    furi_record_close(RECORD_DOLPHIN);
 }
 }
 
 
 void desktop_debug_reset_screen_idx(DesktopDebugView* debug_view) {
 void desktop_debug_reset_screen_idx(DesktopDebugView* debug_view) {

+ 1 - 1
applications/desktop/views/desktop_view_lock_menu.c

@@ -67,7 +67,7 @@ void desktop_lock_menu_render(Canvas* canvas, void* model) {
         const char* str = Lockmenu_Items[i];
         const char* str = Lockmenu_Items[i];
 
 
         if(i == 1 && !m->pin_set) str = "Set PIN";
         if(i == 1 && !m->pin_set) str = "Set PIN";
-        if(m->hint_timeout && m->idx == 2 && m->idx == i) str = "Not implemented";
+        if(m->hint_timeout && m->idx == 2 && m->idx == i) str = "Not Implemented";
 
 
         if(str != NULL)
         if(str != NULL)
             canvas_draw_str_aligned(
             canvas_draw_str_aligned(

+ 29 - 2
applications/desktop/views/desktop_view_slideshow.c

@@ -2,14 +2,19 @@
 #include <furi_hal.h>
 #include <furi_hal.h>
 #include <gui/elements.h>
 #include <gui/elements.h>
 
 
-#include "../desktop_i.h"
 #include "desktop_view_slideshow.h"
 #include "desktop_view_slideshow.h"
+#include "../desktop_i.h"
 #include "../helpers/slideshow.h"
 #include "../helpers/slideshow.h"
+#include "../helpers/slideshow_filename.h"
+
+#define DESKTOP_SLIDESHOW_POWEROFF_SHORT 5000
+#define DESKTOP_SLIDESHOW_POWEROFF_LONG (60 * 60 * 1000)
 
 
 struct DesktopSlideshowView {
 struct DesktopSlideshowView {
     View* view;
     View* view;
     DesktopSlideshowViewCallback callback;
     DesktopSlideshowViewCallback callback;
     void* context;
     void* context;
+    FuriTimer* timer;
 };
 };
 
 
 typedef struct {
 typedef struct {
@@ -50,17 +55,35 @@ static bool desktop_view_slideshow_input(InputEvent* event, void* context) {
             instance->callback(DesktopSlideshowCompleted, instance->context);
             instance->callback(DesktopSlideshowCompleted, instance->context);
         }
         }
         view_commit_model(instance->view, true);
         view_commit_model(instance->view, true);
+    } else if(event->key == InputKeyOk) {
+        if(event->type == InputTypePress) {
+            furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_SHORT);
+        } else if(event->type == InputTypeRelease) {
+            furi_timer_stop(instance->timer);
+            furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG);
+        }
     }
     }
 
 
     return true;
     return true;
 }
 }
 
 
+static void desktop_first_start_timer_callback(void* context) {
+    DesktopSlideshowView* instance = context;
+    instance->callback(DesktopSlideshowPoweroff, instance->context);
+}
+
 static void desktop_view_slideshow_enter(void* context) {
 static void desktop_view_slideshow_enter(void* context) {
     DesktopSlideshowView* instance = context;
     DesktopSlideshowView* instance = context;
 
 
+    furi_assert(instance->timer == NULL);
+    instance->timer =
+        furi_timer_alloc(desktop_first_start_timer_callback, FuriTimerTypeOnce, instance);
+
+    furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG);
+
     DesktopSlideshowViewModel* model = view_get_model(instance->view);
     DesktopSlideshowViewModel* model = view_get_model(instance->view);
     model->slideshow = slideshow_alloc();
     model->slideshow = slideshow_alloc();
-    if(!slideshow_load(model->slideshow, "/int/slideshow")) {
+    if(!slideshow_load(model->slideshow, SLIDESHOW_FS_PATH)) {
         instance->callback(DesktopSlideshowCompleted, instance->context);
         instance->callback(DesktopSlideshowCompleted, instance->context);
     }
     }
     view_commit_model(instance->view, false);
     view_commit_model(instance->view, false);
@@ -69,6 +92,10 @@ static void desktop_view_slideshow_enter(void* context) {
 static void desktop_view_slideshow_exit(void* context) {
 static void desktop_view_slideshow_exit(void* context) {
     DesktopSlideshowView* instance = context;
     DesktopSlideshowView* instance = context;
 
 
+    furi_timer_stop(instance->timer);
+    furi_timer_free(instance->timer);
+    instance->timer = NULL;
+
     DesktopSlideshowViewModel* model = view_get_model(instance->view);
     DesktopSlideshowViewModel* model = view_get_model(instance->view);
     slideshow_free(model->slideshow);
     slideshow_free(model->slideshow);
     view_commit_model(instance->view, false);
     view_commit_model(instance->view, false);

+ 3 - 0
applications/desktop/views/desktop_view_slideshow.h

@@ -3,6 +3,9 @@
 #include <gui/view.h>
 #include <gui/view.h>
 
 
 #include "desktop_events.h"
 #include "desktop_events.h"
+#include "../helpers/slideshow_filename.h"
+
+#define SLIDESHOW_FS_PATH INT_PATH(SLIDESHOW_FILE_NAME)
 
 
 typedef struct DesktopSlideshowView DesktopSlideshowView;
 typedef struct DesktopSlideshowView DesktopSlideshowView;
 
 

+ 1 - 1
applications/dialogs/dialogs.c

@@ -29,7 +29,7 @@ static void dialogs_app_process_message(DialogsApp* app, DialogsAppMessage* mess
 int32_t dialogs_srv(void* p) {
 int32_t dialogs_srv(void* p) {
     UNUSED(p);
     UNUSED(p);
     DialogsApp* app = dialogs_app_alloc();
     DialogsApp* app = dialogs_app_alloc();
-    furi_record_create("dialogs", app);
+    furi_record_create(RECORD_DIALOGS, app);
 
 
     DialogsAppMessage message;
     DialogsAppMessage message;
     while(1) {
     while(1) {

+ 2 - 0
applications/dialogs/dialogs.h

@@ -9,6 +9,8 @@ extern "C" {
 
 
 /****************** COMMON ******************/
 /****************** COMMON ******************/
 
 
+#define RECORD_DIALOGS "dialogs"
+
 typedef struct DialogsApp DialogsApp;
 typedef struct DialogsApp DialogsApp;
 
 
 /****************** FILE BROWSER ******************/
 /****************** FILE BROWSER ******************/

+ 2 - 2
applications/dialogs/dialogs_module_file_browser.c

@@ -23,7 +23,7 @@ static void dialogs_app_file_browser_callback(void* context) {
 
 
 bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrowser* data) {
 bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrowser* data) {
     bool ret = false;
     bool ret = false;
-    Gui* gui = furi_record_open("gui");
+    Gui* gui = furi_record_open(RECORD_GUI);
 
 
     DialogsAppFileBrowserContext* file_browser_context =
     DialogsAppFileBrowserContext* file_browser_context =
         malloc(sizeof(DialogsAppFileBrowserContext));
         malloc(sizeof(DialogsAppFileBrowserContext));
@@ -53,7 +53,7 @@ bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrow
     file_browser_free(file_browser);
     file_browser_free(file_browser);
     API_LOCK_FREE(file_browser_context->lock);
     API_LOCK_FREE(file_browser_context->lock);
     free(file_browser_context);
     free(file_browser_context);
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
 
 
     return ret;
     return ret;
 }
 }

+ 2 - 2
applications/dialogs/dialogs_module_message.c

@@ -54,7 +54,7 @@ static void dialogs_app_message_callback(DialogExResult result, void* context) {
 
 
 DialogMessageButton dialogs_app_process_module_message(const DialogsAppMessageDataDialog* data) {
 DialogMessageButton dialogs_app_process_module_message(const DialogsAppMessageDataDialog* data) {
     DialogMessageButton ret = DialogMessageButtonBack;
     DialogMessageButton ret = DialogMessageButtonBack;
-    Gui* gui = furi_record_open("gui");
+    Gui* gui = furi_record_open(RECORD_GUI);
     const DialogMessage* message = data->message;
     const DialogMessage* message = data->message;
     DialogsAppMessageContext* message_context = malloc(sizeof(DialogsAppMessageContext));
     DialogsAppMessageContext* message_context = malloc(sizeof(DialogsAppMessageContext));
     message_context->lock = API_LOCK_INIT_LOCKED();
     message_context->lock = API_LOCK_INIT_LOCKED();
@@ -96,7 +96,7 @@ DialogMessageButton dialogs_app_process_module_message(const DialogsAppMessageDa
     dialog_ex_free(dialog_ex);
     dialog_ex_free(dialog_ex);
     API_LOCK_FREE(message_context->lock);
     API_LOCK_FREE(message_context->lock);
     free(message_context);
     free(message_context);
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
 
 
     return ret;
     return ret;
 }
 }

+ 1 - 1
applications/dolphin/dolphin.c

@@ -155,7 +155,7 @@ static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin) {
 int32_t dolphin_srv(void* p) {
 int32_t dolphin_srv(void* p) {
     UNUSED(p);
     UNUSED(p);
     Dolphin* dolphin = dolphin_alloc();
     Dolphin* dolphin = dolphin_alloc();
-    furi_record_create("dolphin", dolphin);
+    furi_record_create(RECORD_DOLPHIN, dolphin);
 
 
     dolphin_state_load(dolphin->state);
     dolphin_state_load(dolphin->state);
     xTimerReset(dolphin->butthurt_timer, portMAX_DELAY);
     xTimerReset(dolphin->butthurt_timer, portMAX_DELAY);

+ 2 - 0
applications/dolphin/dolphin.h

@@ -9,6 +9,8 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
+#define RECORD_DOLPHIN "dolphin"
+
 typedef struct Dolphin Dolphin;
 typedef struct Dolphin Dolphin;
 
 
 typedef struct {
 typedef struct {

+ 4 - 1
applications/dolphin/helpers/dolphin_state.c

@@ -1,5 +1,7 @@
 #include "dolphin_state.h"
 #include "dolphin_state.h"
 #include "dolphin/helpers/dolphin_deed.h"
 #include "dolphin/helpers/dolphin_deed.h"
+#include "dolphin_state_filename.h"
+
 #include <stdint.h>
 #include <stdint.h>
 #include <storage/storage.h>
 #include <storage/storage.h>
 #include <furi.h>
 #include <furi.h>
@@ -8,7 +10,8 @@
 #include <toolbox/saved_struct.h>
 #include <toolbox/saved_struct.h>
 
 
 #define TAG "DolphinState"
 #define TAG "DolphinState"
-#define DOLPHIN_STATE_PATH "/int/dolphin.state"
+
+#define DOLPHIN_STATE_PATH INT_PATH(DOLPHIN_STATE_FILE_NAME)
 #define DOLPHIN_STATE_HEADER_MAGIC 0xD0
 #define DOLPHIN_STATE_HEADER_MAGIC 0xD0
 #define DOLPHIN_STATE_HEADER_VERSION 0x01
 #define DOLPHIN_STATE_HEADER_VERSION 0x01
 #define LEVEL2_THRESHOLD 735
 #define LEVEL2_THRESHOLD 735

+ 3 - 0
applications/dolphin/helpers/dolphin_state_filename.h

@@ -0,0 +1,3 @@
+#pragma once
+
+#define DOLPHIN_STATE_FILE_NAME ".dolphin.state"

+ 4 - 4
applications/dolphin/passport/passport.c

@@ -95,12 +95,12 @@ int32_t passport_app(void* p) {
 
 
     ViewPort* view_port = view_port_alloc();
     ViewPort* view_port = view_port_alloc();
 
 
-    Dolphin* dolphin = furi_record_open("dolphin");
+    Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
     DolphinStats stats = dolphin_stats(dolphin);
     DolphinStats stats = dolphin_stats(dolphin);
-    furi_record_close("dolphin");
+    furi_record_close(RECORD_DOLPHIN);
     view_port_draw_callback_set(view_port, render_callback, &stats);
     view_port_draw_callback_set(view_port, render_callback, &stats);
     view_port_input_callback_set(view_port, input_callback, semaphore);
     view_port_input_callback_set(view_port, input_callback, semaphore);
-    Gui* gui = furi_record_open("gui");
+    Gui* gui = furi_record_open(RECORD_GUI);
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
     view_port_update(view_port);
     view_port_update(view_port);
 
 
@@ -108,7 +108,7 @@ int32_t passport_app(void* p) {
 
 
     gui_remove_view_port(gui, view_port);
     gui_remove_view_port(gui, view_port);
     view_port_free(view_port);
     view_port_free(view_port);
-    furi_record_close("gui");
+    furi_record_close(RECORD_GUI);
     furi_semaphore_free(semaphore);
     furi_semaphore_free(semaphore);
 
 
     return 0;
     return 0;

+ 2 - 0
applications/extapps.scons

@@ -38,6 +38,8 @@ appenv.AppendUnique(
         "-Wl,--no-export-dynamic",
         "-Wl,--no-export-dynamic",
         "-fvisibility=hidden",
         "-fvisibility=hidden",
         "-Wl,-e${APP_ENTRY}",
         "-Wl,-e${APP_ENTRY}",
+        "-Xlinker",
+        "-Map=${TARGET}.map",
     ],
     ],
 )
 )
 
 

+ 4 - 4
applications/gpio/gpio_app.c

@@ -24,7 +24,7 @@ static void gpio_app_tick_event_callback(void* context) {
 GpioApp* gpio_app_alloc() {
 GpioApp* gpio_app_alloc() {
     GpioApp* app = malloc(sizeof(GpioApp));
     GpioApp* app = malloc(sizeof(GpioApp));
 
 
-    app->gui = furi_record_open("gui");
+    app->gui = furi_record_open(RECORD_GUI);
 
 
     app->view_dispatcher = view_dispatcher_alloc();
     app->view_dispatcher = view_dispatcher_alloc();
     app->scene_manager = scene_manager_alloc(&gpio_scene_handlers, app);
     app->scene_manager = scene_manager_alloc(&gpio_scene_handlers, app);
@@ -40,7 +40,7 @@ GpioApp* gpio_app_alloc() {
 
 
     view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
     view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
 
 
-    app->notifications = furi_record_open("notification");
+    app->notifications = furi_record_open(RECORD_NOTIFICATION);
 
 
     app->var_item_list = variable_item_list_alloc();
     app->var_item_list = variable_item_list_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
@@ -88,8 +88,8 @@ void gpio_app_free(GpioApp* app) {
     scene_manager_free(app->scene_manager);
     scene_manager_free(app->scene_manager);
 
 
     // Close records
     // Close records
-    furi_record_close("gui");
-    furi_record_close("notification");
+    furi_record_close(RECORD_GUI);
+    furi_record_close(RECORD_NOTIFICATION);
 
 
     free(app);
     free(app);
 }
 }

+ 7 - 19
applications/gpio/scenes/gpio_scene_usb_uart_close_rpc.c

@@ -1,32 +1,20 @@
 #include "../gpio_app_i.h"
 #include "../gpio_app_i.h"
 #include "../gpio_custom_event.h"
 #include "../gpio_custom_event.h"
 
 
-static void gpio_scene_usb_uart_close_rpc_event_callback(
-    GuiButtonType result,
-    InputType type,
-    void* context) {
-    furi_assert(context);
-    GpioApp* app = context;
-
-    if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
-        view_dispatcher_send_custom_event(app->view_dispatcher, GpioCustomEventErrorBack);
-    }
-}
-
 void gpio_scene_usb_uart_close_rpc_on_enter(void* context) {
 void gpio_scene_usb_uart_close_rpc_on_enter(void* context) {
     GpioApp* app = context;
     GpioApp* app = context;
 
 
+    widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
+    widget_add_string_multiline_element(
+        app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nis active!");
     widget_add_string_multiline_element(
     widget_add_string_multiline_element(
         app->widget,
         app->widget,
-        63,
-        10,
-        AlignCenter,
+        3,
+        30,
+        AlignLeft,
         AlignTop,
         AlignTop,
         FontSecondary,
         FontSecondary,
-        "Disconnect from\ncompanion app\nto use this function");
-
-    widget_add_button_element(
-        app->widget, GuiButtonTypeLeft, "Back", gpio_scene_usb_uart_close_rpc_event_callback, app);
+        "Disconnect from\nPC or phone to\nuse this function.");
 
 
     view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewUsbUartCloseRpc);
     view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewUsbUartCloseRpc);
 }
 }

Некоторые файлы не были показаны из-за большого количества измененных файлов