Compare commits
152 Commits
un1-b9a766
...
un1-a6b98c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e30b14d90 | ||
|
|
c07e3a34dd | ||
|
|
be7e11e60f | ||
|
|
e96e414561 | ||
|
|
0c99cb52ec | ||
|
|
ad9e1ce4df | ||
|
|
22dc5190d1 | ||
|
|
f2fd97d9c5 | ||
|
|
08084d5763 | ||
|
|
add1ad6949 | ||
|
|
87654e60b8 | ||
|
|
6f92cd645e | ||
|
|
23f6ea2e05 | ||
|
|
a6b98ccbbe | ||
|
|
ba5f590dab | ||
|
|
f1048733d2 | ||
|
|
ea7f68fcab | ||
|
|
8013aacd94 | ||
|
|
be8f409098 | ||
|
|
97e6fe8f4e | ||
|
|
54757428e6 | ||
|
|
bd39d81324 | ||
|
|
2a2078d9b5 | ||
|
|
01ca588488 | ||
|
|
f86eada292 | ||
|
|
bc777b2eff | ||
|
|
6f91fa42f0 | ||
|
|
e6d22ed147 | ||
|
|
436f70b69b | ||
|
|
ec9ce0cad7 | ||
|
|
7e2008095e | ||
|
|
92e440c77d | ||
|
|
666821e9ce | ||
|
|
1bca477a43 | ||
|
|
41571ce9ad | ||
|
|
038d098c85 | ||
|
|
b03cc8ddc3 | ||
|
|
c8e3d9b040 | ||
|
|
aeb02500de | ||
|
|
eadd7801af | ||
|
|
6d2b0a3b6c | ||
|
|
32a7642761 | ||
|
|
e8bb45496d | ||
|
|
3846852f2b | ||
|
|
17d01f5c29 | ||
|
|
e6bcba6959 | ||
|
|
e13edc2f70 | ||
|
|
de6ff1d9c9 | ||
|
|
bea15134ba | ||
|
|
28a55bf576 | ||
|
|
e70121e20f | ||
|
|
432ff41d6a | ||
|
|
87393a086c | ||
|
|
6000d47a0f | ||
|
|
d986ef4104 | ||
|
|
f85dc1675d | ||
|
|
7c7ac07e6a | ||
|
|
ca02826cfd | ||
|
|
96ad7f3cef | ||
|
|
c213ff596a | ||
|
|
b2589698ff | ||
|
|
3360f818a1 | ||
|
|
066da4080b | ||
|
|
b2c118f267 | ||
|
|
a8db46124e | ||
|
|
672e27f258 | ||
|
|
e762a68265 | ||
|
|
8659becc9d | ||
|
|
82e1e8af6a | ||
|
|
a71d05a114 | ||
|
|
8d68bf62a5 | ||
|
|
2c85adb270 | ||
|
|
e2123c55bb | ||
|
|
f5ff6438d1 | ||
|
|
9f3b80e606 | ||
|
|
111656d2c1 | ||
|
|
2045a29d3f | ||
|
|
26e46f9267 | ||
|
|
d003db0404 | ||
|
|
5a31e35dc2 | ||
|
|
c7cd5721ed | ||
|
|
fb476c29e6 | ||
|
|
d80329b323 | ||
|
|
3d3c422751 | ||
|
|
ed385594a3 | ||
|
|
787df44c79 | ||
|
|
f0eedc3243 | ||
|
|
365d055dc5 | ||
|
|
650ba8a91f | ||
|
|
654d6dc6ec | ||
|
|
18b70ac6b5 | ||
|
|
51369d6219 | ||
|
|
181533df1b | ||
|
|
d85731636f | ||
|
|
6f66f87fab | ||
|
|
85d4dedb15 | ||
|
|
0a4cddb84c | ||
|
|
4e17230290 | ||
|
|
aa99ac53c7 | ||
|
|
875f70196b | ||
|
|
1e71d212fe | ||
|
|
269a6ce562 | ||
|
|
cd2014c51b | ||
|
|
08f80ab645 | ||
|
|
14bd8f2c49 | ||
|
|
8ce5fae626 | ||
|
|
087bf41392 | ||
|
|
d390381d5a | ||
|
|
c3e31663ef | ||
|
|
c28e4ea733 | ||
|
|
96a3da24c9 | ||
|
|
9d4b318357 | ||
|
|
ef5d0aa483 | ||
|
|
66487abaee | ||
|
|
d2bb1ef4d3 | ||
|
|
0e15090629 | ||
|
|
1413d7c937 | ||
|
|
d97a3ef161 | ||
|
|
870dfd188c | ||
|
|
71a6844a5f | ||
|
|
d67d5da034 | ||
|
|
c894948d4f | ||
|
|
e25148ce72 | ||
|
|
07301935b5 | ||
|
|
3a1705bcf9 | ||
|
|
df87b04fa9 | ||
|
|
75f5efce03 | ||
|
|
00585fa16a | ||
|
|
30aaae33be | ||
|
|
c0e7c2a929 | ||
|
|
286b4876ce | ||
|
|
10c2ae5a05 | ||
|
|
8915c0c66c | ||
|
|
ec7676182a | ||
|
|
e23dbb9f99 | ||
|
|
19d201085b | ||
|
|
17a4e03656 | ||
|
|
1fd9240481 | ||
|
|
fc9996377d | ||
|
|
7f4b586b13 | ||
|
|
72de4af6db | ||
|
|
5bbb13c5c9 | ||
|
|
3efb093125 | ||
|
|
60bce7b8d8 | ||
|
|
8b05bd1106 | ||
|
|
668b7857b4 | ||
|
|
8b3b5fa802 | ||
|
|
a6052be0f1 | ||
|
|
007a3d295e | ||
|
|
28beff1ab6 | ||
|
|
9c95562fad | ||
|
|
6b91c660d4 |
30
.drone.yml
@@ -28,35 +28,6 @@ steps:
|
||||
FBT_TOOLS_CUSTOM_LINK:
|
||||
from_secret: fbt_link
|
||||
|
||||
- name: "Bundle resources"
|
||||
image: kramos/alpine-zip
|
||||
commands:
|
||||
- mkdir sd-card
|
||||
- mkdir -p sd-card/subghz/assets
|
||||
- mkdir -p sd-card/nfc/assets
|
||||
- mkdir -p sd-card/infrared/assets
|
||||
- mkdir -p sd-card/unirf
|
||||
- mkdir -p sd-card/rfidfuzzer
|
||||
- mkdir -p sd-card/subplaylist
|
||||
- mkdir -p sd-card/badusb/layouts
|
||||
- cp assets/resources/badusb/layouts/* sd-card/badusb/layouts/
|
||||
- cp assets/resources/subghz/assets/dangerous_settings sd-card/subghz/assets/dangerous_settings
|
||||
- cp assets/resources/subghz/assets/setting_user sd-card/subghz/assets/setting_user
|
||||
- cp assets/resources/subghz/assets/keeloq_mfcodes sd-card/subghz/assets/keeloq_mfcodes
|
||||
- cp assets/resources/nfc/assets/mf_classic_dict.nfc sd-card/nfc/assets/mf_classic_dict.nfc
|
||||
- cp assets/resources/infrared/assets/tv.ir sd-card/infrared/assets/tv.ir
|
||||
- cp assets/resources/infrared/assets/ac.ir sd-card/infrared/assets/ac.ir
|
||||
- cp assets/resources/infrared/assets/fans.ir sd-card/infrared/assets/fans.ir
|
||||
- cp assets/resources/infrared/assets/projectors.ir sd-card/infrared/assets/projectors.ir
|
||||
- cp assets/resources/infrared/assets/audio.ir sd-card/infrared/assets/audio.ir
|
||||
- cp assets/resources/unirf/unirf_map_example.txt sd-card/unirf/unirf_map_example.txt
|
||||
- cp assets/resources/rfidfuzzer/example_uids.txt sd-card/rfidfuzzer/example_uids.txt
|
||||
- cp assets/resources/subplaylist/example_playlist.txt sd-card/subplaylist/example_playlist.txt
|
||||
- cp assets/resources/Manifest sd-card/Manifest
|
||||
- zip -r artifacts-default/sd-card-${DRONE_TAG}.zip sd-card
|
||||
- rm -rf sd-card
|
||||
- ls -laS artifacts-default
|
||||
|
||||
- name: "Bundle self-update packages"
|
||||
image: kramos/alpine-zip
|
||||
commands:
|
||||
@@ -93,7 +64,6 @@ steps:
|
||||
files:
|
||||
- artifacts-default/*.tgz
|
||||
- artifacts-default/*.zip
|
||||
- artifacts-default/flipper-z-f7-full-${DRONE_TAG}.dfu
|
||||
title: ${DRONE_TAG}
|
||||
note: CHANGELOG.md
|
||||
checksum:
|
||||
|
||||
1
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* @xMasterX
|
||||
4
.vscode/example/launch.json
vendored
@@ -9,6 +9,10 @@
|
||||
"type": "command",
|
||||
"command": "shellCommand.execute",
|
||||
"args": {
|
||||
"useSingleResult": true,
|
||||
"env": {
|
||||
"PATH": "${workspaceFolder};${env:PATH}"
|
||||
},
|
||||
"command": "./fbt get_blackmagic",
|
||||
"description": "Get Blackmagic device",
|
||||
}
|
||||
|
||||
4
.vscode/example/settings.json
vendored
@@ -14,7 +14,7 @@
|
||||
"cortex-debug.openocdPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/openocd/bin/openocd",
|
||||
"cortex-debug.gdbPath.windows": "${workspaceFolder}/toolchain/i686-windows/bin/arm-none-eabi-gdb-py.bat",
|
||||
"cortex-debug.gdbPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/bin/arm-none-eabi-gdb-py",
|
||||
"cortex-debug.gdbPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/bin/arm-none-eabi-gdb",
|
||||
"cortex-debug.gdbPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/bin/arm-none-eabi-gdb-py",
|
||||
"editor.formatOnSave": true,
|
||||
"files.associations": {
|
||||
"*.scons": "python",
|
||||
@@ -22,4 +22,4 @@
|
||||
"SConstruct": "python",
|
||||
"*.fam": "python",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
31
CHANGELOG.md
@@ -1,27 +1,16 @@
|
||||
### New changes
|
||||
* Adapted all plugins to new app system (@xMasterX)
|
||||
* Fix detect raw bug, fix CAME Atomo crash (@xMasterX)
|
||||
* Fix Zombiez (@xMasterX)
|
||||
* Added and fixed DOOM, added sound effects, made it somewhat playable (@xMasterX)
|
||||
* New clock (timer by GMMan and settings by kowalski7cc) (combined together by @xMasterX)
|
||||
* Added some games - Flappy Bird, Zombiez (check readme for links)
|
||||
* Added custom icons for apps (icons by @Svaarich & @Amec0e)
|
||||
* New update slideshow (by @Svaarich) [(idea and first version by ESurge, see PR 61)](https://github.com/Eng1n33r/flipperzero-firmware/pull/61)
|
||||
* Added Brazilian Portuguese badusb keyboard layout (by @web-mancha) [(PR 65)](https://github.com/Eng1n33r/flipperzero-firmware/pull/65)
|
||||
* Save last used SubGHZ config settings (PR 67 by @derskythe) (with some changes) [(link)](https://github.com/Eng1n33r/flipperzero-firmware/pull/67)
|
||||
* Arkanoid: rand_range, remove temp number (PR 66 by @TQMatvey)[(link)](https://github.com/Eng1n33r/flipperzero-firmware/pull/66)
|
||||
* OFW PR: Power: refresh battery indicator on charger plug/unplug (OFW PR 1733 by nminaylov)
|
||||
* OFW PR: Protocol data redecoding before write (OFW PR 1723 by nminaylov)
|
||||
* OFW PR: updater: fixed failing backups on /int with empty files in it (OFW PR 1735 by hedger)
|
||||
* OFW PR: NFC Notifications fix (OFW PR 1731 by Astrrra)
|
||||
* OFW: App loader (.fap Loader)(aka elf loader) !!!
|
||||
* PR: SubGHz bruteforcer plugin - deep refactoring (huge thanks to @derskythe ! | PR #75)
|
||||
* OFW: Preliminary Rust support
|
||||
|
||||
**Note: To avoid issues prefer installing using web updater or by self update package, all needed assets will be installed**
|
||||
#### **DFU files no longer included in releases to avoid issues with wrong manual installation of assets - use .tgz file with qFlipper, or install automatically via web updater or use microSD update package**
|
||||
|
||||
Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip` or `.tgz` for iOS mobile app
|
||||
[- How to install](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md)
|
||||
|
||||
DFU for update using qFlipper - `flipper-z-f7-full-(version).dfu`
|
||||
[- Download qFlipper 1.2.0 (allows .tgz installation) (official link)](https://update.flipperzero.one/builds/qFlipper/1.2.0/)
|
||||
|
||||
If using DFU update method, download this archive and unpack it to your microSD, replacing all files except files you have edited manually -
|
||||
`sd-card-(version).zip`
|
||||
**Note: To avoid issues with .dfu, prefer installing using .tgz with qFlipper, web updater or by self update package, all needed assets will be installed**
|
||||
|
||||
Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip` or download `.tgz` for iOS mobile app / qFlipper
|
||||
|
||||
Update using qFlipper (1.2.0) is now possible with `.tgz` update package! Also you can use Web Updater or self-update package.
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ See changelog in releases for latest updates!
|
||||
- Keeloq [Not ALL systems supported yet!]
|
||||
- Nice Flor S
|
||||
- Security+ v1 & v2
|
||||
- Star Line
|
||||
- Star Line (saving only)
|
||||
|
||||
## Support us so we can buy equipment and develop new features
|
||||
* ETH/BSC/ERC20-Tokens: `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`
|
||||
@@ -87,7 +87,6 @@ Games:
|
||||
- BadUSB -> Keyboard layouts [(by rien > dummy-decoy)](https://github.com/dummy-decoy/flipperzero-firmware/tree/dummy_decoy/bad_usb_keyboard_layout)
|
||||
- SubGHz -> New frequency analyzer - [(by ClusterM)](https://github.com/ClusterM)
|
||||
- SubGHz -> Detect RAW feature - [(by perspecdev)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/152)
|
||||
- SubGHz -> Save last used config settings - [(by derskythe)](https://github.com/Eng1n33r/flipperzero-firmware/pull/67)
|
||||
|
||||
# Instructions
|
||||
## [- How to install firmware](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md)
|
||||
@@ -100,6 +99,8 @@ Games:
|
||||
|
||||
### **Plugins**
|
||||
|
||||
## [- 💎 Extra plugins precompiled for Unleashed](https://github.com/UberGuidoZ/Flipper/tree/main/Applications/Unleashed)
|
||||
|
||||
## [- Configure Sub-GHz Remote App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)
|
||||
|
||||
## [- Barcode Generator](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/BarcodeGenerator.md)
|
||||
@@ -165,4 +166,4 @@ Games:
|
||||
- `site_scons` - Build helpers
|
||||
- `scripts` - Supplementary scripts and python libraries home
|
||||
|
||||
Also pay attention to `ReadMe.md` files inside of those directories.
|
||||
Also pay attention to `ReadMe.md` files inside those directories.
|
||||
|
||||
13
SConstruct
@@ -44,6 +44,8 @@ distenv = coreenv.Clone(
|
||||
"target extended-remote ${GDBREMOTE}",
|
||||
"-ex",
|
||||
"set confirm off",
|
||||
"-ex",
|
||||
"set pagination off",
|
||||
],
|
||||
GDBOPTS_BLACKMAGIC=[
|
||||
"-ex",
|
||||
@@ -234,10 +236,19 @@ distenv.PhonyTarget(
|
||||
distenv.PhonyTarget(
|
||||
"debug_other",
|
||||
"${GDBPYCOM}",
|
||||
GDBPYOPTS='-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ',
|
||||
GDBOPTS="${GDBOPTS_BASE}",
|
||||
GDBREMOTE="${OPENOCD_GDB_PIPE}",
|
||||
GDBPYOPTS='-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ',
|
||||
)
|
||||
|
||||
distenv.PhonyTarget(
|
||||
"debug_other_blackmagic",
|
||||
"${GDBPYCOM}",
|
||||
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
||||
GDBREMOTE="$${BLACKMAGIC_ADDR}",
|
||||
)
|
||||
|
||||
|
||||
# Just start OpenOCD
|
||||
distenv.PhonyTarget(
|
||||
"openocd",
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
# Structure
|
||||
|
||||
- `application.h` - Firmware application list header
|
||||
|
||||
|
||||
## debug
|
||||
|
||||
Applications for factory testing the Flipper.
|
||||
@@ -53,6 +50,8 @@ Extra apps for Plugins & App Loader menus.
|
||||
|
||||
Background services providing system APIs to applications.
|
||||
|
||||
- `applications.h` - Firmware application list header
|
||||
|
||||
- `bt` - BLE service and application
|
||||
- `cli` - Console service and API
|
||||
- `crypto` - Crypto cli tools
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
App(
|
||||
appid="uart_echo",
|
||||
name="UART Echo",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="uart_echo_app",
|
||||
cdefines=["APP_UART_ECHO"],
|
||||
requires=["gui"],
|
||||
stack_size=2 * 1024,
|
||||
order=70,
|
||||
fap_category="Debug",
|
||||
fap_icon="../../../assets/icons/Archive/keyboard_10px.png",
|
||||
fap_category="Misc",
|
||||
)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <storage/storage.h>
|
||||
#include <lib/flipper_format/flipper_format.h>
|
||||
#include <lib/nfc/protocols/nfca.h>
|
||||
#include <lib/nfc/helpers/mf_classic_dict.h>
|
||||
#include <lib/digital_signal/digital_signal.h>
|
||||
|
||||
#include <lib/flipper_format/flipper_format_i.h>
|
||||
@@ -170,10 +171,59 @@ MU_TEST(nfc_digital_signal_test) {
|
||||
"NFC long digital signal test failed\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(mf_classic_dict_test) {
|
||||
MfClassicDict* instance = NULL;
|
||||
uint64_t key = 0;
|
||||
string_t temp_str;
|
||||
string_init(temp_str);
|
||||
|
||||
instance = mf_classic_dict_alloc(MfClassicDictTypeUnitTest);
|
||||
mu_assert(instance != NULL, "mf_classic_dict_alloc\r\n");
|
||||
|
||||
mu_assert(
|
||||
mf_classic_dict_get_total_keys(instance) == 0,
|
||||
"mf_classic_dict_get_total_keys == 0 assert failed\r\n");
|
||||
|
||||
string_set(temp_str, "2196FAD8115B");
|
||||
mu_assert(
|
||||
mf_classic_dict_add_key_str(instance, temp_str),
|
||||
"mf_classic_dict_add_key == true assert failed\r\n");
|
||||
|
||||
mu_assert(
|
||||
mf_classic_dict_get_total_keys(instance) == 1,
|
||||
"mf_classic_dict_get_total_keys == 1 assert failed\r\n");
|
||||
|
||||
mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n");
|
||||
|
||||
mu_assert(
|
||||
mf_classic_dict_get_key_at_index_str(instance, temp_str, 0),
|
||||
"mf_classic_dict_get_key_at_index_str == true assert failed\r\n");
|
||||
mu_assert(
|
||||
string_cmp(temp_str, "2196FAD8115B") == 0,
|
||||
"string_cmp(temp_str, \"2196FAD8115B\") == 0 assert failed\r\n");
|
||||
|
||||
mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n");
|
||||
|
||||
mu_assert(
|
||||
mf_classic_dict_get_key_at_index(instance, &key, 0),
|
||||
"mf_classic_dict_get_key_at_index == true assert failed\r\n");
|
||||
mu_assert(key == 0x2196FAD8115B, "key == 0x2196FAD8115B assert failed\r\n");
|
||||
|
||||
mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n");
|
||||
|
||||
mu_assert(
|
||||
mf_classic_dict_delete_index(instance, 0),
|
||||
"mf_classic_dict_delete_index == true assert failed\r\n");
|
||||
|
||||
mf_classic_dict_free(instance);
|
||||
string_clear(temp_str);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(nfc) {
|
||||
nfc_test_alloc();
|
||||
|
||||
MU_RUN_TEST(nfc_digital_signal_test);
|
||||
MU_RUN_TEST(mf_classic_dict_test);
|
||||
|
||||
nfc_test_free();
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo")
|
||||
#define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s")
|
||||
#define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub")
|
||||
#define TEST_RANDOM_COUNT_PARSE 232
|
||||
#define TEST_RANDOM_COUNT_PARSE 233
|
||||
#define TEST_TIMEOUT 10000
|
||||
|
||||
static SubGhzEnvironment* environment_handler;
|
||||
@@ -434,6 +434,13 @@ MU_TEST(subghz_decoder_clemsa_test) {
|
||||
"Test decoder " SUBGHZ_PROTOCOL_CLEMSA_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_oregon2_test) {
|
||||
mu_assert(
|
||||
subghz_decoder_test(
|
||||
EXT_PATH("unit_tests/subghz/oregon2_raw.sub"), SUBGHZ_PROTOCOL_OREGON2_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_OREGON2_NAME " error\r\n");
|
||||
}
|
||||
|
||||
//test encoders
|
||||
MU_TEST(subghz_encoder_princeton_test) {
|
||||
mu_assert(
|
||||
@@ -595,6 +602,7 @@ MU_TEST_SUITE(subghz) {
|
||||
MU_RUN_TEST(subghz_decoder_magellen_test);
|
||||
MU_RUN_TEST(subghz_decoder_intertechno_v3_test);
|
||||
MU_RUN_TEST(subghz_decoder_clemsa_test);
|
||||
MU_RUN_TEST(subghz_decoder_oregon2_test);
|
||||
|
||||
MU_RUN_TEST(subghz_encoder_princeton_test);
|
||||
MU_RUN_TEST(subghz_encoder_came_test);
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
App(
|
||||
appid="usb_mouse",
|
||||
name="USB Mouse Demo",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
name="USB Mouse",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="usb_mouse_app",
|
||||
cdefines=["APP_USB_MOUSE"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=60,
|
||||
fap_category="Debug",
|
||||
fap_icon="../../plugins/mousejacker/mouse_10px.png",
|
||||
fap_category="Misc",
|
||||
)
|
||||
|
||||
@@ -15,6 +15,23 @@ App(
|
||||
"archive",
|
||||
"clock",
|
||||
"unirfremix",
|
||||
"spectrum_analyzer",
|
||||
],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="main_apps_default",
|
||||
name="Basic applications for main menu",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=[
|
||||
"gpio",
|
||||
#"ibutton",
|
||||
"infrared",
|
||||
"lfrfid",
|
||||
"nfc",
|
||||
"subghz",
|
||||
#"bad_usb",
|
||||
#"u2f",
|
||||
"fap_loader",
|
||||
"archive",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,66 +1,90 @@
|
||||
#include "archive_i.h"
|
||||
#include "m-string.h"
|
||||
|
||||
bool archive_custom_event_callback(void* context, uint32_t event) {
|
||||
static bool archive_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
ArchiveApp* archive = (ArchiveApp*)context;
|
||||
ArchiveApp* archive = context;
|
||||
return scene_manager_handle_custom_event(archive->scene_manager, event);
|
||||
}
|
||||
|
||||
bool archive_back_event_callback(void* context) {
|
||||
static bool archive_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
ArchiveApp* archive = (ArchiveApp*)context;
|
||||
ArchiveApp* archive = context;
|
||||
return scene_manager_handle_back_event(archive->scene_manager);
|
||||
}
|
||||
|
||||
ArchiveApp* archive_alloc() {
|
||||
static void archive_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
ArchiveApp* archive = context;
|
||||
scene_manager_handle_tick_event(archive->scene_manager);
|
||||
}
|
||||
|
||||
static ArchiveApp* archive_alloc() {
|
||||
ArchiveApp* archive = malloc(sizeof(ArchiveApp));
|
||||
|
||||
archive->gui = furi_record_open(RECORD_GUI);
|
||||
archive->text_input = text_input_alloc();
|
||||
string_init(archive->fav_move_str);
|
||||
|
||||
archive->view_dispatcher = view_dispatcher_alloc();
|
||||
archive->scene_manager = scene_manager_alloc(&archive_scene_handlers, archive);
|
||||
archive->view_dispatcher = view_dispatcher_alloc();
|
||||
|
||||
view_dispatcher_enable_queue(archive->view_dispatcher);
|
||||
view_dispatcher_attach_to_gui(
|
||||
archive->view_dispatcher, archive->gui, ViewDispatcherTypeFullscreen);
|
||||
archive->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
view_dispatcher_set_event_callback_context(archive->view_dispatcher, archive);
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
archive->view_dispatcher, archive_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
archive->view_dispatcher, archive_back_event_callback);
|
||||
ViewDispatcher* view_dispatcher = archive->view_dispatcher;
|
||||
view_dispatcher_enable_queue(view_dispatcher);
|
||||
view_dispatcher_set_event_callback_context(view_dispatcher, archive);
|
||||
view_dispatcher_set_custom_event_callback(view_dispatcher, archive_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(view_dispatcher, archive_back_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(view_dispatcher, archive_tick_event_callback, 100);
|
||||
|
||||
archive->browser = browser_alloc();
|
||||
archive->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
archive->text_input = text_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
archive->view_dispatcher, ArchiveViewBrowser, archive_browser_get_view(archive->browser));
|
||||
|
||||
view_dispatcher_add_view(
|
||||
archive->view_dispatcher, ArchiveViewTextInput, text_input_get_view(archive->text_input));
|
||||
view_dispatcher, ArchiveViewTextInput, text_input_get_view(archive->text_input));
|
||||
|
||||
archive->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
archive->view_dispatcher, ArchiveViewWidget, widget_get_view(archive->widget));
|
||||
|
||||
archive->view_stack = view_stack_alloc();
|
||||
view_dispatcher_add_view(
|
||||
view_dispatcher, ArchiveViewStack, view_stack_get_view(archive->view_stack));
|
||||
|
||||
archive->browser = browser_alloc();
|
||||
view_dispatcher_add_view(
|
||||
archive->view_dispatcher, ArchiveViewBrowser, archive_browser_get_view(archive->browser));
|
||||
|
||||
// Loading
|
||||
archive->loading = loading_alloc();
|
||||
|
||||
return archive;
|
||||
}
|
||||
|
||||
void archive_free(ArchiveApp* archive) {
|
||||
furi_assert(archive);
|
||||
ViewDispatcher* view_dispatcher = archive->view_dispatcher;
|
||||
|
||||
view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewBrowser);
|
||||
view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewTextInput);
|
||||
view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewWidget);
|
||||
// Loading
|
||||
loading_free(archive->loading);
|
||||
|
||||
view_dispatcher_remove_view(view_dispatcher, ArchiveViewTextInput);
|
||||
text_input_free(archive->text_input);
|
||||
|
||||
view_dispatcher_remove_view(view_dispatcher, ArchiveViewWidget);
|
||||
widget_free(archive->widget);
|
||||
|
||||
view_dispatcher_remove_view(view_dispatcher, ArchiveViewStack);
|
||||
view_stack_free(archive->view_stack);
|
||||
|
||||
view_dispatcher_remove_view(view_dispatcher, ArchiveViewBrowser);
|
||||
|
||||
view_dispatcher_free(archive->view_dispatcher);
|
||||
scene_manager_free(archive->scene_manager);
|
||||
|
||||
browser_free(archive->browser);
|
||||
string_clear(archive->fav_move_str);
|
||||
|
||||
text_input_free(archive->text_input);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
archive->dialogs = NULL;
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
archive->gui = NULL;
|
||||
@@ -68,12 +92,31 @@ void archive_free(ArchiveApp* archive) {
|
||||
free(archive);
|
||||
}
|
||||
|
||||
void archive_show_loading_popup(ArchiveApp* context, bool show) {
|
||||
TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME);
|
||||
ViewStack* view_stack = context->view_stack;
|
||||
Loading* loading = context->loading;
|
||||
|
||||
if(show) {
|
||||
// Raise timer priority so that animations can play
|
||||
vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1);
|
||||
view_stack_add_view(view_stack, loading_get_view(loading));
|
||||
} else {
|
||||
view_stack_remove_view(view_stack, loading_get_view(loading));
|
||||
// Restore default timer priority
|
||||
vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t archive_app(void* p) {
|
||||
UNUSED(p);
|
||||
|
||||
ArchiveApp* archive = archive_alloc();
|
||||
view_dispatcher_attach_to_gui(
|
||||
archive->view_dispatcher, archive->gui, ViewDispatcherTypeFullscreen);
|
||||
scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneBrowser);
|
||||
view_dispatcher_run(archive->view_dispatcher);
|
||||
archive_free(archive);
|
||||
|
||||
archive_free(archive);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include <gui/view_stack.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <gui/modules/loading.h>
|
||||
#include <loader/loader.h>
|
||||
|
||||
#include "views/archive_browser_view.h"
|
||||
@@ -18,17 +21,24 @@ typedef enum {
|
||||
ArchiveViewTextInput,
|
||||
ArchiveViewWidget,
|
||||
ArchiveViewTotal,
|
||||
ArchiveViewStack,
|
||||
} ArchiveViewEnum;
|
||||
|
||||
struct ArchiveApp {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
ViewStack* view_stack;
|
||||
SceneManager* scene_manager;
|
||||
ArchiveBrowserView* browser;
|
||||
TextInput* text_input;
|
||||
Widget* widget;
|
||||
DialogsApp* dialogs;
|
||||
Loading* loading;
|
||||
FuriPubSubSubscription* loader_stop_subscription;
|
||||
|
||||
string_t fav_move_str;
|
||||
char text_store[MAX_NAME_LEN];
|
||||
char file_extension[MAX_EXT_LEN + 1];
|
||||
};
|
||||
|
||||
void archive_show_loading_popup(ArchiveApp* context, bool show);
|
||||
@@ -270,7 +270,7 @@ void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) {
|
||||
ArchiveFile_t* archive_get_current_file(ArchiveBrowserView* browser) {
|
||||
furi_assert(browser);
|
||||
|
||||
ArchiveFile_t* selected;
|
||||
ArchiveFile_t* selected = NULL;
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
selected = files_array_size(model->files) ?
|
||||
@@ -284,7 +284,7 @@ ArchiveFile_t* archive_get_current_file(ArchiveBrowserView* browser) {
|
||||
ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx) {
|
||||
furi_assert(browser);
|
||||
|
||||
ArchiveFile_t* selected;
|
||||
ArchiveFile_t* selected = NULL;
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
@@ -298,7 +298,7 @@ ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx) {
|
||||
ArchiveTabEnum archive_get_tab(ArchiveBrowserView* browser) {
|
||||
furi_assert(browser);
|
||||
|
||||
ArchiveTabEnum tab_id;
|
||||
ArchiveTabEnum tab_id = 0;
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
tab_id = model->tab_idx;
|
||||
@@ -377,6 +377,7 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show) {
|
||||
if(archive_is_item_in_array(model, model->item_idx)) {
|
||||
model->menu = true;
|
||||
model->menu_idx = 0;
|
||||
menu_array_reset(model->context_menu);
|
||||
ArchiveFile_t* selected =
|
||||
files_array_get(model->files, model->item_idx - model->array_offset);
|
||||
selected->fav = archive_is_favorite("%s", string_get_cstr(selected->path));
|
||||
@@ -451,8 +452,6 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
|
||||
archive_file_browser_set_path(
|
||||
browser, browser->path, archive_get_tab_ext(tab), skip_assets);
|
||||
tab_empty = false; // Empty check will be performed later
|
||||
} else {
|
||||
tab_empty = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ static const char* tab_default_paths[] = {
|
||||
[ArchiveTabInfrared] = ANY_PATH("infrared"),
|
||||
[ArchiveTabBadUsb] = ANY_PATH("badusb"),
|
||||
[ArchiveTabU2f] = "/app:u2f",
|
||||
[ArchiveTabApps] = ANY_PATH("apps"),
|
||||
[ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX,
|
||||
};
|
||||
|
||||
@@ -27,6 +28,7 @@ static const char* known_ext[] = {
|
||||
[ArchiveFileTypeInfrared] = ".ir",
|
||||
[ArchiveFileTypeBadUsb] = ".txt",
|
||||
[ArchiveFileTypeU2f] = "?",
|
||||
[ArchiveFileTypeApps] = ".fap",
|
||||
[ArchiveFileTypeUpdateManifest] = ".fuf",
|
||||
[ArchiveFileTypeFolder] = "?",
|
||||
[ArchiveFileTypeUnknown] = "*",
|
||||
@@ -41,6 +43,7 @@ static const ArchiveFileTypeEnum known_type[] = {
|
||||
[ArchiveTabInfrared] = ArchiveFileTypeInfrared,
|
||||
[ArchiveTabBadUsb] = ArchiveFileTypeBadUsb,
|
||||
[ArchiveTabU2f] = ArchiveFileTypeU2f,
|
||||
[ArchiveTabApps] = ArchiveFileTypeApps,
|
||||
[ArchiveTabBrowser] = ArchiveFileTypeUnknown,
|
||||
};
|
||||
|
||||
|
||||
@@ -109,3 +109,38 @@ void archive_delete_file(void* context, const char* format, ...) {
|
||||
|
||||
string_clear(filename);
|
||||
}
|
||||
|
||||
FS_Error archive_rename_file_or_dir(void* context, const char* src_path, const char* dst_path) {
|
||||
furi_assert(context);
|
||||
|
||||
FURI_LOG_I(TAG, "Rename from %s to %s", src_path, dst_path);
|
||||
|
||||
ArchiveBrowserView* browser = context;
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
FileInfo fileinfo;
|
||||
storage_common_stat(fs_api, src_path, &fileinfo);
|
||||
|
||||
FS_Error error = FSE_OK;
|
||||
|
||||
if(!path_contains_only_ascii(dst_path)) {
|
||||
error = FSE_INVALID_NAME;
|
||||
} else {
|
||||
error = storage_common_rename(fs_api, src_path, dst_path);
|
||||
}
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
if(archive_is_favorite("%s", src_path)) {
|
||||
archive_favorites_rename(src_path, dst_path);
|
||||
}
|
||||
|
||||
if(error == FSE_OK || error == FSE_EXIST) {
|
||||
FURI_LOG_I(TAG, "Rename from %s to %s is DONE", src_path, dst_path);
|
||||
archive_refresh_dir(browser);
|
||||
} else {
|
||||
FURI_LOG_E(
|
||||
TAG, "Rename failed: %s, Code: %d", filesystem_api_error_get_desc(error), error);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <m-array.h>
|
||||
#include <m-string.h>
|
||||
#include <storage/storage.h>
|
||||
#include "toolbox/path.h"
|
||||
|
||||
typedef enum {
|
||||
ArchiveFileTypeIButton,
|
||||
@@ -12,6 +13,7 @@ typedef enum {
|
||||
ArchiveFileTypeInfrared,
|
||||
ArchiveFileTypeBadUsb,
|
||||
ArchiveFileTypeU2f,
|
||||
ArchiveFileTypeApps,
|
||||
ArchiveFileTypeUpdateManifest,
|
||||
ArchiveFileTypeFolder,
|
||||
ArchiveFileTypeUnknown,
|
||||
@@ -62,3 +64,4 @@ void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder
|
||||
bool archive_get_items(void* context, const char* path);
|
||||
void archive_file_append(const char* path, const char* format, ...);
|
||||
void archive_delete_file(void* context, const char* format, ...);
|
||||
FS_Error archive_rename_file_or_dir(void* context, const char* src_path, const char* dst_path);
|
||||
|
||||
49
applications/main/archive/helpers/archive_menu.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <m-array.h>
|
||||
#include <m-string.h>
|
||||
|
||||
typedef struct {
|
||||
string_t text;
|
||||
uint32_t event;
|
||||
} ArchiveContextMenuItem_t;
|
||||
|
||||
static void ArchiveContextMenuItem_t_init(ArchiveContextMenuItem_t* obj) {
|
||||
string_init(obj->text);
|
||||
obj->event = 0; // ArchiveBrowserEventFileMenuNone
|
||||
}
|
||||
|
||||
static void ArchiveContextMenuItem_t_init_set(
|
||||
ArchiveContextMenuItem_t* obj,
|
||||
const ArchiveContextMenuItem_t* src) {
|
||||
string_init_set(obj->text, src->text);
|
||||
obj->event = src->event;
|
||||
}
|
||||
|
||||
static void ArchiveContextMenuItem_t_set(
|
||||
ArchiveContextMenuItem_t* obj,
|
||||
const ArchiveContextMenuItem_t* src) {
|
||||
string_init_set(obj->text, src->text);
|
||||
obj->event = src->event;
|
||||
}
|
||||
|
||||
static void ArchiveContextMenuItem_t_clear(ArchiveContextMenuItem_t* obj) {
|
||||
string_clear(obj->text);
|
||||
}
|
||||
|
||||
ARRAY_DEF(
|
||||
menu_array,
|
||||
ArchiveContextMenuItem_t,
|
||||
(INIT(API_2(ArchiveContextMenuItem_t_init)),
|
||||
SET(API_6(ArchiveContextMenuItem_t_set)),
|
||||
INIT_SET(API_6(ArchiveContextMenuItem_t_init_set)),
|
||||
CLEAR(API_2(ArchiveContextMenuItem_t_clear))))
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
// Using in applications/archive/views/archive_browser_view.c
|
||||
static void archive_menu_add_item(ArchiveContextMenuItem_t* obj, string_t text, uint32_t event) {
|
||||
string_init_move(obj->text, text);
|
||||
obj->event = event;
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -19,6 +19,7 @@ static const char* flipper_app_name[] = {
|
||||
[ArchiveFileTypeInfrared] = "Infrared",
|
||||
[ArchiveFileTypeBadUsb] = "Bad USB",
|
||||
[ArchiveFileTypeU2f] = "U2F",
|
||||
[ArchiveFileTypeApps] = "Applications",
|
||||
[ArchiveFileTypeUpdateManifest] = "UpdaterApp",
|
||||
};
|
||||
|
||||
@@ -132,7 +133,9 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
||||
case ArchiveBrowserEventFileMenuRename:
|
||||
if(favorites) {
|
||||
browser->callback(ArchiveBrowserEventEnterFavMove, browser->context);
|
||||
} else if((archive_is_known_app(selected->type)) && (selected->is_app == false)) {
|
||||
//} else if((archive_is_known_app(selected->type)) && (selected->is_app == false)) {
|
||||
} else {
|
||||
// Added ability to rename files and folders
|
||||
archive_show_file_menu(browser, false);
|
||||
scene_manager_set_scene_state(
|
||||
archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH);
|
||||
@@ -140,6 +143,13 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventFileMenuInfo:
|
||||
archive_show_file_menu(browser, false);
|
||||
scene_manager_set_scene_state(
|
||||
archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_DEFAULT);
|
||||
scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneInfo);
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventFileMenuDelete:
|
||||
if(archive_get_tab(browser) != ArchiveTabFavorites) {
|
||||
scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneDelete);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
ADD_SCENE(archive, browser, Browser)
|
||||
ADD_SCENE(archive, rename, Rename)
|
||||
ADD_SCENE(archive, delete, Delete)
|
||||
ADD_SCENE(archive, info, Info)
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
#include "../archive_i.h"
|
||||
#include "../helpers/archive_favorites.h"
|
||||
#include "../helpers/archive_files.h"
|
||||
#include "../helpers/archive_apps.h"
|
||||
#include "../helpers/archive_browser.h"
|
||||
#include "toolbox/path.h"
|
||||
#include "m-string.h"
|
||||
|
||||
#define SCENE_DELETE_CUSTOM_EVENT (0UL)
|
||||
#define MAX_TEXT_INPUT_LEN 22
|
||||
|
||||
96
applications/main/archive/scenes/archive_scene_info.c
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "../archive_i.h"
|
||||
#include "../helpers/archive_browser.h"
|
||||
|
||||
#define TAG "Archive"
|
||||
|
||||
void archive_scene_info_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
ArchiveApp* app = (ArchiveApp*)context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void archive_scene_info_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
ArchiveApp* instance = context;
|
||||
|
||||
widget_add_button_element(
|
||||
instance->widget, GuiButtonTypeLeft, "Back", archive_scene_info_widget_callback, instance);
|
||||
|
||||
string_t filename;
|
||||
string_t dirname;
|
||||
string_t str_size;
|
||||
string_init(filename);
|
||||
string_init(dirname);
|
||||
string_init(str_size);
|
||||
|
||||
ArchiveFile_t* current = archive_get_current_file(instance->browser);
|
||||
char file_info_message[128];
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
// Filename
|
||||
path_extract_filename(current->path, filename, false);
|
||||
snprintf(file_info_message, sizeof(file_info_message), "\e#%s\e#", string_get_cstr(filename));
|
||||
widget_add_text_box_element(
|
||||
instance->widget, 0, 0, 128, 25, AlignLeft, AlignCenter, file_info_message, false);
|
||||
|
||||
// Directory path
|
||||
path_extract_dirname(string_get_cstr(current->path), dirname);
|
||||
if(strcmp(string_get_cstr(dirname), "/any") == 0) {
|
||||
string_replace_str(dirname, STORAGE_ANY_PATH_PREFIX, "/");
|
||||
} else {
|
||||
string_replace_str(dirname, STORAGE_ANY_PATH_PREFIX, "");
|
||||
}
|
||||
|
||||
// File size
|
||||
FileInfo fileinfo;
|
||||
storage_common_stat(fs_api, string_get_cstr(current->path), &fileinfo);
|
||||
if(fileinfo.size <= 1024) {
|
||||
string_printf(str_size, "%d", fileinfo.size);
|
||||
snprintf(
|
||||
file_info_message,
|
||||
sizeof(file_info_message),
|
||||
"Size: \e#%s\e# bytes\n%s",
|
||||
string_get_cstr(str_size),
|
||||
string_get_cstr(dirname));
|
||||
} else {
|
||||
string_printf(str_size, "%d", fileinfo.size / 1024);
|
||||
snprintf(
|
||||
file_info_message,
|
||||
sizeof(file_info_message),
|
||||
"Size: \e#%s\e# Kb.\n%s",
|
||||
string_get_cstr(str_size),
|
||||
string_get_cstr(dirname));
|
||||
}
|
||||
widget_add_text_box_element(
|
||||
instance->widget, 0, 25, 128, 25, AlignLeft, AlignCenter, file_info_message, true);
|
||||
|
||||
// This one to return and cursor select this file
|
||||
path_extract_filename_no_ext(string_get_cstr(current->path), filename);
|
||||
strlcpy(instance->text_store, string_get_cstr(filename), MAX_NAME_LEN);
|
||||
|
||||
string_clear(filename);
|
||||
string_clear(dirname);
|
||||
string_clear(str_size);
|
||||
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, ArchiveViewWidget);
|
||||
}
|
||||
|
||||
bool archive_scene_info_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
ArchiveApp* app = (ArchiveApp*)context;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
scene_manager_next_scene(app->scene_manager, ArchiveAppSceneBrowser);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void archive_scene_info_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
ArchiveApp* app = (ArchiveApp*)context;
|
||||
|
||||
widget_reset(app->widget);
|
||||
}
|
||||
@@ -4,6 +4,9 @@
|
||||
#include "../helpers/archive_browser.h"
|
||||
#include "archive/views/archive_browser_view.h"
|
||||
#include "toolbox/path.h"
|
||||
#include <dialogs/dialogs.h>
|
||||
|
||||
#define TAG "Archive"
|
||||
|
||||
#define SCENE_RENAME_CUSTOM_EVENT (0UL)
|
||||
#define MAX_TEXT_INPUT_LEN 22
|
||||
@@ -14,63 +17,87 @@ void archive_scene_rename_text_input_callback(void* context) {
|
||||
}
|
||||
|
||||
void archive_scene_rename_on_enter(void* context) {
|
||||
ArchiveApp* archive = (ArchiveApp*)context;
|
||||
ArchiveApp* archive = context;
|
||||
|
||||
TextInput* text_input = archive->text_input;
|
||||
ArchiveFile_t* current = archive_get_current_file(archive->browser);
|
||||
|
||||
string_t filename;
|
||||
string_init(filename);
|
||||
path_extract_filename(current->path, filename, true);
|
||||
strlcpy(archive->text_store, string_get_cstr(filename), MAX_NAME_LEN);
|
||||
string_t path_name;
|
||||
string_init(path_name);
|
||||
|
||||
path_extract_extension(current->path, archive->file_extension, MAX_EXT_LEN);
|
||||
if(current->type == ArchiveFileTypeFolder) {
|
||||
path_extract_basename(string_get_cstr(current->path), path_name);
|
||||
strlcpy(archive->text_store, string_get_cstr(path_name), MAX_NAME_LEN);
|
||||
text_input_set_header_text(text_input, "Rename directory:");
|
||||
} else /*if(current->type != ArchiveFileTypeUnknown) */ {
|
||||
path_extract_filename(current->path, path_name, true);
|
||||
strlcpy(archive->text_store, string_get_cstr(path_name), MAX_NAME_LEN);
|
||||
|
||||
text_input_set_header_text(text_input, "Rename:");
|
||||
path_extract_extension(current->path, archive->file_extension, MAX_EXT_LEN);
|
||||
text_input_set_header_text(text_input, "Rename file:");
|
||||
} /*else {
|
||||
path_extract_filename(current->path, path_name, false);
|
||||
strlcpy(archive->text_store, string_get_cstr(path_name), MAX_NAME_LEN);
|
||||
text_input_set_header_text(text_input, "Rename unknown file:");
|
||||
}*/
|
||||
|
||||
text_input_set_result_callback(
|
||||
text_input,
|
||||
archive_scene_rename_text_input_callback,
|
||||
archive,
|
||||
context,
|
||||
archive->text_store,
|
||||
MAX_TEXT_INPUT_LEN,
|
||||
false);
|
||||
|
||||
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
|
||||
string_get_cstr(archive->browser->path), archive->file_extension, "");
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
|
||||
string_clear(filename);
|
||||
string_clear(path_name);
|
||||
|
||||
view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput);
|
||||
}
|
||||
|
||||
bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) {
|
||||
ArchiveApp* archive = (ArchiveApp*)context;
|
||||
ArchiveApp* archive = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SCENE_RENAME_CUSTOM_EVENT) {
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
const char* path_src = archive_get_name(archive->browser);
|
||||
ArchiveFile_t* file = archive_get_current_file(archive->browser);
|
||||
|
||||
string_t path_dst;
|
||||
string_init(path_dst);
|
||||
path_extract_dirname(path_src, path_dst);
|
||||
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));
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
if(file->fav) {
|
||||
archive_favorites_rename(path_src, string_get_cstr(path_dst));
|
||||
if(file->type == ArchiveFileTypeFolder) {
|
||||
// Rename folder/dir
|
||||
path_extract_dirname(path_src, path_dst);
|
||||
string_cat_printf(path_dst, "/%s", archive->text_store);
|
||||
} else if(file->type != ArchiveFileTypeUnknown) {
|
||||
// Rename known type
|
||||
path_extract_dirname(path_src, path_dst);
|
||||
string_cat_printf(path_dst, "/%s%s", archive->text_store, known_ext[file->type]);
|
||||
} else {
|
||||
// Rename unknown type
|
||||
path_extract_dirname(path_src, path_dst);
|
||||
string_cat_printf(path_dst, "/%s%s", archive->text_store, archive->file_extension);
|
||||
}
|
||||
// Long time process if this is directory
|
||||
view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewStack);
|
||||
archive_show_loading_popup(archive, true);
|
||||
FS_Error error =
|
||||
archive_rename_file_or_dir(archive->browser, path_src, string_get_cstr(path_dst));
|
||||
archive_show_loading_popup(archive, false);
|
||||
archive_show_file_menu(archive->browser, false);
|
||||
|
||||
string_clear(path_dst);
|
||||
|
||||
scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneBrowser);
|
||||
if(error == FSE_OK || error == FSE_EXIST) {
|
||||
scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneBrowser);
|
||||
} else {
|
||||
string_t dialog_msg;
|
||||
string_init(dialog_msg);
|
||||
string_cat_printf(dialog_msg, "Cannot rename\nCode: %d", error);
|
||||
dialog_message_show_storage_error(archive->dialogs, string_get_cstr(dialog_msg));
|
||||
string_clear(dialog_msg);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
@@ -78,12 +105,6 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
|
||||
void archive_scene_rename_on_exit(void* context) {
|
||||
ArchiveApp* archive = (ArchiveApp*)context;
|
||||
|
||||
// Clear view
|
||||
void* validator_context = text_input_get_validator_callback_context(archive->text_input);
|
||||
text_input_set_validator(archive->text_input, NULL, NULL);
|
||||
validator_is_file_free(validator_context);
|
||||
|
||||
ArchiveApp* archive = context;
|
||||
text_input_reset(archive->text_input);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "archive_browser_view.h"
|
||||
#include "../helpers/archive_browser.h"
|
||||
|
||||
#define TAG "Archive"
|
||||
|
||||
static const char* ArchiveTabNames[] = {
|
||||
[ArchiveTabFavorites] = "Favorites",
|
||||
[ArchiveTabIButton] = "iButton",
|
||||
@@ -14,6 +16,7 @@ static const char* ArchiveTabNames[] = {
|
||||
[ArchiveTabInfrared] = "Infrared",
|
||||
[ArchiveTabBadUsb] = "Bad USB",
|
||||
[ArchiveTabU2f] = "U2F",
|
||||
[ArchiveTabApps] = "Apps",
|
||||
[ArchiveTabBrowser] = "Browser",
|
||||
};
|
||||
|
||||
@@ -25,6 +28,7 @@ static const Icon* ArchiveItemIcons[] = {
|
||||
[ArchiveFileTypeInfrared] = &I_ir_10px,
|
||||
[ArchiveFileTypeBadUsb] = &I_badusb_10px,
|
||||
[ArchiveFileTypeU2f] = &I_u2f_10px,
|
||||
[ArchiveFileTypeApps] = &I_Apps_10px,
|
||||
[ArchiveFileTypeUpdateManifest] = &I_update_10px,
|
||||
[ArchiveFileTypeFolder] = &I_dir_10px,
|
||||
[ArchiveFileTypeUnknown] = &I_unknown_10px,
|
||||
@@ -42,43 +46,142 @@ void archive_browser_set_callback(
|
||||
}
|
||||
|
||||
static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_box(canvas, 71, 17, 57, 46);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
elements_slightly_rounded_frame(canvas, 70, 16, 58, 48);
|
||||
if(menu_array_size(model->context_menu) == 0) {
|
||||
// Context menu is empty, init array
|
||||
string_t item_run;
|
||||
string_t item_pin;
|
||||
string_t item_info;
|
||||
string_t item_rename;
|
||||
string_t item_delete;
|
||||
|
||||
string_t menu[MENU_ITEMS];
|
||||
string_init_set_str(item_run, "Run In App");
|
||||
string_init_set_str(item_pin, "Pin");
|
||||
string_init_set_str(item_info, "Info");
|
||||
string_init_set_str(item_rename, "Rename");
|
||||
string_init_set_str(item_delete, "Delete");
|
||||
|
||||
string_init_set_str(menu[0], "Run in app");
|
||||
string_init_set_str(menu[1], "Pin");
|
||||
string_init_set_str(menu[2], "Rename");
|
||||
string_init_set_str(menu[3], "Delete");
|
||||
// Need init context menu
|
||||
ArchiveFile_t* selected =
|
||||
files_array_get(model->files, model->item_idx - model->array_offset);
|
||||
|
||||
ArchiveFile_t* selected = files_array_get(model->files, model->item_idx - model->array_offset);
|
||||
|
||||
if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) {
|
||||
string_set_str(menu[1], "Unpin");
|
||||
}
|
||||
|
||||
if(!archive_is_known_app(selected->type)) {
|
||||
string_set_str(menu[0], "---");
|
||||
string_set_str(menu[1], "---");
|
||||
string_set_str(menu[2], "---");
|
||||
} else {
|
||||
if(model->tab_idx == ArchiveTabFavorites) {
|
||||
string_set_str(menu[2], "Move");
|
||||
string_set_str(menu[3], "---");
|
||||
} else if(selected->is_app) {
|
||||
string_set_str(menu[2], "---");
|
||||
if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) {
|
||||
string_set_str(item_pin, "Unpin");
|
||||
}
|
||||
|
||||
if(selected->type == ArchiveFileTypeFolder) {
|
||||
//FURI_LOG_D(TAG, "Directory type");
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_rename,
|
||||
ArchiveBrowserEventFileMenuRename);
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_delete,
|
||||
ArchiveBrowserEventFileMenuDelete);
|
||||
} else if(!archive_is_known_app(selected->type)) {
|
||||
//FURI_LOG_D(TAG, "Unknown type");
|
||||
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_info,
|
||||
ArchiveBrowserEventFileMenuInfo);
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_rename,
|
||||
ArchiveBrowserEventFileMenuRename);
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_delete,
|
||||
ArchiveBrowserEventFileMenuDelete);
|
||||
} else if(model->tab_idx == ArchiveTabFavorites) {
|
||||
//FURI_LOG_D(TAG, "ArchiveTabFavorites");
|
||||
|
||||
string_set_str(item_rename, "Move");
|
||||
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_run,
|
||||
ArchiveBrowserEventFileMenuRun);
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_pin,
|
||||
ArchiveBrowserEventFileMenuPin);
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_rename,
|
||||
ArchiveBrowserEventFileMenuRename);
|
||||
} else if(selected->is_app) {
|
||||
//FURI_LOG_D(TAG, "3 types");
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_run,
|
||||
ArchiveBrowserEventFileMenuRun);
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_info,
|
||||
ArchiveBrowserEventFileMenuInfo);
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_pin,
|
||||
ArchiveBrowserEventFileMenuPin);
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_delete,
|
||||
ArchiveBrowserEventFileMenuDelete);
|
||||
} else {
|
||||
//FURI_LOG_D(TAG, "All menu");
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_run,
|
||||
ArchiveBrowserEventFileMenuRun);
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_pin,
|
||||
ArchiveBrowserEventFileMenuPin);
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_info,
|
||||
ArchiveBrowserEventFileMenuInfo);
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_rename,
|
||||
ArchiveBrowserEventFileMenuRename);
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
item_delete,
|
||||
ArchiveBrowserEventFileMenuDelete);
|
||||
}
|
||||
|
||||
string_clear(item_run);
|
||||
string_clear(item_pin);
|
||||
string_clear(item_info);
|
||||
string_clear(item_rename);
|
||||
string_clear(item_delete);
|
||||
} /*else {
|
||||
FURI_LOG_D(TAG, "menu_array_size already set: %d", menu_array_size(model->context_menu));
|
||||
}*/
|
||||
size_t size_menu = menu_array_size(model->context_menu);
|
||||
const uint8_t menu_height = 48;
|
||||
const uint8_t line_height = 10;
|
||||
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
uint8_t calc_height = menu_height - ((MENU_ITEMS - size_menu) * line_height);
|
||||
canvas_draw_box(canvas, 71, 11, 57, calc_height + 4);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
elements_slightly_rounded_frame(canvas, 70, 12, 58, calc_height + 4);
|
||||
|
||||
/*FURI_LOG_D(
|
||||
TAG,
|
||||
"size_menu: %d, calc_height: %d, menu_idx: %d",
|
||||
size_menu,
|
||||
calc_height,
|
||||
model->menu_idx);*/
|
||||
for(size_t i = 0; i < size_menu; i++) {
|
||||
ArchiveContextMenuItem_t* current = menu_array_get(model->context_menu, i);
|
||||
canvas_draw_str(canvas, 82, 21 + i * line_height, string_get_cstr(current->text));
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < MENU_ITEMS; i++) {
|
||||
canvas_draw_str(canvas, 82, 27 + i * 11, string_get_cstr(menu[i]));
|
||||
string_clear(menu[i]);
|
||||
}
|
||||
|
||||
canvas_draw_icon(canvas, 74, 20 + model->menu_idx * 11, &I_ButtonRight_4x7);
|
||||
canvas_draw_icon(canvas, 74, 14 + model->menu_idx * line_height, &I_ButtonRight_4x7);
|
||||
}
|
||||
|
||||
static void archive_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar, bool moving) {
|
||||
@@ -250,32 +353,33 @@ static bool archive_view_input(InputEvent* event, void* context) {
|
||||
});
|
||||
|
||||
if(in_menu) {
|
||||
if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyUp || event->key == InputKeyDown) {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
if(event->key == InputKeyUp) {
|
||||
model->menu_idx = ((model->menu_idx - 1) + MENU_ITEMS) % MENU_ITEMS;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
model->menu_idx = (model->menu_idx + 1) % MENU_ITEMS;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if(event->key == InputKeyOk) {
|
||||
uint8_t idx;
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
idx = model->menu_idx;
|
||||
return false;
|
||||
});
|
||||
browser->callback(file_menu_actions[idx], browser->context);
|
||||
} else if(event->key == InputKeyBack) {
|
||||
browser->callback(ArchiveBrowserEventFileMenuClose, browser->context);
|
||||
}
|
||||
if(event->type != InputTypeShort) {
|
||||
return true; // RETURN
|
||||
}
|
||||
if(event->key == InputKeyUp || event->key == InputKeyDown) {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
size_t size_menu = menu_array_size(model->context_menu);
|
||||
if(event->key == InputKeyUp) {
|
||||
model->menu_idx = ((model->menu_idx - 1) + size_menu) % size_menu;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
model->menu_idx = (model->menu_idx + 1) % size_menu;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
} else if(event->key == InputKeyOk) {
|
||||
uint32_t idx;
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
ArchiveContextMenuItem_t* current =
|
||||
menu_array_get(model->context_menu, model->menu_idx);
|
||||
idx = current->event;
|
||||
return false;
|
||||
});
|
||||
browser->callback(idx, browser->context);
|
||||
} else if(event->key == InputKeyBack) {
|
||||
browser->callback(ArchiveBrowserEventFileMenuClose, browser->context);
|
||||
}
|
||||
|
||||
} else {
|
||||
if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyLeft || event->key == InputKeyRight) {
|
||||
@@ -366,6 +470,7 @@ ArchiveBrowserView* browser_alloc() {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
files_array_init(model->files);
|
||||
menu_array_init(model->context_menu);
|
||||
model->tab_idx = TAB_DEFAULT;
|
||||
return true;
|
||||
});
|
||||
@@ -383,6 +488,7 @@ void browser_free(ArchiveBrowserView* browser) {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
files_array_clear(model->files);
|
||||
menu_array_clear(model->context_menu);
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -390,4 +496,4 @@ void browser_free(ArchiveBrowserView* browser) {
|
||||
|
||||
view_free(browser->view);
|
||||
free(browser);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <furi.h>
|
||||
#include <storage/storage.h>
|
||||
#include "../helpers/archive_files.h"
|
||||
#include "../helpers/archive_menu.h"
|
||||
#include "../helpers/archive_favorites.h"
|
||||
#include "gui/modules/file_browser_worker.h"
|
||||
|
||||
@@ -14,7 +15,7 @@
|
||||
#define MAX_NAME_LEN 255
|
||||
#define MAX_EXT_LEN 6
|
||||
#define FRAME_HEIGHT 12
|
||||
#define MENU_ITEMS 4u
|
||||
#define MENU_ITEMS 5u
|
||||
#define MOVE_OFFSET 5u
|
||||
|
||||
typedef enum {
|
||||
@@ -26,17 +27,20 @@ typedef enum {
|
||||
ArchiveTabIButton,
|
||||
ArchiveTabBadUsb,
|
||||
ArchiveTabU2f,
|
||||
ArchiveTabApps,
|
||||
ArchiveTabBrowser,
|
||||
ArchiveTabTotal,
|
||||
} ArchiveTabEnum;
|
||||
|
||||
typedef enum {
|
||||
ArchiveBrowserEventFileMenuNone,
|
||||
ArchiveBrowserEventFileMenuOpen,
|
||||
ArchiveBrowserEventFileMenuClose,
|
||||
ArchiveBrowserEventFileMenuRun,
|
||||
ArchiveBrowserEventFileMenuPin,
|
||||
ArchiveBrowserEventFileMenuRename,
|
||||
ArchiveBrowserEventFileMenuDelete,
|
||||
ArchiveBrowserEventFileMenuInfo,
|
||||
ArchiveBrowserEventFileMenuClose,
|
||||
|
||||
ArchiveBrowserEventEnterDir,
|
||||
|
||||
@@ -54,13 +58,6 @@ typedef enum {
|
||||
ArchiveBrowserEventExit,
|
||||
} ArchiveBrowserEvent;
|
||||
|
||||
static const uint8_t file_menu_actions[MENU_ITEMS] = {
|
||||
[0] = ArchiveBrowserEventFileMenuRun,
|
||||
[1] = ArchiveBrowserEventFileMenuPin,
|
||||
[2] = ArchiveBrowserEventFileMenuRename,
|
||||
[3] = ArchiveBrowserEventFileMenuDelete,
|
||||
};
|
||||
|
||||
typedef struct ArchiveBrowserView ArchiveBrowserView;
|
||||
|
||||
typedef void (*ArchiveBrowserViewCallback)(ArchiveBrowserEvent event, void* context);
|
||||
@@ -88,6 +85,8 @@ typedef struct {
|
||||
|
||||
uint8_t menu_idx;
|
||||
bool menu;
|
||||
menu_array_t context_menu;
|
||||
|
||||
bool move_fav;
|
||||
bool list_loading;
|
||||
bool folder_loading;
|
||||
@@ -106,4 +105,5 @@ void archive_browser_set_callback(
|
||||
View* archive_browser_get_view(ArchiveBrowserView* browser);
|
||||
|
||||
ArchiveBrowserView* browser_alloc();
|
||||
|
||||
void browser_free(ArchiveBrowserView* browser);
|
||||
|
||||
@@ -33,5 +33,4 @@ typedef enum {
|
||||
typedef struct {
|
||||
TimeFormat time_format;
|
||||
DateFormat date_format;
|
||||
uint8_t increment_precision;
|
||||
} ClockSettings;
|
||||
@@ -25,7 +25,7 @@ static bool
|
||||
FlipperApplication* app = flipper_application_alloc(loader->storage, &hashtable_api_interface);
|
||||
|
||||
FlipperApplicationPreloadStatus preload_res =
|
||||
flipper_application_preload(app, string_get_cstr(path));
|
||||
flipper_application_preload_manifest(app, string_get_cstr(path));
|
||||
|
||||
bool load_success = false;
|
||||
|
||||
|
||||
@@ -33,8 +33,6 @@ static void infrared_scene_universal_common_hide_popup(Infrared* infrared) {
|
||||
|
||||
void infrared_scene_universal_common_on_enter(void* context) {
|
||||
Infrared* infrared = context;
|
||||
infrared_brute_force_clear_records(infrared->brute_force);
|
||||
button_panel_reset_selection(infrared->button_panel);
|
||||
view_stack_add_view(infrared->view_stack, button_panel_get_view(infrared->button_panel));
|
||||
}
|
||||
|
||||
@@ -89,5 +87,6 @@ void infrared_scene_universal_common_on_exit(void* context) {
|
||||
Infrared* infrared = context;
|
||||
ButtonPanel* button_panel = infrared->button_panel;
|
||||
view_stack_remove_view(infrared->view_stack, button_panel_get_view(button_panel));
|
||||
infrared_brute_force_clear_records(infrared->brute_force);
|
||||
button_panel_reset(button_panel);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ static void lfrfid_view_read_draw_callback(Canvas* canvas, void* _model) {
|
||||
LfRfidReadViewModel* model = _model;
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
canvas_draw_icon(canvas, 0, 8, &I_NFC_manual);
|
||||
canvas_draw_icon(canvas, 0, 8, &I_NFC_manual_60x50);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
|
||||
@@ -231,7 +231,30 @@ void nfc_show_loading_popup(void* context, bool show) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool nfc_is_hal_ready() {
|
||||
if(!furi_hal_nfc_is_init()) {
|
||||
// No connection to the chip, show an error screen
|
||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
dialog_message_set_text(
|
||||
message,
|
||||
"Error!\nNFC chip failed to start\n\n\nSend a photo of this to:\nsupport@flipperzero.one",
|
||||
0,
|
||||
0,
|
||||
AlignLeft,
|
||||
AlignTop);
|
||||
dialog_message_show(dialogs, message);
|
||||
dialog_message_free(message);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t nfc_app(void* p) {
|
||||
if(!nfc_is_hal_ready()) return 0;
|
||||
|
||||
Nfc* nfc = nfc_alloc();
|
||||
char* args = p;
|
||||
|
||||
|
||||
@@ -33,8 +33,14 @@
|
||||
#include <nfc/scenes/nfc_scene.h>
|
||||
#include <nfc/helpers/nfc_custom_event.h>
|
||||
|
||||
#include <dialogs/dialogs.h>
|
||||
|
||||
#include "rpc/rpc_app.h"
|
||||
|
||||
#include <m-array.h>
|
||||
|
||||
ARRAY_DEF(MfClassicUserKeys, char*, M_PTR_OPLIST);
|
||||
|
||||
#define NFC_TEXT_STORE_SIZE 128
|
||||
|
||||
typedef enum {
|
||||
@@ -58,6 +64,7 @@ struct Nfc {
|
||||
char text_store[NFC_TEXT_STORE_SIZE + 1];
|
||||
string_t text_box_store;
|
||||
uint8_t byte_input_store[6];
|
||||
MfClassicUserKeys_t mfc_key_strs; // Used in MFC key listing
|
||||
|
||||
void* rpc_ctx;
|
||||
NfcRpcState rpc_state;
|
||||
|
||||
@@ -32,6 +32,9 @@ ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu)
|
||||
ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate)
|
||||
ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys)
|
||||
ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd)
|
||||
ADD_SCENE(nfc, mf_classic_keys_list, MfClassicKeysList)
|
||||
ADD_SCENE(nfc, mf_classic_keys_delete, MfClassicKeysDelete)
|
||||
ADD_SCENE(nfc, mf_classic_keys_warn_duplicate, MfClassicKeysWarnDuplicate)
|
||||
ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack)
|
||||
ADD_SCENE(nfc, emv_read_success, EmvReadSuccess)
|
||||
ADD_SCENE(nfc, emv_menu, EmvMenu)
|
||||
|
||||
@@ -25,8 +25,13 @@ bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventViewExit) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneFileSelect);
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfClassicKeys);
|
||||
} else {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
|
||||
@@ -47,7 +47,9 @@ void nfc_scene_device_info_on_enter(void* context) {
|
||||
}
|
||||
string_clear(country_name);
|
||||
}
|
||||
} else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) {
|
||||
} else if(
|
||||
dev_data->protocol == NfcDeviceProtocolMifareClassic ||
|
||||
dev_data->protocol == NfcDeviceProtocolMifareUl) {
|
||||
string_set(temp_str, nfc->dev->dev_data.parsed_data);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,10 @@ bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventViewExit) {
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneExtraActions)) {
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfClassicKeys);
|
||||
} else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneExtraActions)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneExtraActions);
|
||||
} else {
|
||||
|
||||
@@ -17,7 +17,7 @@ void nfc_scene_extra_actions_on_enter(void* context) {
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Mf Classic Keys",
|
||||
"Mifare Classic Keys",
|
||||
SubmenuIndexMfClassicKeys,
|
||||
nfc_scene_extra_actions_submenu_callback,
|
||||
nfc);
|
||||
|
||||
@@ -26,15 +26,25 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) {
|
||||
}
|
||||
|
||||
widget_add_string_element(
|
||||
nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "MF Classic Keys");
|
||||
nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Mifare Classic Keys");
|
||||
char temp_str[32];
|
||||
snprintf(temp_str, sizeof(temp_str), "Flipper dict: %ld", flipper_dict_keys_total);
|
||||
snprintf(temp_str, sizeof(temp_str), "Flipper list: %ld", flipper_dict_keys_total);
|
||||
widget_add_string_element(nfc->widget, 0, 20, AlignLeft, AlignTop, FontSecondary, temp_str);
|
||||
snprintf(temp_str, sizeof(temp_str), "User dict: %ld", user_dict_keys_total);
|
||||
snprintf(temp_str, sizeof(temp_str), "User list: %ld", user_dict_keys_total);
|
||||
widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str);
|
||||
widget_add_button_element(
|
||||
nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc);
|
||||
widget_add_icon_element(nfc->widget, 90, 12, &I_Keychain);
|
||||
widget_add_button_element(
|
||||
nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_mf_classic_keys_widget_callback, nfc);
|
||||
widget_add_icon_element(nfc->widget, 87, 13, &I_Keychain_39x36);
|
||||
if(user_dict_keys_total > 0) {
|
||||
widget_add_button_element(
|
||||
nfc->widget,
|
||||
GuiButtonTypeRight,
|
||||
"List",
|
||||
nfc_scene_mf_classic_keys_widget_callback,
|
||||
nfc);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||
}
|
||||
@@ -47,6 +57,12 @@ bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event)
|
||||
if(event.event == GuiButtonTypeCenter) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysAdd);
|
||||
consumed = true;
|
||||
} else if(event.event == GuiButtonTypeLeft) {
|
||||
scene_manager_previous_scene(nfc->scene_manager);
|
||||
consumed = true;
|
||||
} else if(event.event == GuiButtonTypeRight) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysList);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,15 +29,16 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventByteInputDone) {
|
||||
// Add key to dict
|
||||
bool key_added = false;
|
||||
MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser);
|
||||
if(dict) {
|
||||
if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) {
|
||||
key_added = true;
|
||||
if(mf_classic_dict_is_key_present(dict, nfc->byte_input_store)) {
|
||||
scene_manager_next_scene(
|
||||
nfc->scene_manager, NfcSceneMfClassicKeysWarnDuplicate);
|
||||
} else if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
||||
} else {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
||||
}
|
||||
}
|
||||
if(key_added) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
||||
} else {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
void nfc_scene_mf_classic_keys_delete_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
Nfc* nfc = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_keys_delete_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser);
|
||||
uint32_t key_index =
|
||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete);
|
||||
// Setup Custom Widget view
|
||||
string_t key_str;
|
||||
string_init(key_str);
|
||||
|
||||
widget_add_string_element(
|
||||
nfc->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Delete this key?");
|
||||
widget_add_button_element(
|
||||
nfc->widget,
|
||||
GuiButtonTypeLeft,
|
||||
"Cancel",
|
||||
nfc_scene_mf_classic_keys_delete_widget_callback,
|
||||
nfc);
|
||||
widget_add_button_element(
|
||||
nfc->widget,
|
||||
GuiButtonTypeRight,
|
||||
"Delete",
|
||||
nfc_scene_mf_classic_keys_delete_widget_callback,
|
||||
nfc);
|
||||
|
||||
mf_classic_dict_get_key_at_index_str(dict, key_str, key_index);
|
||||
widget_add_string_element(
|
||||
nfc->widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(key_str));
|
||||
|
||||
string_clear(key_str);
|
||||
mf_classic_dict_free(dict);
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_classic_keys_delete_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
uint32_t key_index =
|
||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete);
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfClassicKeys);
|
||||
} else if(event.event == GuiButtonTypeRight) {
|
||||
MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser);
|
||||
if(mf_classic_dict_delete_index(dict, key_index)) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess);
|
||||
} else {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfClassicKeys);
|
||||
}
|
||||
mf_classic_dict_free(dict);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_keys_delete_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
widget_reset(nfc->widget);
|
||||
}
|
||||
100
applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c
Normal file
@@ -0,0 +1,100 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
#define NFC_SCENE_MF_CLASSIC_KEYS_LIST_MAX (100)
|
||||
|
||||
void nfc_scene_mf_classic_keys_list_submenu_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_keys_list_popup_callback(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_keys_list_prepare(Nfc* nfc, MfClassicDict* dict) {
|
||||
Submenu* submenu = nfc->submenu;
|
||||
uint32_t index = 0;
|
||||
string_t temp_key;
|
||||
string_init(temp_key);
|
||||
|
||||
submenu_set_header(submenu, "Select key to delete:");
|
||||
while(mf_classic_dict_get_next_key_str(dict, temp_key)) {
|
||||
char* current_key = (char*)malloc(sizeof(char) * 13);
|
||||
strncpy(current_key, string_get_cstr(temp_key), 12);
|
||||
MfClassicUserKeys_push_back(nfc->mfc_key_strs, current_key);
|
||||
FURI_LOG_D("ListKeys", "Key %d: %s", index, current_key);
|
||||
submenu_add_item(
|
||||
submenu, current_key, index++, nfc_scene_mf_classic_keys_list_submenu_callback, nfc);
|
||||
}
|
||||
string_clear(temp_key);
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_keys_list_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser);
|
||||
MfClassicUserKeys_init(nfc->mfc_key_strs);
|
||||
if(dict) {
|
||||
uint32_t total_user_keys = mf_classic_dict_get_total_keys(dict);
|
||||
if(total_user_keys < NFC_SCENE_MF_CLASSIC_KEYS_LIST_MAX) {
|
||||
nfc_scene_mf_classic_keys_list_prepare(nfc, dict);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
} else {
|
||||
popup_set_header(nfc->popup, "Too many keys!", 64, 0, AlignCenter, AlignTop);
|
||||
popup_set_text(
|
||||
nfc->popup,
|
||||
"Edit user dictionary\nwith file browser",
|
||||
64,
|
||||
12,
|
||||
AlignCenter,
|
||||
AlignTop);
|
||||
popup_set_callback(nfc->popup, nfc_scene_mf_classic_keys_list_popup_callback);
|
||||
popup_set_context(nfc->popup, nfc);
|
||||
popup_set_timeout(nfc->popup, 3000);
|
||||
popup_enable_timeout(nfc->popup);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||
}
|
||||
mf_classic_dict_free(dict);
|
||||
} else {
|
||||
popup_set_header(
|
||||
nfc->popup, "Failed to load dictionary", 64, 32, AlignCenter, AlignCenter);
|
||||
popup_set_callback(nfc->popup, nfc_scene_mf_classic_keys_list_popup_callback);
|
||||
popup_set_context(nfc->popup, nfc);
|
||||
popup_set_timeout(nfc->popup, 3000);
|
||||
popup_enable_timeout(nfc->popup);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||
}
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_classic_keys_list_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventViewExit) {
|
||||
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||
} else {
|
||||
scene_manager_set_scene_state(
|
||||
nfc->scene_manager, NfcSceneMfClassicKeysDelete, event.event);
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysDelete);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_keys_list_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
MfClassicUserKeys_it_t it;
|
||||
for(MfClassicUserKeys_it(it, nfc->mfc_key_strs); !MfClassicUserKeys_end_p(it);
|
||||
MfClassicUserKeys_next(it)) {
|
||||
free(*MfClassicUserKeys_ref(it));
|
||||
}
|
||||
MfClassicUserKeys_clear(nfc->mfc_key_strs);
|
||||
submenu_reset(nfc->submenu);
|
||||
popup_reset(nfc->popup);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "../nfc_i.h"
|
||||
|
||||
void nfc_scene_mf_classic_keys_warn_duplicate_popup_callback(void* context) {
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_keys_warn_duplicate_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Setup view
|
||||
Popup* popup = nfc->popup;
|
||||
popup_set_icon(popup, 72, 16, &I_DolphinCommon_56x48);
|
||||
popup_set_header(popup, "Key already exists!", 64, 3, AlignCenter, AlignTop);
|
||||
popup_set_text(
|
||||
popup,
|
||||
"Please enter a\n"
|
||||
"different key.",
|
||||
4,
|
||||
24,
|
||||
AlignLeft,
|
||||
AlignTop);
|
||||
popup_set_timeout(popup, 5000);
|
||||
popup_set_context(popup, nfc);
|
||||
popup_set_callback(popup, nfc_scene_mf_classic_keys_warn_duplicate_popup_callback);
|
||||
popup_enable_timeout(popup);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_classic_keys_warn_duplicate_on_event(void* context, SceneManagerEvent event) {
|
||||
Nfc* nfc = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventViewExit) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfClassicKeysAdd);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_scene_mf_classic_keys_warn_duplicate_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
popup_reset(nfc->popup);
|
||||
}
|
||||
@@ -7,6 +7,13 @@ enum SubmenuIndex {
|
||||
SubmenuIndexDynamic, // dynamic indexes start here
|
||||
};
|
||||
|
||||
void nfc_scene_mf_desfire_popup_callback(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
Nfc* nfc = context;
|
||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||
}
|
||||
|
||||
MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(Nfc* nfc) {
|
||||
uint32_t app_idx = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp) >>
|
||||
1;
|
||||
@@ -25,46 +32,45 @@ void nfc_scene_mf_desfire_app_submenu_callback(void* context, uint32_t index) {
|
||||
|
||||
void nfc_scene_mf_desfire_app_on_enter(void* context) {
|
||||
Nfc* nfc = context;
|
||||
Submenu* submenu = nfc->submenu;
|
||||
MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc);
|
||||
if(!app) {
|
||||
popup_set_icon(nfc->popup, 5, 5, &I_WarningDolphin_45x42);
|
||||
popup_set_header(nfc->popup, "Internal Error!", 55, 12, AlignLeft, AlignBottom);
|
||||
popup_set_text(
|
||||
nfc->popup,
|
||||
"No app selected.\nThis should\nnever happen,\nplease file a bug.",
|
||||
55,
|
||||
15,
|
||||
AlignLeft,
|
||||
AlignTop);
|
||||
popup_set_header(nfc->popup, "Empty card!", 55, 12, AlignLeft, AlignBottom);
|
||||
popup_set_callback(nfc->popup, nfc_scene_mf_desfire_popup_callback);
|
||||
popup_set_context(nfc->popup, nfc);
|
||||
popup_set_timeout(nfc->popup, 3000);
|
||||
popup_enable_timeout(nfc->popup);
|
||||
popup_set_text(nfc->popup, "No application\nfound.", 55, 15, AlignLeft, AlignTop);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||
FURI_LOG_E(TAG, "Bad state. No app selected?");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
text_box_set_font(nfc->text_box, TextBoxFontHex);
|
||||
submenu_add_item(
|
||||
nfc->submenu,
|
||||
"App info",
|
||||
SubmenuIndexAppInfo,
|
||||
nfc_scene_mf_desfire_app_submenu_callback,
|
||||
nfc);
|
||||
|
||||
text_box_set_font(nfc->text_box, TextBoxFontHex);
|
||||
|
||||
submenu_add_item(
|
||||
submenu, "App info", SubmenuIndexAppInfo, nfc_scene_mf_desfire_app_submenu_callback, nfc);
|
||||
|
||||
uint16_t cap = NFC_TEXT_STORE_SIZE;
|
||||
char* buf = nfc->text_store;
|
||||
int idx = SubmenuIndexDynamic;
|
||||
for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
|
||||
int size = snprintf(buf, cap, "File %d", file->id);
|
||||
if(size < 0 || size >= cap) {
|
||||
FURI_LOG_W(
|
||||
TAG,
|
||||
"Exceeded NFC_TEXT_STORE_SIZE when preparing file id strings; menu truncated");
|
||||
break;
|
||||
uint16_t cap = NFC_TEXT_STORE_SIZE;
|
||||
char* buf = nfc->text_store;
|
||||
int idx = SubmenuIndexDynamic;
|
||||
for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
|
||||
int size = snprintf(buf, cap, "File %d", file->id);
|
||||
if(size < 0 || size >= cap) {
|
||||
FURI_LOG_W(
|
||||
TAG,
|
||||
"Exceeded NFC_TEXT_STORE_SIZE when preparing file id strings; menu truncated");
|
||||
break;
|
||||
}
|
||||
char* label = buf;
|
||||
cap -= size + 1;
|
||||
buf += size + 1;
|
||||
submenu_add_item(
|
||||
nfc->submenu, label, idx++, nfc_scene_mf_desfire_app_submenu_callback, nfc);
|
||||
}
|
||||
char* label = buf;
|
||||
cap -= size + 1;
|
||||
buf += size + 1;
|
||||
submenu_add_item(submenu, label, idx++, nfc_scene_mf_desfire_app_submenu_callback, nfc);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
}
|
||||
}
|
||||
|
||||
bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) {
|
||||
@@ -73,26 +79,30 @@ bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) {
|
||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp);
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc);
|
||||
TextBox* text_box = nfc->text_box;
|
||||
string_reset(nfc->text_box_store);
|
||||
if(event.event == SubmenuIndexAppInfo) {
|
||||
mf_df_cat_application_info(app, nfc->text_box_store);
|
||||
if(event.event == NfcCustomEventViewExit) {
|
||||
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||
} else {
|
||||
uint16_t index = event.event - SubmenuIndexDynamic;
|
||||
MifareDesfireFile* file = app->file_head;
|
||||
for(int i = 0; file && i < index; i++) {
|
||||
file = file->next;
|
||||
MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc);
|
||||
TextBox* text_box = nfc->text_box;
|
||||
string_reset(nfc->text_box_store);
|
||||
if(event.event == SubmenuIndexAppInfo) {
|
||||
mf_df_cat_application_info(app, nfc->text_box_store);
|
||||
} else {
|
||||
uint16_t index = event.event - SubmenuIndexDynamic;
|
||||
MifareDesfireFile* file = app->file_head;
|
||||
for(int i = 0; file && i < index; i++) {
|
||||
file = file->next;
|
||||
}
|
||||
if(!file) {
|
||||
return false;
|
||||
}
|
||||
mf_df_cat_file(file, nfc->text_box_store);
|
||||
}
|
||||
if(!file) {
|
||||
return false;
|
||||
}
|
||||
mf_df_cat_file(file, nfc->text_box_store);
|
||||
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, state | 1);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||
consumed = true;
|
||||
}
|
||||
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
|
||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, state | 1);
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
if(state & 1) {
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||
@@ -108,6 +118,7 @@ void nfc_scene_mf_desfire_app_on_exit(void* context) {
|
||||
Nfc* nfc = context;
|
||||
|
||||
// Clear views
|
||||
popup_reset(nfc->popup);
|
||||
text_box_reset(nfc->text_box);
|
||||
string_reset(nfc->text_box_store);
|
||||
submenu_reset(nfc->submenu);
|
||||
|
||||
@@ -27,7 +27,7 @@ void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState
|
||||
popup_reset(nfc->popup);
|
||||
popup_set_text(
|
||||
nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop);
|
||||
popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual);
|
||||
popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50);
|
||||
} else if(state == NfcSceneMfUlReadStateReading) {
|
||||
popup_reset(nfc->popup);
|
||||
popup_set_header(
|
||||
|
||||
@@ -34,15 +34,19 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) {
|
||||
nfc);
|
||||
|
||||
string_t temp_str;
|
||||
string_init_printf(temp_str, "\e#%s\n", nfc_mf_ul_type(mf_ul_data->type, true));
|
||||
string_cat_printf(temp_str, "UID:");
|
||||
for(size_t i = 0; i < data->uid_len; i++) {
|
||||
string_cat_printf(temp_str, " %02X", data->uid[i]);
|
||||
}
|
||||
string_cat_printf(
|
||||
temp_str, "\nPages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4);
|
||||
if(mf_ul_data->data_read != mf_ul_data->data_size) {
|
||||
string_cat_printf(temp_str, "\nPassword-protected pages!");
|
||||
if(string_size(nfc->dev->dev_data.parsed_data)) {
|
||||
string_init_set(temp_str, nfc->dev->dev_data.parsed_data);
|
||||
} else {
|
||||
string_init_printf(temp_str, "\e#%s\n", nfc_mf_ul_type(mf_ul_data->type, true));
|
||||
string_cat_printf(temp_str, "UID:");
|
||||
for(size_t i = 0; i < data->uid_len; i++) {
|
||||
string_cat_printf(temp_str, " %02X", data->uid[i]);
|
||||
}
|
||||
string_cat_printf(
|
||||
temp_str, "\nPages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4);
|
||||
if(mf_ul_data->data_read != mf_ul_data->data_size) {
|
||||
string_cat_printf(temp_str, "\nPassword-protected pages!");
|
||||
}
|
||||
}
|
||||
widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str));
|
||||
string_clear(temp_str);
|
||||
|
||||
@@ -20,7 +20,7 @@ void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) {
|
||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Enter Password Manually",
|
||||
"Enter PWD Manually",
|
||||
SubmenuIndexMfUlUnlockMenuManual,
|
||||
nfc_scene_mf_ultralight_unlock_menu_submenu_callback,
|
||||
nfc);
|
||||
|
||||
@@ -26,7 +26,7 @@ void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) {
|
||||
popup_reset(nfc->popup);
|
||||
popup_set_text(
|
||||
nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop);
|
||||
popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual);
|
||||
popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50);
|
||||
} else if(state == NfcSceneReadStateReading) {
|
||||
popup_reset(nfc->popup);
|
||||
popup_set_header(
|
||||
|
||||
@@ -11,7 +11,7 @@ void nfc_scene_restore_original_confirm_on_enter(void* context) {
|
||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring);
|
||||
dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring_38x32);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "It will be returned\nto its original state.", 47, 21, AlignLeft, AlignTop);
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
|
||||
|
||||
@@ -27,7 +27,10 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventViewExit) {
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
|
||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneMfClassicKeys);
|
||||
} else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
nfc->scene_manager, NfcSceneSavedMenu);
|
||||
} else {
|
||||
|
||||
@@ -91,7 +91,9 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
bool application_info_present = false;
|
||||
if(dev_data->protocol == NfcDeviceProtocolEMV) {
|
||||
application_info_present = true;
|
||||
} else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) {
|
||||
} else if(
|
||||
dev_data->protocol == NfcDeviceProtocolMifareClassic ||
|
||||
dev_data->protocol == NfcDeviceProtocolMifareUl) {
|
||||
application_info_present = nfc_supported_card_verify_and_parse(dev_data);
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ bool subghz_scene_decode_raw_start(SubGhz* subghz) {
|
||||
} while(false);
|
||||
|
||||
if(success) {
|
||||
FURI_LOG_I(TAG, "Listening at \033[0;33m%s\033[0m.", string_get_cstr(file_name));
|
||||
//FURI_LOG_I(TAG, "Listening at \033[0;33m%s\033[0m.", string_get_cstr(file_name));
|
||||
|
||||
file_worker_encoder = subghz_file_encoder_worker_alloc();
|
||||
if(subghz_file_encoder_worker_start(file_worker_encoder, string_get_cstr(file_name))) {
|
||||
@@ -180,6 +180,7 @@ void subghz_scene_decode_raw_on_enter(void* context) {
|
||||
subghz_receiver_search_decoder_base_by_name(
|
||||
subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME),
|
||||
false);
|
||||
subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable);
|
||||
|
||||
if(decode_raw_state == SubGhzDecodeRawStateStart) {
|
||||
//Decode RAW to history
|
||||
@@ -224,6 +225,8 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz_file_encoder_worker_free(file_worker_encoder);
|
||||
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneMoreRAW);
|
||||
consumed = true;
|
||||
@@ -237,7 +240,7 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
consumed = true;
|
||||
break;
|
||||
case SubGhzCustomEventViewReceiverConfig:
|
||||
FURI_LOG_I(TAG, "No config options");
|
||||
FURI_LOG_W(TAG, "No config options");
|
||||
consumed = true;
|
||||
break;
|
||||
case SubGhzCustomEventViewReceiverOffDisplay:
|
||||
@@ -257,7 +260,7 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
notification_message(subghz->notifications, &sequence_blink_cyan_10);
|
||||
break;
|
||||
case SubGhzNotificationStateRxDone:
|
||||
notification_message(subghz->notifications, &subghs_sequence_rx);
|
||||
notification_message(subghz->notifications, &subghz_sequence_rx);
|
||||
subghz->state_notifications = SubGhzNotificationStateRx;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -50,8 +50,8 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
||||
subghz_preset_init(
|
||||
subghz,
|
||||
string_get_cstr(subghz->last_setting->preset_name),
|
||||
subghz->last_setting->frequency,
|
||||
"AM650",
|
||||
subghz_setting_get_default_frequency(subghz->setting),
|
||||
NULL,
|
||||
0);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
|
||||
@@ -113,11 +113,6 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SubGhzCustomEventViewReadRAWBack:
|
||||
// Check if return from config save values
|
||||
if(subghz->current_scene == SubGhzSceneReceiverConfig) {
|
||||
subghz_last_setting_save(
|
||||
subghz->last_setting, EXT_PATH("subghz/assets/last_used.txt"));
|
||||
}
|
||||
//Stop TX
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
||||
subghz_tx_stop(subghz);
|
||||
@@ -136,14 +131,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) ||
|
||||
(subghz->txrx->rx_key_state == SubGhzRxKeyStateBack)) {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateExit;
|
||||
subghz->current_scene = SubGhzSceneNeedSaving;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
||||
} else {
|
||||
//Restore default setting
|
||||
subghz_preset_init(
|
||||
subghz,
|
||||
string_get_cstr(subghz->last_setting->preset_name),
|
||||
subghz->last_setting->frequency,
|
||||
"AM650",
|
||||
subghz_setting_get_default_frequency(subghz->setting),
|
||||
NULL,
|
||||
0);
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
@@ -152,11 +146,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz->scene_manager, SubGhzSceneStart)) {
|
||||
scene_manager_stop(subghz->scene_manager);
|
||||
view_dispatcher_stop(subghz->view_dispatcher);
|
||||
} else {
|
||||
subghz->current_scene = SubGhzSceneStart;
|
||||
}
|
||||
} else {
|
||||
subghz->current_scene = SubGhzSceneSaved;
|
||||
}
|
||||
}
|
||||
consumed = true;
|
||||
@@ -180,7 +170,6 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
case SubGhzCustomEventViewReadRAWConfig:
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
|
||||
subghz->current_scene = SubGhzSceneReceiverConfig;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
|
||||
consumed = true;
|
||||
break;
|
||||
@@ -202,7 +191,6 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
|
||||
subghz->current_scene = SubGhzSceneMoreRAW;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW);
|
||||
consumed = true;
|
||||
} else {
|
||||
@@ -222,7 +210,6 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
||||
if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
|
||||
subghz->current_scene = SubGhzSceneShowOnlyRx;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
|
||||
} else {
|
||||
DOLPHIN_DEED(DolphinDeedSubGhzSend);
|
||||
@@ -282,7 +269,6 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
case SubGhzCustomEventViewReadRAWREC:
|
||||
if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) {
|
||||
subghz->current_scene = SubGhzSceneNeedSaving;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
||||
} else {
|
||||
//subghz_get_preset_name(subghz, subghz->error_str);
|
||||
@@ -303,7 +289,6 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
|
||||
} else {
|
||||
string_set_str(subghz->error_str, "Function requires\nan SD card.");
|
||||
subghz->current_scene = SubGhzSceneShowError;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
}
|
||||
}
|
||||
@@ -315,7 +300,6 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW);
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
|
||||
subghz->current_scene = SubGhzSceneSaveName;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
||||
}
|
||||
consumed = true;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "../subghz_i.h"
|
||||
#include "../views/receiver.h"
|
||||
|
||||
const NotificationSequence subghs_sequence_rx = {
|
||||
const NotificationSequence subghz_sequence_rx = {
|
||||
&message_green_255,
|
||||
|
||||
&message_vibro_on,
|
||||
@@ -14,7 +14,7 @@ const NotificationSequence subghs_sequence_rx = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
const NotificationSequence subghs_sequence_rx_locked = {
|
||||
const NotificationSequence subghz_sequence_rx_locked = {
|
||||
&message_green_255,
|
||||
|
||||
&message_display_backlight_on,
|
||||
@@ -103,11 +103,7 @@ void subghz_scene_receiver_on_enter(void* context) {
|
||||
|
||||
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) {
|
||||
subghz_preset_init(
|
||||
subghz,
|
||||
string_get_cstr(subghz->last_setting->preset_name),
|
||||
subghz->last_setting->frequency,
|
||||
NULL,
|
||||
0);
|
||||
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
|
||||
subghz_history_reset(subghz->txrx->history);
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateStart;
|
||||
}
|
||||
@@ -136,7 +132,7 @@ void subghz_scene_receiver_on_enter(void* context) {
|
||||
subghz->state_notifications = SubGhzNotificationStateRx;
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
||||
subghz_rx_end(subghz);
|
||||
};
|
||||
}
|
||||
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
||||
subghz_begin(
|
||||
@@ -156,34 +152,27 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SubGhzCustomEventViewReceiverBack:
|
||||
// Check if return from config save values
|
||||
if(subghz->current_scene == SubGhzSceneReceiverConfig) {
|
||||
subghz_last_setting_save(
|
||||
subghz->last_setting, EXT_PATH("subghz/assets/last_used.txt"));
|
||||
}
|
||||
// Stop CC1101 Rx
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
||||
subghz_rx_end(subghz);
|
||||
subghz_sleep(subghz);
|
||||
};
|
||||
}
|
||||
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
|
||||
subghz->txrx->idx_menu_chosen = 0;
|
||||
subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz);
|
||||
|
||||
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateExit;
|
||||
subghz->current_scene = SubGhzSceneNeedSaving;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
||||
} else {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
||||
subghz_preset_init(
|
||||
subghz,
|
||||
string_get_cstr(subghz->last_setting->preset_name),
|
||||
subghz->last_setting->frequency,
|
||||
"AM650",
|
||||
subghz_setting_get_default_frequency(subghz->setting),
|
||||
NULL,
|
||||
0);
|
||||
subghz->current_scene = SubGhzSceneStart;
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneStart);
|
||||
}
|
||||
@@ -192,7 +181,6 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
case SubGhzCustomEventViewReceiverOK:
|
||||
subghz->txrx->idx_menu_chosen =
|
||||
subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
||||
subghz->current_scene = SubGhzSceneReceiverInfo;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
|
||||
consumed = true;
|
||||
break;
|
||||
@@ -200,7 +188,6 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
subghz->txrx->idx_menu_chosen =
|
||||
subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
||||
subghz->current_scene = SubGhzSceneReceiverConfig;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
|
||||
consumed = true;
|
||||
break;
|
||||
@@ -226,9 +213,9 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
break;
|
||||
case SubGhzNotificationStateRxDone:
|
||||
if(subghz->lock != SubGhzLockOn) {
|
||||
notification_message(subghz->notifications, &subghs_sequence_rx);
|
||||
notification_message(subghz->notifications, &subghz_sequence_rx);
|
||||
} else {
|
||||
notification_message(subghz->notifications, &subghs_sequence_rx_locked);
|
||||
notification_message(subghz->notifications, &subghz_sequence_rx_locked);
|
||||
}
|
||||
subghz->state_notifications = SubGhzNotificationStateRx;
|
||||
break;
|
||||
|
||||
@@ -145,8 +145,6 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
|
||||
(subghz_setting_get_frequency(subghz->setting, index) % 1000000) / 10000);
|
||||
variable_item_set_current_value_text(item, text_buf);
|
||||
subghz->txrx->preset->frequency = subghz_setting_get_frequency(subghz->setting, index);
|
||||
subghz->last_setting->frequency = subghz->txrx->preset->frequency;
|
||||
subghz_setting_set_default_frequency(subghz->setting, subghz->txrx->preset->frequency);
|
||||
} else {
|
||||
variable_item_set_current_value_index(
|
||||
item, subghz_setting_get_frequency_default_index(subghz->setting));
|
||||
@@ -156,13 +154,11 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
|
||||
static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
|
||||
SubGhz* subghz = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
const char* preset_name = subghz_setting_get_preset_name(subghz->setting, index);
|
||||
variable_item_set_current_value_text(item, preset_name);
|
||||
string_set_str(subghz->last_setting->preset_name, preset_name);
|
||||
|
||||
variable_item_set_current_value_text(
|
||||
item, subghz_setting_get_preset_name(subghz->setting, index));
|
||||
subghz_preset_init(
|
||||
subghz,
|
||||
preset_name,
|
||||
subghz_setting_get_preset_name(subghz->setting, index),
|
||||
subghz->txrx->preset->frequency,
|
||||
subghz_setting_get_preset_data(subghz->setting, index),
|
||||
subghz_setting_get_preset_data_size(subghz->setting, index));
|
||||
@@ -177,7 +173,6 @@ static void subghz_scene_receiver_config_set_rssi_threshold(VariableItem* item)
|
||||
subghz_receiver_search_decoder_base_by_name(
|
||||
subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME),
|
||||
rssi_threshold_value[index]);
|
||||
subghz->last_setting->rssi_threshold = rssi_threshold_value[index];
|
||||
}
|
||||
|
||||
static void subghz_scene_receiver_config_set_detect_raw(VariableItem* item) {
|
||||
@@ -187,8 +182,6 @@ static void subghz_scene_receiver_config_set_detect_raw(VariableItem* item) {
|
||||
variable_item_set_current_value_text(item, detect_raw_text[index]);
|
||||
subghz_receiver_set_filter(subghz->txrx->receiver, detect_raw_value[index]);
|
||||
|
||||
//subghz->last_setting->detect_raw = detect_raw_value[index];
|
||||
|
||||
subghz_protocol_decoder_raw_set_auto_mode(
|
||||
subghz_receiver_search_decoder_base_by_name(
|
||||
subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME),
|
||||
@@ -228,7 +221,7 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item)
|
||||
subghz_setting_get_frequency_default_index(subghz->setting));
|
||||
}
|
||||
|
||||
subghz->txrx->hopper_state = subghz->last_setting->hopping = hopping_value[index];
|
||||
subghz->txrx->hopper_state = hopping_value[index];
|
||||
}
|
||||
|
||||
static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {
|
||||
@@ -352,6 +345,7 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even
|
||||
|
||||
void subghz_scene_receiver_config_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
variable_item_list_set_selected_item(subghz->variable_item_list, 0);
|
||||
variable_item_list_reset(subghz->variable_item_list);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
|
||||
|
||||
@@ -14,6 +14,22 @@ void subghz_scene_save_name_text_input_callback(void* context) {
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneSaveName);
|
||||
}
|
||||
|
||||
void subghz_scene_save_name_get_timefilename(string_t name, uint32_t frequency) {
|
||||
FuriHalRtcDateTime datetime = {0};
|
||||
furi_hal_rtc_get_datetime(&datetime);
|
||||
string_printf(
|
||||
name,
|
||||
"RAW_%.4d.%.2d.%.2d-%.2d.%.2d.%.2d-%d.%.2dMHz",
|
||||
datetime.year,
|
||||
datetime.month,
|
||||
datetime.day,
|
||||
datetime.hour,
|
||||
datetime.minute,
|
||||
datetime.second,
|
||||
frequency / 1000000,
|
||||
(frequency / 10000) % 100);
|
||||
}
|
||||
|
||||
void subghz_scene_save_name_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
@@ -42,9 +58,9 @@ void subghz_scene_save_name_on_enter(void* context) {
|
||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) ==
|
||||
SubGhzCustomEventManagerSetRAW) {
|
||||
dev_name_empty = true;
|
||||
subghz_get_next_name_file(subghz, SUBGHZ_MAX_LEN_NAME);
|
||||
subghz_scene_save_name_get_timefilename(
|
||||
file_name, subghz->txrx->preset->frequency);
|
||||
}
|
||||
path_extract_filename(subghz->file_path, file_name, true);
|
||||
}
|
||||
string_set(subghz->file_path, dir_name);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "../subghz_i.h"
|
||||
#include "../helpers/subghz_custom_event.h"
|
||||
|
||||
static const NotificationSequence subghs_sequence_sd_error = {
|
||||
static const NotificationSequence subghz_sequence_sd_error = {
|
||||
&message_red_255,
|
||||
&message_green_255,
|
||||
&message_do_not_reset,
|
||||
@@ -39,7 +39,7 @@ void subghz_scene_show_error_on_enter(void* context) {
|
||||
widget_add_button_element(
|
||||
subghz->widget, GuiButtonTypeRight, "OK", subghz_scene_show_error_callback, subghz);
|
||||
} else {
|
||||
notification_message(subghz->notifications, &subghs_sequence_sd_error);
|
||||
notification_message(subghz->notifications, &subghz_sequence_sd_error);
|
||||
}
|
||||
|
||||
widget_add_button_element(
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "../subghz_i.h"
|
||||
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexRead = 10,
|
||||
SubmenuIndexSaved,
|
||||
@@ -19,6 +21,12 @@ void subghz_scene_start_on_enter(void* context) {
|
||||
if(subghz->state_notifications == SubGhzNotificationStateStarting) {
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
}
|
||||
subghz_protocol_decoder_raw_set_auto_mode(
|
||||
subghz_receiver_search_decoder_base_by_name(
|
||||
subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME),
|
||||
false);
|
||||
subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable);
|
||||
|
||||
submenu_add_item(
|
||||
subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz);
|
||||
submenu_add_item(
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* Abandon hope, all ye who enter here. */
|
||||
|
||||
#include "m-string.h"
|
||||
#include "subghz/types.h"
|
||||
#include "subghz_i.h"
|
||||
#include <m-string.h>
|
||||
#include <subghz/types.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
#include "subghz_i.h"
|
||||
|
||||
bool subghz_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
@@ -174,25 +174,16 @@ SubGhz* subghz_alloc() {
|
||||
subghz->setting = subghz_setting_alloc();
|
||||
subghz_setting_load(subghz->setting, EXT_PATH("subghz/assets/setting_user"));
|
||||
|
||||
// Load last used values for Read, Read RAW, etc. or default
|
||||
subghz->last_setting = subghz_last_setting_alloc();
|
||||
subghz_last_setting_load(subghz->last_setting, EXT_PATH("subghz/assets/last_used.txt"));
|
||||
subghz_setting_set_default_frequency(subghz->setting, subghz->last_setting->frequency);
|
||||
|
||||
//init Worker & Protocol & History & KeyBoard
|
||||
subghz->lock = SubGhzLockOff;
|
||||
subghz->txrx = malloc(sizeof(SubGhzTxRx));
|
||||
subghz->txrx->preset = malloc(sizeof(SubGhzPresetDefinition));
|
||||
string_init(subghz->txrx->preset->name);
|
||||
subghz_preset_init(
|
||||
subghz,
|
||||
string_get_cstr(subghz->last_setting->preset_name),
|
||||
subghz->last_setting->frequency,
|
||||
NULL,
|
||||
0);
|
||||
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
|
||||
|
||||
subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
|
||||
subghz->txrx->hopper_state = subghz->last_setting->hopping;
|
||||
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
||||
subghz->txrx->history = subghz_history_alloc();
|
||||
subghz->txrx->worker = subghz_worker_alloc();
|
||||
@@ -205,9 +196,7 @@ SubGhz* subghz_alloc() {
|
||||
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
|
||||
subghz->txrx->environment, EXT_PATH("subghz/assets/nice_flor_s"));
|
||||
subghz->txrx->receiver = subghz_receiver_alloc_init(subghz->txrx->environment);
|
||||
|
||||
// Setup values
|
||||
subghz_last_setting_set_receiver_values(subghz->last_setting, subghz->txrx->receiver);
|
||||
subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable);
|
||||
|
||||
subghz_worker_set_overrun_callback(
|
||||
subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
|
||||
@@ -299,9 +288,6 @@ void subghz_free(SubGhz* subghz) {
|
||||
//setting
|
||||
subghz_setting_free(subghz->setting);
|
||||
|
||||
// Last setting
|
||||
subghz_last_setting_free(subghz->last_setting);
|
||||
|
||||
//Worker & Protocol & History
|
||||
subghz_receiver_free(subghz->txrx->receiver);
|
||||
subghz_environment_free(subghz->txrx->environment);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#include "subghz_history.h"
|
||||
#include <lib/subghz/receiver.h>
|
||||
#include <lib/subghz/protocols/came.h>
|
||||
|
||||
#include <furi.h>
|
||||
#include <m-string.h>
|
||||
|
||||
#define SUBGHZ_HISTORY_MAX 99
|
||||
#define SUBGHZ_HISTORY_MAX 65
|
||||
#define TAG "SubGhzHistory"
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
|
||||
#include "subghz_history.h"
|
||||
#include "subghz_setting.h"
|
||||
#include "subghz_last_setting.h"
|
||||
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
@@ -101,11 +100,10 @@ struct SubGhz {
|
||||
SubGhzTestPacket* subghz_test_packet;
|
||||
string_t error_str;
|
||||
SubGhzSetting* setting;
|
||||
SubGhzLastSetting* last_setting;
|
||||
SubGhzLock lock;
|
||||
|
||||
bool in_decoder_scene;
|
||||
SubGhzScene current_scene;
|
||||
|
||||
void* rpc_ctx;
|
||||
};
|
||||
|
||||
@@ -142,5 +140,5 @@ bool subghz_path_is_file(string_t path);
|
||||
uint32_t subghz_random_serial(void);
|
||||
void subghz_hopper_update(SubGhz* subghz);
|
||||
|
||||
extern const NotificationSequence subghs_sequence_rx;
|
||||
extern const NotificationSequence subghs_sequence_rx_locked;
|
||||
extern const NotificationSequence subghz_sequence_rx;
|
||||
extern const NotificationSequence subghz_sequence_rx_locked;
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
#include "subghz_setting.h"
|
||||
#include "subghz_i.h"
|
||||
|
||||
#include "subghz_last_setting.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <m-list.h>
|
||||
#include "furi_hal_subghz.h"
|
||||
#include "furi_hal_subghz_configs.h"
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
|
||||
#define TAG "SubGhzLastSetting"
|
||||
|
||||
#define SUBGHZ_LAST_SETTING_FILE_TYPE "Flipper SubGhz Last Setting File"
|
||||
#define SUBGHZ_LAST_SETTING_FILE_VERSION 1
|
||||
#define SUBGHZ_LAST_SETTING_DEFAULT_PRESET "AM650"
|
||||
#define SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY 433920000
|
||||
|
||||
SubGhzLastSetting* subghz_last_setting_alloc(void) {
|
||||
SubGhzLastSetting* instance = malloc(sizeof(SubGhzLastSetting));
|
||||
string_init(instance->preset_name);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void subghz_last_setting_free(SubGhzLastSetting* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
string_clear(instance->preset_name);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void subghz_last_setting_load(SubGhzLastSetting* instance, const char* file_path) {
|
||||
furi_assert(instance);
|
||||
string_init(instance->preset_name);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
|
||||
string_t temp_preset;
|
||||
string_init(temp_preset);
|
||||
uint32_t temp_frequency = 0; // Default 433920000
|
||||
uint32_t temp_hopping = 0; // Default 0
|
||||
//uint32_t temp_detect_raw = 0; Default 2
|
||||
int32_t temp_rssi_threshold = 0; // Default -72
|
||||
|
||||
if(FSE_OK == storage_sd_status(storage) && file_path &&
|
||||
flipper_format_file_open_existing(fff_data_file, file_path)) {
|
||||
flipper_format_read_string(fff_data_file, "Preset", temp_preset);
|
||||
flipper_format_read_uint32(fff_data_file, "Frequency", (uint32_t*)&temp_frequency, 1);
|
||||
flipper_format_read_uint32(fff_data_file, "Hopping", (uint32_t*)&temp_hopping, 1);
|
||||
//flipper_format_read_uint32(fff_data_file, "DetectRaw", (uint32_t*)&temp_detect_raw, 1);
|
||||
flipper_format_read_int32(fff_data_file, "Rssi", (int32_t*)&temp_rssi_threshold, 1);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Error open file %s", file_path);
|
||||
}
|
||||
|
||||
if(string_empty_p(temp_preset)) {
|
||||
//FURI_LOG_I(TAG, "Last used preset not found");
|
||||
string_set(instance->preset_name, SUBGHZ_LAST_SETTING_DEFAULT_PRESET);
|
||||
} else {
|
||||
string_set(instance->preset_name, temp_preset);
|
||||
}
|
||||
|
||||
if(temp_frequency == 0 || !furi_hal_subghz_is_tx_allowed(temp_frequency)) {
|
||||
//FURI_LOG_I(TAG, "Last used frequency not found or can't be used!");
|
||||
instance->frequency = SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY;
|
||||
} else {
|
||||
instance->frequency = temp_frequency;
|
||||
}
|
||||
|
||||
/*if(temp_detect_raw == 0) {
|
||||
instance->detect_raw = SubGhzProtocolFlag_Decodable;
|
||||
} else {
|
||||
instance->detect_raw = temp_detect_raw;
|
||||
}*/
|
||||
|
||||
if(temp_rssi_threshold == 0) {
|
||||
instance->rssi_threshold = -72;
|
||||
} else {
|
||||
instance->rssi_threshold = temp_rssi_threshold;
|
||||
}
|
||||
instance->hopping = temp_hopping;
|
||||
|
||||
string_clear(temp_preset);
|
||||
flipper_format_free(fff_data_file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
bool subghz_last_setting_save(SubGhzLastSetting* instance, const char* file_path) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool saved = false;
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
|
||||
do {
|
||||
if(FSE_OK != storage_sd_status(storage)) break;
|
||||
|
||||
// Open file
|
||||
if(!flipper_format_file_open_always(file, file_path)) break;
|
||||
|
||||
// Write header
|
||||
if(!flipper_format_write_header_cstr(
|
||||
file, SUBGHZ_LAST_SETTING_FILE_TYPE, SUBGHZ_LAST_SETTING_FILE_VERSION))
|
||||
break;
|
||||
|
||||
//FURI_LOG_D(TAG, "Preset %s", string_get_cstr(instance->preset_name));
|
||||
if(!flipper_format_insert_or_update_string_cstr(
|
||||
file, "Preset", string_get_cstr(instance->preset_name)))
|
||||
break;
|
||||
if(!flipper_format_insert_or_update_uint32(file, "Frequency", &instance->frequency, 1))
|
||||
break;
|
||||
if(!flipper_format_insert_or_update_uint32(file, "Hopping", &instance->hopping, 1)) break;
|
||||
//if(!flipper_format_insert_or_update_uint32(file, "DetectRaw", &instance->detect_raw, 1))
|
||||
// break;
|
||||
if(!flipper_format_insert_or_update_int32(file, "Rssi", &instance->rssi_threshold, 1))
|
||||
break;
|
||||
|
||||
saved = true;
|
||||
} while(0);
|
||||
|
||||
if(!saved) {
|
||||
FURI_LOG_E(TAG, "Error save file %s", file_path);
|
||||
}
|
||||
|
||||
flipper_format_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
void subghz_last_setting_set_receiver_values(SubGhzLastSetting* instance, SubGhzReceiver* receiver) {
|
||||
/*subghz_receiver_set_filter(receiver, instance->detect_raw);
|
||||
|
||||
subghz_protocol_decoder_raw_set_auto_mode(
|
||||
subghz_receiver_search_decoder_base_by_name(receiver, SUBGHZ_PROTOCOL_RAW_NAME),
|
||||
(instance->detect_raw != SubGhzProtocolFlag_Decodable));*/
|
||||
|
||||
subghz_protocol_decoder_raw_set_rssi_threshold(
|
||||
subghz_receiver_search_decoder_base_by_name(receiver, SUBGHZ_PROTOCOL_RAW_NAME),
|
||||
instance->rssi_threshold);
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <lib/flipper_format/flipper_format.h>
|
||||
|
||||
typedef struct {
|
||||
string_t preset_name;
|
||||
uint32_t frequency;
|
||||
uint32_t hopping;
|
||||
//uint32_t detect_raw;
|
||||
int32_t rssi_threshold;
|
||||
} SubGhzLastSetting;
|
||||
|
||||
SubGhzLastSetting* subghz_last_setting_alloc(void);
|
||||
|
||||
void subghz_last_setting_free(SubGhzLastSetting* instance);
|
||||
|
||||
void subghz_last_setting_load(SubGhzLastSetting* instance, const char* file_path);
|
||||
|
||||
bool subghz_last_setting_save(SubGhzLastSetting* instance, const char* file_path);
|
||||
|
||||
void subghz_last_setting_set_receiver_values(SubGhzLastSetting* instance, SubGhzReceiver* receiver);
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <furi.h>
|
||||
#include <m-list.h>
|
||||
#include "furi_hal_subghz_configs.h"
|
||||
#include <furi_hal_subghz_configs.h>
|
||||
|
||||
#define TAG "SubGhzSetting"
|
||||
|
||||
@@ -260,7 +260,13 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) {
|
||||
break;
|
||||
}
|
||||
if(flipper_format_read_uint32(fff_data_file, "Default_frequency", &temp_data32, 1)) {
|
||||
subghz_setting_set_default_frequency(instance, temp_data32);
|
||||
for
|
||||
M_EACH(frequency, instance->frequencies, FrequencyList_t) {
|
||||
*frequency &= FREQUENCY_MASK;
|
||||
if(*frequency == temp_data32) {
|
||||
*frequency |= FREQUENCY_FLAG_DEFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// custom preset (optional)
|
||||
@@ -288,16 +294,6 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) {
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_setting_set_default_frequency(SubGhzSetting* instance, uint32_t frequency_to_setup) {
|
||||
for
|
||||
M_EACH(frequency, instance->frequencies, FrequencyList_t) {
|
||||
*frequency &= FREQUENCY_MASK;
|
||||
if(*frequency == frequency_to_setup) {
|
||||
*frequency |= FREQUENCY_FLAG_DEFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t subghz_setting_get_frequency_count(SubGhzSetting* instance) {
|
||||
furi_assert(instance);
|
||||
return FrequencyList_size(instance->frequencies);
|
||||
|
||||
@@ -46,5 +46,3 @@ uint32_t subghz_setting_get_hopper_frequency(SubGhzSetting* instance, size_t idx
|
||||
uint32_t subghz_setting_get_frequency_default_index(SubGhzSetting* instance);
|
||||
|
||||
uint32_t subghz_setting_get_default_frequency(SubGhzSetting* instance);
|
||||
|
||||
void subghz_setting_set_default_frequency(SubGhzSetting* instance, uint32_t frequency_to_setup);
|
||||
@@ -45,7 +45,7 @@ void subghz_view_transmitter_add_data_to_show(
|
||||
}
|
||||
|
||||
static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str) {
|
||||
const uint8_t button_height = 13;
|
||||
const uint8_t button_height = 12;
|
||||
const uint8_t vertical_offset = 3;
|
||||
const uint8_t horizontal_offset = 1;
|
||||
const uint8_t string_width = canvas_string_width(canvas, str);
|
||||
@@ -69,7 +69,10 @@ static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str
|
||||
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_icon(
|
||||
canvas, x + horizontal_offset, y - button_height + vertical_offset, &I_ButtonCenter_7x7);
|
||||
canvas,
|
||||
x + horizontal_offset,
|
||||
y - button_height + vertical_offset - 1,
|
||||
&I_ButtonCenter_7x7);
|
||||
canvas_draw_str(
|
||||
canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str);
|
||||
canvas_invert_color(canvas);
|
||||
|
||||
@@ -790,7 +790,7 @@ static void render_callback(Canvas* canvas, void* ctx) {
|
||||
break;
|
||||
case 1:
|
||||
canvas_draw_icon(canvas, 113, 15, &I_Pin_cell_13x13);
|
||||
canvas_draw_icon(canvas, 116, 17, &I_Pin_arrow_up7x9);
|
||||
canvas_draw_icon(canvas, 116, 17, &I_Pin_arrow_up_7x9);
|
||||
break;
|
||||
case 2:
|
||||
canvas_draw_icon(canvas, 113, 15, &I_Pin_cell_13x13);
|
||||
@@ -845,6 +845,8 @@ void unirfremix_subghz_alloc(UniRFRemix* app) {
|
||||
UniRFRemix* unirfremix_alloc(void) {
|
||||
UniRFRemix* app = malloc(sizeof(UniRFRemix));
|
||||
|
||||
furi_hal_power_suppress_charge_enter();
|
||||
|
||||
app->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
|
||||
app->input_queue = furi_message_queue_alloc(32, sizeof(InputEvent));
|
||||
@@ -862,7 +864,9 @@ UniRFRemix* unirfremix_alloc(void) {
|
||||
return app;
|
||||
}
|
||||
|
||||
void unirfremix_free(UniRFRemix* app) {
|
||||
void unirfremix_free(UniRFRemix* app, bool with_subghz) {
|
||||
furi_hal_power_suppress_charge_exit();
|
||||
|
||||
string_clear(app->up_file);
|
||||
string_clear(app->down_file);
|
||||
string_clear(app->left_file);
|
||||
@@ -882,17 +886,21 @@ void unirfremix_free(UniRFRemix* app) {
|
||||
gui_remove_view_port(app->gui, app->view_port);
|
||||
furi_record_close(RECORD_GUI);
|
||||
view_port_free(app->view_port);
|
||||
app->gui = NULL;
|
||||
|
||||
furi_message_queue_free(app->input_queue);
|
||||
|
||||
furi_mutex_free(app->model_mutex);
|
||||
|
||||
furi_hal_subghz_sleep();
|
||||
subghz_setting_free(app->setting);
|
||||
subghz_receiver_free(app->subghz_receiver);
|
||||
subghz_environment_free(app->environment);
|
||||
if(with_subghz) {
|
||||
furi_hal_subghz_sleep();
|
||||
subghz_setting_free(app->setting);
|
||||
subghz_receiver_free(app->subghz_receiver);
|
||||
subghz_environment_free(app->environment);
|
||||
}
|
||||
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
app->notification = NULL;
|
||||
|
||||
free(app);
|
||||
}
|
||||
@@ -937,6 +945,8 @@ int32_t unirfremix_app(void* p) {
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
if(!res) {
|
||||
FURI_LOG_E(TAG, "No file selected");
|
||||
unirfremix_free(app, false);
|
||||
return 255;
|
||||
} else {
|
||||
//check map and population variables
|
||||
unirfremix_cfg_set_check(app, app->file_path);
|
||||
@@ -968,8 +978,6 @@ int32_t unirfremix_app(void* p) {
|
||||
furi_mutex_release(app->model_mutex);
|
||||
view_port_update(app->view_port);
|
||||
|
||||
furi_hal_power_suppress_charge_enter();
|
||||
|
||||
//input detect loop start
|
||||
InputEvent input;
|
||||
while(1) {
|
||||
@@ -1162,9 +1170,7 @@ int32_t unirfremix_app(void* p) {
|
||||
}
|
||||
|
||||
// remove & free all stuff created by app
|
||||
unirfremix_free(app);
|
||||
|
||||
furi_hal_power_suppress_charge_exit();
|
||||
unirfremix_free(app, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
App(
|
||||
appid="arkanoid_game",
|
||||
name="Arkanoid",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="arkanoid_game_app",
|
||||
cdefines=["APP_ARKANOID_GAME"],
|
||||
requires=["gui"],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
App(
|
||||
appid="barcode_generator",
|
||||
name="UPC-A Generator",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="barcode_UPCA_generator_app",
|
||||
cdefines=["APP_BARCODE_GEN"],
|
||||
requires=[
|
||||
|
||||
@@ -109,7 +109,7 @@ const BtHidKeyboardKey bt_hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = {
|
||||
{.width = 1, .icon = NULL, .key = "-", .shift_key = "_", .value = HID_KEYBOARD_MINUS},
|
||||
},
|
||||
{
|
||||
{.width = 1, .icon = &I_Pin_arrow_up7x9, .value = HID_KEYBOARD_L_SHIFT},
|
||||
{.width = 1, .icon = &I_Pin_arrow_up_7x9, .value = HID_KEYBOARD_L_SHIFT},
|
||||
{.width = 1, .icon = NULL, .key = ",", .shift_key = "<", .value = HID_KEYPAD_COMMA},
|
||||
{.width = 1, .icon = NULL, .key = ".", .shift_key = ">", .value = HID_KEYBOARD_DOT},
|
||||
{.width = 4, .icon = NULL, .key = " ", .value = HID_KEYBOARD_SPACEBAR},
|
||||
|
||||
@@ -53,7 +53,7 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) {
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up7x9);
|
||||
canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up_7x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Down
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Doom Flipper Zero edition
|
||||
|
||||
<div style="text-align:center"><img src="assets/intro-screen.png"/></div>
|
||||
<div style="text-align:center"><img src="assets/logo_inv.png"/></div>
|
||||
|
||||
## Will it run Doom?
|
||||
As tradition goes, Doom is being ported to almost every possible embedded electronic device. Therefore I did an attempt to come up with something close to Doom and still compatible on the Flipper Zero's hardware.<br> This is not the actual Doom game but a port made from yet another Doom port to the Arduino Nano (https://github.com/daveruiz/doom-nano/). This port is basically a raycasting engine, using Doom sprites.<br>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
App(
|
||||
appid="game_doom",
|
||||
name="DOOM",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="doom_app",
|
||||
cdefines=["APP_DOOM_GAME"],
|
||||
requires=[
|
||||
|
||||
|
Before Width: | Height: | Size: 2.1 KiB |
BIN
applications/plugins/doom/assets/logo_inv.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
@@ -36,30 +36,32 @@ const uint8_t _I_gun_mask_inv_0[] = {
|
||||
const uint8_t* const _I_gun_mask_inv[] = {_I_gun_mask_inv_0};
|
||||
|
||||
const uint8_t _I_logo_inv_0[] = {
|
||||
0x01, 0x00, 0x71, 0x01, 0x00, 0x44, 0x0a, 0x21, 0x00, 0xc0, 0x48, 0x20, 0x91, 0x0c, 0x05, 0x20,
|
||||
0x14, 0x30, 0x80, 0x71, 0x80, 0x8e, 0x03, 0x00, 0x85, 0x40, 0x22, 0x98, 0x8a, 0x00, 0x20, 0x60,
|
||||
0xa0, 0x83, 0xa8, 0x50, 0x20, 0xd8, 0x00, 0x41, 0xcd, 0x01, 0x03, 0x82, 0xc3, 0xc3, 0x61, 0xf0,
|
||||
0xa8, 0xf0, 0x44, 0x6c, 0x14, 0x68, 0x26, 0x16, 0x3b, 0x0a, 0x89, 0xcd, 0x24, 0x14, 0x0a, 0x96,
|
||||
0x32, 0x1b, 0x11, 0x85, 0xc4, 0x62, 0x92, 0x00, 0x88, 0xe1, 0x30, 0xb1, 0x18, 0x54, 0x46, 0x6d,
|
||||
0x28, 0xa0, 0x70, 0x82, 0x23, 0x51, 0xa5, 0x54, 0x62, 0x90, 0x1b, 0x05, 0x0b, 0x19, 0x15, 0x89,
|
||||
0x86, 0x86, 0x69, 0x42, 0xb0, 0xf5, 0xb2, 0x9a, 0x58, 0xac, 0xae, 0xaf, 0x35, 0x85, 0x50, 0xb8,
|
||||
0xda, 0x69, 0x6d, 0x6e, 0x95, 0x9b, 0x9b, 0x50, 0xac, 0x9c, 0xac, 0x6e, 0x36, 0x37, 0x2b, 0xad,
|
||||
0xed, 0xa2, 0x41, 0xa1, 0xd7, 0x6b, 0x42, 0x23, 0x3f, 0xdb, 0x75, 0xad, 0x5d, 0x6c, 0x2c, 0x37,
|
||||
0xbf, 0x5b, 0x0d, 0x0e, 0x5a, 0xc5, 0xca, 0xdb, 0xef, 0x6b, 0xf6, 0xea, 0xff, 0xde, 0x6d, 0x4d,
|
||||
0xfb, 0x75, 0xe5, 0xfb, 0xfd, 0xde, 0xfe, 0x6d, 0xe7, 0xb9, 0x7b, 0xba, 0xff, 0xdb, 0xfd, 0xaf,
|
||||
0xbf, 0x77, 0xc7, 0xd9, 0xf3, 0x5f, 0x79, 0xed, 0x3c, 0x10, 0x3f, 0x79, 0x7d, 0xbf, 0x9f, 0xed,
|
||||
0xff, 0xf7, 0xe7, 0x5f, 0xff, 0xbd, 0xae, 0xbd, 0xd6, 0xfe, 0xdf, 0x62, 0x34, 0xbf, 0xdf, 0xde,
|
||||
0x77, 0x6b, 0xe9, 0x7f, 0xbf, 0xf5, 0x38, 0x77, 0xe7, 0xef, 0x7b, 0xb9, 0xf4, 0xbf, 0x7f, 0xde,
|
||||
0xbd, 0xb8, 0x34, 0x3f, 0xbb, 0x5f, 0xbb, 0xff, 0xff, 0xbf, 0xda, 0x80, 0x63, 0xfb, 0xa1, 0xfe,
|
||||
0xc1, 0x05, 0xdf, 0x11, 0x8f, 0xce, 0xdd, 0xf2, 0xff, 0xff, 0x40, 0xe3, 0xff, 0xf3, 0xfd, 0xe9,
|
||||
0x42, 0xb1, 0xfc, 0x84, 0xc4, 0x32, 0x3f, 0xbb, 0xf0, 0x10, 0x7e, 0x60, 0x82, 0xfe, 0xdc, 0xe8,
|
||||
0xc1, 0x11, 0x07, 0x97, 0xff, 0xfd, 0x7f, 0xbf, 0x82, 0x07, 0x8f, 0xff, 0xf8, 0x82, 0x06, 0xef,
|
||||
0x7e, 0x04, 0x0e, 0x0f, 0xff, 0xe0, 0x9f, 0xfe, 0x04, 0x67, 0x01, 0x9f, 0x60, 0x21, 0xff, 0x0d,
|
||||
0xf8, 0x68, 0xa0, 0x11, 0xcc, 0x04, 0x1f, 0xc1, 0xbf, 0x0d, 0x0c, 0xfe, 0x01, 0x08, 0x80, 0x40,
|
||||
0xb8, 0x1f, 0xc0, 0x88, 0xc7, 0xe0, 0x00, 0x03, 0xe4, 0x5f, 0xff, 0xf0, 0xf0, 0x42, 0x70, 0x03,
|
||||
0x43, 0x03, 0x04, 0x28, 0x68, 0x60, 0x20, 0x87, 0x03, 0xa4, 0x03, 0xc1, 0x7f, 0x1a, 0x08, 0x45,
|
||||
0x86, 0x8b, 0x00, 0xc0, 0x5f, 0xe1, 0xc0, 0x85, 0x80, 0x5f, 0xe0, 0x80, 0x86, 0xfe, 0x01, 0xda,
|
||||
0x01, 0x78, 0x04, 0x3c, 0xc0,
|
||||
0x01, 0x00, 0x92, 0x01, 0x00, 0x78, 0x03, 0xc0, 0x03, 0xfc, 0xff, 0xff, 0xfc, 0x1f, 0xf9, 0xff,
|
||||
0xe3, 0xff, 0x0f, 0x8f, 0xfc, 0x2f, 0xe0, 0xf3, 0xdc, 0x6e, 0xf7, 0x7b, 0x1d, 0xdd, 0xef, 0x79,
|
||||
0xbb, 0xcd, 0xce, 0xf7, 0x13, 0xb0, 0x79, 0xfc, 0x03, 0xe3, 0xfb, 0x01, 0x0f, 0xfb, 0xff, 0xbf,
|
||||
0x11, 0x8c, 0x7c, 0x1e, 0x7e, 0x0f, 0x77, 0xbb, 0xd4, 0x02, 0x10, 0x00, 0xeb, 0xad, 0xde, 0xc8,
|
||||
0x70, 0x3c, 0xf8, 0x01, 0xf7, 0xbf, 0xff, 0x20, 0xe0, 0xf3, 0xc0, 0x6e, 0x80, 0x0d, 0x7a, 0xde,
|
||||
0x40, 0x83, 0xf8, 0x03, 0x10, 0xfa, 0x70, 0x07, 0xee, 0x02, 0x18, 0x30, 0x3d, 0x0a, 0xe3, 0xfb,
|
||||
0x83, 0x86, 0xc7, 0x82, 0x1f, 0x1f, 0xf8, 0xfd, 0x61, 0x5a, 0x0d, 0x54, 0x0b, 0x55, 0xaa, 0xc0,
|
||||
0x00, 0x84, 0x0c, 0x21, 0xf4, 0x8f, 0xf4, 0x3b, 0x70, 0x3e, 0xf7, 0x7b, 0x01, 0x9f, 0xef, 0xf7,
|
||||
0xc3, 0xfe, 0x1f, 0x6f, 0x87, 0xee, 0x07, 0xfe, 0xff, 0x60, 0x07, 0xfe, 0x1f, 0x88, 0xef, 0xc3,
|
||||
0xf3, 0x01, 0xfe, 0x7f, 0x30, 0x1b, 0xdf, 0xef, 0xf6, 0x0a, 0x1f, 0xf0, 0x79, 0xd0, 0x22, 0xf7,
|
||||
0x0b, 0x9c, 0x0e, 0xed, 0x76, 0x80, 0x4d, 0xee, 0xf7, 0x71, 0xff, 0x87, 0xd6, 0x2b, 0x50, 0xa8,
|
||||
0xc0, 0x6a, 0x95, 0x48, 0x04, 0x56, 0xab, 0x55, 0x1f, 0xf8, 0xff, 0xc7, 0xfe, 0x3f, 0xaa, 0xe4,
|
||||
0x02, 0x3b, 0x55, 0xae, 0x8f, 0xfc, 0xbf, 0xe1, 0xff, 0x0f, 0xf8, 0x7d, 0x61, 0x18, 0x0c, 0x44,
|
||||
0x03, 0x11, 0x88, 0x02, 0x0e, 0x23, 0x04, 0x0e, 0x30, 0xfa, 0x41, 0x43, 0xe2, 0x06, 0x18, 0xa8,
|
||||
0x18, 0x43, 0xe9, 0x02, 0xd0, 0x68, 0xa1, 0x5a, 0x2d, 0x51, 0x10, 0x70, 0x5a, 0x21, 0xfc, 0x45,
|
||||
0x43, 0xe3, 0x50, 0x0f, 0xc4, 0x20, 0x72, 0x20, 0x22, 0x02, 0x16, 0x00, 0x7e, 0xd5, 0x4a, 0x8d,
|
||||
0x54, 0x3e, 0x35, 0x40, 0xfb, 0x80, 0x3c, 0x3e, 0x35, 0x5a, 0x09, 0xe8, 0x6a, 0x87, 0xc1, 0x23,
|
||||
0x88, 0xfd, 0x40, 0x0c, 0x09, 0x20, 0xfa, 0x87, 0x06, 0x00, 0x1f, 0x38, 0x0c, 0x50, 0x3e, 0xa0,
|
||||
0x0f, 0x0f, 0x8c, 0x56, 0x00, 0x5c, 0x1a, 0x80, 0x90, 0x62, 0x03, 0xf6, 0x80, 0x42, 0x17, 0xc2,
|
||||
0x7b, 0x10, 0x20, 0x87, 0xde, 0xa9, 0x04, 0x80, 0x54, 0x20, 0x94, 0x08, 0xa0, 0x24, 0x47, 0xf5,
|
||||
0x01, 0x20, 0x54, 0x44, 0x18, 0x80, 0x42, 0x88, 0x17, 0xfc, 0x7e, 0xb4, 0x40, 0x4c, 0x12, 0x04,
|
||||
0x01, 0xe3, 0xf4, 0x2a, 0xf8, 0x03, 0xc0, 0x1f, 0xe0, 0xbc, 0xcf, 0xb8, 0xf8, 0x1e, 0xbf, 0xcc,
|
||||
0x5b, 0x12, 0x0c, 0x56, 0x0a, 0x51, 0x82, 0xa8, 0x28, 0x08, 0x1f, 0x32, 0x0c, 0x00, 0x3e, 0x85,
|
||||
0xe3, 0x1e, 0x17, 0x8f, 0x4f, 0xe6, 0x1f, 0x99, 0x44, 0x0a, 0x10, 0x2f, 0x13, 0xb4, 0xc8, 0x29,
|
||||
0x03, 0xf3, 0x89, 0x03, 0xe7, 0x10, 0x5f, 0x2a, 0x87, 0xd1, 0x1b, 0xe0, 0x0f, 0x00, 0x78, 0x03,
|
||||
0xc0, 0x1e, 0x00, 0xf0, 0x02, 0x00,
|
||||
};
|
||||
const uint8_t* const _I_logo_inv[] = {_I_logo_inv_0};
|
||||
|
||||
@@ -70,7 +72,7 @@ const Icon I_gun_inv =
|
||||
const Icon I_gun_mask_inv =
|
||||
{.width = 32, .height = 32, .frame_count = 1, .frame_rate = 0, .frames = _I_gun_mask_inv};
|
||||
const Icon I_logo_inv =
|
||||
{.width = 72, .height = 47, .frame_count = 1, .frame_rate = 0, .frames = _I_logo_inv};
|
||||
{.width = 128, .height = 64, .frame_count = 1, .frame_rate = 0, .frames = _I_logo_inv};
|
||||
|
||||
const uint8_t space[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
const uint8_t zero[] = {0x00, 0x60, 0x90, 0x90, 0x90, 0x60};
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
#define BMP_ITEMS_HEIGHT 16
|
||||
#define BMP_ITEMS_COUNT 2
|
||||
|
||||
#define BMP_LOGO_WIDTH 72
|
||||
#define BMP_LOGO_HEIGHT 47
|
||||
#define BMP_LOGO_WIDTH 128
|
||||
#define BMP_LOGO_HEIGHT 64
|
||||
|
||||
#define GRADIENT_WIDTH 2
|
||||
#define GRADIENT_HEIGHT 8
|
||||
|
||||
@@ -759,12 +759,8 @@ void renderStats(Canvas* const canvas, PluginState* plugin_state) {
|
||||
|
||||
// Intro screen
|
||||
void loopIntro(Canvas* const canvas) {
|
||||
canvas_draw_icon(
|
||||
canvas,
|
||||
(SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2,
|
||||
(SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 3,
|
||||
&I_logo_inv);
|
||||
drawTextSpace(SCREEN_WIDTH / 2 - 25, SCREEN_HEIGHT * .8, "PRESS FIRE", 1, canvas);
|
||||
canvas_draw_icon(canvas, 0, 0, &I_logo_inv);
|
||||
//drawTextSpace(SCREEN_WIDTH / 2 - 25, SCREEN_HEIGHT * .8, "PRESS FIRE", 1, canvas);
|
||||
}
|
||||
|
||||
static void render_callback(Canvas* const canvas, void* ctx) {
|
||||
|
||||
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -1,7 +1,7 @@
|
||||
App(
|
||||
appid="esp8266_deauth",
|
||||
name="[ESP8266] Deauther",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="esp8266_deauth_app",
|
||||
cdefines=["APP_ESP8266_deauth"],
|
||||
requires=["gui"],
|
||||
|
||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -1,7 +1,7 @@
|
||||
App(
|
||||
appid="game_flappybird",
|
||||
name="Flappy Bird",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="flappy_game_app",
|
||||
cdefines=["APP_FLAPPY_GAME"],
|
||||
requires=["gui"],
|
||||
|
||||
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -1,21 +1,35 @@
|
||||
# Flipfrid
|
||||
|
||||
Basic EM4100 Fuzzer
|
||||
Basic EM4100 and HIDProx Fuzzer.
|
||||
|
||||
## Why
|
||||
|
||||
Flipfrid is a simple Rfid fuzzer using EM4100 protocol (125khz).
|
||||
Objective is to provide a simple to use fuzzer to test readers by emulating various cards.
|
||||
|
||||
EM4100 cards use a 1 byte customer id and 4 bytes card id.
|
||||
- EM4100 cards use a 1 byte customer id and 4 bytes card id.
|
||||
- HIDProx cards use a 2 byte customer id and 3 byte card id.
|
||||
|
||||
## How
|
||||
|
||||
There is 4 modes :
|
||||
- Default key loop over 16 factory/default keys and emulate each one after one ;
|
||||
- BF customer id. just an iteration from 0X00 to 0XFF on the first byte ;
|
||||
- Load Dump file : Load an existing EM4100 dump generated by Flipperzero, select an index and bruteforce from 0X00 to 0XFF;
|
||||
- Uids list: loop over a text file (one uid per line)
|
||||
1) Select the Protocol with the left and right arrows
|
||||
2) Select the Mode with the up and down arrows
|
||||
|
||||
### Info
|
||||
|
||||
There are 2 Protocols:
|
||||
- EM4100
|
||||
- HIDProx
|
||||
|
||||
There are 4 modes:
|
||||
- Default Values: Try factory/default keys and emulate one after the other.
|
||||
- BF customer id: An iteration from 0X00 to 0XFF on the first byte.
|
||||
- Load Dump file: Load an existing dump (.rfid) generated by Flipperzero, select an index and bruteforce from 0X00 to 0XFF;
|
||||
- Uids list: Iterate over an input text file (one uid per line) and emulate one after the other.
|
||||
|
||||
|
||||
|
||||
|
||||
TODO :
|
||||
- blank screen on back press
|
||||
- Add second byte test to `BF customer id`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
App(
|
||||
appid="flipfrid",
|
||||
name="RFID Fuzzer",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="flipfrid_start",
|
||||
cdefines=["APP_FLIP_FRID"],
|
||||
requires=["gui", "storage", "dialogs", "input", "notification"],
|
||||
|
||||
@@ -64,6 +64,7 @@ FlipFridState* flipfrid_alloc() {
|
||||
flipfrid->is_attacking = false;
|
||||
flipfrid->key_index = 0;
|
||||
flipfrid->menu_index = 0;
|
||||
flipfrid->menu_proto_index = 0;
|
||||
|
||||
flipfrid->attack = FlipFridAttackDefaultValues;
|
||||
flipfrid->notify = furi_record_open(RECORD_NOTIFICATION);
|
||||
@@ -73,12 +74,14 @@ FlipFridState* flipfrid_alloc() {
|
||||
flipfrid->data[2] = 0x00;
|
||||
flipfrid->data[3] = 0x00;
|
||||
flipfrid->data[4] = 0x00;
|
||||
flipfrid->data[5] = 0x00;
|
||||
|
||||
flipfrid->payload[0] = 0x00;
|
||||
flipfrid->payload[1] = 0x00;
|
||||
flipfrid->payload[2] = 0x00;
|
||||
flipfrid->payload[3] = 0x00;
|
||||
flipfrid->payload[4] = 0x00;
|
||||
flipfrid->payload[5] = 0x00;
|
||||
|
||||
//Dialog
|
||||
flipfrid->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
@@ -28,6 +28,11 @@ typedef enum {
|
||||
FlipFridAttackLoadFileCustomUids,
|
||||
} FlipFridAttacks;
|
||||
|
||||
typedef enum {
|
||||
EM4100,
|
||||
HIDProx,
|
||||
} FlipFridProtos;
|
||||
|
||||
typedef enum {
|
||||
NoneScene,
|
||||
SceneEntryPoint,
|
||||
@@ -56,13 +61,16 @@ typedef struct {
|
||||
FlipFridScene previous_scene;
|
||||
NotificationApp* notify;
|
||||
u_int8_t menu_index;
|
||||
u_int8_t menu_proto_index;
|
||||
|
||||
string_t data_str;
|
||||
uint8_t data[5];
|
||||
uint8_t payload[5];
|
||||
uint8_t data[6];
|
||||
uint8_t payload[6];
|
||||
uint8_t attack_step;
|
||||
FlipFridAttacks attack;
|
||||
FlipFridProtos proto;
|
||||
string_t attack_name;
|
||||
string_t proto_name;
|
||||
|
||||
DialogsApp* dialogs;
|
||||
string_t notification_msg;
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
#include "flipfrid_scene_entrypoint.h"
|
||||
|
||||
string_t menu_items[4];
|
||||
string_t menu_proto_items[2];
|
||||
|
||||
void flipfrid_scene_entrypoint_menu_callback(FlipFridState* context, uint32_t index) {
|
||||
void flipfrid_scene_entrypoint_menu_callback(
|
||||
FlipFridState* context,
|
||||
uint32_t index,
|
||||
uint32_t proto_index) {
|
||||
switch(index) {
|
||||
case FlipFridAttackDefaultValues:
|
||||
context->attack = FlipFridAttackDefaultValues;
|
||||
@@ -27,6 +31,19 @@ void flipfrid_scene_entrypoint_menu_callback(FlipFridState* context, uint32_t in
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch(proto_index) {
|
||||
case EM4100:
|
||||
context->proto = EM4100;
|
||||
string_set_str(context->proto_name, "EM4100");
|
||||
break;
|
||||
case HIDProx:
|
||||
context->proto = HIDProx;
|
||||
string_set_str(context->proto_name, "HIDProx");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) {
|
||||
@@ -36,6 +53,7 @@ void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) {
|
||||
context->payload[2] = 0x00;
|
||||
context->payload[3] = 0x00;
|
||||
context->payload[4] = 0x00;
|
||||
context->payload[5] = 0x00;
|
||||
|
||||
context->menu_index = 0;
|
||||
for(uint32_t i = 0; i < 4; i++) {
|
||||
@@ -46,6 +64,14 @@ void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) {
|
||||
string_set(menu_items[1], "BF Customer ID");
|
||||
string_set(menu_items[2], "Load File");
|
||||
string_set(menu_items[3], "Load uids from file");
|
||||
|
||||
context->menu_proto_index = 0;
|
||||
for(uint32_t i = 0; i < 2; i++) {
|
||||
string_init(menu_proto_items[i]);
|
||||
}
|
||||
|
||||
string_set(menu_proto_items[0], "EM4100");
|
||||
string_set(menu_proto_items[1], "HIDProx");
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_exit(FlipFridState* context) {
|
||||
@@ -53,6 +79,10 @@ void flipfrid_scene_entrypoint_on_exit(FlipFridState* context) {
|
||||
for(uint32_t i = 0; i < 4; i++) {
|
||||
string_clear(menu_items[i]);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < 2; i++) {
|
||||
string_clear(menu_proto_items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_tick(FlipFridState* context) {
|
||||
@@ -74,10 +104,18 @@ void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* cont
|
||||
}
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(context->menu_proto_index > EM4100) {
|
||||
context->menu_proto_index--;
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(context->menu_proto_index < HIDProx) {
|
||||
context->menu_proto_index++;
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
flipfrid_scene_entrypoint_menu_callback(context, context->menu_index);
|
||||
flipfrid_scene_entrypoint_menu_callback(
|
||||
context, context->menu_index, context->menu_proto_index);
|
||||
break;
|
||||
case InputKeyBack:
|
||||
context->is_running = false;
|
||||
@@ -91,10 +129,6 @@ void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Title
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignTop, "RFID Fuzzer");
|
||||
|
||||
if(context->menu_index > FlipFridAttackDefaultValues) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
@@ -120,4 +154,41 @@ void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
AlignTop,
|
||||
string_get_cstr(menu_items[context->menu_index + 1]));
|
||||
}
|
||||
|
||||
if(context->menu_proto_index > EM4100) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
string_get_cstr(menu_proto_items[context->menu_proto_index - 1]));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 34, 4, AlignCenter, AlignTop, "<");
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
4,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
string_get_cstr(menu_proto_items[context->menu_proto_index]));
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 94, 4, AlignCenter, AlignTop, ">");
|
||||
|
||||
if(context->menu_proto_index < HIDProx) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
string_get_cstr(menu_proto_items[context->menu_proto_index + 1]));
|
||||
}
|
||||
}
|
||||
@@ -36,11 +36,21 @@ bool flipfrid_load(FlipFridState* context, const char* file_path) {
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Key type: %s", string_get_cstr(temp_str));
|
||||
if(strcmp(string_get_cstr(temp_str), "EM4100") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
|
||||
if(context->proto == EM4100) {
|
||||
if(strcmp(string_get_cstr(temp_str), "EM4100") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(strcmp(string_get_cstr(temp_str), "HIDProx") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,15 +63,24 @@ bool flipfrid_load(FlipFridState* context, const char* file_path) {
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Key: %s", string_get_cstr(context->data_str));
|
||||
|
||||
// Check data size
|
||||
if(string_size(context->data_str) != 14) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
if(context->proto == EM4100) {
|
||||
if(string_size(context->data_str) != 14) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(string_size(context->data_str) != 17) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// String to uint8_t
|
||||
for(uint8_t i = 0; i < 5; i++) {
|
||||
for(uint8_t i = 0; i < 6; i++) {
|
||||
char temp_str2[3];
|
||||
temp_str2[0] = string_get_cstr(context->data_str)[i * 3];
|
||||
temp_str2[1] = string_get_cstr(context->data_str)[i * 3 + 1];
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#include <gui/elements.h>
|
||||
|
||||
uint8_t counter = 0;
|
||||
#define TIME_BETWEEN_CARDS 5
|
||||
uint8_t id_list[16][5] = {
|
||||
#define TIME_BETWEEN_CARDS 6
|
||||
uint8_t id_list[17][5] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||
@@ -16,17 +16,39 @@ uint8_t id_list[16][5] = {
|
||||
{0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56, 0x78, 0x9A}, // Incremental UID
|
||||
{0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID
|
||||
{0x04, 0xd0, 0x9b, 0x0d, 0x6a}, // From arha
|
||||
{0x34, 0x00, 0x29, 0x3d, 0x9e}, // From arha
|
||||
{0x04, 0xdf, 0x00, 0x00, 0x01}, // From arha
|
||||
{0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
uint8_t id_list_hid[14][6] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}, // Incremental UID
|
||||
{0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID
|
||||
{0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
void flipfrid_scene_run_attack_on_enter(FlipFridState* context) {
|
||||
context->attack_step = 0;
|
||||
context->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
|
||||
context->worker = lfrfid_worker_alloc(context->dict);
|
||||
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100");
|
||||
if(context->proto == HIDProx) {
|
||||
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "HIDProx");
|
||||
} else {
|
||||
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100");
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_run_attack_on_exit(FlipFridState* context) {
|
||||
@@ -40,7 +62,7 @@ void flipfrid_scene_run_attack_on_exit(FlipFridState* context) {
|
||||
void flipfrid_scene_run_attack_on_tick(FlipFridState* context) {
|
||||
if(context->is_attacking) {
|
||||
if(1 == counter) {
|
||||
protocol_dict_set_data(context->dict, context->protocol, context->payload, 5);
|
||||
protocol_dict_set_data(context->dict, context->protocol, context->payload, 6);
|
||||
lfrfid_worker_free(context->worker);
|
||||
context->worker = lfrfid_worker_alloc(context->dict);
|
||||
lfrfid_worker_start_thread(context->worker);
|
||||
@@ -50,87 +72,180 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) {
|
||||
lfrfid_worker_stop_thread(context->worker);
|
||||
switch(context->attack) {
|
||||
case FlipFridAttackDefaultValues:
|
||||
context->payload[0] = id_list[context->attack_step][0];
|
||||
context->payload[1] = id_list[context->attack_step][1];
|
||||
context->payload[2] = id_list[context->attack_step][2];
|
||||
context->payload[3] = id_list[context->attack_step][3];
|
||||
context->payload[4] = id_list[context->attack_step][4];
|
||||
if(context->proto == EM4100) {
|
||||
context->payload[0] = id_list[context->attack_step][0];
|
||||
context->payload[1] = id_list[context->attack_step][1];
|
||||
context->payload[2] = id_list[context->attack_step][2];
|
||||
context->payload[3] = id_list[context->attack_step][3];
|
||||
context->payload[4] = id_list[context->attack_step][4];
|
||||
|
||||
if(context->attack_step == 15) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
|
||||
case FlipFridAttackBfCustomerId:
|
||||
context->payload[0] = context->attack_step;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
context->payload[3] = 0x00;
|
||||
context->payload[4] = 0x00;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
case FlipFridAttackLoadFile:
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
context->payload[2] = context->data[2];
|
||||
context->payload[3] = context->data[3];
|
||||
context->payload[4] = context->data[4];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
if(context->attack_step == 15) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
context->payload[0] = id_list_hid[context->attack_step][0];
|
||||
context->payload[1] = id_list_hid[context->attack_step][1];
|
||||
context->payload[2] = id_list_hid[context->attack_step][2];
|
||||
context->payload[3] = id_list_hid[context->attack_step][3];
|
||||
context->payload[4] = id_list_hid[context->attack_step][4];
|
||||
context->payload[5] = id_list_hid[context->attack_step][5];
|
||||
|
||||
if(context->attack_step == 15) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FlipFridAttackLoadFileCustomUids:
|
||||
while(true) {
|
||||
string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
|
||||
case FlipFridAttackBfCustomerId:
|
||||
if(context->proto == EM4100) {
|
||||
context->payload[0] = context->attack_step;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
context->payload[3] = 0x00;
|
||||
context->payload[4] = 0x00;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
context->payload[0] = context->attack_step;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
context->payload[3] = 0x00;
|
||||
context->payload[4] = 0x00;
|
||||
context->payload[5] = 0x00;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FlipFridAttackLoadFile:
|
||||
if(context->proto == EM4100) {
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
context->payload[2] = context->data[2];
|
||||
context->payload[3] = context->data[3];
|
||||
context->payload[4] = context->data[4];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
};
|
||||
if(string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(string_size(context->data_str) != 11) continue;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
context->payload[2] = context->data[2];
|
||||
context->payload[3] = context->data[3];
|
||||
context->payload[4] = context->data[4];
|
||||
context->payload[5] = context->data[5];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
FURI_LOG_D(TAG, string_get_cstr(context->data_str));
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 5; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
case FlipFridAttackLoadFileCustomUids:
|
||||
if(context->proto == EM4100) {
|
||||
while(true) {
|
||||
string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
};
|
||||
if(string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(string_size(context->data_str) != 11) continue;
|
||||
break;
|
||||
}
|
||||
FURI_LOG_D(TAG, string_get_cstr(context->data_str));
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 5; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
while(true) {
|
||||
string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
};
|
||||
if(string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(string_size(context->data_str) != 13) continue;
|
||||
break;
|
||||
}
|
||||
FURI_LOG_D(TAG, string_get_cstr(context->data_str));
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 6; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,16 +305,30 @@ void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 8, AlignCenter, AlignTop, string_get_cstr(context->attack_name));
|
||||
|
||||
char uid[16];
|
||||
snprintf(
|
||||
uid,
|
||||
sizeof(uid),
|
||||
"%02X:%02X:%02X:%02X:%02X",
|
||||
context->payload[0],
|
||||
context->payload[1],
|
||||
context->payload[2],
|
||||
context->payload[3],
|
||||
context->payload[4]);
|
||||
char uid[18];
|
||||
if(context->proto == HIDProx) {
|
||||
snprintf(
|
||||
uid,
|
||||
sizeof(uid),
|
||||
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
context->payload[0],
|
||||
context->payload[1],
|
||||
context->payload[2],
|
||||
context->payload[3],
|
||||
context->payload[4],
|
||||
context->payload[5]);
|
||||
} else {
|
||||
snprintf(
|
||||
uid,
|
||||
sizeof(uid),
|
||||
"%02X:%02X:%02X:%02X:%02X",
|
||||
context->payload[0],
|
||||
context->payload[1],
|
||||
context->payload[2],
|
||||
context->payload[3],
|
||||
context->payload[4]);
|
||||
}
|
||||
|
||||
canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignTop, uid);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
App(
|
||||
appid="mouse_jacker",
|
||||
name="[NRF24] Mouse Jacker",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="mousejacker_app",
|
||||
cdefines=["APP_MOUSEJACKER"],
|
||||
requires=[
|
||||
|
||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -47,7 +47,8 @@ static void render_callback(Canvas* const canvas, void* ctx) {
|
||||
canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
if(!plugin_state->addr_err && !plugin_state->ducky_err && !plugin_state->is_thread_running) {
|
||||
if(!plugin_state->addr_err && !plugin_state->ducky_err && !plugin_state->is_thread_running &&
|
||||
!plugin_state->is_ducky_running) {
|
||||
snprintf(target_text, sizeof(target_text), target_fmt_text, target_address_str);
|
||||
canvas_draw_str_aligned(canvas, 7, 10, AlignLeft, AlignBottom, target_text);
|
||||
canvas_draw_str_aligned(canvas, 22, 20, AlignLeft, AlignBottom, "<- select address ->");
|
||||
@@ -66,7 +67,10 @@ static void render_callback(Canvas* const canvas, void* ctx) {
|
||||
canvas, 3, 10, AlignLeft, AlignBottom, "Error: No mousejacker folder");
|
||||
canvas_draw_str_aligned(canvas, 3, 20, AlignLeft, AlignBottom, "or duckyscript file");
|
||||
canvas_draw_str_aligned(canvas, 3, 30, AlignLeft, AlignBottom, "loading error");
|
||||
} else if(plugin_state->is_thread_running) {
|
||||
} else if(plugin_state->is_thread_running && !plugin_state->is_ducky_running) {
|
||||
canvas_draw_str_aligned(canvas, 3, 10, AlignLeft, AlignBottom, "Loading...");
|
||||
canvas_draw_str_aligned(canvas, 3, 20, AlignLeft, AlignBottom, "Please wait!");
|
||||
} else if(plugin_state->is_thread_running && plugin_state->is_ducky_running) {
|
||||
canvas_draw_str_aligned(canvas, 3, 10, AlignLeft, AlignBottom, "Running duckyscript");
|
||||
canvas_draw_str_aligned(canvas, 3, 20, AlignLeft, AlignBottom, "Please wait!");
|
||||
canvas_draw_str_aligned(
|
||||
@@ -97,7 +101,7 @@ static void hexlify(uint8_t* in, uint8_t size, char* out) {
|
||||
snprintf(out + strlen(out), sizeof(out + strlen(out)), "%02X", in[i]);
|
||||
}
|
||||
|
||||
static bool open_ducky_script(Stream* stream) {
|
||||
static bool open_ducky_script(Stream* stream, PluginState* plugin_state) {
|
||||
DialogsApp* dialogs = furi_record_open("dialogs");
|
||||
bool result = false;
|
||||
string_t path;
|
||||
@@ -120,6 +124,9 @@ static bool open_ducky_script(Stream* stream) {
|
||||
}
|
||||
}
|
||||
string_clear(path);
|
||||
|
||||
plugin_state->is_ducky_running = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -160,10 +167,11 @@ static bool process_ducky_file(
|
||||
uint8_t* file_buf;
|
||||
bool loaded = false;
|
||||
FURI_LOG_D(TAG, "opening ducky script");
|
||||
if(open_ducky_script(file_stream)) {
|
||||
if(open_ducky_script(file_stream, plugin_state)) {
|
||||
file_size = stream_size(file_stream);
|
||||
if(file_size == (size_t)0) {
|
||||
FURI_LOG_D(TAG, "load failed. file_size: %d", file_size);
|
||||
plugin_state->is_ducky_running = false;
|
||||
return loaded;
|
||||
}
|
||||
file_buf = malloc(file_size);
|
||||
@@ -180,6 +188,7 @@ static bool process_ducky_file(
|
||||
}
|
||||
free(file_buf);
|
||||
}
|
||||
plugin_state->is_ducky_running = false;
|
||||
return loaded;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ typedef struct {
|
||||
bool ducky_err;
|
||||
bool addr_err;
|
||||
bool is_thread_running;
|
||||
bool is_ducky_running;
|
||||
bool close_thread_please;
|
||||
Storage* storage;
|
||||
FuriThread* mjthread;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
App(
|
||||
appid="multi_converter",
|
||||
name="Multi Converter",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="multi_converter_app",
|
||||
cdefines=["APP_DEC_HEX_CONVERTER"],
|
||||
requires=["gui"],
|
||||
|
||||
@@ -12,7 +12,7 @@ App(
|
||||
stack_size=2 * 1024,
|
||||
order=45,
|
||||
fap_icon="../../../assets/icons/Archive/music_10px.png",
|
||||
fap_category="Games",
|
||||
fap_category="Music",
|
||||
)
|
||||
|
||||
App(
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
App(
|
||||
appid="nrf_sniff",
|
||||
name="[NRF24] Sniffer",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="nrfsniff_app",
|
||||
cdefines=["APP_NRFSNIFF"],
|
||||
requires=["gui"],
|
||||
stack_size=2 * 1024,
|
||||
order=70,
|
||||
fap_icon="../../../assets/icons/Archive/sub1_10px.png",
|
||||
fap_icon="nrfsniff_10px.png",
|
||||
fap_category="GPIO",
|
||||
)
|
||||
|
||||
@@ -402,9 +402,6 @@ int32_t nrfsniff_app(void* p) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "osMessageQueue: event timeout");
|
||||
// event timeout
|
||||
}
|
||||
|
||||
if(sniffing_state) {
|
||||
@@ -451,6 +448,7 @@ int32_t nrfsniff_app(void* p) {
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
view_port_free(view_port);
|
||||
furi_message_queue_free(event_queue);
|
||||
free(plugin_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BIN
applications/plugins/nrfsniff/nrfsniff_10px.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |