mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-13 05:06:30 +04:00
Compare commits
438 Commits
un3-60bce7
...
un2-f61a8f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a7fa30199 | ||
|
|
e4cdae4922 | ||
|
|
c7a67c1308 | ||
|
|
fd3e70492d | ||
|
|
a4ee73b470 | ||
|
|
8f5cbdc4c2 | ||
|
|
6d999abb80 | ||
|
|
89d49fdba7 | ||
|
|
04d67ca8ae | ||
|
|
4f7ca617cc | ||
|
|
f61a8fda53 | ||
|
|
5e35e51c57 | ||
|
|
dfbe21e720 | ||
|
|
18e7d2eb41 | ||
|
|
e7aaf3dbb2 | ||
|
|
d2018dfa1d | ||
|
|
8ec5527ae4 | ||
|
|
3a50021348 | ||
|
|
20c63664ca | ||
|
|
9b6abd8ef0 | ||
|
|
f96f2e2411 | ||
|
|
6442caa3e4 | ||
|
|
f06930e4ae | ||
|
|
865baed0bb | ||
|
|
f81999ea4a | ||
|
|
89a4b77e73 | ||
|
|
ead9f134f4 | ||
|
|
9ff29d12b2 | ||
|
|
5f3637ca44 | ||
|
|
effcb445ce | ||
|
|
55bad280ee | ||
|
|
b003ede76c | ||
|
|
57362b3eab | ||
|
|
cb0d9ec591 | ||
|
|
dad4772bec | ||
|
|
a16542cda6 | ||
|
|
a5d22154a9 | ||
|
|
ce173fd44c | ||
|
|
d547307357 | ||
|
|
c198a51b1c | ||
|
|
d5b239595f | ||
|
|
947e44ce86 | ||
|
|
55f8beef9f | ||
|
|
e46e6f8ee9 | ||
|
|
ff6c4f9957 | ||
|
|
8fdee1e460 | ||
|
|
558f85603d | ||
|
|
b909321699 | ||
|
|
ff52f7d9ba | ||
|
|
abfe53f156 | ||
|
|
9a2228bfa4 | ||
|
|
da17adb5ee | ||
|
|
7b16de2d6f | ||
|
|
735056628c | ||
|
|
9941df48bb | ||
|
|
8e0e4b5e2c | ||
|
|
220adf2375 | ||
|
|
39cd10f061 | ||
|
|
af1fb2018a | ||
|
|
3dde6089fc | ||
|
|
5f28eafcd2 | ||
|
|
94d2d5c99f | ||
|
|
3a569d4be8 | ||
|
|
db2f4847ba | ||
|
|
50dc2d7389 | ||
|
|
ede3bac799 | ||
|
|
eb4ff3c0fd | ||
|
|
afff1adf8f | ||
|
|
92a738bf77 | ||
|
|
b3d9523322 | ||
|
|
155cbeeb11 | ||
|
|
0d273bd15c | ||
|
|
2e047ff411 | ||
|
|
80a406afd3 | ||
|
|
6b5631e5b0 | ||
|
|
80735d4f51 | ||
|
|
e1e46b89b1 | ||
|
|
b7bdc4c985 | ||
|
|
f429d14ab5 | ||
|
|
744b61ca28 | ||
|
|
8520daf28b | ||
|
|
aa9f958f07 | ||
|
|
b3f96306ed | ||
|
|
022315e93d | ||
|
|
702786078d | ||
|
|
e78d73c35f | ||
|
|
2552278a3d | ||
|
|
34406f0607 | ||
|
|
04f5ad83f8 | ||
|
|
06c0adfe98 | ||
|
|
b0d4146c76 | ||
|
|
be293757c0 | ||
|
|
79e7c87b94 | ||
|
|
b6dfeac7ca | ||
|
|
349a151330 | ||
|
|
40dc80499f | ||
|
|
b0c31da36a | ||
|
|
a76259add9 | ||
|
|
3f3ee1822a | ||
|
|
0714df4a4a | ||
|
|
52361b4adf | ||
|
|
61fe66c178 | ||
|
|
016ebd3afc | ||
|
|
82b9d74b38 | ||
|
|
6d1929af25 | ||
|
|
384397c282 | ||
|
|
0abd54ccc8 | ||
|
|
ea833d891f | ||
|
|
9152299562 | ||
|
|
906124b091 | ||
|
|
9c0391a887 | ||
|
|
7ded162c94 | ||
|
|
382f620aff | ||
|
|
323a56e987 | ||
|
|
b65a2e9c94 | ||
|
|
eed8cd1824 | ||
|
|
500456b03d | ||
|
|
4b8221d813 | ||
|
|
c7a454752a | ||
|
|
b1f8073333 | ||
|
|
e489c57fc0 | ||
|
|
b4a3ac468f | ||
|
|
877a9202fd | ||
|
|
acbe7a10e2 | ||
|
|
b6b33a70e9 | ||
|
|
1132653d7a | ||
|
|
3fd30a9132 | ||
|
|
50e9f7d3ca | ||
|
|
e7de975885 | ||
|
|
f5a1872db4 | ||
|
|
409d2e5f05 | ||
|
|
91d7a38ca6 | ||
|
|
00323892f2 | ||
|
|
45840a1146 | ||
|
|
b0c9af9c06 | ||
|
|
7643fdad7c | ||
|
|
a1ede0a2fc | ||
|
|
b86f42e7fb | ||
|
|
31c0346adc | ||
|
|
9ba7e625ca | ||
|
|
981f7ff8b0 | ||
|
|
c38c42906f | ||
|
|
7c8eacb168 | ||
|
|
c13929330e | ||
|
|
88ca267466 | ||
|
|
1adf76d54d | ||
|
|
7ec4cb4b7a | ||
|
|
aedde45de8 | ||
|
|
184b467f62 | ||
|
|
0c5146e047 | ||
|
|
221ac1ed3b | ||
|
|
464c725a48 | ||
|
|
3e538a8ade | ||
|
|
ae76f45339 | ||
|
|
4cb585e4b9 | ||
|
|
16ea8dc568 | ||
|
|
4c9d62a33f | ||
|
|
d10e16ca3c | ||
|
|
37b5e58a60 | ||
|
|
b4b3c182c5 | ||
|
|
bdd052937b | ||
|
|
1a1f711897 | ||
|
|
4000f0cac5 | ||
|
|
1f742b611a | ||
|
|
38a82a1907 | ||
|
|
d1843c0094 | ||
|
|
3367bc6f68 | ||
|
|
515e6db69c | ||
|
|
81faca79ee | ||
|
|
eaa3adf98a | ||
|
|
dde18cd343 | ||
|
|
72b3d7f414 | ||
|
|
19cb469e4b | ||
|
|
01f7a3e5b5 | ||
|
|
6dde5586af | ||
|
|
5de2c32c81 | ||
|
|
69b9c54b2f | ||
|
|
dbf4b65d84 | ||
|
|
2ffb246e69 | ||
|
|
e3a5df5959 | ||
|
|
90eefeb2ed | ||
|
|
fda541c7fb | ||
|
|
42494d801f | ||
|
|
1253a78dba | ||
|
|
d07c2dbe54 | ||
|
|
8f1812655e | ||
|
|
3802171009 | ||
|
|
03ad1770f8 | ||
|
|
b86756b581 | ||
|
|
11681d8ee8 | ||
|
|
061f53cd3c | ||
|
|
4bbeeb19e2 | ||
|
|
61189c3c82 | ||
|
|
9bf11d9fd2 | ||
|
|
c76fcf5072 | ||
|
|
007a11d70d | ||
|
|
b61e41163b | ||
|
|
a69e150e2f | ||
|
|
f16cdd1477 | ||
|
|
ac286dfed8 | ||
|
|
a93008b218 | ||
|
|
31aaa593fc | ||
|
|
5a2719663f | ||
|
|
adccb87499 | ||
|
|
693f78e501 | ||
|
|
6eb610762e | ||
|
|
3e4d8a41e0 | ||
|
|
c60bfbf271 | ||
|
|
0796263e81 | ||
|
|
4bf29827f8 | ||
|
|
baf5034817 | ||
|
|
04e16970db | ||
|
|
a8b48771e4 | ||
|
|
1424878d65 | ||
|
|
a37b0d464c | ||
|
|
96502e21ae | ||
|
|
b5d6d60535 | ||
|
|
32e64fd29e | ||
|
|
8f9d81b972 | ||
|
|
23e0566273 | ||
|
|
4141483147 | ||
|
|
30e005d5c4 | ||
|
|
e3a2711eb3 | ||
|
|
8569641ce6 | ||
|
|
cafd06c71b | ||
|
|
06a7bda69b | ||
|
|
c43ce93936 | ||
|
|
2288855163 | ||
|
|
c0765c1114 | ||
|
|
683c6254da | ||
|
|
2ef515ef56 | ||
|
|
667be798fc | ||
|
|
0f9598099a | ||
|
|
0d6f729386 | ||
|
|
b452b6fd32 | ||
|
|
9403128a03 | ||
|
|
71589b28a7 | ||
|
|
8b0fa6d0b1 | ||
|
|
cf47da0ff4 | ||
|
|
d6b7fae7e4 | ||
|
|
110dc48b96 | ||
|
|
37c666ddf5 | ||
|
|
6ddca568b9 | ||
|
|
8993db56b8 | ||
|
|
3c1efda1db | ||
|
|
b62b7956a6 | ||
|
|
dce5af5c2e | ||
|
|
fbacdc5b7b | ||
|
|
8dba4f25ae | ||
|
|
43ef4046ed | ||
|
|
1e63f57bf7 | ||
|
|
649887fe0f | ||
|
|
be42c390f2 | ||
|
|
cbda5d996f | ||
|
|
de1ec97512 | ||
|
|
8af749c965 | ||
|
|
4d3f45e911 | ||
|
|
63fee41a1f | ||
|
|
f441fed68d | ||
|
|
6e0eeed773 | ||
|
|
6bf306200e | ||
|
|
e2faf31b45 | ||
|
|
85eb740559 | ||
|
|
cea14ae9c5 | ||
|
|
e9a11cfce0 | ||
|
|
87a14b96e1 | ||
|
|
bbd3f9cf71 | ||
|
|
230f09dddd | ||
|
|
24e744f1d1 | ||
|
|
127b700642 | ||
|
|
0f9ea925d3 | ||
|
|
836de3df16 | ||
|
|
c92217a109 | ||
|
|
41c93431c8 | ||
|
|
f0ea8f3a84 | ||
|
|
4d8f294e7a | ||
|
|
f543753873 | ||
|
|
1fb1a68842 | ||
|
|
54fedb9bc8 | ||
|
|
8af9c00ddb | ||
|
|
5a22803bbc | ||
|
|
824f5ea027 | ||
|
|
76d38e832e | ||
|
|
aba20b6af8 | ||
|
|
226f8517f3 | ||
|
|
7df70d7c62 | ||
|
|
9176387b9f | ||
|
|
972c0dcb4a | ||
|
|
62e56e2618 | ||
|
|
f202d27206 | ||
|
|
bcfb12bf28 | ||
|
|
5883e134d4 | ||
|
|
f8b532f063 | ||
|
|
e25b424188 | ||
|
|
4241ad24a3 | ||
|
|
6bcc6f363b | ||
|
|
3dcd8a73f1 | ||
|
|
9ad7f7825d | ||
|
|
aa00606d22 | ||
|
|
9c62e1f6ac | ||
|
|
b934c41ed0 | ||
|
|
0ebb3f060e | ||
|
|
8f2bd3be57 | ||
|
|
cc02d57857 | ||
|
|
0c5f11f713 | ||
|
|
006d27ed93 | ||
|
|
746b732034 | ||
|
|
2ec9aeeefa | ||
|
|
8be08093e2 | ||
|
|
406247c5d8 | ||
|
|
22a87d5707 | ||
|
|
4271246d8a | ||
|
|
a3db6718c2 | ||
|
|
0f0473bee6 | ||
|
|
497be7ccb0 | ||
|
|
12a6290e91 | ||
|
|
e6e1e7fe15 | ||
|
|
cb14d23108 | ||
|
|
c4783664c0 | ||
|
|
91f3774246 | ||
|
|
1f8a034a71 | ||
|
|
8cc3e2f35a | ||
|
|
069dd29f08 | ||
|
|
91c06a2168 | ||
|
|
545c4349d6 | ||
|
|
a40e1a2be2 | ||
|
|
286300b35b | ||
|
|
633145495c | ||
|
|
a0bcbf731d | ||
|
|
60242cd7c4 | ||
|
|
3e9409a1a8 | ||
|
|
a9210b2849 | ||
|
|
a58807c57a | ||
|
|
5bb7cabea6 | ||
|
|
f201062819 | ||
|
|
9f501034c3 | ||
|
|
7bd0c8ff2c | ||
|
|
cdcf80ed05 | ||
|
|
3e3a167764 | ||
|
|
fa9602bd68 | ||
|
|
efb09380bd | ||
|
|
61fee8e269 | ||
|
|
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 | ||
|
|
8093721c24 | ||
|
|
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 |
@@ -31,7 +31,6 @@ steps:
|
||||
- name: "Bundle self-update packages"
|
||||
image: kramos/alpine-zip
|
||||
commands:
|
||||
- tar czpf artifacts-default/flipper-z-f7-update-${DRONE_TAG}.tgz -C artifacts-default f7-update-${DRONE_TAG}
|
||||
- cp artifacts-default/flipper-z-f7-update-${DRONE_TAG}.tgz .
|
||||
- zip -r artifacts-default/flipper-z-f7-update-${DRONE_TAG}.zip artifacts-default/f7-update-${DRONE_TAG}
|
||||
- rm -rf artifacts-default/f7-update-${DRONE_TAG}
|
||||
@@ -85,7 +84,7 @@ steps:
|
||||
Version: {{build.tag}}
|
||||
|
||||
|
||||
[-Github-](https://github.com/Eng1n33r/flipperzero-firmware/releases/tag/${DRONE_TAG})
|
||||
[-Github-](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/${DRONE_TAG})
|
||||
|
||||
|
||||
[-Install via Web Updater-](https://my.flipp.dev/?url=https://unleashedflip.com/builds/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})"
|
||||
@@ -105,7 +104,7 @@ steps:
|
||||
Version: {{build.tag}}
|
||||
|
||||
|
||||
[[Github]](https://github.com/Eng1n33r/flipperzero-firmware/releases/tag/${DRONE_TAG})
|
||||
[[Github]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/${DRONE_TAG})
|
||||
|
||||
|
||||
[-Install via Web Updater-](https://my.flipp.dev/?url=https://unleashedflip.com/builds/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})"
|
||||
|
||||
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* @xMasterX
|
||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -4,5 +4,5 @@ contact_links:
|
||||
url: https://t.me/flipperzero_unofficial
|
||||
about: Unofficial Telegram chat
|
||||
- name: Discord
|
||||
url: https://discord.gg/58D6E8BtTU
|
||||
url: https://discord.unleashedflip.com
|
||||
about: Unofficial Discord Community
|
||||
|
||||
7
.vscode/example/launch.json
vendored
7
.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",
|
||||
}
|
||||
@@ -24,13 +28,14 @@
|
||||
"servertype": "openocd",
|
||||
"device": "stlink",
|
||||
"svdFile": "./debug/STM32WB55_CM4.svd",
|
||||
// If you're debugging early in the boot process, before OS scheduler is running,
|
||||
// you have to comment out the following line.
|
||||
"rtos": "FreeRTOS",
|
||||
"configFiles": [
|
||||
"interface/stlink.cfg",
|
||||
"./debug/stm32wbx.cfg",
|
||||
],
|
||||
"postAttachCommands": [
|
||||
// "attach 1",
|
||||
// "compare-sections",
|
||||
"source debug/flipperapps.py",
|
||||
// "source debug/FreeRTOS/FreeRTOS.py",
|
||||
|
||||
2
.vscode/example/settings.json
vendored
2
.vscode/example/settings.json
vendored
@@ -22,4 +22,4 @@
|
||||
"SConstruct": "python",
|
||||
"*.fam": "python",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
37
CHANGELOG.md
37
CHANGELOG.md
@@ -1,15 +1,36 @@
|
||||
### New changes
|
||||
* Fixed all known issues with SubGHz settings (broken menu when you select last item in read and go into read raw config, issues with hopper and detect raw modes, bugs with frequency selector) (@xMasterX)
|
||||
* Removed subghz last settings saving feature (may be returned in future) (caused issues with freq selector, hopper mode)
|
||||
* Updated universal IR assets (by @Amec0e)
|
||||
* SubGHz: Keeloq - added support for FAAC RC,XT, Mutancode, Normstahl
|
||||
* LFRFID: CLI - Add raw_analyze to usage help
|
||||
* PR -> Plugins: Minesweeper: Set cursor to initial position on death (by @TQMatvey | PR #113)
|
||||
* PR -> Plugins: Flappy bird: Border hitboxes, bigger Pilars (by @TQMatvey | PR #114)
|
||||
* Plugins: Updated Minesweeper [(by panki27)](https://github.com/panki27/minesweeper)
|
||||
* Plugins: Added DTMF Dolphin [(by litui)](https://github.com/litui/dtmf_dolphin)
|
||||
* Plugins: Updated TOTP (Authenticator) [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator)
|
||||
* Infrared: Updated universal remote assets (by @Amec0e)
|
||||
* OFW: Feature: infrared add remote to cli
|
||||
* OFW: Remove the back button from MFC keys list
|
||||
* OFW: NFC fixes part 3
|
||||
* OFW: Enable all `view_` methods in SDK
|
||||
* OFW: fbt: fix for cincludes in app's private library definition
|
||||
* OFW: Desktop: fix fap in settings
|
||||
* OFW: Add BLE disconnect request
|
||||
|
||||
#### **DFU files no longer included in releases to avoid issues with wrong manual installation of assets - use web updater or microSD update package**
|
||||
#### [🎲 Download extra apps pack](https://download-directory.github.io/?url=https://github.com/UberGuidoZ/Flipper/tree/main/Applications/Unleashed)
|
||||
|
||||
[- How to install](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md)
|
||||
[-> How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)
|
||||
|
||||
**Note: To avoid issues prefer installing using web updater or by self update package, all needed assets will be installed**
|
||||
[-> Download qFlipper 1.2.1 (allows .tgz installation) (official link)](https://update.flipperzero.one/builds/qFlipper/1.2.1/)
|
||||
|
||||
Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip` or `.tgz` for iOS mobile app
|
||||
## Please support development of the project
|
||||
* Boosty: https://boosty.to/mmxdev
|
||||
* ETH/BSC/ERC20-Tokens: `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`
|
||||
* BTC: `bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`
|
||||
* DOGE: `D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`
|
||||
* LTC: `ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`
|
||||
|
||||
DFU for update using qFlipper is no longer included in releases to avoid issues with assets - Use Web Updater or self-update package!
|
||||
**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.
|
||||
|
||||
|
||||
77
ReadMe.md
77
ReadMe.md
@@ -1,5 +1,5 @@
|
||||
<h3 align="center">
|
||||
<a href="https://github.com/Eng1n33r/flipperzero-firmware">
|
||||
<a href="https://github.com/DarkFlippers/unleashed-firmware">
|
||||
<img src="https://user-images.githubusercontent.com/10697207/186202043-26947e28-b1cc-459a-8f20-ffcc7fc0c71c.png" align="center" alt="fzCUSTOM" border="0">
|
||||
</a>
|
||||
</h3>
|
||||
@@ -16,7 +16,7 @@ Please help us implement emulation for all subghz dynamic (rolling code) protoco
|
||||
<br>
|
||||
Our Discord Community:
|
||||
<br>
|
||||
<a href="https://discord.gg/flipperzero-unofficial"><img src="https://discordapp.com/api/guilds/937479784148115456/widget.png?style=banner4" alt="Unofficial Discord Community"></a>
|
||||
<a href="https://discord.unleashedflip.com"><img src="https://discordapp.com/api/guilds/937479784148115456/widget.png?style=banner4" alt="Unofficial Discord Community"></a>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
@@ -36,22 +36,33 @@ Our Discord Community:
|
||||
* Universal remote for Projectors, Fans, A/Cs and Audio(soundbars, etc.)
|
||||
* BadUSB keyboard layouts
|
||||
* Customizable Flipper name
|
||||
* SubGHz -> Press OK in frequency analyzer to use detected frequency in Read modes
|
||||
* SubGHz -> Long press OK button in SubGHz Frequency analyzer to switch to Read menu
|
||||
* Other small fixes and changes throughout
|
||||
* See other changes in changelog and in readme below
|
||||
|
||||
See changelog in releases for latest updates!
|
||||
Also check changelog in releases for latest updates!
|
||||
|
||||
### Current modified and new SubGHz protocols list:
|
||||
- HCS101
|
||||
- An-Motors
|
||||
- Keeloq [Not ALL systems supported for decode or emulation yet!] - [Supported manufacturers list](https://0bin.net/paste/VwR2lNJY#WH9vnPgvcp7w6zVKucFCuNREKAcOij8KsJ6vqLfMn3b)
|
||||
- Keeloq: HCS101
|
||||
- Keeloq: AN-Motors
|
||||
- Keeloq: JCM Tech
|
||||
- Keeloq: MHouse
|
||||
- Keeloq: Nice Smilo
|
||||
- Keeloq: DTM Neo
|
||||
- Keeloq: FAAC RC,XT
|
||||
- Keeloq: Mutancode
|
||||
- Keeloq: Normstahl
|
||||
- CAME Atomo
|
||||
- FAAC SLH (Spa) [External seed calculation required]
|
||||
- BFT Mitto [External seed calculation required]
|
||||
- Keeloq [Not ALL systems supported yet!]
|
||||
- Nice Flor S
|
||||
- FAAC SLH (Spa) [External seed calculation required (For info conatct me in Discord: Nano#8998)]
|
||||
- BFT Mitto [External seed calculation required (For info conatct me in Discord: Nano#8998)]
|
||||
- Security+ v1 & v2
|
||||
- Star Line
|
||||
- Star Line (saving only)
|
||||
|
||||
## Support us so we can buy equipment and develop new features
|
||||
* Boosty: https://boosty.to/mmxdev
|
||||
* ETH/BSC/ERC20-Tokens: `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`
|
||||
* BTC: `bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`
|
||||
* DOGE: `D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`
|
||||
@@ -59,12 +70,13 @@ See changelog in releases for latest updates!
|
||||
|
||||
### Community apps included:
|
||||
|
||||
- RFID Fuzzer plugin [(by Ganapati)](https://github.com/Eng1n33r/flipperzero-firmware/pull/54) with some changes by xMasterX
|
||||
- Sub-GHz bruteforce plugin [(by Ganapati & xMasterX)](https://github.com/Eng1n33r/flipperzero-firmware/pull/57)
|
||||
- Sub-GHz playlist plugin [(by darmiel)](https://github.com/Eng1n33r/flipperzero-firmware/pull/62)
|
||||
- RFID Fuzzer plugin [(by Ganapati)](https://github.com/DarkFlippers/unleashed-firmware/pull/54) with changes by @xMasterX & New protocols by @mvanzanten
|
||||
- Sub-GHz bruteforce plugin [(by Ganapati & xMasterX)](https://github.com/DarkFlippers/unleashed-firmware/pull/57) & Refactored by @derskythe
|
||||
- Sub-GHz playlist plugin [(by darmiel)](https://github.com/DarkFlippers/unleashed-firmware/pull/62)
|
||||
- ESP8266 Deauther plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module)
|
||||
- WiFi Scanner plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module)
|
||||
- MultiConverter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff)
|
||||
- USB Keyboard plugin [(by huuck)](https://github.com/huuck/FlipperZeroUSBKeyboard)
|
||||
- WAV player plugin (fixed) [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player)
|
||||
- UPC-A Barcode generator plugin [(by McAzzaMan)](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator)
|
||||
- GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin)
|
||||
@@ -73,6 +85,9 @@ See changelog in releases for latest updates!
|
||||
- Simple Clock (timer by GMMan / settings by kowalski7cc) [(Original by CompaqDisc)](https://gist.github.com/CompaqDisc/4e329c501bd03c1e801849b81f48ea61)
|
||||
- UniversalRF Remix / Sub-GHz Remote [(by ESurge)](https://github.com/ESurge/flipperzero-firmware-unirfremix)[(updated and all protocol support added by darmiel & xMasterX)](https://github.com/darmiel/flipper-playlist/tree/feat/unirf-protocols)
|
||||
- Spectrum Analyzer (with changes) [(by jolcese)](https://github.com/jolcese/flipperzero-firmware/tree/spectrum/applications/spectrum_analyzer) - [Ultra Narrow mode & scan channels non-consecutively](https://github.com/theY4Kman/flipperzero-firmware/commits?author=theY4Kman)
|
||||
- Metronome [(by panki27)](https://github.com/panki27/Metronome)
|
||||
- DTMF Dolphin [(by litui)](https://github.com/litui/dtmf_dolphin)
|
||||
- **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator)
|
||||
|
||||
Games:
|
||||
- DOOM (fixed) [(By p4nic4ttack)](https://github.com/p4nic4ttack/doom-flipper-zero/)
|
||||
@@ -81,32 +96,37 @@ Games:
|
||||
- Arkanoid (refactored by xMasterX) [(by gotnull)](https://github.com/gotnull/flipperzero-firmware-wPlugins)
|
||||
- Tic Tac Toe (refactored by xMasterX) [(by gotnull)](https://github.com/gotnull/flipperzero-firmware-wPlugins)
|
||||
- Tetris (with fixes) [(by jeffplang)](https://github.com/jeffplang/flipperzero-firmware/tree/tetris_game/applications/tetris_game)
|
||||
- Minesweeper [(by panki27)](https://github.com/panki27/minesweeper)
|
||||
|
||||
### Other changes
|
||||
|
||||
- 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 -> New frequency analyzer - [(by ClusterM)](https://github.com/DarkFlippers/unleashed-firmware/pull/43)
|
||||
- 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)
|
||||
- SubGHz -> Save last used frequency and moduluation [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
|
||||
- SubGHz -> Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
|
||||
- SubGHz -> Long press OK button in SubGHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79)
|
||||
|
||||
# Instructions
|
||||
## [- How to install firmware](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md)
|
||||
## [- How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)
|
||||
|
||||
## [- How to build firmware](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToBuild.md)
|
||||
## [- How to build firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToBuild.md)
|
||||
|
||||
## [- BadUSB: how to add new keyboard layouts](https://github.com/dummy-decoy/flipperzero_badusb_kl)
|
||||
|
||||
## [- How to change Flipper name](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/CustomFlipperName.md)
|
||||
## [- How to change Flipper name](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/CustomFlipperName.md)
|
||||
|
||||
### **Plugins**
|
||||
|
||||
## [- 💎 Extra plugins precompiled for Unleashed](https://github.com/UberGuidoZ/Flipper/tree/main/Applications/Unleashed)
|
||||
## [- 🎲 Download Extra plugins 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)
|
||||
## [- Configure Sub-GHz Remote App](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)
|
||||
|
||||
## [- Barcode Generator](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/BarcodeGenerator.md)
|
||||
## [- TOTP (Authenticator) config description](https://github.com/akopachov/flipper-zero_authenticator/blob/master/.github/conf-file_description.md)
|
||||
|
||||
## [- Multi Converter](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/MultiConverter.md)
|
||||
## [- Barcode Generator](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/BarcodeGenerator.md)
|
||||
|
||||
## [- Multi Converter](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/MultiConverter.md)
|
||||
|
||||
## [- WAV Player sample files & how to convert](https://github.com/UberGuidoZ/Flipper/tree/main/Wav_Player#readme)
|
||||
|
||||
@@ -114,7 +134,7 @@ Games:
|
||||
|
||||
### **Plugins that works with external hardware**
|
||||
|
||||
## [- How to use: [NRF24] plugins](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/NRF24.md)
|
||||
## [- How to use: [NRF24] plugins](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/NRF24.md)
|
||||
|
||||
## [- How to use: [WiFi] Scanner](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module#readme)
|
||||
|
||||
@@ -128,28 +148,29 @@ Games:
|
||||
|
||||
## [- Windows: How to Upload .bin to ESP32/ESP8266](https://github.com/SequoiaSan/Guide-How-To-Upload-bin-to-ESP8266-ESP32)
|
||||
|
||||
## [- How to use: [GPIO] SentrySafe plugin](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SentrySafe.md)
|
||||
## [- How to use: [GPIO] SentrySafe plugin](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SentrySafe.md)
|
||||
|
||||
### **SubGHz**
|
||||
|
||||
## [- Transmission is blocked? - How to extend SubGHz frequency range](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/DangerousSettings.md)
|
||||
## [- Transmission is blocked? - How to extend SubGHz frequency range](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md)
|
||||
|
||||
## [- How to add extra SubGHz frequencies](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SubGHzSettings.md)
|
||||
## [- How to add extra SubGHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md)
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
# Where I can find IR, SubGhz, ... files, DBs, and other stuff?
|
||||
## [Awesome Flipper Zero - Github](https://github.com/djsime1/awesome-flipperzero)
|
||||
## [UberGuidoZ Playground - Large collection of files - Github](https://github.com/UberGuidoZ/Flipper)
|
||||
## [Awesome Flipper Zero - Github](https://github.com/djsime1/awesome-flipperzero)
|
||||
## [CAME-12bit, NICE-12bit, Linear-10bit, PT-2240 - SubGHz fixed code bruteforce](https://github.com/tobiabocchi/flipperzero-bruteforce)
|
||||
## [SMC5326, UNILARM - SubGHz fixed code bruteforce](https://github.com/Hong5489/flipperzero-gate-bruteforce)
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
# Links
|
||||
|
||||
* Unofficial Discord: [discord.gg/flipperzero-unofficial](https://discord.gg/flipperzero-unofficial)
|
||||
* Unofficial Discord: [discord.unleashedflip.com](https://discord.unleashedflip.com)
|
||||
* Docs by atmanos / How to write your own app (outdated API): [https://flipper.atmanos.com/docs/overview/intro](https://flipper.atmanos.com/docs/overview/intro)
|
||||
|
||||
* Official Docs: [http://docs.flipperzero.one](http://docs.flipperzero.one)
|
||||
@@ -167,4 +188,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.
|
||||
|
||||
72
SConstruct
72
SConstruct
@@ -7,7 +7,6 @@
|
||||
# construction of certain targets behind command-line options.
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
DefaultEnvironment(tools=[])
|
||||
|
||||
@@ -15,17 +14,22 @@ EnsurePythonVersion(3, 8)
|
||||
|
||||
# Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15)
|
||||
|
||||
|
||||
# This environment is created only for loading options & validating file/dir existence
|
||||
fbt_variables = SConscript("site_scons/commandline.scons")
|
||||
cmd_environment = Environment(tools=[], variables=fbt_variables)
|
||||
Help(fbt_variables.GenerateHelpText(cmd_environment))
|
||||
cmd_environment = Environment(
|
||||
toolpath=["#/scripts/fbt_tools"],
|
||||
tools=[
|
||||
("fbt_help", {"vars": fbt_variables}),
|
||||
],
|
||||
variables=fbt_variables,
|
||||
)
|
||||
|
||||
# Building basic environment - tools, utility methods, cross-compilation
|
||||
# settings, gcc flags for Cortex-M4, basic builders and more
|
||||
coreenv = SConscript(
|
||||
"site_scons/environ.scons",
|
||||
exports={"VAR_ENV": cmd_environment},
|
||||
toolpath=["#/scripts/fbt_tools"],
|
||||
)
|
||||
SConscript("site_scons/cc.scons", exports={"ENV": coreenv})
|
||||
|
||||
@@ -35,39 +39,13 @@ coreenv["ROOT_DIR"] = Dir(".")
|
||||
|
||||
# Create a separate "dist" environment and add construction envs to it
|
||||
distenv = coreenv.Clone(
|
||||
tools=["fbt_dist", "openocd", "blackmagic", "jflash"],
|
||||
OPENOCD_GDB_PIPE=[
|
||||
"|openocd -c 'gdb_port pipe; log_output debug/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"
|
||||
tools=[
|
||||
"fbt_dist",
|
||||
"fbt_debugopts",
|
||||
"openocd",
|
||||
"blackmagic",
|
||||
"jflash",
|
||||
],
|
||||
GDBOPTS_BASE=[
|
||||
"-ex",
|
||||
"target extended-remote ${GDBREMOTE}",
|
||||
"-ex",
|
||||
"set confirm off",
|
||||
],
|
||||
GDBOPTS_BLACKMAGIC=[
|
||||
"-ex",
|
||||
"monitor swdp_scan",
|
||||
"-ex",
|
||||
"monitor debug_bmp enable",
|
||||
"-ex",
|
||||
"attach 1",
|
||||
"-ex",
|
||||
"set mem inaccessible-by-default off",
|
||||
],
|
||||
GDBPYOPTS=[
|
||||
"-ex",
|
||||
"source debug/FreeRTOS/FreeRTOS.py",
|
||||
"-ex",
|
||||
"source debug/flipperapps.py",
|
||||
"-ex",
|
||||
"source debug/PyCortexMDebug/PyCortexMDebug.py",
|
||||
"-ex",
|
||||
"svd_load ${SVD_FILE}",
|
||||
"-ex",
|
||||
"compare-sections",
|
||||
],
|
||||
JFLASHPROJECT="${ROOT_DIR.abspath}/debug/fw.jflash",
|
||||
ENV=os.environ,
|
||||
)
|
||||
|
||||
@@ -164,7 +142,7 @@ basic_dist = distenv.DistCommand("fw_dist", distenv["DIST_DEPENDS"])
|
||||
distenv.Default(basic_dist)
|
||||
|
||||
dist_dir = distenv.GetProjetDirName()
|
||||
plugin_dist = [
|
||||
fap_dist = [
|
||||
distenv.Install(
|
||||
f"#/dist/{dist_dir}/apps/debug_elf",
|
||||
firmware_env["FW_EXTAPPS"]["debug"].values(),
|
||||
@@ -174,9 +152,9 @@ plugin_dist = [
|
||||
for dist_entry in firmware_env["FW_EXTAPPS"]["dist"].values()
|
||||
),
|
||||
]
|
||||
Depends(plugin_dist, firmware_env["FW_EXTAPPS"]["validators"].values())
|
||||
Alias("plugin_dist", plugin_dist)
|
||||
# distenv.Default(plugin_dist)
|
||||
Depends(fap_dist, firmware_env["FW_EXTAPPS"]["validators"].values())
|
||||
Alias("fap_dist", fap_dist)
|
||||
# distenv.Default(fap_dist)
|
||||
|
||||
plugin_resources_dist = list(
|
||||
distenv.Install(f"#/assets/resources/apps/{dist_entry[0]}", dist_entry[1])
|
||||
@@ -187,9 +165,10 @@ distenv.Depends(firmware_env["FW_RESOURCES"], plugin_resources_dist)
|
||||
|
||||
# Target for bundling core2 package for qFlipper
|
||||
copro_dist = distenv.CoproBuilder(
|
||||
distenv.Dir("assets/core2_firmware"),
|
||||
"#/build/core2_firmware.tgz",
|
||||
[],
|
||||
)
|
||||
distenv.AlwaysBuild(copro_dist)
|
||||
distenv.Alias("copro_dist", copro_dist)
|
||||
|
||||
firmware_flash = distenv.AddOpenOCDFlashTarget(firmware_env)
|
||||
@@ -234,10 +213,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",
|
||||
|
||||
@@ -7,8 +7,8 @@ App(
|
||||
"vibro_test",
|
||||
"keypad_test",
|
||||
"usb_test",
|
||||
"usb_mouse",
|
||||
"uart_echo",
|
||||
"USB_Mouse",
|
||||
"UART_Echo",
|
||||
"display_test",
|
||||
"text_box_test",
|
||||
"file_browser_test",
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
#include <gui/canvas.h>
|
||||
#include <gui/elements.h>
|
||||
#include <m-array.h>
|
||||
#include <m-string.h>
|
||||
#include <furi.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct BtTestParam {
|
||||
const char* label;
|
||||
uint8_t current_value_index;
|
||||
string_t current_value_text;
|
||||
FuriString* current_value_text;
|
||||
uint8_t values_count;
|
||||
BtTestParamChangeCallback change_callback;
|
||||
void* context;
|
||||
@@ -85,7 +84,8 @@ static void bt_test_draw_callback(Canvas* canvas, void* _model) {
|
||||
canvas_draw_str(canvas, 50, param_text_y, "<");
|
||||
}
|
||||
|
||||
canvas_draw_str(canvas, 61, param_text_y, string_get_cstr(param->current_value_text));
|
||||
canvas_draw_str(
|
||||
canvas, 61, param_text_y, furi_string_get_cstr(param->current_value_text));
|
||||
|
||||
if(param->current_value_index < (param->values_count - 1)) {
|
||||
canvas_draw_str(canvas, 113, param_text_y, ">");
|
||||
@@ -154,7 +154,9 @@ static bool bt_test_input_callback(InputEvent* event, void* context) {
|
||||
|
||||
void bt_test_process_up(BtTest* bt_test) {
|
||||
with_view_model(
|
||||
bt_test->view, (BtTestModel * model) {
|
||||
bt_test->view,
|
||||
BtTestModel * model,
|
||||
{
|
||||
uint8_t params_on_screen = 3;
|
||||
if(model->position > 0) {
|
||||
model->position--;
|
||||
@@ -168,13 +170,15 @@ void bt_test_process_up(BtTest* bt_test) {
|
||||
model->window_position = model->position - (params_on_screen - 1);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void bt_test_process_down(BtTest* bt_test) {
|
||||
with_view_model(
|
||||
bt_test->view, (BtTestModel * model) {
|
||||
bt_test->view,
|
||||
BtTestModel * model,
|
||||
{
|
||||
uint8_t params_on_screen = 3;
|
||||
if(model->position < (BtTestParamArray_size(model->params) - 1)) {
|
||||
model->position++;
|
||||
@@ -187,8 +191,8 @@ void bt_test_process_down(BtTest* bt_test) {
|
||||
model->position = 0;
|
||||
model->window_position = 0;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
BtTestParam* bt_test_get_selected_param(BtTestModel* model) {
|
||||
@@ -213,7 +217,9 @@ BtTestParam* bt_test_get_selected_param(BtTestModel* model) {
|
||||
void bt_test_process_left(BtTest* bt_test) {
|
||||
BtTestParam* param;
|
||||
with_view_model(
|
||||
bt_test->view, (BtTestModel * model) {
|
||||
bt_test->view,
|
||||
BtTestModel * model,
|
||||
{
|
||||
param = bt_test_get_selected_param(model);
|
||||
if(param->current_value_index > 0) {
|
||||
param->current_value_index--;
|
||||
@@ -225,8 +231,8 @@ void bt_test_process_left(BtTest* bt_test) {
|
||||
model->packets_num_tx = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
if(param->change_callback) {
|
||||
param->change_callback(param);
|
||||
}
|
||||
@@ -235,7 +241,9 @@ void bt_test_process_left(BtTest* bt_test) {
|
||||
void bt_test_process_right(BtTest* bt_test) {
|
||||
BtTestParam* param;
|
||||
with_view_model(
|
||||
bt_test->view, (BtTestModel * model) {
|
||||
bt_test->view,
|
||||
BtTestModel * model,
|
||||
{
|
||||
param = bt_test_get_selected_param(model);
|
||||
if(param->current_value_index < (param->values_count - 1)) {
|
||||
param->current_value_index++;
|
||||
@@ -247,8 +255,8 @@ void bt_test_process_right(BtTest* bt_test) {
|
||||
model->packets_num_tx = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
if(param->change_callback) {
|
||||
param->change_callback(param);
|
||||
}
|
||||
@@ -257,7 +265,9 @@ void bt_test_process_right(BtTest* bt_test) {
|
||||
void bt_test_process_ok(BtTest* bt_test) {
|
||||
BtTestState state;
|
||||
with_view_model(
|
||||
bt_test->view, (BtTestModel * model) {
|
||||
bt_test->view,
|
||||
BtTestModel * model,
|
||||
{
|
||||
if(model->state == BtTestStateStarted) {
|
||||
model->state = BtTestStateStopped;
|
||||
model->message = BT_TEST_START_MESSAGE;
|
||||
@@ -269,8 +279,8 @@ void bt_test_process_ok(BtTest* bt_test) {
|
||||
model->message = BT_TEST_STOP_MESSAGE;
|
||||
}
|
||||
state = model->state;
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
if(bt_test->change_state_callback) {
|
||||
bt_test->change_state_callback(state, bt_test->context);
|
||||
}
|
||||
@@ -278,13 +288,15 @@ void bt_test_process_ok(BtTest* bt_test) {
|
||||
|
||||
void bt_test_process_back(BtTest* bt_test) {
|
||||
with_view_model(
|
||||
bt_test->view, (BtTestModel * model) {
|
||||
bt_test->view,
|
||||
BtTestModel * model,
|
||||
{
|
||||
model->state = BtTestStateStopped;
|
||||
model->rssi = 0.0f;
|
||||
model->packets_num_rx = 0;
|
||||
model->packets_num_tx = 0;
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
if(bt_test->back_callback) {
|
||||
bt_test->back_callback(bt_test->context);
|
||||
}
|
||||
@@ -299,7 +311,9 @@ BtTest* bt_test_alloc() {
|
||||
view_set_input_callback(bt_test->view, bt_test_input_callback);
|
||||
|
||||
with_view_model(
|
||||
bt_test->view, (BtTestModel * model) {
|
||||
bt_test->view,
|
||||
BtTestModel * model,
|
||||
{
|
||||
model->state = BtTestStateStopped;
|
||||
model->message = "Ok - Start";
|
||||
BtTestParamArray_init(model->params);
|
||||
@@ -308,8 +322,8 @@ BtTest* bt_test_alloc() {
|
||||
model->rssi = 0.0f;
|
||||
model->packets_num_tx = 0;
|
||||
model->packets_num_rx = 0;
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
|
||||
return bt_test;
|
||||
}
|
||||
@@ -318,15 +332,17 @@ void bt_test_free(BtTest* bt_test) {
|
||||
furi_assert(bt_test);
|
||||
|
||||
with_view_model(
|
||||
bt_test->view, (BtTestModel * model) {
|
||||
bt_test->view,
|
||||
BtTestModel * model,
|
||||
{
|
||||
BtTestParamArray_it_t it;
|
||||
for(BtTestParamArray_it(it, model->params); !BtTestParamArray_end_p(it);
|
||||
BtTestParamArray_next(it)) {
|
||||
string_clear(BtTestParamArray_ref(it)->current_value_text);
|
||||
furi_string_free(BtTestParamArray_ref(it)->current_value_text);
|
||||
}
|
||||
BtTestParamArray_clear(model->params);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
view_free(bt_test->view);
|
||||
free(bt_test);
|
||||
}
|
||||
@@ -347,16 +363,18 @@ BtTestParam* bt_test_param_add(
|
||||
furi_assert(bt_test);
|
||||
|
||||
with_view_model(
|
||||
bt_test->view, (BtTestModel * model) {
|
||||
bt_test->view,
|
||||
BtTestModel * model,
|
||||
{
|
||||
param = BtTestParamArray_push_new(model->params);
|
||||
param->label = label;
|
||||
param->values_count = values_count;
|
||||
param->change_callback = change_callback;
|
||||
param->context = context;
|
||||
param->current_value_index = 0;
|
||||
string_init(param->current_value_text);
|
||||
return true;
|
||||
});
|
||||
param->current_value_text = furi_string_alloc();
|
||||
},
|
||||
true);
|
||||
|
||||
return param;
|
||||
}
|
||||
@@ -364,28 +382,19 @@ BtTestParam* bt_test_param_add(
|
||||
void bt_test_set_rssi(BtTest* bt_test, float rssi) {
|
||||
furi_assert(bt_test);
|
||||
with_view_model(
|
||||
bt_test->view, (BtTestModel * model) {
|
||||
model->rssi = rssi;
|
||||
return true;
|
||||
});
|
||||
bt_test->view, BtTestModel * model, { model->rssi = rssi; }, true);
|
||||
}
|
||||
|
||||
void bt_test_set_packets_tx(BtTest* bt_test, uint32_t packets_num) {
|
||||
furi_assert(bt_test);
|
||||
with_view_model(
|
||||
bt_test->view, (BtTestModel * model) {
|
||||
model->packets_num_tx = packets_num;
|
||||
return true;
|
||||
});
|
||||
bt_test->view, BtTestModel * model, { model->packets_num_tx = packets_num; }, true);
|
||||
}
|
||||
|
||||
void bt_test_set_packets_rx(BtTest* bt_test, uint32_t packets_num) {
|
||||
furi_assert(bt_test);
|
||||
with_view_model(
|
||||
bt_test->view, (BtTestModel * model) {
|
||||
model->packets_num_rx = packets_num;
|
||||
return true;
|
||||
});
|
||||
bt_test->view, BtTestModel * model, { model->packets_num_rx = packets_num; }, true);
|
||||
}
|
||||
|
||||
void bt_test_set_change_state_callback(BtTest* bt_test, BtTestChangeStateCallback callback) {
|
||||
@@ -410,7 +419,7 @@ void bt_test_set_current_value_index(BtTestParam* param, uint8_t current_value_i
|
||||
}
|
||||
|
||||
void bt_test_set_current_value_text(BtTestParam* param, const char* current_value_text) {
|
||||
string_set_str(param->current_value_text, current_value_text);
|
||||
furi_string_set(param->current_value_text, current_value_text);
|
||||
}
|
||||
|
||||
uint8_t bt_test_get_current_value_index(BtTestParam* param) {
|
||||
|
||||
@@ -113,11 +113,11 @@ static void display_config_set_regulation_ratio(VariableItem* item) {
|
||||
static void display_config_set_contrast(VariableItem* item) {
|
||||
DisplayTest* instance = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
string_t temp;
|
||||
string_init(temp);
|
||||
string_cat_printf(temp, "%d", index);
|
||||
variable_item_set_current_value_text(item, string_get_cstr(temp));
|
||||
string_clear(temp);
|
||||
FuriString* temp;
|
||||
temp = furi_string_alloc();
|
||||
furi_string_cat_printf(temp, "%d", index);
|
||||
variable_item_set_current_value_text(item, furi_string_get_cstr(temp));
|
||||
furi_string_free(temp);
|
||||
instance->config_contrast = index;
|
||||
display_test_reload_config(instance);
|
||||
}
|
||||
|
||||
@@ -110,7 +110,9 @@ static bool view_display_test_input_callback(InputEvent* event, void* context) {
|
||||
bool consumed = false;
|
||||
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
|
||||
with_view_model(
|
||||
instance->view, (ViewDisplayTestModel * model) {
|
||||
instance->view,
|
||||
ViewDisplayTestModel * model,
|
||||
{
|
||||
if(event->key == InputKeyLeft && model->test > 0) {
|
||||
model->test--;
|
||||
consumed = true;
|
||||
@@ -129,8 +131,8 @@ static bool view_display_test_input_callback(InputEvent* event, void* context) {
|
||||
model->flip_flop = !model->flip_flop;
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
});
|
||||
},
|
||||
consumed);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
@@ -149,10 +151,7 @@ static void view_display_test_exit(void* context) {
|
||||
static void view_display_test_timer_callback(void* context) {
|
||||
ViewDisplayTest* instance = context;
|
||||
with_view_model(
|
||||
instance->view, (ViewDisplayTestModel * model) {
|
||||
model->counter++;
|
||||
return true;
|
||||
});
|
||||
instance->view, ViewDisplayTestModel * model, { model->counter++; }, true);
|
||||
}
|
||||
|
||||
ViewDisplayTest* view_display_test_alloc() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "assets_icons.h"
|
||||
#include "file_browser_app_i.h"
|
||||
#include "gui/modules/file_browser.h"
|
||||
#include "m-string.h"
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <storage/storage.h>
|
||||
@@ -47,7 +46,7 @@ FileBrowserApp* file_browser_app_alloc(char* arg) {
|
||||
|
||||
app->widget = widget_alloc();
|
||||
|
||||
string_init(app->file_path);
|
||||
app->file_path = furi_string_alloc();
|
||||
app->file_browser = file_browser_alloc(app->file_path);
|
||||
file_browser_configure(app->file_browser, "*", true, &I_badusb_10px, true);
|
||||
|
||||
@@ -84,7 +83,7 @@ void file_browser_app_free(FileBrowserApp* app) {
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
|
||||
string_clear(app->file_path);
|
||||
furi_string_free(app->file_path);
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ struct FileBrowserApp {
|
||||
Widget* widget;
|
||||
FileBrowser* file_browser;
|
||||
|
||||
string_t file_path;
|
||||
FuriString* file_path;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#include "../file_browser_app_i.h"
|
||||
#include <core/check.h>
|
||||
#include <core/log.h>
|
||||
#include "furi_hal.h"
|
||||
#include "m-string.h"
|
||||
#include <furi.h>
|
||||
|
||||
#define DEFAULT_PATH "/"
|
||||
#define EXTENSION "*"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "../file_browser_app_i.h"
|
||||
#include "furi_hal.h"
|
||||
#include "m-string.h"
|
||||
#include <furi.h>
|
||||
|
||||
void file_browser_scene_result_ok_callback(InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
@@ -24,7 +23,13 @@ void file_browser_scene_result_on_enter(void* context) {
|
||||
FileBrowserApp* app = context;
|
||||
|
||||
widget_add_string_multiline_element(
|
||||
app->widget, 64, 10, AlignCenter, AlignTop, FontSecondary, string_get_cstr(app->file_path));
|
||||
app->widget,
|
||||
64,
|
||||
10,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
FontSecondary,
|
||||
furi_string_get_cstr(app->file_path));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, FileBrowserAppViewResult);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ bool file_browser_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
string_set_str(app->file_path, ANY_PATH("badusb/demo_windows.txt"));
|
||||
furi_string_set(app->file_path, ANY_PATH("badusb/demo_windows.txt"));
|
||||
scene_manager_next_scene(app->scene_manager, FileBrowserSceneBrowser);
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
|
||||
@@ -52,23 +52,29 @@ static void lfrfid_debug_view_tune_draw_callback(Canvas* canvas, void* _model) {
|
||||
|
||||
static void lfrfid_debug_view_tune_button_up(LfRfidTuneView* tune_view) {
|
||||
with_view_model(
|
||||
tune_view->view, (LfRfidTuneViewModel * model) {
|
||||
tune_view->view,
|
||||
LfRfidTuneViewModel * model,
|
||||
{
|
||||
if(model->pos > 0) model->pos--;
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
static void lfrfid_debug_view_tune_button_down(LfRfidTuneView* tune_view) {
|
||||
with_view_model(
|
||||
tune_view->view, (LfRfidTuneViewModel * model) {
|
||||
tune_view->view,
|
||||
LfRfidTuneViewModel * model,
|
||||
{
|
||||
if(model->pos < 1) model->pos++;
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
static void lfrfid_debug_view_tune_button_left(LfRfidTuneView* tune_view) {
|
||||
with_view_model(
|
||||
tune_view->view, (LfRfidTuneViewModel * model) {
|
||||
tune_view->view,
|
||||
LfRfidTuneViewModel * model,
|
||||
{
|
||||
if(model->pos == 0) {
|
||||
if(model->fine) {
|
||||
model->ARR -= 1;
|
||||
@@ -84,13 +90,15 @@ static void lfrfid_debug_view_tune_button_left(LfRfidTuneView* tune_view) {
|
||||
}
|
||||
|
||||
model->dirty = true;
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
static void lfrfid_debug_view_tune_button_right(LfRfidTuneView* tune_view) {
|
||||
with_view_model(
|
||||
tune_view->view, (LfRfidTuneViewModel * model) {
|
||||
tune_view->view,
|
||||
LfRfidTuneViewModel * model,
|
||||
{
|
||||
if(model->pos == 0) {
|
||||
if(model->fine) {
|
||||
model->ARR += 1;
|
||||
@@ -106,16 +114,13 @@ static void lfrfid_debug_view_tune_button_right(LfRfidTuneView* tune_view) {
|
||||
}
|
||||
|
||||
model->dirty = true;
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
static void lfrfid_debug_view_tune_button_ok(LfRfidTuneView* tune_view) {
|
||||
with_view_model(
|
||||
tune_view->view, (LfRfidTuneViewModel * model) {
|
||||
model->fine = !model->fine;
|
||||
return true;
|
||||
});
|
||||
tune_view->view, LfRfidTuneViewModel * model, { model->fine = !model->fine; }, true);
|
||||
}
|
||||
|
||||
static bool lfrfid_debug_view_tune_input_callback(InputEvent* event, void* context) {
|
||||
@@ -158,14 +163,16 @@ LfRfidTuneView* lfrfid_debug_view_tune_alloc() {
|
||||
view_allocate_model(tune_view->view, ViewModelTypeLocking, sizeof(LfRfidTuneViewModel));
|
||||
|
||||
with_view_model(
|
||||
tune_view->view, (LfRfidTuneViewModel * model) {
|
||||
tune_view->view,
|
||||
LfRfidTuneViewModel * model,
|
||||
{
|
||||
model->dirty = true;
|
||||
model->fine = false;
|
||||
model->ARR = 511;
|
||||
model->CCR = 255;
|
||||
model->pos = 0;
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
|
||||
view_set_draw_callback(tune_view->view, lfrfid_debug_view_tune_draw_callback);
|
||||
view_set_input_callback(tune_view->view, lfrfid_debug_view_tune_input_callback);
|
||||
@@ -184,24 +191,28 @@ View* lfrfid_debug_view_tune_get_view(LfRfidTuneView* tune_view) {
|
||||
|
||||
void lfrfid_debug_view_tune_clean(LfRfidTuneView* tune_view) {
|
||||
with_view_model(
|
||||
tune_view->view, (LfRfidTuneViewModel * model) {
|
||||
tune_view->view,
|
||||
LfRfidTuneViewModel * model,
|
||||
{
|
||||
model->dirty = true;
|
||||
model->fine = false;
|
||||
model->ARR = 511;
|
||||
model->CCR = 255;
|
||||
model->pos = 0;
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) {
|
||||
bool result = false;
|
||||
with_view_model(
|
||||
tune_view->view, (LfRfidTuneViewModel * model) {
|
||||
tune_view->view,
|
||||
LfRfidTuneViewModel * model,
|
||||
{
|
||||
result = model->dirty;
|
||||
model->dirty = false;
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -209,10 +220,7 @@ bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) {
|
||||
uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) {
|
||||
uint32_t result = false;
|
||||
with_view_model(
|
||||
tune_view->view, (LfRfidTuneViewModel * model) {
|
||||
result = model->ARR;
|
||||
return false;
|
||||
});
|
||||
tune_view->view, LfRfidTuneViewModel * model, { result = model->ARR; }, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -220,10 +228,7 @@ uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) {
|
||||
uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view) {
|
||||
uint32_t result = false;
|
||||
with_view_model(
|
||||
tune_view->view, (LfRfidTuneViewModel * model) {
|
||||
result = model->CCR;
|
||||
return false;
|
||||
});
|
||||
tune_view->view, LfRfidTuneViewModel * model, { result = model->CCR; }, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="uart_echo",
|
||||
appid="UART_Echo",
|
||||
name="UART Echo",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="uart_echo_app",
|
||||
@@ -7,6 +7,6 @@ App(
|
||||
requires=["gui"],
|
||||
stack_size=2 * 1024,
|
||||
order=70,
|
||||
fap_icon="../../../assets/icons/Archive/keyboard_10px.png",
|
||||
fap_icon="uart_10px.png",
|
||||
fap_category="Misc",
|
||||
)
|
||||
|
||||
BIN
applications/debug/uart_echo/uart_10px.png
Normal file
BIN
applications/debug/uart_echo/uart_10px.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
@@ -1,10 +1,8 @@
|
||||
#include <furi.h>
|
||||
#include <m-string.h>
|
||||
#include <gui/gui.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/elements.h>
|
||||
#include <stream_buffer.h>
|
||||
#include <furi_hal_uart.h>
|
||||
#include <furi_hal_console.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
@@ -21,11 +19,11 @@ typedef struct {
|
||||
ViewDispatcher* view_dispatcher;
|
||||
View* view;
|
||||
FuriThread* worker_thread;
|
||||
StreamBufferHandle_t rx_stream;
|
||||
FuriStreamBuffer* rx_stream;
|
||||
} UartEchoApp;
|
||||
|
||||
typedef struct {
|
||||
string_t text;
|
||||
FuriString* text;
|
||||
} ListElement;
|
||||
|
||||
struct UartDumpModel {
|
||||
@@ -64,10 +62,11 @@ static void uart_echo_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
canvas,
|
||||
0,
|
||||
(i + 1) * (canvas_current_font_height(canvas) - 1),
|
||||
string_get_cstr(model->list[i]->text));
|
||||
furi_string_get_cstr(model->list[i]->text));
|
||||
|
||||
if(i == model->line) {
|
||||
uint8_t width = canvas_string_width(canvas, string_get_cstr(model->list[i]->text));
|
||||
uint8_t width =
|
||||
canvas_string_width(canvas, furi_string_get_cstr(model->list[i]->text));
|
||||
|
||||
canvas_draw_box(
|
||||
canvas,
|
||||
@@ -92,13 +91,11 @@ static uint32_t uart_echo_exit(void* context) {
|
||||
|
||||
static void uart_echo_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) {
|
||||
furi_assert(context);
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
UartEchoApp* app = context;
|
||||
|
||||
if(ev == UartIrqEventRXNE) {
|
||||
xStreamBufferSendFromISR(app->rx_stream, &data, 1, &xHigherPriorityTaskWoken);
|
||||
furi_stream_buffer_send(app->rx_stream, &data, 1, 0);
|
||||
furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventRx);
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +110,7 @@ static void uart_echo_push_to_list(UartDumpModel* model, const char data) {
|
||||
model->escape = true;
|
||||
} else if((data >= ' ' && data <= '~') || (data == '\n' || data == '\r')) {
|
||||
bool new_string_needed = false;
|
||||
if(string_size(model->list[model->line]->text) >= COLUMNS_ON_SCREEN) {
|
||||
if(furi_string_size(model->list[model->line]->text) >= COLUMNS_ON_SCREEN) {
|
||||
new_string_needed = true;
|
||||
} else if((data == '\n' || data == '\r')) {
|
||||
// pack line breaks
|
||||
@@ -132,13 +129,13 @@ static void uart_echo_push_to_list(UartDumpModel* model, const char data) {
|
||||
model->list[i - 1] = model->list[i];
|
||||
}
|
||||
|
||||
string_reset(first->text);
|
||||
furi_string_reset(first->text);
|
||||
model->list[model->line] = first;
|
||||
}
|
||||
}
|
||||
|
||||
if(data != '\n' && data != '\r') {
|
||||
string_push_back(model->list[model->line]->text, data);
|
||||
furi_string_push_back(model->list[model->line]->text, data);
|
||||
}
|
||||
}
|
||||
model->last_char = data;
|
||||
@@ -158,25 +155,24 @@ static int32_t uart_echo_worker(void* context) {
|
||||
size_t length = 0;
|
||||
do {
|
||||
uint8_t data[64];
|
||||
length = xStreamBufferReceive(app->rx_stream, data, 64, 0);
|
||||
length = furi_stream_buffer_receive(app->rx_stream, data, 64, 0);
|
||||
if(length > 0) {
|
||||
furi_hal_uart_tx(FuriHalUartIdUSART1, data, length);
|
||||
with_view_model(
|
||||
app->view, (UartDumpModel * model) {
|
||||
app->view,
|
||||
UartDumpModel * model,
|
||||
{
|
||||
for(size_t i = 0; i < length; i++) {
|
||||
uart_echo_push_to_list(model, data[i]);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
}
|
||||
} while(length > 0);
|
||||
|
||||
notification_message(app->notification, &sequence_notification);
|
||||
with_view_model(
|
||||
app->view, (UartDumpModel * model) {
|
||||
UNUSED(model);
|
||||
return true;
|
||||
});
|
||||
app->view, UartDumpModel * model, { UNUSED(model); }, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +182,7 @@ static int32_t uart_echo_worker(void* context) {
|
||||
static UartEchoApp* uart_echo_app_alloc() {
|
||||
UartEchoApp* app = malloc(sizeof(UartEchoApp));
|
||||
|
||||
app->rx_stream = xStreamBufferCreate(2048, 1);
|
||||
app->rx_stream = furi_stream_buffer_alloc(2048, 1);
|
||||
|
||||
// Gui
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
@@ -203,15 +199,17 @@ static UartEchoApp* uart_echo_app_alloc() {
|
||||
view_set_input_callback(app->view, uart_echo_view_input_callback);
|
||||
view_allocate_model(app->view, ViewModelTypeLocking, sizeof(UartDumpModel));
|
||||
with_view_model(
|
||||
app->view, (UartDumpModel * model) {
|
||||
app->view,
|
||||
UartDumpModel * model,
|
||||
{
|
||||
for(size_t i = 0; i < LINES_ON_SCREEN; i++) {
|
||||
model->line = 0;
|
||||
model->escape = false;
|
||||
model->list[i] = malloc(sizeof(ListElement));
|
||||
string_init(model->list[i]->text);
|
||||
model->list[i]->text = furi_string_alloc();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
|
||||
view_set_previous_callback(app->view, uart_echo_exit);
|
||||
view_dispatcher_add_view(app->view_dispatcher, 0, app->view);
|
||||
@@ -245,13 +243,15 @@ static void uart_echo_app_free(UartEchoApp* app) {
|
||||
view_dispatcher_remove_view(app->view_dispatcher, 0);
|
||||
|
||||
with_view_model(
|
||||
app->view, (UartDumpModel * model) {
|
||||
app->view,
|
||||
UartDumpModel * model,
|
||||
{
|
||||
for(size_t i = 0; i < LINES_ON_SCREEN; i++) {
|
||||
string_clear(model->list[i]->text);
|
||||
furi_string_free(model->list[i]->text);
|
||||
free(model->list[i]);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
view_free(app->view);
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
|
||||
@@ -260,7 +260,7 @@ static void uart_echo_app_free(UartEchoApp* app) {
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
app->gui = NULL;
|
||||
|
||||
vStreamBufferDelete(app->rx_stream);
|
||||
furi_stream_buffer_free(app->rx_stream);
|
||||
|
||||
// Free rest
|
||||
free(app);
|
||||
|
||||
@@ -58,7 +58,7 @@ static const char* test_data_win = "Filetype: Flipper Format test\r\n"
|
||||
#define ARRAY_W_BSIZE(x) (x), (sizeof(x))
|
||||
|
||||
MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) {
|
||||
string_t tmpstr;
|
||||
FuriString* tmpstr;
|
||||
uint32_t version;
|
||||
uint32_t uint32_data[COUNT_OF(test_uint_data)];
|
||||
int32_t int32_data[COUNT_OF(test_int_data)];
|
||||
@@ -101,14 +101,14 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) {
|
||||
mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format)));
|
||||
|
||||
// read test
|
||||
string_init(tmpstr);
|
||||
tmpstr = furi_string_alloc();
|
||||
|
||||
mu_check(flipper_format_read_header(flipper_format, tmpstr, &version));
|
||||
mu_assert_string_eq(test_filetype, string_get_cstr(tmpstr));
|
||||
mu_assert_string_eq(test_filetype, furi_string_get_cstr(tmpstr));
|
||||
mu_assert_int_eq(test_version, version);
|
||||
|
||||
mu_check(flipper_format_read_string(flipper_format, test_string_key, tmpstr));
|
||||
mu_assert_string_eq(test_string_data, string_get_cstr(tmpstr));
|
||||
mu_assert_string_eq(test_string_data, furi_string_get_cstr(tmpstr));
|
||||
|
||||
mu_check(flipper_format_get_value_count(flipper_format, test_int_key, &count));
|
||||
mu_assert_int_eq(COUNT_OF(test_int_data), count);
|
||||
@@ -133,7 +133,7 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) {
|
||||
|
||||
mu_check(!flipper_format_read_string(flipper_format, "Key that doesn't exist", tmpstr));
|
||||
|
||||
string_clear(tmpstr);
|
||||
furi_string_free(tmpstr);
|
||||
|
||||
// update data
|
||||
mu_check(flipper_format_rewind(flipper_format));
|
||||
@@ -155,14 +155,14 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) {
|
||||
uint8_t hex_updated_data[COUNT_OF(test_hex_updated_data)];
|
||||
|
||||
mu_check(flipper_format_rewind(flipper_format));
|
||||
string_init(tmpstr);
|
||||
tmpstr = furi_string_alloc();
|
||||
|
||||
mu_check(flipper_format_read_header(flipper_format, tmpstr, &version));
|
||||
mu_assert_string_eq(test_filetype, string_get_cstr(tmpstr));
|
||||
mu_assert_string_eq(test_filetype, furi_string_get_cstr(tmpstr));
|
||||
mu_assert_int_eq(test_version, version);
|
||||
|
||||
mu_check(flipper_format_read_string(flipper_format, test_string_key, tmpstr));
|
||||
mu_assert_string_eq(test_string_updated_data, string_get_cstr(tmpstr));
|
||||
mu_assert_string_eq(test_string_updated_data, furi_string_get_cstr(tmpstr));
|
||||
|
||||
mu_check(flipper_format_get_value_count(flipper_format, test_int_key, &count));
|
||||
mu_assert_int_eq(COUNT_OF(test_int_updated_data), count);
|
||||
@@ -190,7 +190,7 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) {
|
||||
|
||||
mu_check(!flipper_format_read_string(flipper_format, "Key that doesn't exist", tmpstr));
|
||||
|
||||
string_clear(tmpstr);
|
||||
furi_string_free(tmpstr);
|
||||
|
||||
// update data
|
||||
mu_check(flipper_format_rewind(flipper_format));
|
||||
@@ -214,14 +214,14 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) {
|
||||
uint8_t hex_new_data[COUNT_OF(test_hex_new_data)];
|
||||
|
||||
mu_check(flipper_format_rewind(flipper_format));
|
||||
string_init(tmpstr);
|
||||
tmpstr = furi_string_alloc();
|
||||
|
||||
mu_check(flipper_format_read_header(flipper_format, tmpstr, &version));
|
||||
mu_assert_string_eq(test_filetype, string_get_cstr(tmpstr));
|
||||
mu_assert_string_eq(test_filetype, furi_string_get_cstr(tmpstr));
|
||||
mu_assert_int_eq(test_version, version);
|
||||
|
||||
mu_check(flipper_format_read_string(flipper_format, test_string_key, tmpstr));
|
||||
mu_assert_string_eq(test_string_updated_2_data, string_get_cstr(tmpstr));
|
||||
mu_assert_string_eq(test_string_updated_2_data, furi_string_get_cstr(tmpstr));
|
||||
|
||||
mu_check(flipper_format_get_value_count(flipper_format, test_int_key, &count));
|
||||
mu_assert_int_eq(COUNT_OF(test_int_updated_2_data), count);
|
||||
@@ -255,7 +255,7 @@ MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) {
|
||||
|
||||
mu_check(!flipper_format_read_string(flipper_format, "Key that doesn't exist", tmpstr));
|
||||
|
||||
string_clear(tmpstr);
|
||||
furi_string_free(tmpstr);
|
||||
|
||||
// delete key test
|
||||
mu_check(flipper_format_rewind(flipper_format));
|
||||
|
||||
@@ -57,6 +57,23 @@ static const char* test_data_win = "Filetype: Flipper File test\r\n"
|
||||
"Hex data: DE AD BE";
|
||||
|
||||
#define READ_TEST_FLP "ff_flp.test"
|
||||
#define READ_TEST_ODD "ff_oddities.test"
|
||||
static const char* test_data_odd = "Filetype: Flipper File test\n"
|
||||
// Tabs before newline
|
||||
"Version: 666\t\t\n"
|
||||
"# This is comment\n"
|
||||
// Windows newline in a UNIX file
|
||||
"String data: String\r\n"
|
||||
// Trailing whitespace
|
||||
"Int32 data: 1234 -6345 7813 0 \n"
|
||||
// Extra whitespace
|
||||
"Uint32 data: 1234 0 5678 9098 7654321 \n"
|
||||
// Mixed whitespace
|
||||
"Float data: 1.5\t \t1000.0\n"
|
||||
// Leading tabs after key
|
||||
"Bool data:\t\ttrue false\n"
|
||||
// Mixed trailing whitespace
|
||||
"Hex data: DE AD BE\t ";
|
||||
|
||||
// data created by user on linux machine
|
||||
static const char* test_file_linux = TEST_DIR READ_TEST_NIX;
|
||||
@@ -64,6 +81,8 @@ static const char* test_file_linux = TEST_DIR READ_TEST_NIX;
|
||||
static const char* test_file_windows = TEST_DIR READ_TEST_WIN;
|
||||
// data created by flipper itself
|
||||
static const char* test_file_flipper = TEST_DIR READ_TEST_FLP;
|
||||
// data containing odd user input
|
||||
static const char* test_file_oddities = TEST_DIR READ_TEST_ODD;
|
||||
|
||||
static bool storage_write_string(const char* path, const char* data) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
@@ -102,8 +121,8 @@ static bool test_read(const char* file_name) {
|
||||
bool result = false;
|
||||
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
string_t string_value;
|
||||
string_init(string_value);
|
||||
FuriString* string_value;
|
||||
string_value = furi_string_alloc();
|
||||
uint32_t uint32_value;
|
||||
void* scratchpad = malloc(512);
|
||||
|
||||
@@ -111,11 +130,11 @@ static bool test_read(const char* file_name) {
|
||||
if(!flipper_format_file_open_existing(file, file_name)) break;
|
||||
|
||||
if(!flipper_format_read_header(file, string_value, &uint32_value)) break;
|
||||
if(string_cmp_str(string_value, test_filetype) != 0) break;
|
||||
if(furi_string_cmp_str(string_value, test_filetype) != 0) break;
|
||||
if(uint32_value != test_version) break;
|
||||
|
||||
if(!flipper_format_read_string(file, test_string_key, string_value)) break;
|
||||
if(string_cmp_str(string_value, test_string_data) != 0) break;
|
||||
if(furi_string_cmp_str(string_value, test_string_data) != 0) break;
|
||||
|
||||
if(!flipper_format_get_value_count(file, test_int_key, &uint32_value)) break;
|
||||
if(uint32_value != COUNT_OF(test_int_data)) break;
|
||||
@@ -150,7 +169,7 @@ static bool test_read(const char* file_name) {
|
||||
} while(false);
|
||||
|
||||
free(scratchpad);
|
||||
string_clear(string_value);
|
||||
furi_string_free(string_value);
|
||||
|
||||
flipper_format_free(file);
|
||||
|
||||
@@ -164,8 +183,8 @@ static bool test_read_updated(const char* file_name) {
|
||||
bool result = false;
|
||||
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
string_t string_value;
|
||||
string_init(string_value);
|
||||
FuriString* string_value;
|
||||
string_value = furi_string_alloc();
|
||||
uint32_t uint32_value;
|
||||
void* scratchpad = malloc(512);
|
||||
|
||||
@@ -173,11 +192,11 @@ static bool test_read_updated(const char* file_name) {
|
||||
if(!flipper_format_file_open_existing(file, file_name)) break;
|
||||
|
||||
if(!flipper_format_read_header(file, string_value, &uint32_value)) break;
|
||||
if(string_cmp_str(string_value, test_filetype) != 0) break;
|
||||
if(furi_string_cmp_str(string_value, test_filetype) != 0) break;
|
||||
if(uint32_value != test_version) break;
|
||||
|
||||
if(!flipper_format_read_string(file, test_string_key, string_value)) break;
|
||||
if(string_cmp_str(string_value, test_string_updated_data) != 0) break;
|
||||
if(furi_string_cmp_str(string_value, test_string_updated_data) != 0) break;
|
||||
|
||||
if(!flipper_format_get_value_count(file, test_int_key, &uint32_value)) break;
|
||||
if(uint32_value != COUNT_OF(test_int_updated_data)) break;
|
||||
@@ -228,7 +247,7 @@ static bool test_read_updated(const char* file_name) {
|
||||
} while(false);
|
||||
|
||||
free(scratchpad);
|
||||
string_clear(string_value);
|
||||
furi_string_free(string_value);
|
||||
|
||||
flipper_format_free(file);
|
||||
|
||||
@@ -401,14 +420,14 @@ static bool test_read_multikey(const char* file_name) {
|
||||
bool result = false;
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
|
||||
string_t string_value;
|
||||
string_init(string_value);
|
||||
FuriString* string_value;
|
||||
string_value = furi_string_alloc();
|
||||
uint32_t uint32_value;
|
||||
|
||||
do {
|
||||
if(!flipper_format_file_open_existing(file, file_name)) break;
|
||||
if(!flipper_format_read_header(file, string_value, &uint32_value)) break;
|
||||
if(string_cmp_str(string_value, test_filetype) != 0) break;
|
||||
if(furi_string_cmp_str(string_value, test_filetype) != 0) break;
|
||||
if(uint32_value != test_version) break;
|
||||
|
||||
bool error = false;
|
||||
@@ -429,7 +448,7 @@ static bool test_read_multikey(const char* file_name) {
|
||||
result = true;
|
||||
} while(false);
|
||||
|
||||
string_clear(string_value);
|
||||
furi_string_free(string_value);
|
||||
|
||||
flipper_format_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
@@ -503,6 +522,12 @@ MU_TEST(flipper_format_multikey_test) {
|
||||
mu_assert(test_read_multikey(TEST_DIR "ff_multiline.test"), "Multikey read test error");
|
||||
}
|
||||
|
||||
MU_TEST(flipper_format_oddities_test) {
|
||||
mu_assert(
|
||||
storage_write_string(test_file_oddities, test_data_odd), "Write test error [Oddities]");
|
||||
mu_assert(test_read(test_file_linux), "Read test error [Oddities]");
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(flipper_format) {
|
||||
tests_setup();
|
||||
MU_RUN_TEST(flipper_format_write_test);
|
||||
@@ -516,6 +541,7 @@ MU_TEST_SUITE(flipper_format) {
|
||||
MU_RUN_TEST(flipper_format_update_2_test);
|
||||
MU_RUN_TEST(flipper_format_update_2_result_test);
|
||||
MU_RUN_TEST(flipper_format_multikey_test);
|
||||
MU_RUN_TEST(flipper_format_oddities_test);
|
||||
tests_teardown();
|
||||
}
|
||||
|
||||
|
||||
469
applications/debug/unit_tests/furi/furi_string_test.c
Normal file
469
applications/debug/unit_tests/furi/furi_string_test.c
Normal file
@@ -0,0 +1,469 @@
|
||||
#include <furi.h>
|
||||
#include "../minunit.h"
|
||||
|
||||
static void test_setup(void) {
|
||||
}
|
||||
|
||||
static void test_teardown(void) {
|
||||
}
|
||||
|
||||
static FuriString* furi_string_alloc_vprintf_test(const char format[], ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
FuriString* string = furi_string_alloc_vprintf(format, args);
|
||||
va_end(args);
|
||||
return string;
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_string_alloc_free) {
|
||||
FuriString* tmp;
|
||||
FuriString* string;
|
||||
|
||||
// test alloc and free
|
||||
string = furi_string_alloc();
|
||||
mu_check(string != NULL);
|
||||
mu_check(furi_string_empty(string));
|
||||
furi_string_free(string);
|
||||
|
||||
// test furi_string_alloc_set_str and free
|
||||
string = furi_string_alloc_set_str("test");
|
||||
mu_check(string != NULL);
|
||||
mu_check(!furi_string_empty(string));
|
||||
mu_check(furi_string_cmp(string, "test") == 0);
|
||||
furi_string_free(string);
|
||||
|
||||
// test furi_string_alloc_set and free
|
||||
tmp = furi_string_alloc_set("more");
|
||||
string = furi_string_alloc_set(tmp);
|
||||
furi_string_free(tmp);
|
||||
mu_check(string != NULL);
|
||||
mu_check(!furi_string_empty(string));
|
||||
mu_check(furi_string_cmp(string, "more") == 0);
|
||||
furi_string_free(string);
|
||||
|
||||
// test alloc_printf and free
|
||||
string = furi_string_alloc_printf("test %d %s %c 0x%02x", 1, "two", '3', 0x04);
|
||||
mu_check(string != NULL);
|
||||
mu_check(!furi_string_empty(string));
|
||||
mu_check(furi_string_cmp(string, "test 1 two 3 0x04") == 0);
|
||||
furi_string_free(string);
|
||||
|
||||
// test alloc_vprintf and free
|
||||
string = furi_string_alloc_vprintf_test("test %d %s %c 0x%02x", 4, "five", '6', 0x07);
|
||||
mu_check(string != NULL);
|
||||
mu_check(!furi_string_empty(string));
|
||||
mu_check(furi_string_cmp(string, "test 4 five 6 0x07") == 0);
|
||||
furi_string_free(string);
|
||||
|
||||
// test alloc_move and free
|
||||
tmp = furi_string_alloc_set("move");
|
||||
string = furi_string_alloc_move(tmp);
|
||||
mu_check(string != NULL);
|
||||
mu_check(!furi_string_empty(string));
|
||||
mu_check(furi_string_cmp(string, "move") == 0);
|
||||
furi_string_free(string);
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_string_mem) {
|
||||
FuriString* string = furi_string_alloc_set("test");
|
||||
mu_check(string != NULL);
|
||||
mu_check(!furi_string_empty(string));
|
||||
|
||||
// TODO: how to test furi_string_reserve?
|
||||
|
||||
// test furi_string_reset
|
||||
furi_string_reset(string);
|
||||
mu_check(furi_string_empty(string));
|
||||
|
||||
// test furi_string_swap
|
||||
furi_string_set(string, "test");
|
||||
FuriString* swap_string = furi_string_alloc_set("swap");
|
||||
furi_string_swap(string, swap_string);
|
||||
mu_check(furi_string_cmp(string, "swap") == 0);
|
||||
mu_check(furi_string_cmp(swap_string, "test") == 0);
|
||||
furi_string_free(swap_string);
|
||||
|
||||
// test furi_string_move
|
||||
FuriString* move_string = furi_string_alloc_set("move");
|
||||
furi_string_move(string, move_string);
|
||||
mu_check(furi_string_cmp(string, "move") == 0);
|
||||
// move_string is now empty
|
||||
// and tested by leaked memory check at the end of the tests
|
||||
|
||||
furi_string_set(string, "abracadabra");
|
||||
|
||||
// test furi_string_hash
|
||||
mu_assert_int_eq(0xc3bc16d7, furi_string_hash(string));
|
||||
|
||||
// test furi_string_size
|
||||
mu_assert_int_eq(11, furi_string_size(string));
|
||||
|
||||
// test furi_string_empty
|
||||
mu_check(!furi_string_empty(string));
|
||||
furi_string_reset(string);
|
||||
mu_check(furi_string_empty(string));
|
||||
|
||||
furi_string_free(string);
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_string_getters) {
|
||||
FuriString* string = furi_string_alloc_set("test");
|
||||
|
||||
// test furi_string_get_char
|
||||
mu_check(furi_string_get_char(string, 0) == 't');
|
||||
mu_check(furi_string_get_char(string, 1) == 'e');
|
||||
mu_check(furi_string_get_char(string, 2) == 's');
|
||||
mu_check(furi_string_get_char(string, 3) == 't');
|
||||
|
||||
// test furi_string_get_cstr
|
||||
mu_assert_string_eq("test", furi_string_get_cstr(string));
|
||||
furi_string_free(string);
|
||||
}
|
||||
|
||||
static FuriString* furi_string_vprintf_test(FuriString* string, const char format[], ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
furi_string_vprintf(string, format, args);
|
||||
va_end(args);
|
||||
return string;
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_string_setters) {
|
||||
FuriString* tmp;
|
||||
FuriString* string = furi_string_alloc();
|
||||
|
||||
// test furi_string_set_str
|
||||
furi_string_set_str(string, "test");
|
||||
mu_assert_string_eq("test", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_set
|
||||
tmp = furi_string_alloc_set("more");
|
||||
furi_string_set(string, tmp);
|
||||
furi_string_free(tmp);
|
||||
mu_assert_string_eq("more", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_set_strn
|
||||
furi_string_set_strn(string, "test", 2);
|
||||
mu_assert_string_eq("te", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_set_char
|
||||
furi_string_set_char(string, 0, 'a');
|
||||
furi_string_set_char(string, 1, 'b');
|
||||
mu_assert_string_eq("ab", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_set_n
|
||||
tmp = furi_string_alloc_set("dodecahedron");
|
||||
furi_string_set_n(string, tmp, 4, 5);
|
||||
furi_string_free(tmp);
|
||||
mu_assert_string_eq("cahed", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_printf
|
||||
furi_string_printf(string, "test %d %s %c 0x%02x", 1, "two", '3', 0x04);
|
||||
mu_assert_string_eq("test 1 two 3 0x04", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_vprintf
|
||||
furi_string_vprintf_test(string, "test %d %s %c 0x%02x", 4, "five", '6', 0x07);
|
||||
mu_assert_string_eq("test 4 five 6 0x07", furi_string_get_cstr(string));
|
||||
|
||||
furi_string_free(string);
|
||||
}
|
||||
|
||||
static FuriString* furi_string_cat_vprintf_test(FuriString* string, const char format[], ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
furi_string_cat_vprintf(string, format, args);
|
||||
va_end(args);
|
||||
return string;
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_string_appends) {
|
||||
FuriString* tmp;
|
||||
FuriString* string = furi_string_alloc();
|
||||
|
||||
// test furi_string_push_back
|
||||
furi_string_push_back(string, 't');
|
||||
furi_string_push_back(string, 'e');
|
||||
furi_string_push_back(string, 's');
|
||||
furi_string_push_back(string, 't');
|
||||
mu_assert_string_eq("test", furi_string_get_cstr(string));
|
||||
furi_string_push_back(string, '!');
|
||||
mu_assert_string_eq("test!", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_cat_str
|
||||
furi_string_cat_str(string, "test");
|
||||
mu_assert_string_eq("test!test", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_cat
|
||||
tmp = furi_string_alloc_set("more");
|
||||
furi_string_cat(string, tmp);
|
||||
furi_string_free(tmp);
|
||||
mu_assert_string_eq("test!testmore", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_cat_printf
|
||||
furi_string_cat_printf(string, "test %d %s %c 0x%02x", 1, "two", '3', 0x04);
|
||||
mu_assert_string_eq("test!testmoretest 1 two 3 0x04", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_cat_vprintf
|
||||
furi_string_cat_vprintf_test(string, "test %d %s %c 0x%02x", 4, "five", '6', 0x07);
|
||||
mu_assert_string_eq(
|
||||
"test!testmoretest 1 two 3 0x04test 4 five 6 0x07", furi_string_get_cstr(string));
|
||||
|
||||
furi_string_free(string);
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_string_compare) {
|
||||
FuriString* string_1 = furi_string_alloc_set("string_1");
|
||||
FuriString* string_2 = furi_string_alloc_set("string_2");
|
||||
|
||||
// test furi_string_cmp
|
||||
mu_assert_int_eq(0, furi_string_cmp(string_1, string_1));
|
||||
mu_assert_int_eq(0, furi_string_cmp(string_2, string_2));
|
||||
mu_assert_int_eq(-1, furi_string_cmp(string_1, string_2));
|
||||
mu_assert_int_eq(1, furi_string_cmp(string_2, string_1));
|
||||
|
||||
// test furi_string_cmp_str
|
||||
mu_assert_int_eq(0, furi_string_cmp_str(string_1, "string_1"));
|
||||
mu_assert_int_eq(0, furi_string_cmp_str(string_2, "string_2"));
|
||||
mu_assert_int_eq(-1, furi_string_cmp_str(string_1, "string_2"));
|
||||
mu_assert_int_eq(1, furi_string_cmp_str(string_2, "string_1"));
|
||||
|
||||
// test furi_string_cmpi
|
||||
furi_string_set(string_1, "string");
|
||||
furi_string_set(string_2, "StrIng");
|
||||
mu_assert_int_eq(0, furi_string_cmpi(string_1, string_1));
|
||||
mu_assert_int_eq(0, furi_string_cmpi(string_2, string_2));
|
||||
mu_assert_int_eq(0, furi_string_cmpi(string_1, string_2));
|
||||
mu_assert_int_eq(0, furi_string_cmpi(string_2, string_1));
|
||||
furi_string_set(string_1, "string_1");
|
||||
furi_string_set(string_2, "StrIng_2");
|
||||
mu_assert_int_eq(32, furi_string_cmp(string_1, string_2));
|
||||
mu_assert_int_eq(-32, furi_string_cmp(string_2, string_1));
|
||||
mu_assert_int_eq(-1, furi_string_cmpi(string_1, string_2));
|
||||
mu_assert_int_eq(1, furi_string_cmpi(string_2, string_1));
|
||||
|
||||
// test furi_string_cmpi_str
|
||||
furi_string_set(string_1, "string");
|
||||
mu_assert_int_eq(0, furi_string_cmp_str(string_1, "string"));
|
||||
mu_assert_int_eq(32, furi_string_cmp_str(string_1, "String"));
|
||||
mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STring"));
|
||||
mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STRing"));
|
||||
mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STRIng"));
|
||||
mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STRINg"));
|
||||
mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STRING"));
|
||||
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "string"));
|
||||
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "String"));
|
||||
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STring"));
|
||||
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STRing"));
|
||||
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STRIng"));
|
||||
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STRINg"));
|
||||
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STRING"));
|
||||
|
||||
furi_string_free(string_1);
|
||||
furi_string_free(string_2);
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_string_search) {
|
||||
// 012345678901234567
|
||||
FuriString* haystack = furi_string_alloc_set("test321test123test");
|
||||
FuriString* needle = furi_string_alloc_set("test");
|
||||
|
||||
// test furi_string_search
|
||||
mu_assert_int_eq(0, furi_string_search(haystack, needle));
|
||||
mu_assert_int_eq(7, furi_string_search(haystack, needle, 1));
|
||||
mu_assert_int_eq(14, furi_string_search(haystack, needle, 8));
|
||||
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search(haystack, needle, 15));
|
||||
|
||||
FuriString* tmp = furi_string_alloc_set("testnone");
|
||||
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search(haystack, tmp));
|
||||
furi_string_free(tmp);
|
||||
|
||||
// test furi_string_search_str
|
||||
mu_assert_int_eq(0, furi_string_search_str(haystack, "test"));
|
||||
mu_assert_int_eq(7, furi_string_search_str(haystack, "test", 1));
|
||||
mu_assert_int_eq(14, furi_string_search_str(haystack, "test", 8));
|
||||
mu_assert_int_eq(4, furi_string_search_str(haystack, "321"));
|
||||
mu_assert_int_eq(11, furi_string_search_str(haystack, "123"));
|
||||
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_str(haystack, "testnone"));
|
||||
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_str(haystack, "test", 15));
|
||||
|
||||
// test furi_string_search_char
|
||||
mu_assert_int_eq(0, furi_string_search_char(haystack, 't'));
|
||||
mu_assert_int_eq(1, furi_string_search_char(haystack, 'e'));
|
||||
mu_assert_int_eq(2, furi_string_search_char(haystack, 's'));
|
||||
mu_assert_int_eq(3, furi_string_search_char(haystack, 't', 1));
|
||||
mu_assert_int_eq(7, furi_string_search_char(haystack, 't', 4));
|
||||
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_char(haystack, 'x'));
|
||||
|
||||
// test furi_string_search_rchar
|
||||
mu_assert_int_eq(17, furi_string_search_rchar(haystack, 't'));
|
||||
mu_assert_int_eq(15, furi_string_search_rchar(haystack, 'e'));
|
||||
mu_assert_int_eq(16, furi_string_search_rchar(haystack, 's'));
|
||||
mu_assert_int_eq(13, furi_string_search_rchar(haystack, '3'));
|
||||
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_rchar(haystack, '3', 14));
|
||||
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_rchar(haystack, 'x'));
|
||||
|
||||
furi_string_free(haystack);
|
||||
furi_string_free(needle);
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_string_equality) {
|
||||
FuriString* string = furi_string_alloc_set("test");
|
||||
FuriString* string_eq = furi_string_alloc_set("test");
|
||||
FuriString* string_neq = furi_string_alloc_set("test2");
|
||||
|
||||
// test furi_string_equal
|
||||
mu_check(furi_string_equal(string, string_eq));
|
||||
mu_check(!furi_string_equal(string, string_neq));
|
||||
|
||||
// test furi_string_equal_str
|
||||
mu_check(furi_string_equal_str(string, "test"));
|
||||
mu_check(!furi_string_equal_str(string, "test2"));
|
||||
mu_check(furi_string_equal_str(string_neq, "test2"));
|
||||
mu_check(!furi_string_equal_str(string_neq, "test"));
|
||||
|
||||
furi_string_free(string);
|
||||
furi_string_free(string_eq);
|
||||
furi_string_free(string_neq);
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_string_replace) {
|
||||
FuriString* needle = furi_string_alloc_set("test");
|
||||
FuriString* replace = furi_string_alloc_set("replace");
|
||||
FuriString* string = furi_string_alloc_set("test123test");
|
||||
|
||||
// test furi_string_replace_at
|
||||
furi_string_replace_at(string, 4, 3, "!biglongword!");
|
||||
mu_assert_string_eq("test!biglongword!test", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_replace
|
||||
mu_assert_int_eq(17, furi_string_replace(string, needle, replace, 1));
|
||||
mu_assert_string_eq("test!biglongword!replace", furi_string_get_cstr(string));
|
||||
mu_assert_int_eq(0, furi_string_replace(string, needle, replace));
|
||||
mu_assert_string_eq("replace!biglongword!replace", furi_string_get_cstr(string));
|
||||
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_replace(string, needle, replace));
|
||||
mu_assert_string_eq("replace!biglongword!replace", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_replace_str
|
||||
mu_assert_int_eq(20, furi_string_replace_str(string, "replace", "test", 1));
|
||||
mu_assert_string_eq("replace!biglongword!test", furi_string_get_cstr(string));
|
||||
mu_assert_int_eq(0, furi_string_replace_str(string, "replace", "test"));
|
||||
mu_assert_string_eq("test!biglongword!test", furi_string_get_cstr(string));
|
||||
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_replace_str(string, "replace", "test"));
|
||||
mu_assert_string_eq("test!biglongword!test", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_replace_all
|
||||
furi_string_replace_all(string, needle, replace);
|
||||
mu_assert_string_eq("replace!biglongword!replace", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_replace_all_str
|
||||
furi_string_replace_all_str(string, "replace", "test");
|
||||
mu_assert_string_eq("test!biglongword!test", furi_string_get_cstr(string));
|
||||
|
||||
furi_string_free(string);
|
||||
furi_string_free(needle);
|
||||
furi_string_free(replace);
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_string_start_end) {
|
||||
FuriString* string = furi_string_alloc_set("start_end");
|
||||
FuriString* start = furi_string_alloc_set("start");
|
||||
FuriString* end = furi_string_alloc_set("end");
|
||||
|
||||
// test furi_string_start_with
|
||||
mu_check(furi_string_start_with(string, start));
|
||||
mu_check(!furi_string_start_with(string, end));
|
||||
|
||||
// test furi_string_start_with_str
|
||||
mu_check(furi_string_start_with_str(string, "start"));
|
||||
mu_check(!furi_string_start_with_str(string, "end"));
|
||||
|
||||
// test furi_string_end_with
|
||||
mu_check(furi_string_end_with(string, end));
|
||||
mu_check(!furi_string_end_with(string, start));
|
||||
|
||||
// test furi_string_end_with_str
|
||||
mu_check(furi_string_end_with_str(string, "end"));
|
||||
mu_check(!furi_string_end_with_str(string, "start"));
|
||||
|
||||
furi_string_free(string);
|
||||
furi_string_free(start);
|
||||
furi_string_free(end);
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_string_trim) {
|
||||
FuriString* string = furi_string_alloc_set("biglongstring");
|
||||
|
||||
// test furi_string_left
|
||||
furi_string_left(string, 7);
|
||||
mu_assert_string_eq("biglong", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_right
|
||||
furi_string_right(string, 3);
|
||||
mu_assert_string_eq("long", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_mid
|
||||
furi_string_mid(string, 1, 2);
|
||||
mu_assert_string_eq("on", furi_string_get_cstr(string));
|
||||
|
||||
// test furi_string_trim
|
||||
furi_string_set(string, " \n\r\tbiglongstring \n\r\t ");
|
||||
furi_string_trim(string);
|
||||
mu_assert_string_eq("biglongstring", furi_string_get_cstr(string));
|
||||
furi_string_set(string, "aaaabaaaabbaaabaaaabbtestaaaaaabbaaabaababaa");
|
||||
furi_string_trim(string, "ab");
|
||||
mu_assert_string_eq("test", furi_string_get_cstr(string));
|
||||
|
||||
furi_string_free(string);
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_string_utf8) {
|
||||
FuriString* utf8_string = furi_string_alloc_set("イルカ");
|
||||
|
||||
// test furi_string_utf8_length
|
||||
mu_assert_int_eq(9, furi_string_size(utf8_string));
|
||||
mu_assert_int_eq(3, furi_string_utf8_length(utf8_string));
|
||||
|
||||
// test furi_string_utf8_decode
|
||||
const uint8_t dolphin_emoji_array[4] = {0xF0, 0x9F, 0x90, 0xAC};
|
||||
FuriStringUTF8State state = FuriStringUTF8StateStarting;
|
||||
FuriStringUnicodeValue value = 0;
|
||||
furi_string_utf8_decode(dolphin_emoji_array[0], &state, &value);
|
||||
mu_assert_int_eq(FuriStringUTF8StateDecoding3, state);
|
||||
furi_string_utf8_decode(dolphin_emoji_array[1], &state, &value);
|
||||
mu_assert_int_eq(FuriStringUTF8StateDecoding2, state);
|
||||
furi_string_utf8_decode(dolphin_emoji_array[2], &state, &value);
|
||||
mu_assert_int_eq(FuriStringUTF8StateDecoding1, state);
|
||||
furi_string_utf8_decode(dolphin_emoji_array[3], &state, &value);
|
||||
mu_assert_int_eq(FuriStringUTF8StateStarting, state);
|
||||
mu_assert_int_eq(0x1F42C, value);
|
||||
|
||||
// test furi_string_utf8_push
|
||||
furi_string_set(utf8_string, "");
|
||||
furi_string_utf8_push(utf8_string, value);
|
||||
mu_assert_string_eq("🐬", furi_string_get_cstr(utf8_string));
|
||||
|
||||
furi_string_free(utf8_string);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_suite) {
|
||||
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||
|
||||
MU_RUN_TEST(mu_test_furi_string_alloc_free);
|
||||
MU_RUN_TEST(mu_test_furi_string_mem);
|
||||
MU_RUN_TEST(mu_test_furi_string_getters);
|
||||
MU_RUN_TEST(mu_test_furi_string_setters);
|
||||
MU_RUN_TEST(mu_test_furi_string_appends);
|
||||
MU_RUN_TEST(mu_test_furi_string_compare);
|
||||
MU_RUN_TEST(mu_test_furi_string_search);
|
||||
MU_RUN_TEST(mu_test_furi_string_equality);
|
||||
MU_RUN_TEST(mu_test_furi_string_replace);
|
||||
MU_RUN_TEST(mu_test_furi_string_start_end);
|
||||
MU_RUN_TEST(mu_test_furi_string_trim);
|
||||
MU_RUN_TEST(mu_test_furi_string_utf8);
|
||||
}
|
||||
|
||||
int run_minunit_test_furi_string() {
|
||||
MU_RUN_SUITE(test_suite);
|
||||
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
typedef struct {
|
||||
InfraredDecoderHandler* decoder_handler;
|
||||
InfraredEncoderHandler* encoder_handler;
|
||||
string_t file_path;
|
||||
FuriString* file_path;
|
||||
FlipperFormat* ff;
|
||||
} InfraredTest;
|
||||
|
||||
@@ -23,7 +23,7 @@ static void infrared_test_alloc() {
|
||||
test->decoder_handler = infrared_alloc_decoder();
|
||||
test->encoder_handler = infrared_alloc_encoder();
|
||||
test->ff = flipper_format_buffered_file_alloc(storage);
|
||||
string_init(test->file_path);
|
||||
test->file_path = furi_string_alloc();
|
||||
}
|
||||
|
||||
static void infrared_test_free() {
|
||||
@@ -31,18 +31,18 @@ static void infrared_test_free() {
|
||||
infrared_free_decoder(test->decoder_handler);
|
||||
infrared_free_encoder(test->encoder_handler);
|
||||
flipper_format_free(test->ff);
|
||||
string_clear(test->file_path);
|
||||
furi_string_free(test->file_path);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
free(test);
|
||||
test = NULL;
|
||||
}
|
||||
|
||||
static bool infrared_test_prepare_file(const char* protocol_name) {
|
||||
string_t file_type;
|
||||
string_init(file_type);
|
||||
FuriString* file_type;
|
||||
file_type = furi_string_alloc();
|
||||
bool success = false;
|
||||
|
||||
string_printf(
|
||||
furi_string_printf(
|
||||
test->file_path,
|
||||
"%s%s%s%s",
|
||||
IR_TEST_FILES_DIR,
|
||||
@@ -52,14 +52,15 @@ static bool infrared_test_prepare_file(const char* protocol_name) {
|
||||
|
||||
do {
|
||||
uint32_t format_version;
|
||||
if(!flipper_format_buffered_file_open_existing(test->ff, string_get_cstr(test->file_path)))
|
||||
if(!flipper_format_buffered_file_open_existing(
|
||||
test->ff, furi_string_get_cstr(test->file_path)))
|
||||
break;
|
||||
if(!flipper_format_read_header(test->ff, file_type, &format_version)) break;
|
||||
if(string_cmp_str(file_type, "IR tests file") || format_version != 1) break;
|
||||
if(furi_string_cmp_str(file_type, "IR tests file") || format_version != 1) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
string_clear(file_type);
|
||||
furi_string_free(file_type);
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -68,18 +69,18 @@ static bool infrared_test_load_raw_signal(
|
||||
const char* signal_name,
|
||||
uint32_t** timings,
|
||||
uint32_t* timings_count) {
|
||||
string_t buf;
|
||||
string_init(buf);
|
||||
FuriString* buf;
|
||||
buf = furi_string_alloc();
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
bool is_name_found = false;
|
||||
for(; !is_name_found && flipper_format_read_string(ff, "name", buf);
|
||||
is_name_found = !string_cmp_str(buf, signal_name))
|
||||
is_name_found = !furi_string_cmp(buf, signal_name))
|
||||
;
|
||||
|
||||
if(!is_name_found) break;
|
||||
if(!flipper_format_read_string(ff, "type", buf) || string_cmp_str(buf, "raw")) break;
|
||||
if(!flipper_format_read_string(ff, "type", buf) || furi_string_cmp_str(buf, "raw")) break;
|
||||
if(!flipper_format_get_value_count(ff, "data", timings_count)) break;
|
||||
if(!*timings_count) break;
|
||||
|
||||
@@ -91,18 +92,18 @@ static bool infrared_test_load_raw_signal(
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
string_clear(buf);
|
||||
furi_string_free(buf);
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool infrared_test_read_message(FlipperFormat* ff, InfraredMessage* message) {
|
||||
string_t buf;
|
||||
string_init(buf);
|
||||
FuriString* buf;
|
||||
buf = furi_string_alloc();
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!flipper_format_read_string(ff, "protocol", buf)) break;
|
||||
message->protocol = infrared_get_protocol_by_name(string_get_cstr(buf));
|
||||
message->protocol = infrared_get_protocol_by_name(furi_string_get_cstr(buf));
|
||||
if(!infrared_is_protocol_valid(message->protocol)) break;
|
||||
if(!flipper_format_read_hex(ff, "address", (uint8_t*)&message->address, sizeof(uint32_t)))
|
||||
break;
|
||||
@@ -112,7 +113,7 @@ static bool infrared_test_read_message(FlipperFormat* ff, InfraredMessage* messa
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
string_clear(buf);
|
||||
furi_string_free(buf);
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -121,18 +122,19 @@ static bool infrared_test_load_messages(
|
||||
const char* signal_name,
|
||||
InfraredMessage** messages,
|
||||
uint32_t* messages_count) {
|
||||
string_t buf;
|
||||
string_init(buf);
|
||||
FuriString* buf;
|
||||
buf = furi_string_alloc();
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
bool is_name_found = false;
|
||||
for(; !is_name_found && flipper_format_read_string(ff, "name", buf);
|
||||
is_name_found = !string_cmp_str(buf, signal_name))
|
||||
is_name_found = !furi_string_cmp(buf, signal_name))
|
||||
;
|
||||
|
||||
if(!is_name_found) break;
|
||||
if(!flipper_format_read_string(ff, "type", buf) || string_cmp_str(buf, "parsed_array"))
|
||||
if(!flipper_format_read_string(ff, "type", buf) ||
|
||||
furi_string_cmp_str(buf, "parsed_array"))
|
||||
break;
|
||||
if(!flipper_format_read_uint32(ff, "count", messages_count, 1)) break;
|
||||
if(!*messages_count) break;
|
||||
@@ -151,7 +153,7 @@ static bool infrared_test_load_messages(
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
string_clear(buf);
|
||||
furi_string_free(buf);
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -213,26 +215,26 @@ static void infrared_test_run_encoder(InfraredProtocol protocol, uint32_t test_i
|
||||
InfraredMessage* input_messages;
|
||||
uint32_t input_messages_count;
|
||||
|
||||
string_t buf;
|
||||
string_init(buf);
|
||||
FuriString* buf;
|
||||
buf = furi_string_alloc();
|
||||
|
||||
const char* protocol_name = infrared_get_protocol_name(protocol);
|
||||
mu_assert(infrared_test_prepare_file(protocol_name), "Failed to prepare test file");
|
||||
|
||||
string_printf(buf, "encoder_input%d", test_index);
|
||||
furi_string_printf(buf, "encoder_input%ld", test_index);
|
||||
mu_assert(
|
||||
infrared_test_load_messages(
|
||||
test->ff, string_get_cstr(buf), &input_messages, &input_messages_count),
|
||||
test->ff, furi_string_get_cstr(buf), &input_messages, &input_messages_count),
|
||||
"Failed to load messages from file");
|
||||
|
||||
string_printf(buf, "encoder_expected%d", test_index);
|
||||
furi_string_printf(buf, "encoder_expected%ld", test_index);
|
||||
mu_assert(
|
||||
infrared_test_load_raw_signal(
|
||||
test->ff, string_get_cstr(buf), &expected_timings, &expected_timings_count),
|
||||
test->ff, furi_string_get_cstr(buf), &expected_timings, &expected_timings_count),
|
||||
"Failed to load raw signal from file");
|
||||
|
||||
flipper_format_buffered_file_close(test->ff);
|
||||
string_clear(buf);
|
||||
furi_string_free(buf);
|
||||
|
||||
uint32_t j = 0;
|
||||
timings = malloc(sizeof(uint32_t) * timings_count);
|
||||
@@ -267,22 +269,22 @@ static void infrared_test_run_encoder_decoder(InfraredProtocol protocol, uint32_
|
||||
uint32_t input_messages_count;
|
||||
bool level = false;
|
||||
|
||||
string_t buf;
|
||||
string_init(buf);
|
||||
FuriString* buf;
|
||||
buf = furi_string_alloc();
|
||||
|
||||
timings = malloc(sizeof(uint32_t) * timings_count);
|
||||
|
||||
const char* protocol_name = infrared_get_protocol_name(protocol);
|
||||
mu_assert(infrared_test_prepare_file(protocol_name), "Failed to prepare test file");
|
||||
|
||||
string_printf(buf, "encoder_decoder_input%d", test_index);
|
||||
furi_string_printf(buf, "encoder_decoder_input%ld", test_index);
|
||||
mu_assert(
|
||||
infrared_test_load_messages(
|
||||
test->ff, string_get_cstr(buf), &input_messages, &input_messages_count),
|
||||
test->ff, furi_string_get_cstr(buf), &input_messages, &input_messages_count),
|
||||
"Failed to load messages from file");
|
||||
|
||||
flipper_format_buffered_file_close(test->ff);
|
||||
string_clear(buf);
|
||||
furi_string_free(buf);
|
||||
|
||||
for(uint32_t message_counter = 0; message_counter < input_messages_count; ++message_counter) {
|
||||
const InfraredMessage* message_encoded = &input_messages[message_counter];
|
||||
@@ -327,25 +329,27 @@ static void infrared_test_run_decoder(InfraredProtocol protocol, uint32_t test_i
|
||||
InfraredMessage* messages;
|
||||
uint32_t messages_count;
|
||||
|
||||
string_t buf;
|
||||
string_init(buf);
|
||||
FuriString* buf;
|
||||
buf = furi_string_alloc();
|
||||
|
||||
mu_assert(
|
||||
infrared_test_prepare_file(infrared_get_protocol_name(protocol)),
|
||||
"Failed to prepare test file");
|
||||
|
||||
string_printf(buf, "decoder_input%d", test_index);
|
||||
furi_string_printf(buf, "decoder_input%ld", test_index);
|
||||
mu_assert(
|
||||
infrared_test_load_raw_signal(test->ff, string_get_cstr(buf), &timings, &timings_count),
|
||||
infrared_test_load_raw_signal(
|
||||
test->ff, furi_string_get_cstr(buf), &timings, &timings_count),
|
||||
"Failed to load raw signal from file");
|
||||
|
||||
string_printf(buf, "decoder_expected%d", test_index);
|
||||
furi_string_printf(buf, "decoder_expected%ld", test_index);
|
||||
mu_assert(
|
||||
infrared_test_load_messages(test->ff, string_get_cstr(buf), &messages, &messages_count),
|
||||
infrared_test_load_messages(
|
||||
test->ff, furi_string_get_cstr(buf), &messages, &messages_count),
|
||||
"Failed to load messages from file");
|
||||
|
||||
flipper_format_buffered_file_close(test->ff);
|
||||
string_clear(buf);
|
||||
furi_string_free(buf);
|
||||
|
||||
InfraredMessage message_decoded_check_local;
|
||||
bool level = 0;
|
||||
|
||||
@@ -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>
|
||||
@@ -15,6 +16,7 @@
|
||||
#define NFC_TEST_RESOURCES_DIR EXT_PATH("unit_tests/nfc/")
|
||||
#define NFC_TEST_SIGNAL_SHORT_FILE "nfc_nfca_signal_short.nfc"
|
||||
#define NFC_TEST_SIGNAL_LONG_FILE "nfc_nfca_signal_long.nfc"
|
||||
#define NFC_TEST_DICT_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc")
|
||||
|
||||
static const char* nfc_test_file_type = "Flipper NFC test";
|
||||
static const uint32_t nfc_test_file_version = 1;
|
||||
@@ -52,14 +54,15 @@ static bool nfc_test_read_signal_from_file(const char* file_name) {
|
||||
bool success = false;
|
||||
|
||||
FlipperFormat* file = flipper_format_file_alloc(nfc_test->storage);
|
||||
string_t file_type;
|
||||
string_init(file_type);
|
||||
FuriString* file_type;
|
||||
file_type = furi_string_alloc();
|
||||
uint32_t file_version = 0;
|
||||
|
||||
do {
|
||||
if(!flipper_format_file_open_existing(file, file_name)) break;
|
||||
if(!flipper_format_read_header(file, file_type, &file_version)) break;
|
||||
if(string_cmp_str(file_type, nfc_test_file_type) || file_version != nfc_test_file_version)
|
||||
if(furi_string_cmp_str(file_type, nfc_test_file_type) ||
|
||||
file_version != nfc_test_file_version)
|
||||
break;
|
||||
if(!flipper_format_read_uint32(file, "Data length", &nfc_test->test_data_len, 1)) break;
|
||||
if(nfc_test->test_data_len > NFC_TEST_DATA_MAX_LEN) break;
|
||||
@@ -75,7 +78,7 @@ static bool nfc_test_read_signal_from_file(const char* file_name) {
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
string_clear(file_type);
|
||||
furi_string_free(file_type);
|
||||
flipper_format_free(file);
|
||||
|
||||
return success;
|
||||
@@ -110,7 +113,7 @@ static bool nfc_test_digital_signal_test_encode(
|
||||
// Check timings
|
||||
if(time > encode_max_time) {
|
||||
FURI_LOG_E(
|
||||
TAG, "Encoding time: %d us while accepted value: %d us", time, encode_max_time);
|
||||
TAG, "Encoding time: %ld us while accepted value: %ld us", time, encode_max_time);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -130,7 +133,7 @@ static bool nfc_test_digital_signal_test_encode(
|
||||
ref_timings_sum += ref[i];
|
||||
if(timings_diff > timing_tolerance) {
|
||||
FURI_LOG_E(
|
||||
TAG, "Too big differece in %d timings. Ref: %d, DUT: %d", i, ref[i], dut[i]);
|
||||
TAG, "Too big differece in %d timings. Ref: %ld, DUT: %ld", i, ref[i], dut[i]);
|
||||
timing_check_success = false;
|
||||
break;
|
||||
}
|
||||
@@ -141,16 +144,16 @@ static bool nfc_test_digital_signal_test_encode(
|
||||
if(sum_diff > timings_sum_tolerance) {
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"Too big difference in timings sum. Ref: %d, DUT: %d",
|
||||
"Too big difference in timings sum. Ref: %ld, DUT: %ld",
|
||||
ref_timings_sum,
|
||||
dut_timings_sum);
|
||||
break;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Encoding time: %d us. Acceptable time: %d us", time, encode_max_time);
|
||||
FURI_LOG_I(TAG, "Encoding time: %ld us. Acceptable time: %ld us", time, encode_max_time);
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"Timings sum difference: %d [1/64MHZ]. Acceptable difference: %d [1/64MHz]",
|
||||
"Timings sum difference: %ld [1/64MHZ]. Acceptable difference: %ld [1/64MHz]",
|
||||
sum_diff,
|
||||
timings_sum_tolerance);
|
||||
success = true;
|
||||
@@ -170,10 +173,126 @@ 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;
|
||||
FuriString* temp_str;
|
||||
temp_str = furi_string_alloc();
|
||||
|
||||
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");
|
||||
|
||||
furi_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(
|
||||
furi_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);
|
||||
furi_string_free(temp_str);
|
||||
}
|
||||
|
||||
MU_TEST(mf_classic_dict_load_test) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
mu_assert(storage != NULL, "storage != NULL assert failed\r\n");
|
||||
|
||||
// Delete unit test dict file if exists
|
||||
if(storage_file_exists(storage, NFC_TEST_DICT_PATH)) {
|
||||
mu_assert(
|
||||
storage_simply_remove(storage, NFC_TEST_DICT_PATH),
|
||||
"remove == true assert failed\r\n");
|
||||
}
|
||||
|
||||
// Create unit test dict file
|
||||
Stream* file_stream = file_stream_alloc(storage);
|
||||
mu_assert(file_stream != NULL, "file_stream != NULL assert failed\r\n");
|
||||
mu_assert(
|
||||
file_stream_open(file_stream, NFC_TEST_DICT_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS),
|
||||
"file_stream_open == true assert failed\r\n");
|
||||
|
||||
// Write unit test dict file
|
||||
char key_str[] = "a0a1a2a3a4a5";
|
||||
mu_assert(
|
||||
stream_write_cstring(file_stream, key_str) == strlen(key_str),
|
||||
"write == true assert failed\r\n");
|
||||
// Close unit test dict file
|
||||
mu_assert(file_stream_close(file_stream), "file_stream_close == true assert failed\r\n");
|
||||
|
||||
// Load unit test dict file
|
||||
MfClassicDict* instance = NULL;
|
||||
instance = mf_classic_dict_alloc(MfClassicDictTypeUnitTest);
|
||||
mu_assert(instance != NULL, "mf_classic_dict_alloc\r\n");
|
||||
uint32_t total_keys = mf_classic_dict_get_total_keys(instance);
|
||||
mu_assert(total_keys == 1, "total_keys == 1 assert failed\r\n");
|
||||
|
||||
// Read key
|
||||
uint64_t key_ref = 0xa0a1a2a3a4a5;
|
||||
uint64_t key_dut = 0;
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
mu_assert(
|
||||
mf_classic_dict_get_next_key_str(instance, temp_str),
|
||||
"get_next_key_str == true assert failed\r\n");
|
||||
mu_assert(furi_string_cmp_str(temp_str, key_str) == 0, "invalid key loaded\r\n");
|
||||
mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n");
|
||||
mu_assert(
|
||||
mf_classic_dict_get_next_key(instance, &key_dut),
|
||||
"get_next_key == true assert failed\r\n");
|
||||
mu_assert(key_dut == key_ref, "invalid key loaded\r\n");
|
||||
furi_string_free(temp_str);
|
||||
mf_classic_dict_free(instance);
|
||||
|
||||
// Check that MfClassicDict added new line to the end of the file
|
||||
mu_assert(
|
||||
file_stream_open(file_stream, NFC_TEST_DICT_PATH, FSAM_READ, FSOM_OPEN_EXISTING),
|
||||
"file_stream_open == true assert failed\r\n");
|
||||
mu_assert(stream_seek(file_stream, -1, StreamOffsetFromEnd), "seek == true assert failed\r\n");
|
||||
uint8_t last_char = 0;
|
||||
mu_assert(stream_read(file_stream, &last_char, 1) == 1, "read == true assert failed\r\n");
|
||||
mu_assert(last_char == '\n', "last_char == '\\n' assert failed\r\n");
|
||||
mu_assert(file_stream_close(file_stream), "file_stream_close == true assert failed\r\n");
|
||||
|
||||
// Delete unit test dict file
|
||||
mu_assert(
|
||||
storage_simply_remove(storage, NFC_TEST_DICT_PATH), "remove == true assert failed\r\n");
|
||||
stream_free(file_stream);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(nfc) {
|
||||
nfc_test_alloc();
|
||||
|
||||
MU_RUN_TEST(nfc_digital_signal_test);
|
||||
MU_RUN_TEST(mf_classic_dict_test);
|
||||
MU_RUN_TEST(mf_classic_dict_load_test);
|
||||
|
||||
nfc_test_free();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <furi.h>
|
||||
#include "../minunit.h"
|
||||
#include <stdint.h>
|
||||
#include <stream_buffer.h>
|
||||
#include <pb.h>
|
||||
#include <pb_encode.h>
|
||||
#include <m-list.h>
|
||||
@@ -34,7 +33,7 @@ static uint32_t command_id = 0;
|
||||
|
||||
typedef struct {
|
||||
RpcSession* session;
|
||||
StreamBufferHandle_t output_stream;
|
||||
FuriStreamBuffer* output_stream;
|
||||
SemaphoreHandle_t close_session_semaphore;
|
||||
SemaphoreHandle_t terminate_semaphore;
|
||||
TickType_t timeout;
|
||||
@@ -90,7 +89,7 @@ static void test_rpc_setup(void) {
|
||||
}
|
||||
furi_check(rpc_session[0].session);
|
||||
|
||||
rpc_session[0].output_stream = xStreamBufferCreate(1000, 1);
|
||||
rpc_session[0].output_stream = furi_stream_buffer_alloc(1000, 1);
|
||||
rpc_session_set_send_bytes_callback(rpc_session[0].session, output_bytes_callback);
|
||||
rpc_session[0].close_session_semaphore = xSemaphoreCreateBinary();
|
||||
rpc_session[0].terminate_semaphore = xSemaphoreCreateBinary();
|
||||
@@ -110,7 +109,7 @@ static void test_rpc_setup_second_session(void) {
|
||||
}
|
||||
furi_check(rpc_session[1].session);
|
||||
|
||||
rpc_session[1].output_stream = xStreamBufferCreate(1000, 1);
|
||||
rpc_session[1].output_stream = furi_stream_buffer_alloc(1000, 1);
|
||||
rpc_session_set_send_bytes_callback(rpc_session[1].session, output_bytes_callback);
|
||||
rpc_session[1].close_session_semaphore = xSemaphoreCreateBinary();
|
||||
rpc_session[1].terminate_semaphore = xSemaphoreCreateBinary();
|
||||
@@ -126,7 +125,7 @@ static void test_rpc_teardown(void) {
|
||||
rpc_session_close(rpc_session[0].session);
|
||||
furi_check(xSemaphoreTake(rpc_session[0].terminate_semaphore, portMAX_DELAY));
|
||||
furi_record_close(RECORD_RPC);
|
||||
vStreamBufferDelete(rpc_session[0].output_stream);
|
||||
furi_stream_buffer_free(rpc_session[0].output_stream);
|
||||
vSemaphoreDelete(rpc_session[0].close_session_semaphore);
|
||||
vSemaphoreDelete(rpc_session[0].terminate_semaphore);
|
||||
++command_id;
|
||||
@@ -141,7 +140,7 @@ static void test_rpc_teardown_second_session(void) {
|
||||
xSemaphoreTake(rpc_session[1].terminate_semaphore, 0);
|
||||
rpc_session_close(rpc_session[1].session);
|
||||
furi_check(xSemaphoreTake(rpc_session[1].terminate_semaphore, portMAX_DELAY));
|
||||
vStreamBufferDelete(rpc_session[1].output_stream);
|
||||
furi_stream_buffer_free(rpc_session[1].output_stream);
|
||||
vSemaphoreDelete(rpc_session[1].close_session_semaphore);
|
||||
vSemaphoreDelete(rpc_session[1].terminate_semaphore);
|
||||
++command_id;
|
||||
@@ -268,8 +267,8 @@ static PB_CommandStatus test_rpc_storage_get_file_error(File* file) {
|
||||
static void output_bytes_callback(void* ctx, uint8_t* got_bytes, size_t got_size) {
|
||||
RpcSessionContext* callbacks_context = ctx;
|
||||
|
||||
size_t bytes_sent =
|
||||
xStreamBufferSend(callbacks_context->output_stream, got_bytes, got_size, FuriWaitForever);
|
||||
size_t bytes_sent = furi_stream_buffer_send(
|
||||
callbacks_context->output_stream, got_bytes, got_size, FuriWaitForever);
|
||||
(void)bytes_sent;
|
||||
furi_check(bytes_sent == got_size);
|
||||
}
|
||||
@@ -534,7 +533,8 @@ static bool test_rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_
|
||||
TickType_t now = xTaskGetTickCount();
|
||||
int32_t time_left = session_context->timeout - now;
|
||||
time_left = MAX(time_left, 0);
|
||||
bytes_received = xStreamBufferReceive(session_context->output_stream, buf, count, time_left);
|
||||
bytes_received =
|
||||
furi_stream_buffer_receive(session_context->output_stream, buf, count, time_left);
|
||||
return (count == bytes_received);
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ typedef struct {
|
||||
bool visited;
|
||||
} StorageTestPath;
|
||||
|
||||
DICT_DEF2(StorageTestPathDict, string_t, STRING_OPLIST, StorageTestPath, M_POD_OPLIST)
|
||||
DICT_DEF2(StorageTestPathDict, FuriString*, FURI_STRING_OPLIST, StorageTestPath, M_POD_OPLIST)
|
||||
|
||||
static StorageTestPathDict_t*
|
||||
storage_test_paths_alloc(const StorageTestPathDesc paths[], size_t paths_count) {
|
||||
@@ -83,15 +83,15 @@ static StorageTestPathDict_t*
|
||||
StorageTestPathDict_init(*data);
|
||||
|
||||
for(size_t i = 0; i < paths_count; i++) {
|
||||
string_t key;
|
||||
string_init_set(key, paths[i].path);
|
||||
FuriString* key;
|
||||
key = furi_string_alloc_set(paths[i].path);
|
||||
StorageTestPath value = {
|
||||
.is_dir = paths[i].is_dir,
|
||||
.visited = false,
|
||||
};
|
||||
|
||||
StorageTestPathDict_set_at(*data, key, value);
|
||||
string_clear(key);
|
||||
furi_string_free(key);
|
||||
}
|
||||
|
||||
return data;
|
||||
@@ -102,7 +102,7 @@ static void storage_test_paths_free(StorageTestPathDict_t* data) {
|
||||
free(data);
|
||||
}
|
||||
|
||||
static bool storage_test_paths_mark(StorageTestPathDict_t* data, string_t path, bool is_dir) {
|
||||
static bool storage_test_paths_mark(StorageTestPathDict_t* data, FuriString* path, bool is_dir) {
|
||||
bool found = false;
|
||||
|
||||
StorageTestPath* record = StorageTestPathDict_get(*data, path);
|
||||
@@ -148,27 +148,27 @@ static bool write_file_13DA(Storage* storage, const char* path) {
|
||||
}
|
||||
|
||||
static void storage_dirs_create(Storage* storage, const char* base) {
|
||||
string_t path;
|
||||
string_init(path);
|
||||
FuriString* path;
|
||||
path = furi_string_alloc();
|
||||
|
||||
storage_common_mkdir(storage, base);
|
||||
|
||||
for(size_t i = 0; i < COUNT_OF(storage_test_dirwalk_paths); i++) {
|
||||
string_printf(path, "%s/%s", base, storage_test_dirwalk_paths[i]);
|
||||
storage_common_mkdir(storage, string_get_cstr(path));
|
||||
furi_string_printf(path, "%s/%s", base, storage_test_dirwalk_paths[i]);
|
||||
storage_common_mkdir(storage, furi_string_get_cstr(path));
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < COUNT_OF(storage_test_dirwalk_files); i++) {
|
||||
string_printf(path, "%s/%s", base, storage_test_dirwalk_files[i]);
|
||||
write_file_13DA(storage, string_get_cstr(path));
|
||||
furi_string_printf(path, "%s/%s", base, storage_test_dirwalk_files[i]);
|
||||
write_file_13DA(storage, furi_string_get_cstr(path));
|
||||
}
|
||||
|
||||
string_clear(path);
|
||||
furi_string_free(path);
|
||||
}
|
||||
|
||||
MU_TEST_1(test_dirwalk_full, Storage* storage) {
|
||||
string_t path;
|
||||
string_init(path);
|
||||
FuriString* path;
|
||||
path = furi_string_alloc();
|
||||
FileInfo fileinfo;
|
||||
|
||||
StorageTestPathDict_t* paths =
|
||||
@@ -178,12 +178,12 @@ MU_TEST_1(test_dirwalk_full, Storage* storage) {
|
||||
mu_check(dir_walk_open(dir_walk, EXT_PATH("dirwalk")));
|
||||
|
||||
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
|
||||
string_right(path, strlen(EXT_PATH("dirwalk/")));
|
||||
furi_string_right(path, strlen(EXT_PATH("dirwalk/")));
|
||||
mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY)));
|
||||
}
|
||||
|
||||
dir_walk_free(dir_walk);
|
||||
string_clear(path);
|
||||
furi_string_free(path);
|
||||
|
||||
mu_check(storage_test_paths_check(paths) == false);
|
||||
|
||||
@@ -191,8 +191,8 @@ MU_TEST_1(test_dirwalk_full, Storage* storage) {
|
||||
}
|
||||
|
||||
MU_TEST_1(test_dirwalk_no_recursive, Storage* storage) {
|
||||
string_t path;
|
||||
string_init(path);
|
||||
FuriString* path;
|
||||
path = furi_string_alloc();
|
||||
FileInfo fileinfo;
|
||||
|
||||
StorageTestPathDict_t* paths = storage_test_paths_alloc(
|
||||
@@ -203,12 +203,12 @@ MU_TEST_1(test_dirwalk_no_recursive, Storage* storage) {
|
||||
mu_check(dir_walk_open(dir_walk, EXT_PATH("dirwalk")));
|
||||
|
||||
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
|
||||
string_right(path, strlen(EXT_PATH("dirwalk/")));
|
||||
furi_string_right(path, strlen(EXT_PATH("dirwalk/")));
|
||||
mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY)));
|
||||
}
|
||||
|
||||
dir_walk_free(dir_walk);
|
||||
string_clear(path);
|
||||
furi_string_free(path);
|
||||
|
||||
mu_check(storage_test_paths_check(paths) == false);
|
||||
|
||||
@@ -230,8 +230,8 @@ static bool test_dirwalk_filter_no_folder_ext(const char* name, FileInfo* filein
|
||||
}
|
||||
|
||||
MU_TEST_1(test_dirwalk_filter, Storage* storage) {
|
||||
string_t path;
|
||||
string_init(path);
|
||||
FuriString* path;
|
||||
path = furi_string_alloc();
|
||||
FileInfo fileinfo;
|
||||
|
||||
StorageTestPathDict_t* paths = storage_test_paths_alloc(
|
||||
@@ -242,12 +242,12 @@ MU_TEST_1(test_dirwalk_filter, Storage* storage) {
|
||||
mu_check(dir_walk_open(dir_walk, EXT_PATH("dirwalk")));
|
||||
|
||||
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
|
||||
string_right(path, strlen(EXT_PATH("dirwalk/")));
|
||||
furi_string_right(path, strlen(EXT_PATH("dirwalk/")));
|
||||
mu_check(storage_test_paths_mark(paths, path, (fileinfo.flags & FSF_DIRECTORY)));
|
||||
}
|
||||
|
||||
dir_walk_free(dir_walk);
|
||||
string_clear(path);
|
||||
furi_string_free(path);
|
||||
|
||||
mu_check(storage_test_paths_check(paths) == false);
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ MU_TEST(storage_file_open_lock) {
|
||||
storage_file_close(file);
|
||||
|
||||
// file_locker thread stop
|
||||
mu_check(furi_thread_join(locker_thread) == FuriStatusOk);
|
||||
mu_check(furi_thread_join(locker_thread));
|
||||
furi_thread_free(locker_thread);
|
||||
|
||||
// clean data
|
||||
@@ -148,7 +148,7 @@ MU_TEST(storage_dir_open_lock) {
|
||||
storage_dir_close(file);
|
||||
|
||||
// file_locker thread stop
|
||||
mu_check(furi_thread_join(locker_thread) == FuriStatusOk);
|
||||
mu_check(furi_thread_join(locker_thread));
|
||||
furi_thread_free(locker_thread);
|
||||
|
||||
// clean data
|
||||
@@ -211,22 +211,22 @@ static bool check_file_13DA(Storage* storage, const char* path) {
|
||||
}
|
||||
|
||||
static void storage_dir_create(Storage* storage, const char* base) {
|
||||
string_t path;
|
||||
string_init(path);
|
||||
FuriString* path;
|
||||
path = furi_string_alloc();
|
||||
|
||||
storage_common_mkdir(storage, base);
|
||||
|
||||
for(size_t i = 0; i < COUNT_OF(storage_copy_test_paths); i++) {
|
||||
string_printf(path, "%s/%s", base, storage_copy_test_paths[i]);
|
||||
storage_common_mkdir(storage, string_get_cstr(path));
|
||||
furi_string_printf(path, "%s/%s", base, storage_copy_test_paths[i]);
|
||||
storage_common_mkdir(storage, furi_string_get_cstr(path));
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < COUNT_OF(storage_copy_test_files); i++) {
|
||||
string_printf(path, "%s/%s", base, storage_copy_test_files[i]);
|
||||
write_file_13DA(storage, string_get_cstr(path));
|
||||
furi_string_printf(path, "%s/%s", base, storage_copy_test_files[i]);
|
||||
write_file_13DA(storage, furi_string_get_cstr(path));
|
||||
}
|
||||
|
||||
string_clear(path);
|
||||
furi_string_free(path);
|
||||
}
|
||||
|
||||
static void storage_dir_remove(Storage* storage, const char* base) {
|
||||
@@ -235,15 +235,15 @@ static void storage_dir_remove(Storage* storage, const char* base) {
|
||||
|
||||
static bool storage_dir_rename_check(Storage* storage, const char* base) {
|
||||
bool result = false;
|
||||
string_t path;
|
||||
string_init(path);
|
||||
FuriString* path;
|
||||
path = furi_string_alloc();
|
||||
|
||||
result = (storage_common_stat(storage, base, NULL) == FSE_OK);
|
||||
|
||||
if(result) {
|
||||
for(size_t i = 0; i < COUNT_OF(storage_copy_test_paths); i++) {
|
||||
string_printf(path, "%s/%s", base, storage_copy_test_paths[i]);
|
||||
result = (storage_common_stat(storage, string_get_cstr(path), NULL) == FSE_OK);
|
||||
furi_string_printf(path, "%s/%s", base, storage_copy_test_paths[i]);
|
||||
result = (storage_common_stat(storage, furi_string_get_cstr(path), NULL) == FSE_OK);
|
||||
if(!result) {
|
||||
break;
|
||||
}
|
||||
@@ -252,15 +252,15 @@ static bool storage_dir_rename_check(Storage* storage, const char* base) {
|
||||
|
||||
if(result) {
|
||||
for(size_t i = 0; i < COUNT_OF(storage_copy_test_files); i++) {
|
||||
string_printf(path, "%s/%s", base, storage_copy_test_files[i]);
|
||||
result = check_file_13DA(storage, string_get_cstr(path));
|
||||
furi_string_printf(path, "%s/%s", base, storage_copy_test_files[i]);
|
||||
result = check_file_13DA(storage, furi_string_get_cstr(path));
|
||||
if(!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string_clear(path);
|
||||
furi_string_free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ static const char* stream_test_right_data =
|
||||
MU_TEST_1(stream_composite_subtest, Stream* stream) {
|
||||
const size_t data_size = 128;
|
||||
uint8_t data[data_size];
|
||||
string_t string_lee;
|
||||
string_init_set(string_lee, "lee");
|
||||
FuriString* string_lee;
|
||||
string_lee = furi_string_alloc_set("lee");
|
||||
|
||||
// test that stream is empty
|
||||
// "" -> ""
|
||||
@@ -267,7 +267,7 @@ MU_TEST_1(stream_composite_subtest, Stream* stream) {
|
||||
mu_assert_int_eq(9, stream_tell(stream));
|
||||
mu_check(stream_eof(stream));
|
||||
|
||||
string_clear(string_lee);
|
||||
furi_string_free(string_lee);
|
||||
}
|
||||
|
||||
MU_TEST(stream_composite_test) {
|
||||
@@ -416,10 +416,10 @@ MU_TEST(stream_buffered_write_after_read_test) {
|
||||
}
|
||||
|
||||
MU_TEST(stream_buffered_large_file_test) {
|
||||
string_t input_data;
|
||||
string_t output_data;
|
||||
string_init(input_data);
|
||||
string_init(output_data);
|
||||
FuriString* input_data;
|
||||
FuriString* output_data;
|
||||
input_data = furi_string_alloc();
|
||||
output_data = furi_string_alloc();
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
@@ -429,7 +429,7 @@ MU_TEST(stream_buffered_large_file_test) {
|
||||
const size_t rep_count = data_size / line_size + 1;
|
||||
|
||||
for(size_t i = 0; i < rep_count; ++i) {
|
||||
string_cat_printf(input_data, "%s\n", stream_test_data);
|
||||
furi_string_cat_printf(input_data, "%s\n", stream_test_data);
|
||||
}
|
||||
|
||||
// write test data to file
|
||||
@@ -437,8 +437,8 @@ MU_TEST(stream_buffered_large_file_test) {
|
||||
mu_check(buffered_file_stream_open(
|
||||
stream, EXT_PATH("filestream.str"), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS));
|
||||
mu_assert_int_eq(0, stream_size(stream));
|
||||
mu_assert_int_eq(string_size(input_data), stream_write_string(stream, input_data));
|
||||
mu_assert_int_eq(string_size(input_data), stream_size(stream));
|
||||
mu_assert_int_eq(furi_string_size(input_data), stream_write_string(stream, input_data));
|
||||
mu_assert_int_eq(furi_string_size(input_data), stream_size(stream));
|
||||
|
||||
const size_t substr_start = 8;
|
||||
const size_t substr_len = 11;
|
||||
@@ -475,23 +475,23 @@ MU_TEST(stream_buffered_large_file_test) {
|
||||
|
||||
// read the whole file
|
||||
mu_check(stream_rewind(stream));
|
||||
string_t tmp;
|
||||
string_init(tmp);
|
||||
FuriString* tmp;
|
||||
tmp = furi_string_alloc();
|
||||
while(stream_read_line(stream, tmp)) {
|
||||
string_cat(output_data, tmp);
|
||||
furi_string_cat(output_data, tmp);
|
||||
}
|
||||
string_clear(tmp);
|
||||
furi_string_free(tmp);
|
||||
|
||||
// check against generated data
|
||||
mu_assert_int_eq(string_size(input_data), string_size(output_data));
|
||||
mu_check(string_equal_p(input_data, output_data));
|
||||
mu_assert_int_eq(furi_string_size(input_data), furi_string_size(output_data));
|
||||
mu_check(furi_string_equal(input_data, output_data));
|
||||
mu_check(stream_eof(stream));
|
||||
|
||||
stream_free(stream);
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
string_clear(input_data);
|
||||
string_clear(output_data);
|
||||
furi_string_free(input_data);
|
||||
furi_string_free(output_data);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(stream_suite) {
|
||||
|
||||
@@ -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;
|
||||
@@ -28,12 +28,12 @@ static void subghz_test_rx_callback(
|
||||
void* context) {
|
||||
UNUSED(receiver);
|
||||
UNUSED(context);
|
||||
string_t text;
|
||||
string_init(text);
|
||||
FuriString* text;
|
||||
text = furi_string_alloc();
|
||||
subghz_protocol_decoder_base_get_string(decoder_base, text);
|
||||
subghz_receiver_reset(receiver_handler);
|
||||
FURI_LOG_T(TAG, "\r\n%s", string_get_cstr(text));
|
||||
string_clear(text);
|
||||
FURI_LOG_T(TAG, "\r\n%s", furi_string_get_cstr(text));
|
||||
furi_string_free(text);
|
||||
subghz_test_decoder_count++;
|
||||
}
|
||||
|
||||
@@ -141,8 +141,8 @@ static bool subghz_decode_random_test(const char* path) {
|
||||
static bool subghz_encoder_test(const char* path) {
|
||||
subghz_test_decoder_count = 0;
|
||||
uint32_t test_start = furi_get_tick();
|
||||
string_t temp_str;
|
||||
string_init(temp_str);
|
||||
FuriString* temp_str;
|
||||
temp_str = furi_string_alloc();
|
||||
bool file_load = false;
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
@@ -167,11 +167,11 @@ static bool subghz_encoder_test(const char* path) {
|
||||
} while(false);
|
||||
if(file_load) {
|
||||
SubGhzTransmitter* transmitter =
|
||||
subghz_transmitter_alloc_init(environment_handler, string_get_cstr(temp_str));
|
||||
subghz_transmitter_alloc_init(environment_handler, furi_string_get_cstr(temp_str));
|
||||
subghz_transmitter_deserialize(transmitter, fff_data_file);
|
||||
|
||||
SubGhzProtocolDecoderBase* decoder = subghz_receiver_search_decoder_base_by_name(
|
||||
receiver_handler, string_get_cstr(temp_str));
|
||||
receiver_handler, furi_string_get_cstr(temp_str));
|
||||
|
||||
if(decoder) {
|
||||
LevelDuration level_duration;
|
||||
@@ -192,10 +192,11 @@ static bool subghz_encoder_test(const char* path) {
|
||||
flipper_format_free(fff_data_file);
|
||||
FURI_LOG_T(TAG, "\r\n Decoder count parse \033[0;33m%d\033[0m ", subghz_test_decoder_count);
|
||||
if(furi_get_tick() - test_start > TEST_TIMEOUT) {
|
||||
printf("\033[0;31mTest encoder %s ERROR TimeOut\033[0m\r\n", string_get_cstr(temp_str));
|
||||
printf(
|
||||
"\033[0;31mTest encoder %s ERROR TimeOut\033[0m\r\n", furi_string_get_cstr(temp_str));
|
||||
subghz_test_decoder_count = 0;
|
||||
}
|
||||
string_clear(temp_str);
|
||||
furi_string_free(temp_str);
|
||||
|
||||
return subghz_test_decoder_count ? true : false;
|
||||
}
|
||||
@@ -434,6 +435,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 +603,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,5 +1,3 @@
|
||||
#include "m-string.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
@@ -11,6 +9,7 @@
|
||||
#define TAG "UnitTests"
|
||||
|
||||
int run_minunit_test_furi();
|
||||
int run_minunit_test_furi_string();
|
||||
int run_minunit_test_infrared();
|
||||
int run_minunit_test_rpc();
|
||||
int run_minunit_test_flipper_format();
|
||||
@@ -33,6 +32,7 @@ typedef struct {
|
||||
|
||||
const UnitTest unit_tests[] = {
|
||||
{.name = "furi", .entry = run_minunit_test_furi},
|
||||
{.name = "furi_string", .entry = run_minunit_test_furi_string},
|
||||
{.name = "storage", .entry = run_minunit_test_storage},
|
||||
{.name = "stream", .entry = run_minunit_test_stream},
|
||||
{.name = "dirwalk", .entry = run_minunit_test_dirwalk},
|
||||
@@ -63,7 +63,7 @@ void minunit_print_fail(const char* str) {
|
||||
printf(FURI_LOG_CLR_E "%s\r\n" FURI_LOG_CLR_RESET, str);
|
||||
}
|
||||
|
||||
void unit_tests_cli(Cli* cli, string_t args, void* context) {
|
||||
void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(cli);
|
||||
UNUSED(args);
|
||||
UNUSED(context);
|
||||
@@ -91,8 +91,8 @@ void unit_tests_cli(Cli* cli, string_t args, void* context) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(string_size(args)) {
|
||||
if(string_cmp_str(args, unit_tests[i].name) == 0) {
|
||||
if(furi_string_size(args)) {
|
||||
if(furi_string_cmp_str(args, unit_tests[i].name) == 0) {
|
||||
failed_tests += unit_tests[i].entry();
|
||||
} else {
|
||||
printf("Skipping %s\r\n", unit_tests[i].name);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
App(
|
||||
appid="usb_mouse",
|
||||
appid="USB_Mouse",
|
||||
name="USB Mouse",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="usb_mouse_app",
|
||||
cdefines=["APP_USB_MOUSE"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=60,
|
||||
fap_icon="../../plugins/mousejacker/mouse_10px.png",
|
||||
fap_category="Misc",
|
||||
fap_category="Debug",
|
||||
)
|
||||
|
||||
5
applications/examples/application.fam
Normal file
5
applications/examples/application.fam
Normal file
@@ -0,0 +1,5 @@
|
||||
App(
|
||||
appid="sample_apps",
|
||||
name="Sample apps bundle",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
)
|
||||
10
applications/examples/example_images/application.fam
Normal file
10
applications/examples/example_images/application.fam
Normal file
@@ -0,0 +1,10 @@
|
||||
App(
|
||||
appid="example_images",
|
||||
name="Example: Images",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="example_images_main",
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
fap_category="Examples",
|
||||
fap_icon_assets="images",
|
||||
)
|
||||
81
applications/examples/example_images/example_images.c
Normal file
81
applications/examples/example_images/example_images.c
Normal file
@@ -0,0 +1,81 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
|
||||
/* Magic happens here -- this file is generated by fbt.
|
||||
* Just set fap_icon_assets in application.fam and #include {APPID}_icons.h */
|
||||
#include "example_images_icons.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t x, y;
|
||||
} ImagePosition;
|
||||
|
||||
static ImagePosition image_position = {.x = 0, .y = 0};
|
||||
|
||||
// Screen is 128x64 px
|
||||
static void app_draw_callback(Canvas* canvas, void* ctx) {
|
||||
UNUSED(ctx);
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_draw_icon(canvas, image_position.x % 128, image_position.y % 64, &I_dolphin_71x25);
|
||||
}
|
||||
|
||||
static void app_input_callback(InputEvent* input_event, void* ctx) {
|
||||
furi_assert(ctx);
|
||||
|
||||
FuriMessageQueue* event_queue = ctx;
|
||||
furi_message_queue_put(event_queue, input_event, FuriWaitForever);
|
||||
}
|
||||
|
||||
int32_t example_images_main(void* p) {
|
||||
UNUSED(p);
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
|
||||
|
||||
// Configure view port
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, app_draw_callback, view_port);
|
||||
view_port_input_callback_set(view_port, app_input_callback, event_queue);
|
||||
|
||||
// Register view port in GUI
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
InputEvent event;
|
||||
|
||||
bool running = true;
|
||||
while(running) {
|
||||
if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
|
||||
if((event.type == InputTypePress) || (event.type == InputTypeRepeat)) {
|
||||
switch(event.key) {
|
||||
case InputKeyLeft:
|
||||
image_position.x -= 2;
|
||||
break;
|
||||
case InputKeyRight:
|
||||
image_position.x += 2;
|
||||
break;
|
||||
case InputKeyUp:
|
||||
image_position.y -= 2;
|
||||
break;
|
||||
case InputKeyDown:
|
||||
image_position.y += 2;
|
||||
break;
|
||||
default:
|
||||
running = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
view_port_update(view_port);
|
||||
}
|
||||
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
furi_message_queue_free(event_queue);
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
applications/examples/example_images/images/dolphin_71x25.png
Normal file
BIN
applications/examples/example_images/images/dolphin_71x25.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -21,7 +21,7 @@ static void archive_tick_event_callback(void* context) {
|
||||
static ArchiveApp* archive_alloc() {
|
||||
ArchiveApp* archive = malloc(sizeof(ArchiveApp));
|
||||
|
||||
string_init(archive->fav_move_str);
|
||||
archive->fav_move_str = furi_string_alloc();
|
||||
|
||||
archive->scene_manager = scene_manager_alloc(&archive_scene_handlers, archive);
|
||||
archive->view_dispatcher = view_dispatcher_alloc();
|
||||
@@ -81,7 +81,7 @@ void archive_free(ArchiveApp* archive) {
|
||||
scene_manager_free(archive->scene_manager);
|
||||
|
||||
browser_free(archive->browser);
|
||||
string_clear(archive->fav_move_str);
|
||||
furi_string_free(archive->fav_move_str);
|
||||
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
archive->dialogs = NULL;
|
||||
|
||||
@@ -36,7 +36,7 @@ struct ArchiveApp {
|
||||
Loading* loading;
|
||||
FuriPubSubSubscription* loader_stop_subscription;
|
||||
|
||||
string_t fav_move_str;
|
||||
FuriString* fav_move_str;
|
||||
char text_store[MAX_NAME_LEN];
|
||||
char file_extension[MAX_EXT_LEN + 1];
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <core/common_defines.h>
|
||||
#include <core/log.h>
|
||||
#include "gui/modules/file_browser_worker.h"
|
||||
#include "m-string.h"
|
||||
#include <fap_loader/fap_loader_app.h>
|
||||
#include <math.h>
|
||||
|
||||
static void
|
||||
@@ -19,9 +19,11 @@ static void
|
||||
|
||||
if((item_cnt == 0) && (archive_is_home(browser)) && (tab != ArchiveTabBrowser)) {
|
||||
archive_switch_tab(browser, browser->last_tab_switch_dir);
|
||||
} else if(!string_start_with_str_p(browser->path, "/app:")) {
|
||||
} else if(!furi_string_start_with_str(browser->path, "/app:")) {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
files_array_reset(model->files);
|
||||
model->item_cnt = item_cnt;
|
||||
model->item_idx = (file_idx > 0) ? file_idx : 0;
|
||||
@@ -31,8 +33,8 @@ static void
|
||||
model->list_offset = 0;
|
||||
model->list_loading = true;
|
||||
model->folder_loading = false;
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
archive_update_offset(browser);
|
||||
|
||||
file_browser_worker_load(browser->worker, load_offset, FILE_LIST_BUF_LEN);
|
||||
@@ -44,25 +46,25 @@ static void archive_list_load_cb(void* context, uint32_t list_load_offset) {
|
||||
ArchiveBrowserView* browser = (ArchiveBrowserView*)context;
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
files_array_reset(model->files);
|
||||
model->array_offset = list_load_offset;
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
}
|
||||
|
||||
static void archive_list_item_cb(void* context, string_t item_path, bool is_folder, bool is_last) {
|
||||
static void
|
||||
archive_list_item_cb(void* context, FuriString* item_path, bool is_folder, bool is_last) {
|
||||
furi_assert(context);
|
||||
ArchiveBrowserView* browser = (ArchiveBrowserView*)context;
|
||||
|
||||
if(!is_last) {
|
||||
archive_add_file_item(browser, is_folder, string_get_cstr(item_path));
|
||||
archive_add_file_item(browser, is_folder, furi_string_get_cstr(item_path));
|
||||
} else {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
model->list_loading = false;
|
||||
return true;
|
||||
});
|
||||
browser->view, ArchiveBrowserViewModel * model, { model->list_loading = false; }, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,15 +73,12 @@ static void archive_long_load_cb(void* context) {
|
||||
ArchiveBrowserView* browser = (ArchiveBrowserView*)context;
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
model->folder_loading = true;
|
||||
return true;
|
||||
});
|
||||
browser->view, ArchiveBrowserViewModel * model, { model->folder_loading = true; }, true);
|
||||
}
|
||||
|
||||
static void archive_file_browser_set_path(
|
||||
ArchiveBrowserView* browser,
|
||||
string_t path,
|
||||
FuriString* path,
|
||||
const char* filter_ext,
|
||||
bool skip_assets) {
|
||||
furi_assert(browser);
|
||||
@@ -112,7 +111,9 @@ void archive_update_offset(ArchiveBrowserView* browser) {
|
||||
furi_assert(browser);
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
uint16_t bounds = model->item_cnt > 3 ? 2 : model->item_cnt;
|
||||
|
||||
if((model->item_cnt > 3u) && (model->item_idx >= ((int32_t)model->item_cnt - 1))) {
|
||||
@@ -124,33 +125,34 @@ void archive_update_offset(ArchiveBrowserView* browser) {
|
||||
model->list_offset =
|
||||
CLAMP(model->item_idx - 1, (int32_t)model->item_cnt - bounds, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void archive_update_focus(ArchiveBrowserView* browser, const char* target) {
|
||||
furi_assert(browser);
|
||||
furi_assert(target);
|
||||
|
||||
archive_get_items(browser, string_get_cstr(browser->path));
|
||||
archive_get_items(browser, furi_string_get_cstr(browser->path));
|
||||
|
||||
if(!archive_file_get_array_size(browser) && archive_is_home(browser)) {
|
||||
archive_switch_tab(browser, TAB_RIGHT);
|
||||
} else {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
uint16_t idx = 0;
|
||||
while(idx < files_array_size(model->files)) {
|
||||
ArchiveFile_t* current = files_array_get(model->files, idx);
|
||||
if(!string_search(current->path, target)) {
|
||||
if(!furi_string_search(current->path, target)) {
|
||||
model->item_idx = idx + model->array_offset;
|
||||
break;
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
|
||||
archive_update_offset(browser);
|
||||
}
|
||||
@@ -161,10 +163,10 @@ size_t archive_file_get_array_size(ArchiveBrowserView* browser) {
|
||||
|
||||
uint16_t size = 0;
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
size = files_array_size(model->files);
|
||||
return false;
|
||||
});
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{ size = files_array_size(model->files); },
|
||||
false);
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -172,11 +174,13 @@ void archive_set_item_count(ArchiveBrowserView* browser, uint32_t count) {
|
||||
furi_assert(browser);
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
model->item_cnt = count;
|
||||
model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
archive_update_offset(browser);
|
||||
}
|
||||
|
||||
@@ -185,7 +189,9 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) {
|
||||
uint32_t items_cnt = 0;
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
files_array_remove_v(
|
||||
model->files,
|
||||
model->item_idx - model->array_offset,
|
||||
@@ -193,8 +199,8 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) {
|
||||
model->item_cnt--;
|
||||
model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0);
|
||||
items_cnt = model->item_cnt;
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
|
||||
if((items_cnt == 0) && (archive_is_home(browser))) {
|
||||
archive_switch_tab(browser, TAB_RIGHT);
|
||||
@@ -207,7 +213,9 @@ void archive_file_array_swap(ArchiveBrowserView* browser, int8_t dir) {
|
||||
furi_assert(browser);
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
ArchiveFile_t temp;
|
||||
size_t array_size = files_array_size(model->files) - 1;
|
||||
uint8_t swap_idx = CLAMP((size_t)(model->item_idx + dir), array_size, 0u);
|
||||
@@ -225,18 +233,18 @@ void archive_file_array_swap(ArchiveBrowserView* browser, int8_t dir) {
|
||||
} else {
|
||||
files_array_swap_at(model->files, model->item_idx, swap_idx);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
}
|
||||
|
||||
void archive_file_array_rm_all(ArchiveBrowserView* browser) {
|
||||
furi_assert(browser);
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
files_array_reset(model->files);
|
||||
return false;
|
||||
});
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{ files_array_reset(model->files); },
|
||||
false);
|
||||
}
|
||||
|
||||
void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) {
|
||||
@@ -245,7 +253,9 @@ void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) {
|
||||
int32_t offset_new = 0;
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
if(model->item_cnt > FILE_LIST_BUF_LEN) {
|
||||
if(dir < 0) {
|
||||
offset_new = model->item_idx - FILE_LIST_BUF_LEN / 4 * 3;
|
||||
@@ -261,8 +271,8 @@ void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) {
|
||||
offset_new = 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
|
||||
file_browser_worker_load(browser->worker, offset_new, FILE_LIST_BUF_LEN);
|
||||
}
|
||||
@@ -272,12 +282,14 @@ ArchiveFile_t* archive_get_current_file(ArchiveBrowserView* browser) {
|
||||
|
||||
ArchiveFile_t* selected = NULL;
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
selected = files_array_size(model->files) ?
|
||||
files_array_get(model->files, model->item_idx - model->array_offset) :
|
||||
NULL;
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
return selected;
|
||||
}
|
||||
|
||||
@@ -287,11 +299,13 @@ ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx) {
|
||||
ArchiveFile_t* selected = NULL;
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
idx = CLAMP(idx - model->array_offset, files_array_size(model->files), 0u);
|
||||
selected = files_array_size(model->files) ? files_array_get(model->files, idx) : NULL;
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
return selected;
|
||||
}
|
||||
|
||||
@@ -300,10 +314,7 @@ ArchiveTabEnum archive_get_tab(ArchiveBrowserView* browser) {
|
||||
|
||||
ArchiveTabEnum tab_id = 0;
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
tab_id = model->tab_idx;
|
||||
return false;
|
||||
});
|
||||
browser->view, ArchiveBrowserViewModel * model, { tab_id = model->tab_idx; }, false);
|
||||
return tab_id;
|
||||
}
|
||||
|
||||
@@ -315,22 +326,19 @@ bool archive_is_home(ArchiveBrowserView* browser) {
|
||||
}
|
||||
|
||||
const char* default_path = archive_get_default_path(archive_get_tab(browser));
|
||||
return (string_cmp_str(browser->path, default_path) == 0);
|
||||
return (furi_string_cmp_str(browser->path, default_path) == 0);
|
||||
}
|
||||
|
||||
const char* archive_get_name(ArchiveBrowserView* browser) {
|
||||
ArchiveFile_t* selected = archive_get_current_file(browser);
|
||||
return string_get_cstr(selected->path);
|
||||
return furi_string_get_cstr(selected->path);
|
||||
}
|
||||
|
||||
void archive_set_tab(ArchiveBrowserView* browser, ArchiveTabEnum tab) {
|
||||
furi_assert(browser);
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
model->tab_idx = tab;
|
||||
return false;
|
||||
});
|
||||
browser->view, ArchiveBrowserViewModel * model, { model->tab_idx = tab; }, false);
|
||||
}
|
||||
|
||||
void archive_add_app_item(ArchiveBrowserView* browser, const char* name) {
|
||||
@@ -339,40 +347,60 @@ void archive_add_app_item(ArchiveBrowserView* browser, const char* name) {
|
||||
|
||||
ArchiveFile_t item;
|
||||
ArchiveFile_t_init(&item);
|
||||
string_set_str(item.path, name);
|
||||
furi_string_set(item.path, name);
|
||||
archive_set_file_type(&item, name, false, true);
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
files_array_push_back(model->files, item);
|
||||
model->item_cnt = files_array_size(model->files);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
ArchiveFile_t_clear(&item);
|
||||
}
|
||||
|
||||
static bool archive_get_fap_meta(FuriString* file_path, FuriString* fap_name, uint8_t** icon_ptr) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
bool success = false;
|
||||
if(fap_loader_load_name_and_icon(file_path, storage, icon_ptr, fap_name)) {
|
||||
success = true;
|
||||
}
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
return success;
|
||||
}
|
||||
|
||||
void archive_add_file_item(ArchiveBrowserView* browser, bool is_folder, const char* name) {
|
||||
furi_assert(browser);
|
||||
furi_assert(name);
|
||||
|
||||
ArchiveFile_t item;
|
||||
|
||||
ArchiveFile_t_init(&item);
|
||||
string_init_set_str(item.path, name);
|
||||
archive_set_file_type(&item, string_get_cstr(browser->path), is_folder, false);
|
||||
|
||||
furi_string_set(item.path, name);
|
||||
archive_set_file_type(&item, furi_string_get_cstr(browser->path), is_folder, false);
|
||||
if(item.type == ArchiveFileTypeApplication) {
|
||||
item.custom_icon_data = malloc(FAP_MANIFEST_MAX_ICON_SIZE);
|
||||
if(!archive_get_fap_meta(item.path, item.custom_name, &item.custom_icon_data)) {
|
||||
free(item.custom_icon_data);
|
||||
item.custom_icon_data = NULL;
|
||||
}
|
||||
}
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
files_array_push_back(model->files, item);
|
||||
return false;
|
||||
});
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{ files_array_push_back(model->files, item); },
|
||||
false);
|
||||
ArchiveFile_t_clear(&item);
|
||||
}
|
||||
|
||||
void archive_show_file_menu(ArchiveBrowserView* browser, bool show) {
|
||||
furi_assert(browser);
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
if(show) {
|
||||
if(archive_is_item_in_array(model, model->item_idx)) {
|
||||
model->menu = true;
|
||||
@@ -380,35 +408,32 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show) {
|
||||
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));
|
||||
selected->fav =
|
||||
archive_is_favorite("%s", furi_string_get_cstr(selected->path));
|
||||
}
|
||||
} else {
|
||||
model->menu = false;
|
||||
model->menu_idx = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) {
|
||||
furi_assert(browser);
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
model->move_fav = active;
|
||||
return true;
|
||||
});
|
||||
browser->view, ArchiveBrowserViewModel * model, { model->move_fav = active; }, true);
|
||||
}
|
||||
|
||||
static bool archive_is_dir_exists(string_t path) {
|
||||
if(string_equal_str_p(path, STORAGE_ANY_PATH_PREFIX)) {
|
||||
static bool archive_is_dir_exists(FuriString* path) {
|
||||
if(furi_string_equal(path, STORAGE_ANY_PATH_PREFIX)) {
|
||||
return true;
|
||||
}
|
||||
bool state = false;
|
||||
FileInfo file_info;
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
if(storage_common_stat(storage, string_get_cstr(path), &file_info) == FSE_OK) {
|
||||
if(storage_common_stat(storage, furi_string_get_cstr(path), &file_info) == FSE_OK) {
|
||||
if(file_info.flags & FSF_DIRECTORY) {
|
||||
state = true;
|
||||
}
|
||||
@@ -432,16 +457,16 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
|
||||
browser->is_root = true;
|
||||
archive_set_tab(browser, tab);
|
||||
|
||||
string_set_str(browser->path, archive_get_default_path(tab));
|
||||
furi_string_set(browser->path, archive_get_default_path(tab));
|
||||
bool tab_empty = true;
|
||||
if(tab == ArchiveTabFavorites) {
|
||||
if(archive_favorites_count(browser) > 0) {
|
||||
tab_empty = false;
|
||||
}
|
||||
} else if(string_start_with_str_p(browser->path, "/app:")) {
|
||||
char* app_name = strchr(string_get_cstr(browser->path), ':');
|
||||
} else if(furi_string_start_with_str(browser->path, "/app:")) {
|
||||
char* app_name = strchr(furi_string_get_cstr(browser->path), ':');
|
||||
if(app_name != NULL) {
|
||||
if(archive_app_is_available(browser, string_get_cstr(browser->path))) {
|
||||
if(archive_app_is_available(browser, furi_string_get_cstr(browser->path))) {
|
||||
tab_empty = false;
|
||||
}
|
||||
}
|
||||
@@ -459,29 +484,28 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
|
||||
archive_switch_tab(browser, key);
|
||||
} else {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
model->item_idx = 0;
|
||||
model->array_offset = 0;
|
||||
return false;
|
||||
});
|
||||
archive_get_items(browser, string_get_cstr(browser->path));
|
||||
},
|
||||
false);
|
||||
archive_get_items(browser, furi_string_get_cstr(browser->path));
|
||||
archive_update_offset(browser);
|
||||
}
|
||||
}
|
||||
|
||||
void archive_enter_dir(ArchiveBrowserView* browser, string_t path) {
|
||||
void archive_enter_dir(ArchiveBrowserView* browser, FuriString* path) {
|
||||
furi_assert(browser);
|
||||
furi_assert(path);
|
||||
|
||||
int32_t idx_temp = 0;
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
idx_temp = model->item_idx;
|
||||
return false;
|
||||
});
|
||||
browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false);
|
||||
|
||||
string_set(browser->path, path);
|
||||
furi_string_set(browser->path, path);
|
||||
file_browser_worker_folder_enter(browser->worker, path, idx_temp);
|
||||
}
|
||||
|
||||
@@ -497,9 +521,6 @@ void archive_refresh_dir(ArchiveBrowserView* browser) {
|
||||
int32_t idx_temp = 0;
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
idx_temp = model->item_idx;
|
||||
return false;
|
||||
});
|
||||
browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false);
|
||||
file_browser_worker_folder_refresh(browser->worker, idx_temp);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ static const char* tab_default_paths[] = {
|
||||
[ArchiveTabInfrared] = ANY_PATH("infrared"),
|
||||
[ArchiveTabBadUsb] = ANY_PATH("badusb"),
|
||||
[ArchiveTabU2f] = "/app:u2f",
|
||||
[ArchiveTabApplications] = ANY_PATH("apps"),
|
||||
[ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX,
|
||||
};
|
||||
|
||||
@@ -27,6 +28,7 @@ static const char* known_ext[] = {
|
||||
[ArchiveFileTypeInfrared] = ".ir",
|
||||
[ArchiveFileTypeBadUsb] = ".txt",
|
||||
[ArchiveFileTypeU2f] = "?",
|
||||
[ArchiveFileTypeApplication] = ".fap",
|
||||
[ArchiveFileTypeUpdateManifest] = ".fuf",
|
||||
[ArchiveFileTypeFolder] = "?",
|
||||
[ArchiveFileTypeUnknown] = "*",
|
||||
@@ -41,6 +43,7 @@ static const ArchiveFileTypeEnum known_type[] = {
|
||||
[ArchiveTabInfrared] = ArchiveFileTypeInfrared,
|
||||
[ArchiveTabBadUsb] = ArchiveFileTypeBadUsb,
|
||||
[ArchiveTabU2f] = ArchiveFileTypeU2f,
|
||||
[ArchiveTabApplications] = ArchiveFileTypeApplication,
|
||||
[ArchiveTabBrowser] = ArchiveFileTypeUnknown,
|
||||
};
|
||||
|
||||
@@ -84,6 +87,6 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show);
|
||||
void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active);
|
||||
|
||||
void archive_switch_tab(ArchiveBrowserView* browser, InputKey key);
|
||||
void archive_enter_dir(ArchiveBrowserView* browser, string_t name);
|
||||
void archive_enter_dir(ArchiveBrowserView* browser, FuriString* name);
|
||||
void archive_leave_dir(ArchiveBrowserView* browser);
|
||||
void archive_refresh_dir(ArchiveBrowserView* browser);
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
#define ARCHIVE_FAV_FILE_BUF_LEN 32
|
||||
|
||||
static bool archive_favorites_read_line(File* file, string_t str_result) {
|
||||
string_reset(str_result);
|
||||
static bool archive_favorites_read_line(File* file, FuriString* str_result) {
|
||||
furi_string_reset(str_result);
|
||||
uint8_t buffer[ARCHIVE_FAV_FILE_BUF_LEN];
|
||||
bool result = false;
|
||||
|
||||
@@ -34,7 +34,7 @@ static bool archive_favorites_read_line(File* file, string_t str_result) {
|
||||
result = true;
|
||||
break;
|
||||
} else {
|
||||
string_push_back(str_result, buffer[i]);
|
||||
furi_string_push_back(str_result, buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,8 +52,8 @@ uint16_t archive_favorites_count(void* context) {
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
string_t buffer;
|
||||
string_init(buffer);
|
||||
FuriString* buffer;
|
||||
buffer = furi_string_alloc();
|
||||
|
||||
bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
uint16_t lines = 0;
|
||||
@@ -63,7 +63,7 @@ uint16_t archive_favorites_count(void* context) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
if(!furi_string_size(buffer)) {
|
||||
continue; // Skip empty lines
|
||||
}
|
||||
++lines;
|
||||
@@ -72,7 +72,7 @@ uint16_t archive_favorites_count(void* context) {
|
||||
|
||||
storage_file_close(file);
|
||||
|
||||
string_clear(buffer);
|
||||
furi_string_free(buffer);
|
||||
storage_file_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
@@ -80,8 +80,8 @@ uint16_t archive_favorites_count(void* context) {
|
||||
}
|
||||
|
||||
static bool archive_favourites_rescan() {
|
||||
string_t buffer;
|
||||
string_init(buffer);
|
||||
FuriString* buffer;
|
||||
buffer = furi_string_alloc();
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(storage);
|
||||
|
||||
@@ -91,23 +91,25 @@ static bool archive_favourites_rescan() {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
if(!furi_string_size(buffer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(string_search(buffer, "/app:") == 0) {
|
||||
if(archive_app_is_available(NULL, string_get_cstr(buffer))) {
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
|
||||
if(furi_string_search(buffer, "/app:") == 0) {
|
||||
if(archive_app_is_available(NULL, furi_string_get_cstr(buffer))) {
|
||||
archive_file_append(
|
||||
ARCHIVE_FAV_TEMP_PATH, "%s\n", furi_string_get_cstr(buffer));
|
||||
}
|
||||
} else {
|
||||
if(storage_file_exists(storage, string_get_cstr(buffer))) {
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
|
||||
if(storage_file_exists(storage, furi_string_get_cstr(buffer))) {
|
||||
archive_file_append(
|
||||
ARCHIVE_FAV_TEMP_PATH, "%s\n", furi_string_get_cstr(buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string_clear(buffer);
|
||||
furi_string_free(buffer);
|
||||
|
||||
storage_file_close(file);
|
||||
storage_common_remove(storage, ARCHIVE_FAV_PATH);
|
||||
@@ -127,9 +129,9 @@ bool archive_favorites_read(void* context) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(storage);
|
||||
|
||||
string_t buffer;
|
||||
FuriString* buffer;
|
||||
FileInfo file_info;
|
||||
string_init(buffer);
|
||||
buffer = furi_string_alloc();
|
||||
|
||||
bool need_refresh = false;
|
||||
uint16_t file_count = 0;
|
||||
@@ -143,33 +145,33 @@ bool archive_favorites_read(void* context) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
if(!furi_string_size(buffer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(string_search(buffer, "/app:") == 0) {
|
||||
if(archive_app_is_available(browser, string_get_cstr(buffer))) {
|
||||
archive_add_app_item(browser, string_get_cstr(buffer));
|
||||
if(furi_string_search(buffer, "/app:") == 0) {
|
||||
if(archive_app_is_available(browser, furi_string_get_cstr(buffer))) {
|
||||
archive_add_app_item(browser, furi_string_get_cstr(buffer));
|
||||
file_count++;
|
||||
} else {
|
||||
need_refresh = true;
|
||||
}
|
||||
} else {
|
||||
if(storage_file_exists(storage, string_get_cstr(buffer))) {
|
||||
storage_common_stat(storage, string_get_cstr(buffer), &file_info);
|
||||
if(storage_file_exists(storage, furi_string_get_cstr(buffer))) {
|
||||
storage_common_stat(storage, furi_string_get_cstr(buffer), &file_info);
|
||||
archive_add_file_item(
|
||||
browser, (file_info.flags & FSF_DIRECTORY), string_get_cstr(buffer));
|
||||
browser, (file_info.flags & FSF_DIRECTORY), furi_string_get_cstr(buffer));
|
||||
file_count++;
|
||||
} else {
|
||||
need_refresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
string_reset(buffer);
|
||||
furi_string_reset(buffer);
|
||||
}
|
||||
}
|
||||
storage_file_close(file);
|
||||
string_clear(buffer);
|
||||
furi_string_free(buffer);
|
||||
storage_file_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
@@ -183,14 +185,14 @@ bool archive_favorites_read(void* context) {
|
||||
}
|
||||
|
||||
bool archive_favorites_delete(const char* format, ...) {
|
||||
string_t buffer;
|
||||
string_t filename;
|
||||
FuriString* buffer;
|
||||
FuriString* filename;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
string_init_vprintf(filename, format, args);
|
||||
filename = furi_string_alloc_vprintf(format, args);
|
||||
va_end(args);
|
||||
|
||||
string_init(buffer);
|
||||
buffer = furi_string_alloc();
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
@@ -201,18 +203,18 @@ bool archive_favorites_delete(const char* format, ...) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
if(!furi_string_size(buffer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(string_search(buffer, filename)) {
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
|
||||
if(furi_string_search(buffer, filename)) {
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", furi_string_get_cstr(buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string_clear(buffer);
|
||||
string_clear(filename);
|
||||
furi_string_free(buffer);
|
||||
furi_string_free(filename);
|
||||
|
||||
storage_file_close(file);
|
||||
storage_common_remove(fs_api, ARCHIVE_FAV_PATH);
|
||||
@@ -226,14 +228,14 @@ bool archive_favorites_delete(const char* format, ...) {
|
||||
}
|
||||
|
||||
bool archive_is_favorite(const char* format, ...) {
|
||||
string_t buffer;
|
||||
string_t filename;
|
||||
FuriString* buffer;
|
||||
FuriString* filename;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
string_init_vprintf(filename, format, args);
|
||||
filename = furi_string_alloc_vprintf(format, args);
|
||||
va_end(args);
|
||||
|
||||
string_init(buffer);
|
||||
buffer = furi_string_alloc();
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
@@ -245,10 +247,10 @@ bool archive_is_favorite(const char* format, ...) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
if(!furi_string_size(buffer)) {
|
||||
continue;
|
||||
}
|
||||
if(!string_search(buffer, filename)) {
|
||||
if(!furi_string_search(buffer, filename)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -256,8 +258,8 @@ bool archive_is_favorite(const char* format, ...) {
|
||||
}
|
||||
|
||||
storage_file_close(file);
|
||||
string_clear(buffer);
|
||||
string_clear(filename);
|
||||
furi_string_free(buffer);
|
||||
furi_string_free(filename);
|
||||
storage_file_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
@@ -271,13 +273,13 @@ bool archive_favorites_rename(const char* src, const char* dst) {
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
string_t path;
|
||||
string_t buffer;
|
||||
FuriString* path;
|
||||
FuriString* buffer;
|
||||
|
||||
string_init(buffer);
|
||||
string_init(path);
|
||||
buffer = furi_string_alloc();
|
||||
path = furi_string_alloc();
|
||||
|
||||
string_printf(path, "%s", src);
|
||||
furi_string_printf(path, "%s", src);
|
||||
bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
|
||||
if(result) {
|
||||
@@ -285,19 +287,19 @@ bool archive_favorites_rename(const char* src, const char* dst) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
if(!furi_string_size(buffer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
archive_file_append(
|
||||
ARCHIVE_FAV_TEMP_PATH,
|
||||
"%s\n",
|
||||
string_search(buffer, path) ? string_get_cstr(buffer) : dst);
|
||||
furi_string_search(buffer, path) ? furi_string_get_cstr(buffer) : dst);
|
||||
}
|
||||
}
|
||||
|
||||
string_clear(buffer);
|
||||
string_clear(path);
|
||||
furi_string_free(buffer);
|
||||
furi_string_free(path);
|
||||
|
||||
storage_file_close(file);
|
||||
storage_common_remove(fs_api, ARCHIVE_FAV_PATH);
|
||||
@@ -325,7 +327,7 @@ void archive_favorites_save(void* context) {
|
||||
|
||||
for(size_t i = 0; i < archive_file_get_array_size(browser); i++) {
|
||||
ArchiveFile_t* item = archive_get_file_at(browser, i);
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(item->path));
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", furi_string_get_cstr(item->path));
|
||||
}
|
||||
|
||||
storage_common_remove(fs_api, ARCHIVE_FAV_PATH);
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
uint16_t archive_favorites_count(void* context);
|
||||
bool archive_favorites_read(void* context);
|
||||
bool archive_favorites_delete(const char* format, ...);
|
||||
bool archive_is_favorite(const char* format, ...);
|
||||
bool archive_favorites_delete(const char* format, ...) _ATTRIBUTE((__format__(__printf__, 1, 2)));
|
||||
bool archive_is_favorite(const char* format, ...) _ATTRIBUTE((__format__(__printf__, 1, 2)));
|
||||
bool archive_favorites_rename(const char* src, const char* dst);
|
||||
void archive_add_to_favorites(const char* file_path);
|
||||
void archive_favorites_save(void* context);
|
||||
|
||||
@@ -15,10 +15,10 @@ void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder
|
||||
} else {
|
||||
for(size_t i = 0; i < COUNT_OF(known_ext); i++) {
|
||||
if((known_ext[i][0] == '?') || (known_ext[i][0] == '*')) continue;
|
||||
if(string_search_str(file->path, known_ext[i], 0) != STRING_FAILURE) {
|
||||
if(furi_string_search(file->path, known_ext[i], 0) != FURI_STRING_FAILURE) {
|
||||
if(i == ArchiveFileTypeBadUsb) {
|
||||
if(string_search_str(file->path, archive_get_default_path(ArchiveTabBadUsb)) ==
|
||||
0) {
|
||||
if(furi_string_search(
|
||||
file->path, archive_get_default_path(ArchiveTabBadUsb)) == 0) {
|
||||
file->type = i;
|
||||
return; // *.txt file is a BadUSB script only if it is in BadUSB folder
|
||||
}
|
||||
@@ -54,10 +54,10 @@ bool archive_get_items(void* context, const char* path) {
|
||||
void archive_file_append(const char* path, const char* format, ...) {
|
||||
furi_assert(path);
|
||||
|
||||
string_t string;
|
||||
FuriString* string;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
string_init_vprintf(string, format, args);
|
||||
string = furi_string_alloc_vprintf(format, args);
|
||||
va_end(args);
|
||||
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
@@ -66,7 +66,7 @@ void archive_file_append(const char* path, const char* format, ...) {
|
||||
bool res = storage_file_open(file, path, FSAM_WRITE, FSOM_OPEN_APPEND);
|
||||
|
||||
if(res) {
|
||||
storage_file_write(file, string_get_cstr(string), string_size(string));
|
||||
storage_file_write(file, furi_string_get_cstr(string), furi_string_size(string));
|
||||
}
|
||||
|
||||
storage_file_close(file);
|
||||
@@ -77,37 +77,37 @@ void archive_file_append(const char* path, const char* format, ...) {
|
||||
void archive_delete_file(void* context, const char* format, ...) {
|
||||
furi_assert(context);
|
||||
|
||||
string_t filename;
|
||||
FuriString* filename;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
string_init_vprintf(filename, format, args);
|
||||
filename = furi_string_alloc_vprintf(format, args);
|
||||
va_end(args);
|
||||
|
||||
ArchiveBrowserView* browser = context;
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
FileInfo fileinfo;
|
||||
storage_common_stat(fs_api, string_get_cstr(filename), &fileinfo);
|
||||
storage_common_stat(fs_api, furi_string_get_cstr(filename), &fileinfo);
|
||||
|
||||
bool res = false;
|
||||
|
||||
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||
res = storage_simply_remove_recursive(fs_api, string_get_cstr(filename));
|
||||
res = storage_simply_remove_recursive(fs_api, furi_string_get_cstr(filename));
|
||||
} else {
|
||||
res = (storage_common_remove(fs_api, string_get_cstr(filename)) == FSE_OK);
|
||||
res = (storage_common_remove(fs_api, furi_string_get_cstr(filename)) == FSE_OK);
|
||||
}
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
if(archive_is_favorite("%s", string_get_cstr(filename))) {
|
||||
archive_favorites_delete("%s", string_get_cstr(filename));
|
||||
if(archive_is_favorite("%s", furi_string_get_cstr(filename))) {
|
||||
archive_favorites_delete("%s", furi_string_get_cstr(filename));
|
||||
}
|
||||
|
||||
if(res) {
|
||||
archive_file_array_rm_selected(browser);
|
||||
}
|
||||
|
||||
string_clear(filename);
|
||||
furi_string_free(filename);
|
||||
}
|
||||
|
||||
FS_Error archive_rename_file_or_dir(void* context, const char* src_path, const char* dst_path) {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <m-array.h>
|
||||
#include <m-string.h>
|
||||
#include <furi.h>
|
||||
#include <storage/storage.h>
|
||||
#include "toolbox/path.h"
|
||||
|
||||
#define FAP_MANIFEST_MAX_ICON_SIZE 32
|
||||
|
||||
typedef enum {
|
||||
ArchiveFileTypeIButton,
|
||||
ArchiveFileTypeNFC,
|
||||
@@ -13,6 +15,7 @@ typedef enum {
|
||||
ArchiveFileTypeInfrared,
|
||||
ArchiveFileTypeBadUsb,
|
||||
ArchiveFileTypeU2f,
|
||||
ArchiveFileTypeApplication,
|
||||
ArchiveFileTypeUpdateManifest,
|
||||
ArchiveFileTypeFolder,
|
||||
ArchiveFileTypeUnknown,
|
||||
@@ -20,35 +23,58 @@ typedef enum {
|
||||
} ArchiveFileTypeEnum;
|
||||
|
||||
typedef struct {
|
||||
string_t path;
|
||||
FuriString* path;
|
||||
ArchiveFileTypeEnum type;
|
||||
uint8_t* custom_icon_data;
|
||||
FuriString* custom_name;
|
||||
bool fav;
|
||||
bool is_app;
|
||||
} ArchiveFile_t;
|
||||
|
||||
static void ArchiveFile_t_init(ArchiveFile_t* obj) {
|
||||
obj->path = furi_string_alloc();
|
||||
obj->type = ArchiveFileTypeUnknown;
|
||||
obj->is_app = false;
|
||||
obj->custom_icon_data = NULL;
|
||||
obj->custom_name = furi_string_alloc();
|
||||
obj->fav = false;
|
||||
string_init(obj->path);
|
||||
obj->is_app = false;
|
||||
}
|
||||
|
||||
static void ArchiveFile_t_init_set(ArchiveFile_t* obj, const ArchiveFile_t* src) {
|
||||
obj->path = furi_string_alloc_set(src->path);
|
||||
obj->type = src->type;
|
||||
obj->is_app = src->is_app;
|
||||
if(src->custom_icon_data) {
|
||||
obj->custom_icon_data = malloc(FAP_MANIFEST_MAX_ICON_SIZE);
|
||||
memcpy(obj->custom_icon_data, src->custom_icon_data, FAP_MANIFEST_MAX_ICON_SIZE);
|
||||
} else {
|
||||
obj->custom_icon_data = NULL;
|
||||
}
|
||||
obj->custom_name = furi_string_alloc_set(src->custom_name);
|
||||
obj->fav = src->fav;
|
||||
string_init_set(obj->path, src->path);
|
||||
obj->is_app = src->is_app;
|
||||
}
|
||||
|
||||
static void ArchiveFile_t_set(ArchiveFile_t* obj, const ArchiveFile_t* src) {
|
||||
furi_string_set(obj->path, src->path);
|
||||
obj->type = src->type;
|
||||
obj->is_app = src->is_app;
|
||||
if(src->custom_icon_data) {
|
||||
obj->custom_icon_data = malloc(FAP_MANIFEST_MAX_ICON_SIZE);
|
||||
memcpy(obj->custom_icon_data, src->custom_icon_data, FAP_MANIFEST_MAX_ICON_SIZE);
|
||||
} else {
|
||||
obj->custom_icon_data = NULL;
|
||||
}
|
||||
furi_string_set(obj->custom_name, src->custom_name);
|
||||
obj->fav = src->fav;
|
||||
string_set(obj->path, src->path);
|
||||
obj->is_app = src->is_app;
|
||||
}
|
||||
|
||||
static void ArchiveFile_t_clear(ArchiveFile_t* obj) {
|
||||
string_clear(obj->path);
|
||||
furi_string_free(obj->path);
|
||||
if(obj->custom_icon_data) {
|
||||
free(obj->custom_icon_data);
|
||||
obj->custom_icon_data = NULL;
|
||||
}
|
||||
furi_string_free(obj->custom_name);
|
||||
}
|
||||
|
||||
ARRAY_DEF(
|
||||
@@ -61,6 +87,8 @@ ARRAY_DEF(
|
||||
|
||||
void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder, bool is_app);
|
||||
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, ...);
|
||||
void archive_file_append(const char* path, const char* format, ...)
|
||||
_ATTRIBUTE((__format__(__printf__, 2, 3)));
|
||||
void archive_delete_file(void* context, const char* format, ...)
|
||||
_ATTRIBUTE((__format__(__printf__, 2, 3)));
|
||||
FS_Error archive_rename_file_or_dir(void* context, const char* src_path, const char* dst_path);
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <m-array.h>
|
||||
#include <m-string.h>
|
||||
|
||||
typedef struct {
|
||||
string_t text;
|
||||
FuriString* text;
|
||||
uint32_t event;
|
||||
} ArchiveContextMenuItem_t;
|
||||
|
||||
static void ArchiveContextMenuItem_t_init(ArchiveContextMenuItem_t* obj) {
|
||||
string_init(obj->text);
|
||||
obj->text = furi_string_alloc();
|
||||
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->text = furi_string_alloc_set(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);
|
||||
furi_string_set(obj->text, src->text);
|
||||
obj->event = src->event;
|
||||
}
|
||||
|
||||
static void ArchiveContextMenuItem_t_clear(ArchiveContextMenuItem_t* obj) {
|
||||
string_clear(obj->text);
|
||||
furi_string_free(obj->text);
|
||||
}
|
||||
|
||||
ARRAY_DEF(
|
||||
@@ -42,11 +42,9 @@ ARRAY_DEF(
|
||||
#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);
|
||||
static void
|
||||
archive_menu_add_item(ArchiveContextMenuItem_t* obj, FuriString* text, uint32_t event) {
|
||||
obj->text = furi_string_alloc_set(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",
|
||||
[ArchiveFileTypeApplication] = "Applications",
|
||||
[ArchiveFileTypeUpdateManifest] = "UpdaterApp",
|
||||
};
|
||||
|
||||
@@ -40,14 +41,14 @@ static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selec
|
||||
|
||||
LoaderStatus status;
|
||||
if(selected->is_app) {
|
||||
char* param = strrchr(string_get_cstr(selected->path), '/');
|
||||
char* param = strrchr(furi_string_get_cstr(selected->path), '/');
|
||||
if(param != NULL) {
|
||||
param++;
|
||||
}
|
||||
status = loader_start(loader, flipper_app_name[selected->type], param);
|
||||
} else {
|
||||
status = loader_start(
|
||||
loader, flipper_app_name[selected->type], string_get_cstr(selected->path));
|
||||
loader, flipper_app_name[selected->type], furi_string_get_cstr(selected->path));
|
||||
}
|
||||
|
||||
if(status != LoaderStatusOk) {
|
||||
@@ -132,7 +133,7 @@ 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);
|
||||
@@ -168,13 +169,13 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventEnterFavMove:
|
||||
string_set(archive->fav_move_str, selected->path);
|
||||
furi_string_set(archive->fav_move_str, selected->path);
|
||||
archive_show_file_menu(browser, false);
|
||||
archive_favorites_move_mode(archive->browser, true);
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventExitFavMove:
|
||||
archive_update_focus(browser, string_get_cstr(archive->fav_move_str));
|
||||
archive_update_focus(browser, furi_string_get_cstr(archive->fav_move_str));
|
||||
archive_favorites_move_mode(archive->browser, false);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
@@ -22,18 +22,18 @@ void archive_scene_delete_on_enter(void* context) {
|
||||
widget_add_button_element(
|
||||
app->widget, GuiButtonTypeRight, "Delete", archive_scene_delete_widget_callback, app);
|
||||
|
||||
string_t filename;
|
||||
string_init(filename);
|
||||
FuriString* filename;
|
||||
filename = furi_string_alloc();
|
||||
|
||||
ArchiveFile_t* current = archive_get_current_file(app->browser);
|
||||
path_extract_filename(current->path, filename, false);
|
||||
|
||||
char delete_str[64];
|
||||
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", string_get_cstr(filename));
|
||||
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", furi_string_get_cstr(filename));
|
||||
widget_add_text_box_element(
|
||||
app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str, false);
|
||||
|
||||
string_clear(filename);
|
||||
furi_string_free(filename);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, ArchiveViewWidget);
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@ void archive_scene_info_on_enter(void* 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);
|
||||
FuriString* filename;
|
||||
FuriString* dirname;
|
||||
FuriString* str_size;
|
||||
filename = furi_string_alloc();
|
||||
dirname = furi_string_alloc();
|
||||
str_size = furi_string_alloc();
|
||||
|
||||
ArchiveFile_t* current = archive_get_current_file(instance->browser);
|
||||
char file_info_message[128];
|
||||
@@ -31,44 +31,49 @@ void archive_scene_info_on_enter(void* context) {
|
||||
|
||||
// Filename
|
||||
path_extract_filename(current->path, filename, false);
|
||||
snprintf(file_info_message, sizeof(file_info_message), "\e#%s\e#", string_get_cstr(filename));
|
||||
snprintf(
|
||||
file_info_message, sizeof(file_info_message), "\e#%s\e#", furi_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);
|
||||
string_replace_str(dirname, STORAGE_ANY_PATH_PREFIX, "");
|
||||
path_extract_dirname(furi_string_get_cstr(current->path), dirname);
|
||||
if(strcmp(furi_string_get_cstr(dirname), "/any") == 0) {
|
||||
furi_string_replace(dirname, STORAGE_ANY_PATH_PREFIX, "/");
|
||||
} else {
|
||||
furi_string_replace(dirname, STORAGE_ANY_PATH_PREFIX, "");
|
||||
}
|
||||
|
||||
// File size
|
||||
FileInfo fileinfo;
|
||||
storage_common_stat(fs_api, string_get_cstr(current->path), &fileinfo);
|
||||
storage_common_stat(fs_api, furi_string_get_cstr(current->path), &fileinfo);
|
||||
if(fileinfo.size <= 1024) {
|
||||
string_printf(str_size, "%d", fileinfo.size);
|
||||
furi_string_printf(str_size, "%lld", 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));
|
||||
furi_string_get_cstr(str_size),
|
||||
furi_string_get_cstr(dirname));
|
||||
} else {
|
||||
string_printf(str_size, "%d", fileinfo.size / 1024);
|
||||
furi_string_printf(str_size, "%lld", 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));
|
||||
furi_string_get_cstr(str_size),
|
||||
furi_string_get_cstr(dirname));
|
||||
}
|
||||
widget_add_text_box_element(
|
||||
instance->widget, 0, 25, 128, 25, AlignLeft, AlignCenter, file_info_message, false);
|
||||
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);
|
||||
path_extract_filename_no_ext(furi_string_get_cstr(current->path), filename);
|
||||
strlcpy(instance->text_store, furi_string_get_cstr(filename), MAX_NAME_LEN);
|
||||
|
||||
string_clear(filename);
|
||||
string_clear(dirname);
|
||||
string_clear(str_size);
|
||||
furi_string_free(filename);
|
||||
furi_string_free(dirname);
|
||||
furi_string_free(str_size);
|
||||
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, ArchiveViewWidget);
|
||||
}
|
||||
|
||||
@@ -22,22 +22,22 @@ void archive_scene_rename_on_enter(void* context) {
|
||||
TextInput* text_input = archive->text_input;
|
||||
ArchiveFile_t* current = archive_get_current_file(archive->browser);
|
||||
|
||||
string_t path_name;
|
||||
string_init(path_name);
|
||||
FuriString* path_name;
|
||||
path_name = furi_string_alloc();
|
||||
|
||||
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);
|
||||
path_extract_basename(furi_string_get_cstr(current->path), path_name);
|
||||
strlcpy(archive->text_store, furi_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);
|
||||
strlcpy(archive->text_store, furi_string_get_cstr(path_name), MAX_NAME_LEN);
|
||||
|
||||
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);
|
||||
strlcpy(archive->text_store, furi_string_get_cstr(path_name), MAX_NAME_LEN);
|
||||
text_input_set_header_text(text_input, "Rename unknown file:");
|
||||
}*/
|
||||
|
||||
@@ -49,7 +49,7 @@ void archive_scene_rename_on_enter(void* context) {
|
||||
MAX_TEXT_INPUT_LEN,
|
||||
false);
|
||||
|
||||
string_clear(path_name);
|
||||
furi_string_free(path_name);
|
||||
|
||||
view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput);
|
||||
}
|
||||
@@ -63,40 +63,43 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) {
|
||||
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);
|
||||
FuriString* path_dst;
|
||||
path_dst = furi_string_alloc();
|
||||
|
||||
if(file->type == ArchiveFileTypeFolder) {
|
||||
// Rename folder/dir
|
||||
path_extract_dirname(path_src, path_dst);
|
||||
string_cat_printf(path_dst, "/%s", archive->text_store);
|
||||
furi_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]);
|
||||
furi_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);
|
||||
furi_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));
|
||||
FS_Error error = archive_rename_file_or_dir(
|
||||
archive->browser, path_src, furi_string_get_cstr(path_dst));
|
||||
archive_show_loading_popup(archive, false);
|
||||
archive_show_file_menu(archive->browser, false);
|
||||
|
||||
string_clear(path_dst);
|
||||
furi_string_free(path_dst);
|
||||
|
||||
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);
|
||||
FuriString* dialog_msg;
|
||||
dialog_msg = furi_string_alloc();
|
||||
furi_string_cat_printf(dialog_msg, "Cannot rename\nCode: %d", error);
|
||||
dialog_message_show_storage_error(
|
||||
archive->dialogs, furi_string_get_cstr(dialog_msg));
|
||||
furi_string_free(dialog_msg);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ static const char* ArchiveTabNames[] = {
|
||||
[ArchiveTabInfrared] = "Infrared",
|
||||
[ArchiveTabBadUsb] = "Bad USB",
|
||||
[ArchiveTabU2f] = "U2F",
|
||||
[ArchiveTabApplications] = "Apps",
|
||||
[ArchiveTabBrowser] = "Browser",
|
||||
};
|
||||
|
||||
@@ -27,6 +28,7 @@ static const Icon* ArchiveItemIcons[] = {
|
||||
[ArchiveFileTypeInfrared] = &I_ir_10px,
|
||||
[ArchiveFileTypeBadUsb] = &I_badusb_10px,
|
||||
[ArchiveFileTypeU2f] = &I_u2f_10px,
|
||||
[ArchiveFileTypeApplication] = &I_Apps_10px,
|
||||
[ArchiveFileTypeUpdateManifest] = &I_update_10px,
|
||||
[ArchiveFileTypeFolder] = &I_dir_10px,
|
||||
[ArchiveFileTypeUnknown] = &I_unknown_10px,
|
||||
@@ -46,24 +48,18 @@ void archive_browser_set_callback(
|
||||
static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
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_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");
|
||||
FuriString* item_run = furi_string_alloc_set("Run In App");
|
||||
FuriString* item_pin = furi_string_alloc_set("Pin");
|
||||
FuriString* item_info = furi_string_alloc_set("Info");
|
||||
FuriString* item_rename = furi_string_alloc_set("Rename");
|
||||
FuriString* item_delete = furi_string_alloc_set("Delete");
|
||||
|
||||
// Need init context menu
|
||||
ArchiveFile_t* selected =
|
||||
files_array_get(model->files, model->item_idx - model->array_offset);
|
||||
|
||||
if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) {
|
||||
string_set_str(item_pin, "Unpin");
|
||||
furi_string_set(item_pin, "Unpin");
|
||||
}
|
||||
|
||||
if(selected->type == ArchiveFileTypeFolder) {
|
||||
@@ -94,7 +90,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
} else if(model->tab_idx == ArchiveTabFavorites) {
|
||||
//FURI_LOG_D(TAG, "ArchiveTabFavorites");
|
||||
|
||||
string_set_str(item_rename, "Move");
|
||||
furi_string_set(item_rename, "Move");
|
||||
|
||||
archive_menu_add_item(
|
||||
menu_array_push_raw(model->context_menu),
|
||||
@@ -150,11 +146,11 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
ArchiveBrowserEventFileMenuDelete);
|
||||
}
|
||||
|
||||
string_clear(item_run);
|
||||
string_clear(item_pin);
|
||||
string_clear(item_info);
|
||||
string_clear(item_rename);
|
||||
string_clear(item_delete);
|
||||
furi_string_free(item_run);
|
||||
furi_string_free(item_pin);
|
||||
furi_string_free(item_info);
|
||||
furi_string_free(item_rename);
|
||||
furi_string_free(item_delete);
|
||||
} /*else {
|
||||
FURI_LOG_D(TAG, "menu_array_size already set: %d", menu_array_size(model->context_menu));
|
||||
}*/
|
||||
@@ -176,7 +172,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
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));
|
||||
canvas_draw_str(canvas, 82, 21 + i * line_height, furi_string_get_cstr(current->text));
|
||||
}
|
||||
|
||||
canvas_draw_icon(canvas, 74, 14 + model->menu_idx * line_height, &I_ButtonRight_4x7);
|
||||
@@ -219,20 +215,31 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
bool scrollbar = model->item_cnt > 4;
|
||||
|
||||
for(uint32_t i = 0; i < MIN(model->item_cnt, MENU_ITEMS); ++i) {
|
||||
string_t str_buf;
|
||||
string_init(str_buf);
|
||||
FuriString* str_buf;
|
||||
str_buf = furi_string_alloc();
|
||||
int32_t idx = CLAMP((uint32_t)(i + model->list_offset), model->item_cnt, 0u);
|
||||
uint8_t x_offset = (model->move_fav && model->item_idx == idx) ? MOVE_OFFSET : 0;
|
||||
|
||||
ArchiveFileTypeEnum file_type = ArchiveFileTypeLoading;
|
||||
uint8_t* custom_icon_data = NULL;
|
||||
|
||||
if(archive_is_item_in_array(model, idx)) {
|
||||
ArchiveFile_t* file = files_array_get(
|
||||
model->files, CLAMP(idx - model->array_offset, (int32_t)(array_size - 1), 0));
|
||||
path_extract_filename(file->path, str_buf, archive_is_known_app(file->type));
|
||||
file_type = file->type;
|
||||
if(file_type == ArchiveFileTypeApplication) {
|
||||
if(file->custom_icon_data) {
|
||||
custom_icon_data = file->custom_icon_data;
|
||||
furi_string_set(str_buf, file->custom_name);
|
||||
} else {
|
||||
file_type = ArchiveFileTypeUnknown;
|
||||
path_extract_filename(file->path, str_buf, archive_is_known_app(file->type));
|
||||
}
|
||||
} else {
|
||||
path_extract_filename(file->path, str_buf, archive_is_known_app(file->type));
|
||||
}
|
||||
} else {
|
||||
string_set_str(str_buf, "---");
|
||||
furi_string_set(str_buf, "---");
|
||||
}
|
||||
|
||||
elements_string_fit_width(
|
||||
@@ -244,10 +251,17 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
}
|
||||
|
||||
canvas_draw_icon(canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file_type]);
|
||||
canvas_draw_str(canvas, 15 + x_offset, 24 + i * FRAME_HEIGHT, string_get_cstr(str_buf));
|
||||
if(custom_icon_data) {
|
||||
canvas_draw_bitmap(
|
||||
canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, 11, 10, custom_icon_data);
|
||||
} else {
|
||||
canvas_draw_icon(
|
||||
canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file_type]);
|
||||
}
|
||||
canvas_draw_str(
|
||||
canvas, 15 + x_offset, 24 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buf));
|
||||
|
||||
string_clear(str_buf);
|
||||
furi_string_free(str_buf);
|
||||
}
|
||||
|
||||
if(scrollbar) {
|
||||
@@ -344,11 +358,13 @@ static bool archive_view_input(InputEvent* event, void* context) {
|
||||
bool in_menu;
|
||||
bool move_fav_mode;
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
in_menu = model->menu;
|
||||
move_fav_mode = model->move_fav;
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
|
||||
if(in_menu) {
|
||||
if(event->type != InputTypeShort) {
|
||||
@@ -356,24 +372,28 @@ static bool archive_view_input(InputEvent* event, void* context) {
|
||||
}
|
||||
if(event->key == InputKeyUp || event->key == InputKeyDown) {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * 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;
|
||||
});
|
||||
},
|
||||
true);
|
||||
} else if(event->key == InputKeyOk) {
|
||||
uint32_t idx;
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
ArchiveContextMenuItem_t* current =
|
||||
menu_array_get(model->context_menu, model->menu_idx);
|
||||
idx = current->event;
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
browser->callback(idx, browser->context);
|
||||
} else if(event->key == InputKeyBack) {
|
||||
browser->callback(ArchiveBrowserEventFileMenuClose, browser->context);
|
||||
@@ -395,7 +415,9 @@ static bool archive_view_input(InputEvent* event, void* context) {
|
||||
if((event->key == InputKeyUp || event->key == InputKeyDown) &&
|
||||
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
if(event->key == InputKeyUp) {
|
||||
model->item_idx =
|
||||
((model->item_idx - 1) + model->item_cnt) % model->item_cnt;
|
||||
@@ -416,9 +438,8 @@ static bool archive_view_input(InputEvent* event, void* context) {
|
||||
browser->callback(ArchiveBrowserEventFavMoveDown, browser->context);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
archive_update_offset(browser);
|
||||
}
|
||||
|
||||
@@ -463,15 +484,17 @@ ArchiveBrowserView* browser_alloc() {
|
||||
view_set_draw_callback(browser->view, archive_view_render);
|
||||
view_set_input_callback(browser->view, archive_view_input);
|
||||
|
||||
string_init_set_str(browser->path, archive_get_default_path(TAB_DEFAULT));
|
||||
browser->path = furi_string_alloc_set(archive_get_default_path(TAB_DEFAULT));
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
files_array_init(model->files);
|
||||
menu_array_init(model->context_menu);
|
||||
model->tab_idx = TAB_DEFAULT;
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
|
||||
return browser;
|
||||
}
|
||||
@@ -484,13 +507,15 @@ void browser_free(ArchiveBrowserView* browser) {
|
||||
}
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
files_array_clear(model->files);
|
||||
menu_array_clear(model->context_menu);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
|
||||
string_clear(browser->path);
|
||||
furi_string_free(browser->path);
|
||||
|
||||
view_free(browser->view);
|
||||
free(browser);
|
||||
|
||||
@@ -27,6 +27,7 @@ typedef enum {
|
||||
ArchiveTabIButton,
|
||||
ArchiveTabBadUsb,
|
||||
ArchiveTabU2f,
|
||||
ArchiveTabApplications,
|
||||
ArchiveTabBrowser,
|
||||
ArchiveTabTotal,
|
||||
} ArchiveTabEnum;
|
||||
@@ -73,7 +74,7 @@ struct ArchiveBrowserView {
|
||||
bool worker_running;
|
||||
ArchiveBrowserViewCallback callback;
|
||||
void* context;
|
||||
string_t path;
|
||||
FuriString* path;
|
||||
InputKey last_tab_switch_dir;
|
||||
bool is_root;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "bad_usb_app_i.h"
|
||||
#include "bad_usb_settings_filename.h"
|
||||
#include "m-string.h"
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <storage/storage.h>
|
||||
@@ -32,7 +31,7 @@ static void bad_usb_load_settings(BadUsbApp* app) {
|
||||
char chr;
|
||||
while((storage_file_read(settings_file, &chr, 1) == 1) &&
|
||||
!storage_file_eof(settings_file) && !isspace(chr)) {
|
||||
string_push_back(app->keyboard_layout, chr);
|
||||
furi_string_push_back(app->keyboard_layout, chr);
|
||||
}
|
||||
}
|
||||
storage_file_close(settings_file);
|
||||
@@ -44,8 +43,8 @@ static void bad_usb_save_settings(BadUsbApp* app) {
|
||||
if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) {
|
||||
storage_file_write(
|
||||
settings_file,
|
||||
string_get_cstr(app->keyboard_layout),
|
||||
string_size(app->keyboard_layout));
|
||||
furi_string_get_cstr(app->keyboard_layout),
|
||||
furi_string_size(app->keyboard_layout));
|
||||
storage_file_write(settings_file, "\n", 1);
|
||||
}
|
||||
storage_file_close(settings_file);
|
||||
@@ -57,10 +56,10 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
|
||||
|
||||
app->bad_usb_script = NULL;
|
||||
|
||||
string_init(app->file_path);
|
||||
string_init(app->keyboard_layout);
|
||||
app->file_path = furi_string_alloc();
|
||||
app->keyboard_layout = furi_string_alloc();
|
||||
if(arg && strlen(arg)) {
|
||||
string_set_str(app->file_path, arg);
|
||||
furi_string_set(app->file_path, arg);
|
||||
}
|
||||
|
||||
bad_usb_load_settings(app);
|
||||
@@ -101,12 +100,12 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
|
||||
app->error = BadUsbAppErrorCloseRpc;
|
||||
scene_manager_next_scene(app->scene_manager, BadUsbSceneError);
|
||||
} else {
|
||||
if(!string_empty_p(app->file_path)) {
|
||||
if(!furi_string_empty(app->file_path)) {
|
||||
app->bad_usb_script = bad_usb_script_open(app->file_path);
|
||||
bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout);
|
||||
scene_manager_next_scene(app->scene_manager, BadUsbSceneWork);
|
||||
} else {
|
||||
string_set_str(app->file_path, BAD_USB_APP_BASE_FOLDER);
|
||||
furi_string_set(app->file_path, BAD_USB_APP_BASE_FOLDER);
|
||||
scene_manager_next_scene(app->scene_manager, BadUsbSceneFileSelect);
|
||||
}
|
||||
}
|
||||
@@ -145,8 +144,8 @@ void bad_usb_app_free(BadUsbApp* app) {
|
||||
|
||||
bad_usb_save_settings(app);
|
||||
|
||||
string_clear(app->file_path);
|
||||
string_clear(app->keyboard_layout);
|
||||
furi_string_free(app->file_path);
|
||||
furi_string_free(app->keyboard_layout);
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ struct BadUsbApp {
|
||||
Submenu* submenu;
|
||||
|
||||
BadUsbAppError error;
|
||||
string_t file_path;
|
||||
string_t keyboard_layout;
|
||||
FuriString* file_path;
|
||||
FuriString* keyboard_layout;
|
||||
BadUsb* bad_usb_view;
|
||||
BadUsbScript* bad_usb_script;
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ typedef enum {
|
||||
struct BadUsbScript {
|
||||
FuriHalUsbHidConfig hid_cfg;
|
||||
BadUsbState st;
|
||||
string_t file_path;
|
||||
FuriString* file_path;
|
||||
uint32_t defdelay;
|
||||
uint16_t layout[128];
|
||||
FuriThread* thread;
|
||||
@@ -37,9 +37,9 @@ struct BadUsbScript {
|
||||
uint8_t buf_start;
|
||||
uint8_t buf_len;
|
||||
bool file_end;
|
||||
string_t line;
|
||||
FuriString* line;
|
||||
|
||||
string_t line_prev;
|
||||
FuriString* line_prev;
|
||||
uint32_t repeat_cnt;
|
||||
};
|
||||
|
||||
@@ -113,6 +113,7 @@ static const char ducky_cmd_string[] = {"STRING "};
|
||||
static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "};
|
||||
static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "};
|
||||
static const char ducky_cmd_repeat[] = {"REPEAT "};
|
||||
static const char ducky_cmd_sysrq[] = {"SYSRQ "};
|
||||
|
||||
static const char ducky_cmd_altchar[] = {"ALTCHAR "};
|
||||
static const char ducky_cmd_altstr_1[] = {"ALTSTRING "};
|
||||
@@ -236,9 +237,10 @@ static uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
|
||||
uint32_t line_len = string_size(line);
|
||||
const char* line_tmp = string_get_cstr(line);
|
||||
static int32_t
|
||||
ducky_parse_line(BadUsbScript* bad_usb, FuriString* line, char* error, size_t error_len) {
|
||||
uint32_t line_len = furi_string_size(line);
|
||||
const char* line_tmp = furi_string_get_cstr(line);
|
||||
bool state = false;
|
||||
|
||||
for(uint32_t i = 0; i < line_len; i++) {
|
||||
@@ -269,6 +271,9 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
|
||||
if((state) && (delay_val > 0)) {
|
||||
return (int32_t)delay_val;
|
||||
}
|
||||
if(error != NULL) {
|
||||
snprintf(error, error_len, "Invalid number %s", line_tmp);
|
||||
}
|
||||
return SCRIPT_STATE_ERROR;
|
||||
} else if(
|
||||
(strncmp(line_tmp, ducky_cmd_defdelay_1, strlen(ducky_cmd_defdelay_1)) == 0) ||
|
||||
@@ -276,17 +281,26 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
|
||||
// DEFAULT_DELAY
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
state = ducky_get_number(line_tmp, &bad_usb->defdelay);
|
||||
if(!state && error != NULL) {
|
||||
snprintf(error, error_len, "Invalid number %s", line_tmp);
|
||||
}
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
} else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) {
|
||||
// STRING
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
state = ducky_string(bad_usb, line_tmp);
|
||||
if(!state && error != NULL) {
|
||||
snprintf(error, error_len, "Invalid string %s", line_tmp);
|
||||
}
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
} else if(strncmp(line_tmp, ducky_cmd_altchar, strlen(ducky_cmd_altchar)) == 0) {
|
||||
// ALTCHAR
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
ducky_numlock_on();
|
||||
state = ducky_altchar(line_tmp);
|
||||
if(!state && error != NULL) {
|
||||
snprintf(error, error_len, "Invalid altchar %s", line_tmp);
|
||||
}
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
} else if(
|
||||
(strncmp(line_tmp, ducky_cmd_altstr_1, strlen(ducky_cmd_altstr_1)) == 0) ||
|
||||
@@ -295,16 +309,35 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
ducky_numlock_on();
|
||||
state = ducky_altstring(line_tmp);
|
||||
if(!state && error != NULL) {
|
||||
snprintf(error, error_len, "Invalid altstring %s", line_tmp);
|
||||
}
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
} else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) {
|
||||
// REPEAT
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt);
|
||||
if(!state && error != NULL) {
|
||||
snprintf(error, error_len, "Invalid number %s", line_tmp);
|
||||
}
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
} else if(strncmp(line_tmp, ducky_cmd_sysrq, strlen(ducky_cmd_sysrq)) == 0) {
|
||||
// SYSRQ
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true);
|
||||
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
|
||||
furi_hal_hid_kb_press(key);
|
||||
furi_hal_hid_kb_release_all();
|
||||
return (0);
|
||||
} else {
|
||||
// Special keys + modifiers
|
||||
uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false);
|
||||
if(key == HID_KEYBOARD_NONE) return SCRIPT_STATE_ERROR;
|
||||
if(key == HID_KEYBOARD_NONE) {
|
||||
if(error != NULL) {
|
||||
snprintf(error, error_len, "No keycode defined for %s", line_tmp);
|
||||
}
|
||||
return SCRIPT_STATE_ERROR;
|
||||
}
|
||||
if((key & 0xFF00) != 0) {
|
||||
// It's a modifier key
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
@@ -314,6 +347,9 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
|
||||
furi_hal_hid_kb_release(key);
|
||||
return (0);
|
||||
}
|
||||
if(error != NULL) {
|
||||
strncpy(error, "Unknown error", error_len);
|
||||
}
|
||||
return SCRIPT_STATE_ERROR;
|
||||
}
|
||||
|
||||
@@ -332,7 +368,7 @@ static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) {
|
||||
}
|
||||
FURI_LOG_D(
|
||||
WORKER_TAG,
|
||||
"set id: %04X:%04X mfr:%s product:%s",
|
||||
"set id: %04lX:%04lX mfr:%s product:%s",
|
||||
bad_usb->hid_cfg.vid,
|
||||
bad_usb->hid_cfg.pid,
|
||||
bad_usb->hid_cfg.manuf,
|
||||
@@ -346,7 +382,7 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
|
||||
uint8_t ret = 0;
|
||||
uint32_t line_len = 0;
|
||||
|
||||
string_reset(bad_usb->line);
|
||||
furi_string_reset(bad_usb->line);
|
||||
|
||||
do {
|
||||
ret = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN);
|
||||
@@ -356,7 +392,7 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
|
||||
line_len = 0;
|
||||
} else {
|
||||
if(bad_usb->st.line_nb == 0) { // Save first line
|
||||
string_push_back(bad_usb->line, bad_usb->file_buf[i]);
|
||||
furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]);
|
||||
}
|
||||
line_len++;
|
||||
}
|
||||
@@ -369,7 +405,7 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
|
||||
}
|
||||
} while(ret > 0);
|
||||
|
||||
const char* line_tmp = string_get_cstr(bad_usb->line);
|
||||
const char* line_tmp = furi_string_get_cstr(bad_usb->line);
|
||||
bool id_set = false; // Looking for ID command at first line
|
||||
if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) {
|
||||
id_set = ducky_set_usb_id(bad_usb, &line_tmp[strlen(ducky_cmd_id) + 1]);
|
||||
@@ -382,7 +418,7 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
|
||||
}
|
||||
|
||||
storage_file_seek(script_file, 0, true);
|
||||
string_reset(bad_usb->line);
|
||||
furi_string_reset(bad_usb->line);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -392,20 +428,21 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
|
||||
|
||||
if(bad_usb->repeat_cnt > 0) {
|
||||
bad_usb->repeat_cnt--;
|
||||
delay_val = ducky_parse_line(bad_usb, bad_usb->line_prev);
|
||||
delay_val = ducky_parse_line(
|
||||
bad_usb, bad_usb->line_prev, bad_usb->st.error, sizeof(bad_usb->st.error));
|
||||
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
|
||||
return 0;
|
||||
} else if(delay_val < 0) { // Script error
|
||||
bad_usb->st.error_line = bad_usb->st.line_cur - 1;
|
||||
FURI_LOG_E(WORKER_TAG, "Unknown command at line %lu", bad_usb->st.line_cur - 1);
|
||||
FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur - 1);
|
||||
return SCRIPT_STATE_ERROR;
|
||||
} else {
|
||||
return (delay_val + bad_usb->defdelay);
|
||||
}
|
||||
}
|
||||
|
||||
string_set(bad_usb->line_prev, bad_usb->line);
|
||||
string_reset(bad_usb->line);
|
||||
furi_string_set(bad_usb->line_prev, bad_usb->line);
|
||||
furi_string_reset(bad_usb->line);
|
||||
|
||||
while(1) {
|
||||
if(bad_usb->buf_len == 0) {
|
||||
@@ -422,20 +459,22 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
|
||||
if(bad_usb->buf_len == 0) return SCRIPT_STATE_END;
|
||||
}
|
||||
for(uint8_t i = bad_usb->buf_start; i < (bad_usb->buf_start + bad_usb->buf_len); i++) {
|
||||
if(bad_usb->file_buf[i] == '\n' && string_size(bad_usb->line) > 0) {
|
||||
if(bad_usb->file_buf[i] == '\n' && furi_string_size(bad_usb->line) > 0) {
|
||||
bad_usb->st.line_cur++;
|
||||
bad_usb->buf_len = bad_usb->buf_len + bad_usb->buf_start - (i + 1);
|
||||
bad_usb->buf_start = i + 1;
|
||||
delay_val = ducky_parse_line(bad_usb, bad_usb->line);
|
||||
delay_val = ducky_parse_line(
|
||||
bad_usb, bad_usb->line, bad_usb->st.error, sizeof(bad_usb->st.error));
|
||||
|
||||
if(delay_val < 0) {
|
||||
bad_usb->st.error_line = bad_usb->st.line_cur;
|
||||
FURI_LOG_E(WORKER_TAG, "Unknown command at line %lu", bad_usb->st.line_cur);
|
||||
FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur);
|
||||
return SCRIPT_STATE_ERROR;
|
||||
} else {
|
||||
return (delay_val + bad_usb->defdelay);
|
||||
}
|
||||
} else {
|
||||
string_push_back(bad_usb->line, bad_usb->file_buf[i]);
|
||||
furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]);
|
||||
}
|
||||
}
|
||||
bad_usb->buf_len = 0;
|
||||
@@ -465,8 +504,8 @@ static int32_t bad_usb_worker(void* context) {
|
||||
|
||||
FURI_LOG_I(WORKER_TAG, "Init");
|
||||
File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
|
||||
string_init(bad_usb->line);
|
||||
string_init(bad_usb->line_prev);
|
||||
bad_usb->line = furi_string_alloc();
|
||||
bad_usb->line_prev = furi_string_alloc();
|
||||
|
||||
furi_hal_hid_set_state_callback(bad_usb_hid_state_callback, bad_usb);
|
||||
|
||||
@@ -474,7 +513,7 @@ static int32_t bad_usb_worker(void* context) {
|
||||
if(worker_state == BadUsbStateInit) { // State: initialization
|
||||
if(storage_file_open(
|
||||
script_file,
|
||||
string_get_cstr(bad_usb->file_path),
|
||||
furi_string_get_cstr(bad_usb->file_path),
|
||||
FSAM_READ,
|
||||
FSOM_OPEN_EXISTING)) {
|
||||
if((ducky_script_preload(bad_usb, script_file)) && (bad_usb->st.line_nb > 0)) {
|
||||
@@ -586,8 +625,8 @@ static int32_t bad_usb_worker(void* context) {
|
||||
|
||||
storage_file_close(script_file);
|
||||
storage_file_free(script_file);
|
||||
string_clear(bad_usb->line);
|
||||
string_clear(bad_usb->line_prev);
|
||||
furi_string_free(bad_usb->line);
|
||||
furi_string_free(bad_usb->line_prev);
|
||||
|
||||
FURI_LOG_I(WORKER_TAG, "End");
|
||||
|
||||
@@ -600,15 +639,16 @@ static void bad_usb_script_set_default_keyboard_layout(BadUsbScript* bad_usb) {
|
||||
memcpy(bad_usb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_usb->layout)));
|
||||
}
|
||||
|
||||
BadUsbScript* bad_usb_script_open(string_t file_path) {
|
||||
BadUsbScript* bad_usb_script_open(FuriString* file_path) {
|
||||
furi_assert(file_path);
|
||||
|
||||
BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript));
|
||||
string_init(bad_usb->file_path);
|
||||
string_set(bad_usb->file_path, file_path);
|
||||
bad_usb->file_path = furi_string_alloc();
|
||||
furi_string_set(bad_usb->file_path, file_path);
|
||||
bad_usb_script_set_default_keyboard_layout(bad_usb);
|
||||
|
||||
bad_usb->st.state = BadUsbStateInit;
|
||||
bad_usb->st.error[0] = '\0';
|
||||
|
||||
bad_usb->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(bad_usb->thread, "BadUsbWorker");
|
||||
@@ -625,11 +665,11 @@ void bad_usb_script_close(BadUsbScript* bad_usb) {
|
||||
furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtEnd);
|
||||
furi_thread_join(bad_usb->thread);
|
||||
furi_thread_free(bad_usb->thread);
|
||||
string_clear(bad_usb->file_path);
|
||||
furi_string_free(bad_usb->file_path);
|
||||
free(bad_usb);
|
||||
}
|
||||
|
||||
void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, string_t layout_path) {
|
||||
void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, FuriString* layout_path) {
|
||||
furi_assert(bad_usb);
|
||||
|
||||
if((bad_usb->st.state == BadUsbStateRunning) || (bad_usb->st.state == BadUsbStateDelay)) {
|
||||
@@ -638,9 +678,9 @@ void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, string_t layout_p
|
||||
}
|
||||
|
||||
File* layout_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
|
||||
if(!string_empty_p(layout_path)) {
|
||||
if(!furi_string_empty(layout_path)) {
|
||||
if(storage_file_open(
|
||||
layout_file, string_get_cstr(layout_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
layout_file, furi_string_get_cstr(layout_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
uint16_t layout[128];
|
||||
if(storage_file_read(layout_file, layout, sizeof(layout)) == sizeof(layout)) {
|
||||
memcpy(bad_usb->layout, layout, sizeof(layout));
|
||||
|
||||
@@ -5,7 +5,6 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <furi.h>
|
||||
#include <m-string.h>
|
||||
|
||||
typedef struct BadUsbScript BadUsbScript;
|
||||
|
||||
@@ -26,13 +25,14 @@ typedef struct {
|
||||
uint16_t line_nb;
|
||||
uint32_t delay_remain;
|
||||
uint16_t error_line;
|
||||
char error[64];
|
||||
} BadUsbState;
|
||||
|
||||
BadUsbScript* bad_usb_script_open(string_t file_path);
|
||||
BadUsbScript* bad_usb_script_open(FuriString* file_path);
|
||||
|
||||
void bad_usb_script_close(BadUsbScript* bad_usb);
|
||||
|
||||
void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, string_t layout_path);
|
||||
void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, FuriString* layout_path);
|
||||
|
||||
void bad_usb_script_start(BadUsbScript* bad_usb);
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
static bool bad_usb_layout_select(BadUsbApp* bad_usb) {
|
||||
furi_assert(bad_usb);
|
||||
|
||||
string_t predefined_path;
|
||||
string_init(predefined_path);
|
||||
if(!string_empty_p(bad_usb->keyboard_layout)) {
|
||||
string_set(predefined_path, bad_usb->keyboard_layout);
|
||||
FuriString* predefined_path;
|
||||
predefined_path = furi_string_alloc();
|
||||
if(!furi_string_empty(bad_usb->keyboard_layout)) {
|
||||
furi_string_set(predefined_path, bad_usb->keyboard_layout);
|
||||
} else {
|
||||
string_set_str(predefined_path, BAD_USB_APP_PATH_LAYOUT_FOLDER);
|
||||
furi_string_set(predefined_path, BAD_USB_APP_PATH_LAYOUT_FOLDER);
|
||||
}
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
@@ -22,7 +22,7 @@ static bool bad_usb_layout_select(BadUsbApp* bad_usb) {
|
||||
bool res = dialog_file_browser_show(
|
||||
bad_usb->dialogs, bad_usb->keyboard_layout, predefined_path, &browser_options);
|
||||
|
||||
string_clear(predefined_path);
|
||||
furi_string_free(predefined_path);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ static bool bad_usb_file_select(BadUsbApp* bad_usb) {
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(
|
||||
&browser_options, BAD_USB_APP_SCRIPT_EXTENSION, &I_badusb_10px);
|
||||
browser_options.skip_assets = true;
|
||||
|
||||
// Input events and views are managed by file_browser
|
||||
bool res = dialog_file_browser_show(
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "../bad_usb_app_i.h"
|
||||
#include "../views/bad_usb_view.h"
|
||||
#include "furi_hal.h"
|
||||
#include "m-string.h"
|
||||
#include "toolbox/path.h"
|
||||
|
||||
void bad_usb_scene_work_button_callback(InputKey key, void* context) {
|
||||
@@ -32,17 +31,17 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
|
||||
void bad_usb_scene_work_on_enter(void* context) {
|
||||
BadUsbApp* app = context;
|
||||
|
||||
string_t file_name;
|
||||
string_init(file_name);
|
||||
FuriString* file_name;
|
||||
file_name = furi_string_alloc();
|
||||
path_extract_filename(app->file_path, file_name, true);
|
||||
bad_usb_set_file_name(app->bad_usb_view, string_get_cstr(file_name));
|
||||
string_clear(file_name);
|
||||
bad_usb_set_file_name(app->bad_usb_view, furi_string_get_cstr(file_name));
|
||||
furi_string_free(file_name);
|
||||
|
||||
string_t layout;
|
||||
string_init(layout);
|
||||
FuriString* layout;
|
||||
layout = furi_string_alloc();
|
||||
path_extract_filename(app->keyboard_layout, layout, true);
|
||||
bad_usb_set_layout(app->bad_usb_view, string_get_cstr(layout));
|
||||
string_clear(layout);
|
||||
bad_usb_set_layout(app->bad_usb_view, furi_string_get_cstr(layout));
|
||||
furi_string_free(layout);
|
||||
|
||||
bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script));
|
||||
|
||||
|
||||
@@ -21,25 +21,26 @@ typedef struct {
|
||||
static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
|
||||
BadUsbModel* model = _model;
|
||||
|
||||
string_t disp_str;
|
||||
string_init_set_str(disp_str, model->file_name);
|
||||
FuriString* disp_str;
|
||||
disp_str = furi_string_alloc_set(model->file_name);
|
||||
elements_string_fit_width(canvas, disp_str, 128 - 2);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 2, 8, string_get_cstr(disp_str));
|
||||
canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str));
|
||||
|
||||
if(strlen(model->layout) == 0) {
|
||||
string_set(disp_str, "(default)");
|
||||
furi_string_set(disp_str, "(default)");
|
||||
} else {
|
||||
string_reset(disp_str);
|
||||
string_push_back(disp_str, '(');
|
||||
furi_string_reset(disp_str);
|
||||
furi_string_push_back(disp_str, '(');
|
||||
for(size_t i = 0; i < strlen(model->layout); i++)
|
||||
string_push_back(disp_str, model->layout[i]);
|
||||
string_push_back(disp_str, ')');
|
||||
furi_string_push_back(disp_str, model->layout[i]);
|
||||
furi_string_push_back(disp_str, ')');
|
||||
}
|
||||
elements_string_fit_width(canvas, disp_str, 128 - 2);
|
||||
canvas_draw_str(canvas, 2, 8 + canvas_current_font_height(canvas), string_get_cstr(disp_str));
|
||||
canvas_draw_str(
|
||||
canvas, 2, 8 + canvas_current_font_height(canvas), furi_string_get_cstr(disp_str));
|
||||
|
||||
string_reset(disp_str);
|
||||
furi_string_reset(disp_str);
|
||||
|
||||
canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22);
|
||||
|
||||
@@ -69,10 +70,11 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
string_printf(disp_str, "line %u", model->state.error_line);
|
||||
furi_string_printf(disp_str, "line %u", model->state.error_line);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 127, 46, AlignRight, AlignBottom, string_get_cstr(disp_str));
|
||||
string_reset(disp_str);
|
||||
canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
||||
furi_string_reset(disp_str);
|
||||
canvas_draw_str_aligned(canvas, 127, 56, AlignRight, AlignBottom, model->state.error);
|
||||
} else if(model->state.state == BadUsbStateIdle) {
|
||||
canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18);
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
@@ -85,16 +87,17 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
|
||||
canvas_draw_icon(canvas, 4, 23, &I_EviSmile2_18x21);
|
||||
}
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
string_printf(disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb);
|
||||
furi_string_printf(
|
||||
disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 114, 40, AlignRight, AlignBottom, string_get_cstr(disp_str));
|
||||
string_reset(disp_str);
|
||||
canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
||||
furi_string_reset(disp_str);
|
||||
canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14);
|
||||
} else if(model->state.state == BadUsbStateDone) {
|
||||
canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21);
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "100");
|
||||
string_reset(disp_str);
|
||||
furi_string_reset(disp_str);
|
||||
canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14);
|
||||
} else if(model->state.state == BadUsbStateDelay) {
|
||||
if(model->anim_frame == 0) {
|
||||
@@ -103,21 +106,22 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
|
||||
canvas_draw_icon(canvas, 4, 23, &I_EviWaiting2_18x21);
|
||||
}
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
string_printf(disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb);
|
||||
furi_string_printf(
|
||||
disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 114, 40, AlignRight, AlignBottom, string_get_cstr(disp_str));
|
||||
string_reset(disp_str);
|
||||
canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
||||
furi_string_reset(disp_str);
|
||||
canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
string_printf(disp_str, "delay %us", model->state.delay_remain);
|
||||
furi_string_printf(disp_str, "delay %lus", model->state.delay_remain);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 127, 50, AlignRight, AlignBottom, string_get_cstr(disp_str));
|
||||
string_reset(disp_str);
|
||||
canvas, 127, 50, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
||||
furi_string_reset(disp_str);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
|
||||
}
|
||||
|
||||
string_clear(disp_str);
|
||||
furi_string_free(disp_str);
|
||||
}
|
||||
|
||||
static bool bad_usb_input_callback(InputEvent* event, void* context) {
|
||||
@@ -163,37 +167,41 @@ void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback,
|
||||
furi_assert(bad_usb);
|
||||
furi_assert(callback);
|
||||
with_view_model(
|
||||
bad_usb->view, (BadUsbModel * model) {
|
||||
bad_usb->view,
|
||||
BadUsbModel * model,
|
||||
{
|
||||
UNUSED(model);
|
||||
bad_usb->callback = callback;
|
||||
bad_usb->context = context;
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) {
|
||||
furi_assert(name);
|
||||
with_view_model(
|
||||
bad_usb->view, (BadUsbModel * model) {
|
||||
strlcpy(model->file_name, name, MAX_NAME_LEN);
|
||||
return true;
|
||||
});
|
||||
bad_usb->view,
|
||||
BadUsbModel * model,
|
||||
{ strlcpy(model->file_name, name, MAX_NAME_LEN); },
|
||||
true);
|
||||
}
|
||||
|
||||
void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) {
|
||||
furi_assert(layout);
|
||||
with_view_model(
|
||||
bad_usb->view, (BadUsbModel * model) {
|
||||
strlcpy(model->layout, layout, MAX_NAME_LEN);
|
||||
return true;
|
||||
});
|
||||
bad_usb->view,
|
||||
BadUsbModel * model,
|
||||
{ strlcpy(model->layout, layout, MAX_NAME_LEN); },
|
||||
true);
|
||||
}
|
||||
void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) {
|
||||
furi_assert(st);
|
||||
with_view_model(
|
||||
bad_usb->view, (BadUsbModel * model) {
|
||||
bad_usb->view,
|
||||
BadUsbModel * model,
|
||||
{
|
||||
memcpy(&(model->state), st, sizeof(BadUsbState));
|
||||
model->anim_frame ^= 1;
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ static void clock_render_callback(Canvas* const canvas, void* ctx) {
|
||||
time_string, TIME_LEN, CLOCK_TIME_FORMAT, curr_dt.hour, curr_dt.minute, curr_dt.second);
|
||||
} else {
|
||||
bool pm = curr_dt.hour > 12;
|
||||
bool pm12 = curr_dt.hour >= 12;
|
||||
snprintf(
|
||||
time_string,
|
||||
TIME_LEN,
|
||||
@@ -50,7 +51,7 @@ static void clock_render_callback(Canvas* const canvas, void* ctx) {
|
||||
meridian_string,
|
||||
MERIDIAN_LEN,
|
||||
MERIDIAN_FORMAT,
|
||||
pm ? MERIDIAN_STRING_PM : MERIDIAN_STRING_AM);
|
||||
pm12 ? MERIDIAN_STRING_PM : MERIDIAN_STRING_AM);
|
||||
}
|
||||
|
||||
if(state->settings.date_format == Iso) {
|
||||
|
||||
@@ -33,5 +33,4 @@ typedef enum {
|
||||
typedef struct {
|
||||
TimeFormat time_format;
|
||||
DateFormat date_format;
|
||||
uint8_t increment_precision;
|
||||
} ClockSettings;
|
||||
@@ -3,6 +3,7 @@ App(
|
||||
name="Applications",
|
||||
apptype=FlipperAppType.APP,
|
||||
entry_point="fap_loader_app",
|
||||
cdefines=["APP_FAP_LOADER"],
|
||||
requires=[
|
||||
"gui",
|
||||
"storage",
|
||||
|
||||
@@ -31,7 +31,7 @@ bool elf_resolve_from_hashtable(const char* name, Elf32_Addr* address) {
|
||||
|
||||
auto find_res = std::lower_bound(elf_api_table.cbegin(), elf_api_table.cend(), key);
|
||||
if((find_res == elf_api_table.cend() || (find_res->hash != gnu_sym_hash))) {
|
||||
FURI_LOG_W(TAG, "Cant find symbol '%s' (hash %x)!", name, gnu_sym_hash);
|
||||
FURI_LOG_W(TAG, "Cant find symbol '%s' (hash %lx)!", name, gnu_sym_hash);
|
||||
result = false;
|
||||
} else {
|
||||
result = true;
|
||||
|
||||
@@ -1,31 +1,34 @@
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/loading.h>
|
||||
#include <storage/storage.h>
|
||||
#include <gui/modules/loading.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include "elf_cpp/elf_hashtable.h"
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include "elf_cpp/elf_hashtable.h"
|
||||
#include "fap_loader_app.h"
|
||||
|
||||
#define TAG "fap_loader_app"
|
||||
|
||||
typedef struct {
|
||||
struct FapLoader {
|
||||
FlipperApplication* app;
|
||||
Storage* storage;
|
||||
DialogsApp* dialogs;
|
||||
Gui* gui;
|
||||
string_t fap_path;
|
||||
} FapLoader;
|
||||
FuriString* fap_path;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Loading* loading;
|
||||
};
|
||||
|
||||
static bool
|
||||
fap_loader_item_callback(string_t path, void* context, uint8_t** icon_ptr, string_t item_name) {
|
||||
FapLoader* loader = context;
|
||||
furi_assert(loader);
|
||||
|
||||
FlipperApplication* app = flipper_application_alloc(loader->storage, &hashtable_api_interface);
|
||||
bool fap_loader_load_name_and_icon(
|
||||
FuriString* path,
|
||||
Storage* storage,
|
||||
uint8_t** icon_ptr,
|
||||
FuriString* item_name) {
|
||||
FlipperApplication* app = flipper_application_alloc(storage, &hashtable_api_interface);
|
||||
|
||||
FlipperApplicationPreloadStatus preload_res =
|
||||
flipper_application_preload(app, string_get_cstr(path));
|
||||
flipper_application_preload_manifest(app, furi_string_get_cstr(path));
|
||||
|
||||
bool load_success = false;
|
||||
|
||||
@@ -34,10 +37,10 @@ static bool
|
||||
if(manifest->has_icon) {
|
||||
memcpy(*icon_ptr, manifest->icon, FAP_MANIFEST_MAX_ICON_SIZE);
|
||||
}
|
||||
string_set_str(item_name, manifest->name);
|
||||
furi_string_set(item_name, manifest->name);
|
||||
load_success = true;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "FAP Loader failed to preload %s", string_get_cstr(path));
|
||||
FURI_LOG_E(TAG, "FAP Loader failed to preload %s", furi_string_get_cstr(path));
|
||||
load_success = false;
|
||||
}
|
||||
|
||||
@@ -45,30 +48,41 @@ static bool
|
||||
return load_success;
|
||||
}
|
||||
|
||||
static bool fap_loader_item_callback(
|
||||
FuriString* path,
|
||||
void* context,
|
||||
uint8_t** icon_ptr,
|
||||
FuriString* item_name) {
|
||||
FapLoader* fap_loader = context;
|
||||
furi_assert(fap_loader);
|
||||
return fap_loader_load_name_and_icon(path, fap_loader->storage, icon_ptr, item_name);
|
||||
}
|
||||
|
||||
static bool fap_loader_run_selected_app(FapLoader* loader) {
|
||||
furi_assert(loader);
|
||||
|
||||
string_t error_message;
|
||||
FuriString* error_message;
|
||||
|
||||
string_init_set(error_message, "unknown error");
|
||||
error_message = furi_string_alloc_set("unknown error");
|
||||
|
||||
bool file_selected = false;
|
||||
bool show_error = true;
|
||||
do {
|
||||
file_selected = true;
|
||||
loader->app = flipper_application_alloc(loader->storage, &hashtable_api_interface);
|
||||
size_t start = furi_get_tick();
|
||||
|
||||
FURI_LOG_I(TAG, "FAP Loader is loading %s", string_get_cstr(loader->fap_path));
|
||||
FURI_LOG_I(TAG, "FAP Loader is loading %s", furi_string_get_cstr(loader->fap_path));
|
||||
|
||||
FlipperApplicationPreloadStatus preload_res =
|
||||
flipper_application_preload(loader->app, string_get_cstr(loader->fap_path));
|
||||
flipper_application_preload(loader->app, furi_string_get_cstr(loader->fap_path));
|
||||
if(preload_res != FlipperApplicationPreloadStatusSuccess) {
|
||||
const char* err_msg = flipper_application_preload_status_to_string(preload_res);
|
||||
string_printf(error_message, "Preload failed: %s", err_msg);
|
||||
furi_string_printf(error_message, "Preload failed: %s", err_msg);
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"FAP Loader failed to preload %s: %s",
|
||||
string_get_cstr(loader->fap_path),
|
||||
furi_string_get_cstr(loader->fap_path),
|
||||
err_msg);
|
||||
break;
|
||||
}
|
||||
@@ -77,16 +91,17 @@ static bool fap_loader_run_selected_app(FapLoader* loader) {
|
||||
FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(loader->app);
|
||||
if(load_status != FlipperApplicationLoadStatusSuccess) {
|
||||
const char* err_msg = flipper_application_load_status_to_string(load_status);
|
||||
string_printf(error_message, "Load failed: %s", err_msg);
|
||||
furi_string_printf(error_message, "Load failed: %s", err_msg);
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"FAP Loader failed to map to memory %s: %s",
|
||||
string_get_cstr(loader->fap_path),
|
||||
furi_string_get_cstr(loader->fap_path),
|
||||
err_msg);
|
||||
break;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "FAP Loader is staring app");
|
||||
FURI_LOG_I(TAG, "Loaded in %ums", (size_t)(furi_get_tick() - start));
|
||||
FURI_LOG_I(TAG, "FAP Loader is starting app");
|
||||
|
||||
FuriThread* thread = flipper_application_spawn(loader->app, NULL);
|
||||
furi_thread_start(thread);
|
||||
@@ -103,19 +118,19 @@ static bool fap_loader_run_selected_app(FapLoader* loader) {
|
||||
dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_message_set_buttons(message, NULL, NULL, NULL);
|
||||
|
||||
string_t buffer;
|
||||
string_init(buffer);
|
||||
string_printf(buffer, "%s", string_get_cstr(error_message));
|
||||
string_replace_str(buffer, ":", "\n");
|
||||
FuriString* buffer;
|
||||
buffer = furi_string_alloc();
|
||||
furi_string_printf(buffer, "%s", furi_string_get_cstr(error_message));
|
||||
furi_string_replace(buffer, ":", "\n");
|
||||
dialog_message_set_text(
|
||||
message, string_get_cstr(buffer), 64, 32, AlignCenter, AlignCenter);
|
||||
message, furi_string_get_cstr(buffer), 64, 32, AlignCenter, AlignCenter);
|
||||
|
||||
dialog_message_show(loader->dialogs, message);
|
||||
dialog_message_free(message);
|
||||
string_clear(buffer);
|
||||
furi_string_free(buffer);
|
||||
}
|
||||
|
||||
string_clear(error_message);
|
||||
furi_string_free(error_message);
|
||||
|
||||
if(file_selected) {
|
||||
flipper_application_free(loader->app);
|
||||
@@ -128,7 +143,7 @@ static bool fap_loader_select_app(FapLoader* loader) {
|
||||
const DialogsFileBrowserOptions browser_options = {
|
||||
.extension = ".fap",
|
||||
.skip_assets = true,
|
||||
.icon = &I_badusb_10px,
|
||||
.icon = &I_unknown_10px,
|
||||
.hide_ext = true,
|
||||
.item_loader_callback = fap_loader_item_callback,
|
||||
.item_loader_context = loader,
|
||||
@@ -138,39 +153,45 @@ static bool fap_loader_select_app(FapLoader* loader) {
|
||||
loader->dialogs, loader->fap_path, loader->fap_path, &browser_options);
|
||||
}
|
||||
|
||||
int32_t fap_loader_app(void* p) {
|
||||
static FapLoader* fap_loader_alloc(const char* path) {
|
||||
FapLoader* loader = malloc(sizeof(FapLoader));
|
||||
loader->fap_path = furi_string_alloc_set(path);
|
||||
loader->storage = furi_record_open(RECORD_STORAGE);
|
||||
loader->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
loader->gui = furi_record_open(RECORD_GUI);
|
||||
loader->view_dispatcher = view_dispatcher_alloc();
|
||||
loader->loading = loading_alloc();
|
||||
view_dispatcher_attach_to_gui(
|
||||
loader->view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_add_view(loader->view_dispatcher, 0, loading_get_view(loader->loading));
|
||||
return loader;
|
||||
}
|
||||
|
||||
ViewDispatcher* view_dispatcher = view_dispatcher_alloc();
|
||||
Loading* loading = loading_alloc();
|
||||
|
||||
view_dispatcher_enable_queue(view_dispatcher);
|
||||
view_dispatcher_attach_to_gui(view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_add_view(view_dispatcher, 0, loading_get_view(loading));
|
||||
|
||||
if(p) {
|
||||
string_init_set(loader->fap_path, (const char*)p);
|
||||
fap_loader_run_selected_app(loader);
|
||||
} else {
|
||||
string_init_set(loader->fap_path, EXT_PATH("apps"));
|
||||
|
||||
while(fap_loader_select_app(loader)) {
|
||||
view_dispatcher_switch_to_view(view_dispatcher, 0);
|
||||
fap_loader_run_selected_app(loader);
|
||||
};
|
||||
}
|
||||
|
||||
view_dispatcher_remove_view(view_dispatcher, 0);
|
||||
loading_free(loading);
|
||||
view_dispatcher_free(view_dispatcher);
|
||||
|
||||
string_clear(loader->fap_path);
|
||||
static void fap_loader_free(FapLoader* loader) {
|
||||
view_dispatcher_remove_view(loader->view_dispatcher, 0);
|
||||
loading_free(loader->loading);
|
||||
view_dispatcher_free(loader->view_dispatcher);
|
||||
furi_string_free(loader->fap_path);
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
free(loader);
|
||||
}
|
||||
|
||||
int32_t fap_loader_app(void* p) {
|
||||
FapLoader* loader;
|
||||
if(p) {
|
||||
loader = fap_loader_alloc((const char*)p);
|
||||
view_dispatcher_switch_to_view(loader->view_dispatcher, 0);
|
||||
fap_loader_run_selected_app(loader);
|
||||
} else {
|
||||
loader = fap_loader_alloc(EXT_PATH("apps"));
|
||||
while(fap_loader_select_app(loader)) {
|
||||
view_dispatcher_switch_to_view(loader->view_dispatcher, 0);
|
||||
fap_loader_run_selected_app(loader);
|
||||
};
|
||||
}
|
||||
|
||||
fap_loader_free(loader);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
27
applications/main/fap_loader/fap_loader_app.h
Normal file
27
applications/main/fap_loader/fap_loader_app.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include <storage/storage.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct FapLoader FapLoader;
|
||||
|
||||
/**
|
||||
* @brief Load name and icon from FAP file.
|
||||
*
|
||||
* @param path Path to FAP file.
|
||||
* @param storage Storage instance.
|
||||
* @param icon_ptr Icon pointer.
|
||||
* @param item_name Application name.
|
||||
* @return true if icon and name were loaded successfully.
|
||||
*/
|
||||
bool fap_loader_load_name_and_icon(
|
||||
FuriString* path,
|
||||
Storage* storage,
|
||||
uint8_t** icon_ptr,
|
||||
FuriString* item_name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "../gpio_app_i.h"
|
||||
#include "furi_hal_power.h"
|
||||
#include "furi_hal_usb.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
enum GpioItem {
|
||||
GpioItemUsbUart,
|
||||
@@ -88,6 +89,7 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
} else if(event.event == GpioStartEventUsbUart) {
|
||||
scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemUsbUart);
|
||||
if(!furi_hal_usb_is_locked()) {
|
||||
DOLPHIN_DEED(DolphinDeedGpioUartBridge);
|
||||
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUart);
|
||||
} else {
|
||||
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCloseRpc);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "usb_uart_bridge.h"
|
||||
#include "furi_hal.h"
|
||||
#include <stream_buffer.h>
|
||||
#include <furi_hal_usb_cdc.h>
|
||||
#include "usb_cdc.h"
|
||||
#include "cli/cli_vcp.h"
|
||||
@@ -43,7 +42,7 @@ struct UsbUartBridge {
|
||||
FuriThread* thread;
|
||||
FuriThread* tx_thread;
|
||||
|
||||
StreamBufferHandle_t rx_stream;
|
||||
FuriStreamBuffer* rx_stream;
|
||||
|
||||
FuriMutex* usb_mutex;
|
||||
|
||||
@@ -74,12 +73,10 @@ static int32_t usb_uart_tx_thread(void* context);
|
||||
|
||||
static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) {
|
||||
UsbUartBridge* usb_uart = (UsbUartBridge*)context;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
if(ev == UartIrqEventRXNE) {
|
||||
xStreamBufferSendFromISR(usb_uart->rx_stream, &data, 1, &xHigherPriorityTaskWoken);
|
||||
furi_stream_buffer_send(usb_uart->rx_stream, &data, 1, 0);
|
||||
furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtRxDone);
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +153,7 @@ static int32_t usb_uart_worker(void* context) {
|
||||
|
||||
memcpy(&usb_uart->cfg, &usb_uart->cfg_new, sizeof(UsbUartConfig));
|
||||
|
||||
usb_uart->rx_stream = xStreamBufferCreate(USB_UART_RX_BUF_SIZE, 1);
|
||||
usb_uart->rx_stream = furi_stream_buffer_alloc(USB_UART_RX_BUF_SIZE, 1);
|
||||
|
||||
usb_uart->tx_sem = furi_semaphore_alloc(1, 1);
|
||||
usb_uart->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
@@ -189,8 +186,8 @@ static int32_t usb_uart_worker(void* context) {
|
||||
furi_check((events & FuriFlagError) == 0);
|
||||
if(events & WorkerEvtStop) break;
|
||||
if(events & WorkerEvtRxDone) {
|
||||
size_t len =
|
||||
xStreamBufferReceive(usb_uart->rx_stream, usb_uart->rx_buf, USB_CDC_PKT_LEN, 0);
|
||||
size_t len = furi_stream_buffer_receive(
|
||||
usb_uart->rx_stream, usb_uart->rx_buf, USB_CDC_PKT_LEN, 0);
|
||||
if(len > 0) {
|
||||
if(furi_semaphore_acquire(usb_uart->tx_sem, 100) == FuriStatusOk) {
|
||||
usb_uart->st.rx_cnt += len;
|
||||
@@ -199,7 +196,7 @@ static int32_t usb_uart_worker(void* context) {
|
||||
furi_hal_cdc_send(usb_uart->cfg.vcp_ch, usb_uart->rx_buf, len);
|
||||
furi_check(furi_mutex_release(usb_uart->usb_mutex) == FuriStatusOk);
|
||||
} else {
|
||||
xStreamBufferReset(usb_uart->rx_stream);
|
||||
furi_stream_buffer_reset(usb_uart->rx_stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,7 +267,7 @@ static int32_t usb_uart_worker(void* context) {
|
||||
furi_thread_join(usb_uart->tx_thread);
|
||||
furi_thread_free(usb_uart->tx_thread);
|
||||
|
||||
vStreamBufferDelete(usb_uart->rx_stream);
|
||||
furi_stream_buffer_free(usb_uart->rx_stream);
|
||||
furi_mutex_free(usb_uart->usb_mutex);
|
||||
furi_semaphore_free(usb_uart->tx_sem);
|
||||
|
||||
|
||||
@@ -48,23 +48,27 @@ static bool gpio_test_input_callback(InputEvent* event, void* context) {
|
||||
|
||||
static bool gpio_test_process_left(GpioTest* gpio_test) {
|
||||
with_view_model(
|
||||
gpio_test->view, (GpioTestModel * model) {
|
||||
gpio_test->view,
|
||||
GpioTestModel * model,
|
||||
{
|
||||
if(model->pin_idx) {
|
||||
model->pin_idx--;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gpio_test_process_right(GpioTest* gpio_test) {
|
||||
with_view_model(
|
||||
gpio_test->view, (GpioTestModel * model) {
|
||||
gpio_test->view,
|
||||
GpioTestModel * model,
|
||||
{
|
||||
if(model->pin_idx < GPIO_ITEM_COUNT) {
|
||||
model->pin_idx++;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -72,7 +76,9 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
with_view_model(
|
||||
gpio_test->view, (GpioTestModel * model) {
|
||||
gpio_test->view,
|
||||
GpioTestModel * model,
|
||||
{
|
||||
if(event->type == InputTypePress) {
|
||||
if(model->pin_idx < GPIO_ITEM_COUNT) {
|
||||
gpio_item_set_pin(model->pin_idx, true);
|
||||
@@ -89,8 +95,8 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) {
|
||||
consumed = true;
|
||||
}
|
||||
gpio_test->callback(event->type, gpio_test->context);
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
|
||||
return consumed;
|
||||
}
|
||||
@@ -122,10 +128,12 @@ void gpio_test_set_ok_callback(GpioTest* gpio_test, GpioTestOkCallback callback,
|
||||
furi_assert(gpio_test);
|
||||
furi_assert(callback);
|
||||
with_view_model(
|
||||
gpio_test->view, (GpioTestModel * model) {
|
||||
gpio_test->view,
|
||||
GpioTestModel * model,
|
||||
{
|
||||
UNUSED(model);
|
||||
gpio_test->callback = callback;
|
||||
gpio_test->context = context;
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ static void gpio_usb_uart_draw_callback(Canvas* canvas, void* _model) {
|
||||
canvas_draw_str_aligned(canvas, 116, 24, AlignRight, AlignBottom, temp_str);
|
||||
} else {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 127, 24, AlignRight, AlignBottom, "KB.");
|
||||
canvas_draw_str_aligned(canvas, 127, 24, AlignRight, AlignBottom, "KiB.");
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
snprintf(temp_str, 18, "%lu", model->tx_cnt / 1024);
|
||||
canvas_draw_str_aligned(canvas, 111, 24, AlignRight, AlignBottom, temp_str);
|
||||
@@ -68,7 +68,7 @@ static void gpio_usb_uart_draw_callback(Canvas* canvas, void* _model) {
|
||||
canvas_draw_str_aligned(canvas, 116, 41, AlignRight, AlignBottom, temp_str);
|
||||
} else {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 127, 41, AlignRight, AlignBottom, "KB.");
|
||||
canvas_draw_str_aligned(canvas, 127, 41, AlignRight, AlignBottom, "KiB.");
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
snprintf(temp_str, 18, "%lu", model->rx_cnt / 1024);
|
||||
canvas_draw_str_aligned(canvas, 111, 41, AlignRight, AlignBottom, temp_str);
|
||||
@@ -129,12 +129,14 @@ void gpio_usb_uart_set_callback(GpioUsbUart* usb_uart, GpioUsbUartCallback callb
|
||||
furi_assert(callback);
|
||||
|
||||
with_view_model(
|
||||
usb_uart->view, (GpioUsbUartModel * model) {
|
||||
usb_uart->view,
|
||||
GpioUsbUartModel * model,
|
||||
{
|
||||
UNUSED(model);
|
||||
usb_uart->callback = callback;
|
||||
usb_uart->context = context;
|
||||
return false;
|
||||
});
|
||||
},
|
||||
false);
|
||||
}
|
||||
|
||||
void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUartState* st) {
|
||||
@@ -143,7 +145,9 @@ void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUa
|
||||
furi_assert(st);
|
||||
|
||||
with_view_model(
|
||||
instance->view, (GpioUsbUartModel * model) {
|
||||
instance->view,
|
||||
GpioUsbUartModel * model,
|
||||
{
|
||||
model->baudrate = st->baudrate_cur;
|
||||
model->vcp_port = cfg->vcp_ch;
|
||||
model->tx_pin = (cfg->uart_ch == 0) ? (13) : (15);
|
||||
@@ -152,6 +156,6 @@ void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUa
|
||||
model->rx_active = (model->rx_cnt != st->rx_cnt);
|
||||
model->tx_cnt = st->tx_cnt;
|
||||
model->rx_cnt = st->rx_cnt;
|
||||
return true;
|
||||
});
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "assets_icons.h"
|
||||
#include "ibutton_i.h"
|
||||
#include "ibutton/scenes/ibutton_scene.h"
|
||||
#include "m-string.h"
|
||||
#include <toolbox/path.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <rpc/rpc_app.h>
|
||||
@@ -39,25 +38,25 @@ static void ibutton_make_app_folder(iButton* ibutton) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show_dialog) {
|
||||
bool ibutton_load_key_data(iButton* ibutton, FuriString* key_path, bool show_dialog) {
|
||||
FlipperFormat* file = flipper_format_file_alloc(ibutton->storage);
|
||||
bool result = false;
|
||||
string_t data;
|
||||
string_init(data);
|
||||
FuriString* data;
|
||||
data = furi_string_alloc();
|
||||
|
||||
do {
|
||||
if(!flipper_format_file_open_existing(file, string_get_cstr(key_path))) break;
|
||||
if(!flipper_format_file_open_existing(file, furi_string_get_cstr(key_path))) break;
|
||||
|
||||
// header
|
||||
uint32_t version;
|
||||
if(!flipper_format_read_header(file, data, &version)) break;
|
||||
if(string_cmp_str(data, IBUTTON_APP_FILE_TYPE) != 0) break;
|
||||
if(furi_string_cmp_str(data, IBUTTON_APP_FILE_TYPE) != 0) break;
|
||||
if(version != 1) break;
|
||||
|
||||
// key type
|
||||
iButtonKeyType type;
|
||||
if(!flipper_format_read_string(file, "Key type", data)) break;
|
||||
if(!ibutton_key_get_type_by_string(string_get_cstr(data), &type)) break;
|
||||
if(!ibutton_key_get_type_by_string(furi_string_get_cstr(data), &type)) break;
|
||||
|
||||
// key data
|
||||
uint8_t key_data[IBUTTON_KEY_DATA_SIZE] = {0};
|
||||
@@ -71,7 +70,7 @@ bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show_dialog
|
||||
} while(false);
|
||||
|
||||
flipper_format_free(file);
|
||||
string_clear(data);
|
||||
furi_string_free(data);
|
||||
|
||||
if((!result) && (show_dialog)) {
|
||||
dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file");
|
||||
@@ -119,7 +118,7 @@ void ibutton_tick_event_callback(void* context) {
|
||||
iButton* ibutton_alloc() {
|
||||
iButton* ibutton = malloc(sizeof(iButton));
|
||||
|
||||
string_init(ibutton->file_path);
|
||||
ibutton->file_path = furi_string_alloc();
|
||||
|
||||
ibutton->scene_manager = scene_manager_alloc(&ibutton_scene_handlers, ibutton);
|
||||
|
||||
@@ -210,7 +209,7 @@ void ibutton_free(iButton* ibutton) {
|
||||
ibutton_worker_free(ibutton->key_worker);
|
||||
ibutton_key_free(ibutton->key);
|
||||
|
||||
string_clear(ibutton->file_path);
|
||||
furi_string_free(ibutton->file_path);
|
||||
|
||||
free(ibutton);
|
||||
}
|
||||
@@ -240,19 +239,19 @@ bool ibutton_save_key(iButton* ibutton, const char* key_name) {
|
||||
|
||||
do {
|
||||
// Check if we has old key
|
||||
if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
|
||||
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
|
||||
// First remove old key
|
||||
ibutton_delete_key(ibutton);
|
||||
|
||||
// Remove old key name from path
|
||||
size_t filename_start = string_search_rchar(ibutton->file_path, '/');
|
||||
string_left(ibutton->file_path, filename_start);
|
||||
size_t filename_start = furi_string_search_rchar(ibutton->file_path, '/');
|
||||
furi_string_left(ibutton->file_path, filename_start);
|
||||
}
|
||||
|
||||
string_cat_printf(ibutton->file_path, "/%s%s", key_name, IBUTTON_APP_EXTENSION);
|
||||
furi_string_cat_printf(ibutton->file_path, "/%s%s", key_name, IBUTTON_APP_EXTENSION);
|
||||
|
||||
// Open file for write
|
||||
if(!flipper_format_file_open_always(file, string_get_cstr(ibutton->file_path))) break;
|
||||
if(!flipper_format_file_open_always(file, furi_string_get_cstr(ibutton->file_path))) break;
|
||||
|
||||
// Write header
|
||||
if(!flipper_format_write_header_cstr(file, IBUTTON_APP_FILE_TYPE, 1)) break;
|
||||
@@ -286,7 +285,7 @@ bool ibutton_save_key(iButton* ibutton, const char* key_name) {
|
||||
|
||||
bool ibutton_delete_key(iButton* ibutton) {
|
||||
bool result = false;
|
||||
result = storage_simply_remove(ibutton->storage, string_get_cstr(ibutton->file_path));
|
||||
result = storage_simply_remove(ibutton->storage, furi_string_get_cstr(ibutton->file_path));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -326,7 +325,7 @@ int32_t ibutton_app(void* p) {
|
||||
rpc_system_app_set_callback(ibutton->rpc_ctx, ibutton_rpc_command_callback, ibutton);
|
||||
rpc_system_app_send_started(ibutton->rpc_ctx);
|
||||
} else {
|
||||
string_set_str(ibutton->file_path, (const char*)p);
|
||||
furi_string_set(ibutton->file_path, (const char*)p);
|
||||
if(ibutton_load_key_data(ibutton, ibutton->file_path, true)) {
|
||||
key_loaded = true;
|
||||
// TODO: Display an error if the key from p could not be loaded
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#include <one_wire/ibutton/ibutton_worker.h>
|
||||
#include <one_wire/one_wire_host.h>
|
||||
|
||||
static void ibutton_cli(Cli* cli, string_t args, void* context);
|
||||
static void onewire_cli(Cli* cli, string_t args, void* context);
|
||||
static void ibutton_cli(Cli* cli, FuriString* args, void* context);
|
||||
static void onewire_cli(Cli* cli, FuriString* args, void* context);
|
||||
|
||||
// app cli function
|
||||
void ibutton_on_system_start() {
|
||||
@@ -34,16 +34,16 @@ void ibutton_cli_print_usage() {
|
||||
printf("\t<key_data> are hex-formatted\r\n");
|
||||
};
|
||||
|
||||
bool ibutton_cli_get_key_type(string_t data, iButtonKeyType* type) {
|
||||
bool ibutton_cli_get_key_type(FuriString* data, iButtonKeyType* type) {
|
||||
bool result = false;
|
||||
|
||||
if(string_cmp_str(data, "Dallas") == 0 || string_cmp_str(data, "dallas") == 0) {
|
||||
if(furi_string_cmp_str(data, "Dallas") == 0 || furi_string_cmp_str(data, "dallas") == 0) {
|
||||
result = true;
|
||||
*type = iButtonKeyDS1990;
|
||||
} else if(string_cmp_str(data, "Cyfral") == 0 || string_cmp_str(data, "cyfral") == 0) {
|
||||
} else if(furi_string_cmp_str(data, "Cyfral") == 0 || furi_string_cmp_str(data, "cyfral") == 0) {
|
||||
result = true;
|
||||
*type = iButtonKeyCyfral;
|
||||
} else if(string_cmp_str(data, "Metakom") == 0 || string_cmp_str(data, "metakom") == 0) {
|
||||
} else if(furi_string_cmp_str(data, "Metakom") == 0 || furi_string_cmp_str(data, "metakom") == 0) {
|
||||
result = true;
|
||||
*type = iButtonKeyMetakom;
|
||||
}
|
||||
@@ -123,17 +123,17 @@ static void ibutton_cli_worker_write_cb(void* context, iButtonWorkerWriteResult
|
||||
furi_event_flag_set(write_context->event, EVENT_FLAG_IBUTTON_COMPLETE);
|
||||
}
|
||||
|
||||
void ibutton_cli_write(Cli* cli, string_t args) {
|
||||
void ibutton_cli_write(Cli* cli, FuriString* args) {
|
||||
iButtonKey* key = ibutton_key_alloc();
|
||||
iButtonWorker* worker = ibutton_worker_alloc();
|
||||
iButtonKeyType type;
|
||||
iButtonWriteContext write_context;
|
||||
uint8_t key_data[IBUTTON_KEY_DATA_SIZE];
|
||||
string_t data;
|
||||
FuriString* data;
|
||||
|
||||
write_context.event = furi_event_flag_alloc();
|
||||
|
||||
string_init(data);
|
||||
data = furi_string_alloc();
|
||||
ibutton_worker_start_thread(worker);
|
||||
ibutton_worker_write_set_callback(worker, ibutton_cli_worker_write_cb, &write_context);
|
||||
|
||||
@@ -186,7 +186,7 @@ void ibutton_cli_write(Cli* cli, string_t args) {
|
||||
ibutton_worker_stop(worker);
|
||||
} while(false);
|
||||
|
||||
string_clear(data);
|
||||
furi_string_free(data);
|
||||
ibutton_worker_stop_thread(worker);
|
||||
ibutton_worker_free(worker);
|
||||
ibutton_key_free(key);
|
||||
@@ -194,14 +194,14 @@ void ibutton_cli_write(Cli* cli, string_t args) {
|
||||
furi_event_flag_free(write_context.event);
|
||||
};
|
||||
|
||||
void ibutton_cli_emulate(Cli* cli, string_t args) {
|
||||
void ibutton_cli_emulate(Cli* cli, FuriString* args) {
|
||||
iButtonKey* key = ibutton_key_alloc();
|
||||
iButtonWorker* worker = ibutton_worker_alloc();
|
||||
iButtonKeyType type;
|
||||
uint8_t key_data[IBUTTON_KEY_DATA_SIZE];
|
||||
string_t data;
|
||||
FuriString* data;
|
||||
|
||||
string_init(data);
|
||||
data = furi_string_alloc();
|
||||
ibutton_worker_start_thread(worker);
|
||||
|
||||
do {
|
||||
@@ -234,34 +234,34 @@ void ibutton_cli_emulate(Cli* cli, string_t args) {
|
||||
ibutton_worker_stop(worker);
|
||||
} while(false);
|
||||
|
||||
string_clear(data);
|
||||
furi_string_free(data);
|
||||
ibutton_worker_stop_thread(worker);
|
||||
ibutton_worker_free(worker);
|
||||
ibutton_key_free(key);
|
||||
};
|
||||
|
||||
static void ibutton_cli(Cli* cli, string_t args, void* context) {
|
||||
static void ibutton_cli(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(context);
|
||||
string_t cmd;
|
||||
string_init(cmd);
|
||||
FuriString* cmd;
|
||||
cmd = furi_string_alloc();
|
||||
|
||||
if(!args_read_string_and_trim(args, cmd)) {
|
||||
string_clear(cmd);
|
||||
furi_string_free(cmd);
|
||||
ibutton_cli_print_usage();
|
||||
return;
|
||||
}
|
||||
|
||||
if(string_cmp_str(cmd, "read") == 0) {
|
||||
if(furi_string_cmp_str(cmd, "read") == 0) {
|
||||
ibutton_cli_read(cli);
|
||||
} else if(string_cmp_str(cmd, "write") == 0) {
|
||||
} else if(furi_string_cmp_str(cmd, "write") == 0) {
|
||||
ibutton_cli_write(cli, args);
|
||||
} else if(string_cmp_str(cmd, "emulate") == 0) {
|
||||
} else if(furi_string_cmp_str(cmd, "emulate") == 0) {
|
||||
ibutton_cli_emulate(cli, args);
|
||||
} else {
|
||||
ibutton_cli_print_usage();
|
||||
}
|
||||
|
||||
string_clear(cmd);
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
void onewire_cli_print_usage() {
|
||||
@@ -299,20 +299,20 @@ static void onewire_cli_search(Cli* cli) {
|
||||
onewire_host_free(onewire);
|
||||
}
|
||||
|
||||
void onewire_cli(Cli* cli, string_t args, void* context) {
|
||||
void onewire_cli(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(context);
|
||||
string_t cmd;
|
||||
string_init(cmd);
|
||||
FuriString* cmd;
|
||||
cmd = furi_string_alloc();
|
||||
|
||||
if(!args_read_string_and_trim(args, cmd)) {
|
||||
string_clear(cmd);
|
||||
furi_string_free(cmd);
|
||||
onewire_cli_print_usage();
|
||||
return;
|
||||
}
|
||||
|
||||
if(string_cmp_str(cmd, "search") == 0) {
|
||||
if(furi_string_cmp_str(cmd, "search") == 0) {
|
||||
onewire_cli_search(cli);
|
||||
}
|
||||
|
||||
string_clear(cmd);
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ struct iButton {
|
||||
iButtonWorker* key_worker;
|
||||
iButtonKey* key;
|
||||
|
||||
string_t file_path;
|
||||
FuriString* file_path;
|
||||
char text_store[IBUTTON_TEXT_STORE_SIZE + 1];
|
||||
|
||||
Submenu* submenu;
|
||||
@@ -78,7 +78,7 @@ typedef enum {
|
||||
} iButtonNotificationMessage;
|
||||
|
||||
bool ibutton_file_select(iButton* ibutton);
|
||||
bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show_dialog);
|
||||
bool ibutton_load_key_data(iButton* ibutton, FuriString* key_path, bool show_dialog);
|
||||
bool ibutton_save_key(iButton* ibutton, const char* key_name);
|
||||
bool ibutton_delete_key(iButton* ibutton);
|
||||
void ibutton_text_store_set(iButton* ibutton, const char* text, ...);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "../ibutton_i.h"
|
||||
#include "m-string.h"
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexCyfral,
|
||||
@@ -47,7 +46,7 @@ bool ibutton_scene_add_type_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_crash("Unknown key type");
|
||||
}
|
||||
|
||||
string_set_str(ibutton->file_path, IBUTTON_APP_FOLDER);
|
||||
furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER);
|
||||
ibutton_key_clear_data(key);
|
||||
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue);
|
||||
}
|
||||
|
||||
@@ -17,13 +17,13 @@ void ibutton_scene_delete_confirm_on_enter(void* context) {
|
||||
iButtonKey* key = ibutton->key;
|
||||
const uint8_t* key_data = ibutton_key_get_data_p(key);
|
||||
|
||||
string_t key_name;
|
||||
string_init(key_name);
|
||||
FuriString* key_name;
|
||||
key_name = furi_string_alloc();
|
||||
path_extract_filename(ibutton->file_path, key_name, true);
|
||||
|
||||
ibutton_text_store_set(ibutton, "\e#Delete %s?\e#", string_get_cstr(key_name));
|
||||
ibutton_text_store_set(ibutton, "\e#Delete %s?\e#", furi_string_get_cstr(key_name));
|
||||
widget_add_text_box_element(
|
||||
widget, 0, 0, 128, 27, AlignCenter, AlignCenter, ibutton->text_store, false);
|
||||
widget, 0, 0, 128, 27, AlignCenter, AlignCenter, ibutton->text_store, true);
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeLeft, "Cancel", ibutton_scene_delete_confirm_widget_callback, ibutton);
|
||||
widget_add_button_element(
|
||||
@@ -47,28 +47,28 @@ void ibutton_scene_delete_confirm_on_enter(void* context) {
|
||||
key_data[6],
|
||||
key_data[7]);
|
||||
widget_add_string_element(
|
||||
widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Dallas");
|
||||
widget, 64, 34, AlignCenter, AlignBottom, FontSecondary, "Dallas");
|
||||
break;
|
||||
|
||||
case iButtonKeyCyfral:
|
||||
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]);
|
||||
widget_add_string_element(
|
||||
widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Cyfral");
|
||||
widget, 64, 34, AlignCenter, AlignBottom, FontSecondary, "Cyfral");
|
||||
break;
|
||||
|
||||
case iButtonKeyMetakom:
|
||||
ibutton_text_store_set(
|
||||
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
|
||||
widget_add_string_element(
|
||||
widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Metakom");
|
||||
widget, 64, 34, AlignCenter, AlignBottom, FontSecondary, "Metakom");
|
||||
break;
|
||||
}
|
||||
widget_add_string_element(
|
||||
widget, 64, 33, AlignCenter, AlignBottom, FontSecondary, ibutton->text_store);
|
||||
widget, 64, 46, AlignCenter, AlignBottom, FontSecondary, ibutton->text_store);
|
||||
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
|
||||
|
||||
string_clear(key_name);
|
||||
furi_string_free(key_name);
|
||||
}
|
||||
|
||||
bool ibutton_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
@@ -15,31 +15,29 @@ static void ibutton_scene_emulate_callback(void* context, bool emulated) {
|
||||
|
||||
void ibutton_scene_emulate_on_enter(void* context) {
|
||||
iButton* ibutton = context;
|
||||
Popup* popup = ibutton->popup;
|
||||
Widget* widget = ibutton->widget;
|
||||
iButtonKey* key = ibutton->key;
|
||||
|
||||
const uint8_t* key_data = ibutton_key_get_data_p(key);
|
||||
|
||||
string_t key_name;
|
||||
string_init(key_name);
|
||||
if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
|
||||
FuriString* key_name;
|
||||
key_name = furi_string_alloc();
|
||||
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
|
||||
path_extract_filename(ibutton->file_path, key_name, true);
|
||||
}
|
||||
|
||||
uint8_t line_count = 2;
|
||||
DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
|
||||
|
||||
// check that stored key has name
|
||||
if(!string_empty_p(key_name)) {
|
||||
ibutton_text_store_set(ibutton, "emulating\n%s", string_get_cstr(key_name));
|
||||
line_count = 2;
|
||||
if(!furi_string_empty(key_name)) {
|
||||
ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name));
|
||||
} else {
|
||||
// if not, show key data
|
||||
switch(ibutton_key_get_type(key)) {
|
||||
case iButtonKeyDS1990:
|
||||
ibutton_text_store_set(
|
||||
ibutton,
|
||||
"emulating\n%02X %02X %02X %02X\n%02X %02X %02X %02X",
|
||||
"%02X %02X %02X %02X\n%02X %02X %02X %02X",
|
||||
key_data[0],
|
||||
key_data[1],
|
||||
key_data[2],
|
||||
@@ -48,46 +46,30 @@ void ibutton_scene_emulate_on_enter(void* context) {
|
||||
key_data[5],
|
||||
key_data[6],
|
||||
key_data[7]);
|
||||
line_count = 3;
|
||||
break;
|
||||
case iButtonKeyCyfral:
|
||||
ibutton_text_store_set(ibutton, "emulating\n%02X %02X", key_data[0], key_data[1]);
|
||||
line_count = 2;
|
||||
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]);
|
||||
break;
|
||||
case iButtonKeyMetakom:
|
||||
ibutton_text_store_set(
|
||||
ibutton,
|
||||
"emulating\n%02X %02X %02X %02X",
|
||||
key_data[0],
|
||||
key_data[1],
|
||||
key_data[2],
|
||||
key_data[3]);
|
||||
line_count = 2;
|
||||
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch(line_count) {
|
||||
case 3:
|
||||
popup_set_header(popup, "iButton", 82, 18, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, ibutton->text_store, 82, 22, AlignCenter, AlignTop);
|
||||
break;
|
||||
widget_add_string_multiline_element(
|
||||
widget, 90, 10, AlignCenter, AlignTop, FontPrimary, "iButton\nemulating");
|
||||
widget_add_icon_element(widget, 3, 10, &I_iButtonKey_49x44);
|
||||
widget_add_text_box_element(
|
||||
widget, 54, 39, 75, 22, AlignCenter, AlignCenter, ibutton->text_store, true);
|
||||
|
||||
default:
|
||||
popup_set_header(popup, "iButton", 82, 24, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, ibutton->text_store, 82, 28, AlignCenter, AlignTop);
|
||||
break;
|
||||
}
|
||||
|
||||
popup_set_icon(popup, 2, 10, &I_iButtonKey_49x44);
|
||||
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
|
||||
|
||||
ibutton_worker_emulate_set_callback(
|
||||
ibutton->key_worker, ibutton_scene_emulate_callback, ibutton);
|
||||
ibutton_worker_emulate_start(ibutton->key_worker, key);
|
||||
|
||||
string_clear(key_name);
|
||||
furi_string_free(key_name);
|
||||
|
||||
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
|
||||
}
|
||||
@@ -122,10 +104,7 @@ bool ibutton_scene_emulate_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
void ibutton_scene_emulate_on_exit(void* context) {
|
||||
iButton* ibutton = context;
|
||||
Popup* popup = ibutton->popup;
|
||||
ibutton_worker_stop(ibutton->key_worker);
|
||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 0, NULL);
|
||||
widget_reset(ibutton->widget);
|
||||
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@ void ibutton_scene_info_on_enter(void* context) {
|
||||
|
||||
const uint8_t* key_data = ibutton_key_get_data_p(key);
|
||||
|
||||
string_t key_name;
|
||||
string_init(key_name);
|
||||
FuriString* key_name;
|
||||
key_name = furi_string_alloc();
|
||||
path_extract_filename(ibutton->file_path, key_name, true);
|
||||
|
||||
ibutton_text_store_set(ibutton, "%s", string_get_cstr(key_name));
|
||||
ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name));
|
||||
widget_add_text_box_element(
|
||||
widget, 0, 0, 128, 28, AlignCenter, AlignCenter, ibutton->text_store, false);
|
||||
widget, 0, 0, 128, 23, AlignCenter, AlignCenter, ibutton->text_store, true);
|
||||
|
||||
switch(ibutton_key_get_type(key)) {
|
||||
case iButtonKeyDS1990:
|
||||
@@ -29,30 +29,28 @@ void ibutton_scene_info_on_enter(void* context) {
|
||||
key_data[5],
|
||||
key_data[6],
|
||||
key_data[7]);
|
||||
widget_add_string_element(
|
||||
widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Dallas");
|
||||
widget_add_string_element(widget, 64, 36, AlignCenter, AlignBottom, FontPrimary, "Dallas");
|
||||
break;
|
||||
|
||||
case iButtonKeyMetakom:
|
||||
ibutton_text_store_set(
|
||||
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
|
||||
widget_add_string_element(
|
||||
widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Metakom");
|
||||
widget, 64, 36, AlignCenter, AlignBottom, FontPrimary, "Metakom");
|
||||
break;
|
||||
|
||||
case iButtonKeyCyfral:
|
||||
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]);
|
||||
widget_add_string_element(
|
||||
widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Cyfral");
|
||||
widget_add_string_element(widget, 64, 36, AlignCenter, AlignBottom, FontPrimary, "Cyfral");
|
||||
break;
|
||||
}
|
||||
|
||||
widget_add_string_element(
|
||||
widget, 64, 35, AlignCenter, AlignBottom, FontPrimary, ibutton->text_store);
|
||||
widget, 64, 50, AlignCenter, AlignBottom, FontSecondary, ibutton->text_store);
|
||||
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
|
||||
|
||||
string_clear(key_name);
|
||||
furi_string_free(key_name);
|
||||
}
|
||||
|
||||
bool ibutton_scene_info_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
@@ -18,7 +18,7 @@ void ibutton_scene_read_on_enter(void* context) {
|
||||
popup_set_icon(popup, 0, 5, &I_DolphinWait_61x59);
|
||||
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
|
||||
string_set_str(ibutton->file_path, IBUTTON_APP_FOLDER);
|
||||
furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER);
|
||||
|
||||
ibutton_worker_read_set_callback(worker, ibutton_scene_read_callback, ibutton);
|
||||
ibutton_worker_read_start(worker, key);
|
||||
|
||||
@@ -29,19 +29,19 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.event == iButtonCustomEventRpcLoad) {
|
||||
const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx);
|
||||
bool result = false;
|
||||
if(arg && (string_empty_p(ibutton->file_path))) {
|
||||
string_set_str(ibutton->file_path, arg);
|
||||
if(arg && (furi_string_empty(ibutton->file_path))) {
|
||||
furi_string_set(ibutton->file_path, arg);
|
||||
if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) {
|
||||
ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key);
|
||||
string_t key_name;
|
||||
string_init(key_name);
|
||||
if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
|
||||
FuriString* key_name;
|
||||
key_name = furi_string_alloc();
|
||||
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
|
||||
path_extract_filename(ibutton->file_path, key_name, true);
|
||||
}
|
||||
|
||||
if(!string_empty_p(key_name)) {
|
||||
if(!furi_string_empty(key_name)) {
|
||||
ibutton_text_store_set(
|
||||
ibutton, "emulating\n%s", string_get_cstr(key_name));
|
||||
ibutton, "emulating\n%s", furi_string_get_cstr(key_name));
|
||||
} else {
|
||||
ibutton_text_store_set(ibutton, "emulating");
|
||||
}
|
||||
@@ -49,10 +49,10 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
|
||||
|
||||
string_clear(key_name);
|
||||
furi_string_free(key_name);
|
||||
result = true;
|
||||
} else {
|
||||
string_reset(ibutton->file_path);
|
||||
furi_string_reset(ibutton->file_path);
|
||||
}
|
||||
}
|
||||
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "../ibutton_i.h"
|
||||
#include "m-string.h"
|
||||
#include <lib/toolbox/random_name.h>
|
||||
#include <toolbox/path.h>
|
||||
|
||||
@@ -12,17 +11,17 @@ void ibutton_scene_save_name_on_enter(void* context) {
|
||||
iButton* ibutton = context;
|
||||
TextInput* text_input = ibutton->text_input;
|
||||
|
||||
string_t key_name;
|
||||
string_init(key_name);
|
||||
if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
|
||||
FuriString* key_name;
|
||||
key_name = furi_string_alloc();
|
||||
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
|
||||
path_extract_filename(ibutton->file_path, key_name, true);
|
||||
}
|
||||
|
||||
const bool key_name_is_empty = string_empty_p(key_name);
|
||||
const bool key_name_is_empty = furi_string_empty(key_name);
|
||||
if(key_name_is_empty) {
|
||||
set_random_name(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE);
|
||||
} else {
|
||||
ibutton_text_store_set(ibutton, "%s", string_get_cstr(key_name));
|
||||
ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name));
|
||||
}
|
||||
|
||||
text_input_set_header_text(text_input, "Name the key");
|
||||
@@ -34,19 +33,19 @@ void ibutton_scene_save_name_on_enter(void* context) {
|
||||
IBUTTON_KEY_NAME_SIZE,
|
||||
key_name_is_empty);
|
||||
|
||||
string_t folder_path;
|
||||
string_init(folder_path);
|
||||
FuriString* folder_path;
|
||||
folder_path = furi_string_alloc();
|
||||
|
||||
path_extract_dirname(string_get_cstr(ibutton->file_path), folder_path);
|
||||
path_extract_dirname(furi_string_get_cstr(ibutton->file_path), folder_path);
|
||||
|
||||
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
|
||||
string_get_cstr(folder_path), IBUTTON_APP_EXTENSION, string_get_cstr(key_name));
|
||||
furi_string_get_cstr(folder_path), IBUTTON_APP_EXTENSION, furi_string_get_cstr(key_name));
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewTextInput);
|
||||
|
||||
string_clear(key_name);
|
||||
string_clear(folder_path);
|
||||
furi_string_free(key_name);
|
||||
furi_string_free(folder_path);
|
||||
}
|
||||
|
||||
bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
@@ -29,10 +29,8 @@ bool ibutton_scene_save_success_on_event(void* context, SceneManagerEvent event)
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
consumed = true;
|
||||
if(event.event == iButtonCustomEventBack) {
|
||||
const uint32_t possible_scenes[] = {
|
||||
iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType};
|
||||
scene_manager_search_and_switch_to_previous_scene_one_of(
|
||||
ibutton->scene_manager, possible_scenes, COUNT_OF(possible_scenes));
|
||||
scene_manager_search_and_switch_to_another_scene(
|
||||
ibutton->scene_manager, iButtonSceneSelectKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.event == SubmenuIndexRead) {
|
||||
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead);
|
||||
} else if(event.event == SubmenuIndexSaved) {
|
||||
string_set_str(ibutton->file_path, IBUTTON_APP_FOLDER);
|
||||
furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER);
|
||||
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey);
|
||||
} else if(event.event == SubmenuIndexAdd) {
|
||||
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddType);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "../ibutton_i.h"
|
||||
#include "m-string.h"
|
||||
#include "toolbox/path.h"
|
||||
|
||||
typedef enum {
|
||||
@@ -14,31 +13,28 @@ static void ibutton_scene_write_callback(void* context, iButtonWorkerWriteResult
|
||||
|
||||
void ibutton_scene_write_on_enter(void* context) {
|
||||
iButton* ibutton = context;
|
||||
Popup* popup = ibutton->popup;
|
||||
iButtonKey* key = ibutton->key;
|
||||
Widget* widget = ibutton->widget;
|
||||
iButtonWorker* worker = ibutton->key_worker;
|
||||
|
||||
const uint8_t* key_data = ibutton_key_get_data_p(key);
|
||||
|
||||
string_t key_name;
|
||||
string_init(key_name);
|
||||
if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
|
||||
FuriString* key_name;
|
||||
key_name = furi_string_alloc();
|
||||
if(furi_string_end_with(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
|
||||
path_extract_filename(ibutton->file_path, key_name, true);
|
||||
}
|
||||
|
||||
uint8_t line_count = 2;
|
||||
|
||||
// check that stored key has name
|
||||
if(!string_empty_p(key_name)) {
|
||||
ibutton_text_store_set(ibutton, "writing\n%s", string_get_cstr(key_name));
|
||||
line_count = 2;
|
||||
if(!furi_string_empty(key_name)) {
|
||||
ibutton_text_store_set(ibutton, "%s", furi_string_get_cstr(key_name));
|
||||
} else {
|
||||
// if not, show key data
|
||||
switch(ibutton_key_get_type(key)) {
|
||||
case iButtonKeyDS1990:
|
||||
ibutton_text_store_set(
|
||||
ibutton,
|
||||
"writing\n%02X %02X %02X %02X\n%02X %02X %02X %02X",
|
||||
"%02X %02X %02X %02X\n%02X %02X %02X %02X",
|
||||
key_data[0],
|
||||
key_data[1],
|
||||
key_data[2],
|
||||
@@ -47,45 +43,29 @@ void ibutton_scene_write_on_enter(void* context) {
|
||||
key_data[5],
|
||||
key_data[6],
|
||||
key_data[7]);
|
||||
line_count = 3;
|
||||
break;
|
||||
case iButtonKeyCyfral:
|
||||
ibutton_text_store_set(ibutton, "writing\n%02X %02X", key_data[0], key_data[1]);
|
||||
line_count = 2;
|
||||
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]);
|
||||
break;
|
||||
case iButtonKeyMetakom:
|
||||
ibutton_text_store_set(
|
||||
ibutton,
|
||||
"writing\n%02X %02X %02X %02X",
|
||||
key_data[0],
|
||||
key_data[1],
|
||||
key_data[2],
|
||||
key_data[3]);
|
||||
line_count = 2;
|
||||
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch(line_count) {
|
||||
case 3:
|
||||
popup_set_header(popup, "iButton", 82, 18, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, ibutton->text_store, 82, 22, AlignCenter, AlignTop);
|
||||
break;
|
||||
widget_add_string_multiline_element(
|
||||
widget, 90, 10, AlignCenter, AlignTop, FontPrimary, "iButton\nwriting");
|
||||
widget_add_icon_element(widget, 3, 10, &I_iButtonKey_49x44);
|
||||
widget_add_text_box_element(
|
||||
widget, 54, 39, 75, 22, AlignCenter, AlignCenter, ibutton->text_store, true);
|
||||
|
||||
default:
|
||||
popup_set_header(popup, "iButton", 82, 24, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, ibutton->text_store, 82, 28, AlignCenter, AlignTop);
|
||||
break;
|
||||
}
|
||||
|
||||
popup_set_icon(popup, 2, 10, &I_iButtonKey_49x44);
|
||||
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
|
||||
|
||||
ibutton_worker_write_set_callback(worker, ibutton_scene_write_callback, ibutton);
|
||||
ibutton_worker_write_start(worker, key);
|
||||
|
||||
string_clear(key_name);
|
||||
furi_string_free(key_name);
|
||||
|
||||
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
|
||||
}
|
||||
@@ -114,11 +94,8 @@ bool ibutton_scene_write_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
void ibutton_scene_write_on_exit(void* context) {
|
||||
iButton* ibutton = context;
|
||||
Popup* popup = ibutton->popup;
|
||||
ibutton_worker_stop(ibutton->key_worker);
|
||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 0, NULL);
|
||||
widget_reset(ibutton->widget);
|
||||
|
||||
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
|
||||
}
|
||||
|
||||
@@ -65,51 +65,52 @@ static void infrared_rpc_command_callback(RpcAppSystemEvent event, void* context
|
||||
}
|
||||
}
|
||||
|
||||
static void infrared_find_vacant_remote_name(string_t name, const char* path) {
|
||||
static void infrared_find_vacant_remote_name(FuriString* name, const char* path) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
string_t base_path;
|
||||
string_init_set_str(base_path, path);
|
||||
FuriString* base_path;
|
||||
base_path = furi_string_alloc_set(path);
|
||||
|
||||
if(string_end_with_str_p(base_path, INFRARED_APP_EXTENSION)) {
|
||||
size_t filename_start = string_search_rchar(base_path, '/');
|
||||
string_left(base_path, filename_start);
|
||||
if(furi_string_end_with(base_path, INFRARED_APP_EXTENSION)) {
|
||||
size_t filename_start = furi_string_search_rchar(base_path, '/');
|
||||
furi_string_left(base_path, filename_start);
|
||||
}
|
||||
|
||||
string_printf(base_path, "%s/%s%s", path, string_get_cstr(name), INFRARED_APP_EXTENSION);
|
||||
furi_string_printf(
|
||||
base_path, "%s/%s%s", path, furi_string_get_cstr(name), INFRARED_APP_EXTENSION);
|
||||
|
||||
FS_Error status = storage_common_stat(storage, string_get_cstr(base_path), NULL);
|
||||
FS_Error status = storage_common_stat(storage, furi_string_get_cstr(base_path), NULL);
|
||||
|
||||
if(status == FSE_OK) {
|
||||
/* If the suggested name is occupied, try another one (name2, name3, etc) */
|
||||
size_t dot = string_search_rchar(base_path, '.');
|
||||
string_left(base_path, dot);
|
||||
size_t dot = furi_string_search_rchar(base_path, '.');
|
||||
furi_string_left(base_path, dot);
|
||||
|
||||
string_t path_temp;
|
||||
string_init(path_temp);
|
||||
FuriString* path_temp;
|
||||
path_temp = furi_string_alloc();
|
||||
|
||||
uint32_t i = 1;
|
||||
do {
|
||||
string_printf(
|
||||
path_temp, "%s%u%s", string_get_cstr(base_path), ++i, INFRARED_APP_EXTENSION);
|
||||
status = storage_common_stat(storage, string_get_cstr(path_temp), NULL);
|
||||
furi_string_printf(
|
||||
path_temp, "%s%lu%s", furi_string_get_cstr(base_path), ++i, INFRARED_APP_EXTENSION);
|
||||
status = storage_common_stat(storage, furi_string_get_cstr(path_temp), NULL);
|
||||
} while(status == FSE_OK);
|
||||
|
||||
string_clear(path_temp);
|
||||
furi_string_free(path_temp);
|
||||
|
||||
if(status == FSE_NOT_EXIST) {
|
||||
string_cat_printf(name, "%u", i);
|
||||
furi_string_cat_printf(name, "%lu", i);
|
||||
}
|
||||
}
|
||||
|
||||
string_clear(base_path);
|
||||
furi_string_free(base_path);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
static Infrared* infrared_alloc() {
|
||||
Infrared* infrared = malloc(sizeof(Infrared));
|
||||
|
||||
string_init(infrared->file_path);
|
||||
infrared->file_path = furi_string_alloc();
|
||||
|
||||
InfraredAppState* app_state = &infrared->app_state;
|
||||
app_state->is_learning_new_remote = false;
|
||||
@@ -232,7 +233,7 @@ static void infrared_free(Infrared* infrared) {
|
||||
furi_record_close(RECORD_GUI);
|
||||
infrared->gui = NULL;
|
||||
|
||||
string_clear(infrared->file_path);
|
||||
furi_string_free(infrared->file_path);
|
||||
|
||||
free(infrared);
|
||||
}
|
||||
@@ -243,19 +244,20 @@ bool infrared_add_remote_with_button(
|
||||
InfraredSignal* signal) {
|
||||
InfraredRemote* remote = infrared->remote;
|
||||
|
||||
string_t new_name, new_path;
|
||||
string_init_set_str(new_name, INFRARED_DEFAULT_REMOTE_NAME);
|
||||
string_init_set_str(new_path, INFRARED_APP_FOLDER);
|
||||
FuriString *new_name, *new_path;
|
||||
new_name = furi_string_alloc_set(INFRARED_DEFAULT_REMOTE_NAME);
|
||||
new_path = furi_string_alloc_set(INFRARED_APP_FOLDER);
|
||||
|
||||
infrared_find_vacant_remote_name(new_name, string_get_cstr(new_path));
|
||||
string_cat_printf(new_path, "/%s%s", string_get_cstr(new_name), INFRARED_APP_EXTENSION);
|
||||
infrared_find_vacant_remote_name(new_name, furi_string_get_cstr(new_path));
|
||||
furi_string_cat_printf(
|
||||
new_path, "/%s%s", furi_string_get_cstr(new_name), INFRARED_APP_EXTENSION);
|
||||
|
||||
infrared_remote_reset(remote);
|
||||
infrared_remote_set_name(remote, string_get_cstr(new_name));
|
||||
infrared_remote_set_path(remote, string_get_cstr(new_path));
|
||||
infrared_remote_set_name(remote, furi_string_get_cstr(new_name));
|
||||
infrared_remote_set_path(remote, furi_string_get_cstr(new_path));
|
||||
|
||||
string_clear(new_name);
|
||||
string_clear(new_path);
|
||||
furi_string_free(new_name);
|
||||
furi_string_free(new_path);
|
||||
return infrared_remote_add_button(remote, button_name, signal);
|
||||
}
|
||||
|
||||
@@ -267,28 +269,29 @@ bool infrared_rename_current_remote(Infrared* infrared, const char* name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
string_t new_name;
|
||||
string_init_set_str(new_name, name);
|
||||
FuriString* new_name;
|
||||
new_name = furi_string_alloc_set(name);
|
||||
|
||||
infrared_find_vacant_remote_name(new_name, remote_path);
|
||||
|
||||
string_t new_path;
|
||||
string_init_set(new_path, infrared_remote_get_path(remote));
|
||||
if(string_end_with_str_p(new_path, INFRARED_APP_EXTENSION)) {
|
||||
size_t filename_start = string_search_rchar(new_path, '/');
|
||||
string_left(new_path, filename_start);
|
||||
FuriString* new_path;
|
||||
new_path = furi_string_alloc_set(infrared_remote_get_path(remote));
|
||||
if(furi_string_end_with(new_path, INFRARED_APP_EXTENSION)) {
|
||||
size_t filename_start = furi_string_search_rchar(new_path, '/');
|
||||
furi_string_left(new_path, filename_start);
|
||||
}
|
||||
string_cat_printf(new_path, "/%s%s", string_get_cstr(new_name), INFRARED_APP_EXTENSION);
|
||||
furi_string_cat_printf(
|
||||
new_path, "/%s%s", furi_string_get_cstr(new_name), INFRARED_APP_EXTENSION);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
FS_Error status = storage_common_rename(
|
||||
storage, infrared_remote_get_path(remote), string_get_cstr(new_path));
|
||||
infrared_remote_set_name(remote, string_get_cstr(new_name));
|
||||
infrared_remote_set_path(remote, string_get_cstr(new_path));
|
||||
storage, infrared_remote_get_path(remote), furi_string_get_cstr(new_path));
|
||||
infrared_remote_set_name(remote, furi_string_get_cstr(new_name));
|
||||
infrared_remote_set_path(remote, furi_string_get_cstr(new_path));
|
||||
|
||||
string_clear(new_name);
|
||||
string_clear(new_path);
|
||||
furi_string_free(new_name);
|
||||
furi_string_free(new_path);
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
return (status == FSE_OK || status == FSE_EXIST);
|
||||
@@ -435,7 +438,7 @@ int32_t infrared_app(void* p) {
|
||||
rpc_system_app_send_started(infrared->rpc_ctx);
|
||||
is_rpc_mode = true;
|
||||
} else {
|
||||
string_set_str(infrared->file_path, (const char*)p);
|
||||
furi_string_set(infrared->file_path, (const char*)p);
|
||||
is_remote_loaded = infrared_remote_load(infrared->remote, infrared->file_path);
|
||||
if(!is_remote_loaded) {
|
||||
dialog_message_show_storage_error(
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <m-dict.h>
|
||||
#include <m-string.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
|
||||
#include "infrared_signal.h"
|
||||
@@ -14,43 +13,50 @@ typedef struct {
|
||||
|
||||
DICT_DEF2(
|
||||
InfraredBruteForceRecordDict,
|
||||
string_t,
|
||||
STRING_OPLIST,
|
||||
FuriString*,
|
||||
FURI_STRING_OPLIST,
|
||||
InfraredBruteForceRecord,
|
||||
M_POD_OPLIST);
|
||||
|
||||
struct InfraredBruteForce {
|
||||
FlipperFormat* ff;
|
||||
const char* db_filename;
|
||||
string_t current_record_name;
|
||||
FuriString* current_record_name;
|
||||
InfraredSignal* current_signal;
|
||||
InfraredBruteForceRecordDict_t records;
|
||||
bool is_started;
|
||||
};
|
||||
|
||||
InfraredBruteForce* infrared_brute_force_alloc() {
|
||||
InfraredBruteForce* brute_force = malloc(sizeof(InfraredBruteForce));
|
||||
brute_force->ff = NULL;
|
||||
brute_force->db_filename = NULL;
|
||||
string_init(brute_force->current_record_name);
|
||||
brute_force->current_signal = NULL;
|
||||
brute_force->is_started = false;
|
||||
brute_force->current_record_name = furi_string_alloc();
|
||||
InfraredBruteForceRecordDict_init(brute_force->records);
|
||||
return brute_force;
|
||||
}
|
||||
|
||||
void infrared_brute_force_clear_records(InfraredBruteForce* brute_force) {
|
||||
furi_assert(!brute_force->is_started);
|
||||
InfraredBruteForceRecordDict_reset(brute_force->records);
|
||||
}
|
||||
|
||||
void infrared_brute_force_free(InfraredBruteForce* brute_force) {
|
||||
furi_assert(!brute_force->ff);
|
||||
furi_assert(!brute_force->is_started);
|
||||
InfraredBruteForceRecordDict_clear(brute_force->records);
|
||||
string_clear(brute_force->current_record_name);
|
||||
furi_string_free(brute_force->current_record_name);
|
||||
free(brute_force);
|
||||
}
|
||||
|
||||
void infrared_brute_force_set_db_filename(InfraredBruteForce* brute_force, const char* db_filename) {
|
||||
furi_assert(!brute_force->is_started);
|
||||
brute_force->db_filename = db_filename;
|
||||
}
|
||||
|
||||
bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) {
|
||||
furi_assert(!brute_force->is_started);
|
||||
furi_assert(brute_force->db_filename);
|
||||
bool success = false;
|
||||
|
||||
@@ -59,8 +65,8 @@ bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) {
|
||||
|
||||
success = flipper_format_buffered_file_open_existing(ff, brute_force->db_filename);
|
||||
if(success) {
|
||||
string_t signal_name;
|
||||
string_init(signal_name);
|
||||
FuriString* signal_name;
|
||||
signal_name = furi_string_alloc();
|
||||
while(flipper_format_read_string(ff, "name", signal_name)) {
|
||||
InfraredBruteForceRecord* record =
|
||||
InfraredBruteForceRecordDict_get(brute_force->records, signal_name);
|
||||
@@ -68,7 +74,7 @@ bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force) {
|
||||
++(record->count);
|
||||
}
|
||||
}
|
||||
string_clear(signal_name);
|
||||
furi_string_free(signal_name);
|
||||
}
|
||||
|
||||
flipper_format_free(ff);
|
||||
@@ -80,6 +86,7 @@ bool infrared_brute_force_start(
|
||||
InfraredBruteForce* brute_force,
|
||||
uint32_t index,
|
||||
uint32_t* record_count) {
|
||||
furi_assert(!brute_force->is_started);
|
||||
bool success = false;
|
||||
*record_count = 0;
|
||||
|
||||
@@ -91,7 +98,7 @@ bool infrared_brute_force_start(
|
||||
if(record->value.index == index) {
|
||||
*record_count = record->value.count;
|
||||
if(*record_count) {
|
||||
string_set(brute_force->current_record_name, record->key);
|
||||
furi_string_set(brute_force->current_record_name, record->key);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -100,50 +107,37 @@ bool infrared_brute_force_start(
|
||||
if(*record_count) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
brute_force->ff = flipper_format_buffered_file_alloc(storage);
|
||||
brute_force->current_signal = infrared_signal_alloc();
|
||||
brute_force->is_started = true;
|
||||
success =
|
||||
flipper_format_buffered_file_open_existing(brute_force->ff, brute_force->db_filename);
|
||||
if(!success) {
|
||||
flipper_format_free(brute_force->ff);
|
||||
brute_force->ff = NULL;
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
if(!success) infrared_brute_force_stop(brute_force);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool infrared_brute_force_is_started(InfraredBruteForce* brute_force) {
|
||||
return brute_force->ff;
|
||||
return brute_force->is_started;
|
||||
}
|
||||
|
||||
void infrared_brute_force_stop(InfraredBruteForce* brute_force) {
|
||||
furi_assert(string_size(brute_force->current_record_name));
|
||||
furi_assert(brute_force->ff);
|
||||
|
||||
string_reset(brute_force->current_record_name);
|
||||
furi_assert(brute_force->is_started);
|
||||
furi_string_reset(brute_force->current_record_name);
|
||||
infrared_signal_free(brute_force->current_signal);
|
||||
flipper_format_free(brute_force->ff);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
brute_force->current_signal = NULL;
|
||||
brute_force->ff = NULL;
|
||||
brute_force->is_started = false;
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
bool infrared_brute_force_send_next(InfraredBruteForce* brute_force) {
|
||||
furi_assert(string_size(brute_force->current_record_name));
|
||||
furi_assert(brute_force->ff);
|
||||
bool success = false;
|
||||
|
||||
string_t signal_name;
|
||||
string_init(signal_name);
|
||||
InfraredSignal* signal = infrared_signal_alloc();
|
||||
|
||||
do {
|
||||
success = infrared_signal_read(signal, brute_force->ff, signal_name);
|
||||
} while(success && !string_equal_p(brute_force->current_record_name, signal_name));
|
||||
|
||||
furi_assert(brute_force->is_started);
|
||||
const bool success = infrared_signal_search_and_read(
|
||||
brute_force->current_signal, brute_force->ff, brute_force->current_record_name);
|
||||
if(success) {
|
||||
infrared_signal_transmit(signal);
|
||||
infrared_signal_transmit(brute_force->current_signal);
|
||||
}
|
||||
|
||||
infrared_signal_free(signal);
|
||||
string_clear(signal_name);
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -152,8 +146,8 @@ void infrared_brute_force_add_record(
|
||||
uint32_t index,
|
||||
const char* name) {
|
||||
InfraredBruteForceRecord value = {.index = index, .count = 0};
|
||||
string_t key;
|
||||
string_init_set_str(key, name);
|
||||
FuriString* key;
|
||||
key = furi_string_alloc_set(name);
|
||||
InfraredBruteForceRecordDict_set_at(brute_force->records, key, value);
|
||||
string_clear(key);
|
||||
furi_string_free(key);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <m-string.h>
|
||||
#include <cli/cli.h>
|
||||
#include <cli/cli_i.h>
|
||||
#include <infrared.h>
|
||||
#include <infrared_worker.h>
|
||||
#include <furi_hal_infrared.h>
|
||||
@@ -7,20 +7,33 @@
|
||||
#include <toolbox/args.h>
|
||||
|
||||
#include "infrared_signal.h"
|
||||
#include "infrared_brute_force.h"
|
||||
|
||||
#include "m-dict.h"
|
||||
#include "m-string.h"
|
||||
|
||||
#define INFRARED_CLI_BUF_SIZE 10
|
||||
|
||||
static void infrared_cli_start_ir_rx(Cli* cli, string_t args);
|
||||
static void infrared_cli_start_ir_tx(Cli* cli, string_t args);
|
||||
static void infrared_cli_process_decode(Cli* cli, string_t args);
|
||||
DICT_DEF2(dict_signals, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
|
||||
enum RemoteTypes { TV = 0, AC = 1 };
|
||||
|
||||
static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args);
|
||||
static void infrared_cli_start_ir_tx(Cli* cli, FuriString* args);
|
||||
static void infrared_cli_process_decode(Cli* cli, FuriString* args);
|
||||
static void infrared_cli_process_universal(Cli* cli, FuriString* args);
|
||||
static void infrared_cli_list_remote_signals(enum RemoteTypes remote_type);
|
||||
static void
|
||||
infrared_cli_brute_force_signals(Cli* cli, enum RemoteTypes remote_type, FuriString* signal);
|
||||
|
||||
static const struct {
|
||||
const char* cmd;
|
||||
void (*process_function)(Cli* cli, string_t args);
|
||||
void (*process_function)(Cli* cli, FuriString* args);
|
||||
} infrared_cli_commands[] = {
|
||||
{.cmd = "rx", .process_function = infrared_cli_start_ir_rx},
|
||||
{.cmd = "tx", .process_function = infrared_cli_start_ir_tx},
|
||||
{.cmd = "decode", .process_function = infrared_cli_process_decode},
|
||||
{.cmd = "universal", .process_function = infrared_cli_process_universal},
|
||||
};
|
||||
|
||||
static void signal_received_callback(void* context, InfraredWorkerSignal* received_signal) {
|
||||
@@ -58,7 +71,7 @@ static void signal_received_callback(void* context, InfraredWorkerSignal* receiv
|
||||
}
|
||||
}
|
||||
|
||||
static void infrared_cli_start_ir_rx(Cli* cli, string_t args) {
|
||||
static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args) {
|
||||
UNUSED(cli);
|
||||
UNUSED(args);
|
||||
InfraredWorker* worker = infrared_worker_alloc();
|
||||
@@ -91,6 +104,8 @@ static void infrared_cli_print_usage(void) {
|
||||
INFRARED_MIN_FREQUENCY,
|
||||
INFRARED_MAX_FREQUENCY);
|
||||
printf("\tir decode <input_file> [<output_file>]\r\n");
|
||||
printf("\tir universal <tv, ac> <signal name>\r\n");
|
||||
printf("\tir universal list <tv, ac>\r\n");
|
||||
}
|
||||
|
||||
static bool infrared_cli_parse_message(const char* str, InfraredSignal* signal) {
|
||||
@@ -151,9 +166,9 @@ static bool infrared_cli_parse_raw(const char* str, InfraredSignal* signal) {
|
||||
return infrared_signal_is_valid(signal);
|
||||
}
|
||||
|
||||
static void infrared_cli_start_ir_tx(Cli* cli, string_t args) {
|
||||
static void infrared_cli_start_ir_tx(Cli* cli, FuriString* args) {
|
||||
UNUSED(cli);
|
||||
const char* str = string_get_cstr(args);
|
||||
const char* str = furi_string_get_cstr(args);
|
||||
InfraredSignal* signal = infrared_signal_alloc();
|
||||
|
||||
bool success = infrared_cli_parse_message(str, signal) || infrared_cli_parse_raw(str, signal);
|
||||
@@ -231,8 +246,8 @@ static bool infrared_cli_decode_file(FlipperFormat* input_file, FlipperFormat* o
|
||||
InfraredSignal* signal = infrared_signal_alloc();
|
||||
InfraredDecoderHandler* decoder = infrared_alloc_decoder();
|
||||
|
||||
string_t tmp;
|
||||
string_init(tmp);
|
||||
FuriString* tmp;
|
||||
tmp = furi_string_alloc();
|
||||
|
||||
while(infrared_signal_read(signal, input_file, tmp)) {
|
||||
ret = false;
|
||||
@@ -242,7 +257,7 @@ static bool infrared_cli_decode_file(FlipperFormat* input_file, FlipperFormat* o
|
||||
}
|
||||
if(!infrared_signal_is_raw(signal)) {
|
||||
if(output_file &&
|
||||
!infrared_cli_save_signal(signal, output_file, string_get_cstr(tmp))) {
|
||||
!infrared_cli_save_signal(signal, output_file, furi_string_get_cstr(tmp))) {
|
||||
break;
|
||||
} else {
|
||||
printf("Skipping decoded signal\r\n");
|
||||
@@ -250,31 +265,33 @@ static bool infrared_cli_decode_file(FlipperFormat* input_file, FlipperFormat* o
|
||||
}
|
||||
}
|
||||
InfraredRawSignal* raw_signal = infrared_signal_get_raw_signal(signal);
|
||||
printf("Raw signal: %s, %u samples\r\n", string_get_cstr(tmp), raw_signal->timings_size);
|
||||
if(!infrared_cli_decode_raw_signal(raw_signal, decoder, output_file, string_get_cstr(tmp)))
|
||||
printf(
|
||||
"Raw signal: %s, %u samples\r\n", furi_string_get_cstr(tmp), raw_signal->timings_size);
|
||||
if(!infrared_cli_decode_raw_signal(
|
||||
raw_signal, decoder, output_file, furi_string_get_cstr(tmp)))
|
||||
break;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
infrared_free_decoder(decoder);
|
||||
infrared_signal_free(signal);
|
||||
string_clear(tmp);
|
||||
furi_string_free(tmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void infrared_cli_process_decode(Cli* cli, string_t args) {
|
||||
static void infrared_cli_process_decode(Cli* cli, FuriString* args) {
|
||||
UNUSED(cli);
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* input_file = flipper_format_buffered_file_alloc(storage);
|
||||
FlipperFormat* output_file = NULL;
|
||||
|
||||
uint32_t version;
|
||||
string_t tmp, header, input_path, output_path;
|
||||
string_init(tmp);
|
||||
string_init(header);
|
||||
string_init(input_path);
|
||||
string_init(output_path);
|
||||
FuriString *tmp, *header, *input_path, *output_path;
|
||||
tmp = furi_string_alloc();
|
||||
header = furi_string_alloc();
|
||||
input_path = furi_string_alloc();
|
||||
output_path = furi_string_alloc();
|
||||
|
||||
do {
|
||||
if(!args_read_probably_quoted_string_and_trim(args, input_path)) {
|
||||
@@ -283,26 +300,32 @@ static void infrared_cli_process_decode(Cli* cli, string_t args) {
|
||||
break;
|
||||
}
|
||||
args_read_probably_quoted_string_and_trim(args, output_path);
|
||||
if(!flipper_format_buffered_file_open_existing(input_file, string_get_cstr(input_path))) {
|
||||
printf("Failed to open file for reading: \"%s\"\r\n", string_get_cstr(input_path));
|
||||
if(!flipper_format_buffered_file_open_existing(
|
||||
input_file, furi_string_get_cstr(input_path))) {
|
||||
printf(
|
||||
"Failed to open file for reading: \"%s\"\r\n", furi_string_get_cstr(input_path));
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_read_header(input_file, header, &version) ||
|
||||
(!string_start_with_str_p(header, "IR")) || version != 1) {
|
||||
printf("Invalid or corrupted input file: \"%s\"\r\n", string_get_cstr(input_path));
|
||||
(!furi_string_start_with_str(header, "IR")) || version != 1) {
|
||||
printf(
|
||||
"Invalid or corrupted input file: \"%s\"\r\n", furi_string_get_cstr(input_path));
|
||||
break;
|
||||
}
|
||||
if(!string_empty_p(output_path)) {
|
||||
printf("Writing output to file: \"%s\"\r\n", string_get_cstr(output_path));
|
||||
if(!furi_string_empty(output_path)) {
|
||||
printf("Writing output to file: \"%s\"\r\n", furi_string_get_cstr(output_path));
|
||||
output_file = flipper_format_file_alloc(storage);
|
||||
}
|
||||
if(output_file &&
|
||||
!flipper_format_file_open_always(output_file, string_get_cstr(output_path))) {
|
||||
printf("Failed to open file for writing: \"%s\"\r\n", string_get_cstr(output_path));
|
||||
!flipper_format_file_open_always(output_file, furi_string_get_cstr(output_path))) {
|
||||
printf(
|
||||
"Failed to open file for writing: \"%s\"\r\n", furi_string_get_cstr(output_path));
|
||||
break;
|
||||
}
|
||||
if(output_file && !flipper_format_write_header(output_file, header, version)) {
|
||||
printf("Failed to write to the output file: \"%s\"\r\n", string_get_cstr(output_path));
|
||||
printf(
|
||||
"Failed to write to the output file: \"%s\"\r\n",
|
||||
furi_string_get_cstr(output_path));
|
||||
break;
|
||||
}
|
||||
if(!infrared_cli_decode_file(input_file, output_file)) {
|
||||
@@ -311,31 +334,193 @@ static void infrared_cli_process_decode(Cli* cli, string_t args) {
|
||||
printf("File successfully decoded.\r\n");
|
||||
} while(false);
|
||||
|
||||
string_clear(tmp);
|
||||
string_clear(header);
|
||||
string_clear(input_path);
|
||||
string_clear(output_path);
|
||||
furi_string_free(tmp);
|
||||
furi_string_free(header);
|
||||
furi_string_free(input_path);
|
||||
furi_string_free(output_path);
|
||||
|
||||
flipper_format_free(input_file);
|
||||
if(output_file) flipper_format_free(output_file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) {
|
||||
static void infrared_cli_process_universal(Cli* cli, FuriString* args) {
|
||||
enum RemoteTypes Remote;
|
||||
|
||||
FuriString* command;
|
||||
FuriString* remote;
|
||||
FuriString* signal;
|
||||
command = furi_string_alloc();
|
||||
remote = furi_string_alloc();
|
||||
signal = furi_string_alloc();
|
||||
|
||||
do {
|
||||
if(!args_read_string_and_trim(args, command)) {
|
||||
infrared_cli_print_usage();
|
||||
break;
|
||||
}
|
||||
|
||||
if(furi_string_cmp_str(command, "list") == 0) {
|
||||
args_read_string_and_trim(args, remote);
|
||||
if(furi_string_cmp_str(remote, "tv") == 0) {
|
||||
Remote = TV;
|
||||
} else if(furi_string_cmp_str(remote, "ac") == 0) {
|
||||
Remote = AC;
|
||||
} else {
|
||||
printf("Invalid remote type.\r\n");
|
||||
break;
|
||||
}
|
||||
infrared_cli_list_remote_signals(Remote);
|
||||
break;
|
||||
}
|
||||
|
||||
if(furi_string_cmp_str(command, "tv") == 0) {
|
||||
Remote = TV;
|
||||
} else if(furi_string_cmp_str(command, "ac") == 0) {
|
||||
Remote = AC;
|
||||
} else {
|
||||
printf("Invalid remote type.\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
args_read_string_and_trim(args, signal);
|
||||
if(furi_string_empty(signal)) {
|
||||
printf("Must supply a valid signal for type of remote selected.\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
infrared_cli_brute_force_signals(cli, Remote, signal);
|
||||
break;
|
||||
|
||||
} while(false);
|
||||
|
||||
furi_string_free(command);
|
||||
furi_string_free(remote);
|
||||
furi_string_free(signal);
|
||||
}
|
||||
|
||||
static void infrared_cli_list_remote_signals(enum RemoteTypes remote_type) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* ff = flipper_format_buffered_file_alloc(storage);
|
||||
dict_signals_t signals_dict;
|
||||
string_t key;
|
||||
const char* remote_file = NULL;
|
||||
bool success = false;
|
||||
int max = 1;
|
||||
|
||||
switch(remote_type) {
|
||||
case TV:
|
||||
remote_file = EXT_PATH("infrared/assets/tv.ir");
|
||||
break;
|
||||
case AC:
|
||||
remote_file = EXT_PATH("infrared/assets/ac.ir");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
dict_signals_init(signals_dict);
|
||||
string_init(key);
|
||||
|
||||
success = flipper_format_buffered_file_open_existing(ff, remote_file);
|
||||
if(success) {
|
||||
FuriString* signal_name;
|
||||
signal_name = furi_string_alloc();
|
||||
printf("Valid signals:\r\n");
|
||||
while(flipper_format_read_string(ff, "name", signal_name)) {
|
||||
string_set_str(key, furi_string_get_cstr(signal_name));
|
||||
int* v = dict_signals_get(signals_dict, key);
|
||||
if(v != NULL) {
|
||||
(*v)++;
|
||||
max = M_MAX(*v, max);
|
||||
} else {
|
||||
dict_signals_set_at(signals_dict, key, 1);
|
||||
}
|
||||
}
|
||||
dict_signals_it_t it;
|
||||
for(dict_signals_it(it, signals_dict); !dict_signals_end_p(it); dict_signals_next(it)) {
|
||||
const struct dict_signals_pair_s* pair = dict_signals_cref(it);
|
||||
printf("\t%s\r\n", string_get_cstr(pair->key));
|
||||
}
|
||||
furi_string_free(signal_name);
|
||||
}
|
||||
|
||||
string_clear(key);
|
||||
dict_signals_clear(signals_dict);
|
||||
flipper_format_free(ff);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
static void
|
||||
infrared_cli_brute_force_signals(Cli* cli, enum RemoteTypes remote_type, FuriString* signal) {
|
||||
InfraredBruteForce* brute_force = infrared_brute_force_alloc();
|
||||
const char* remote_file = NULL;
|
||||
uint32_t i = 0;
|
||||
bool success = false;
|
||||
|
||||
switch(remote_type) {
|
||||
case TV:
|
||||
remote_file = EXT_PATH("infrared/assets/tv.ir");
|
||||
break;
|
||||
case AC:
|
||||
remote_file = EXT_PATH("infrared/assets/ac.ir");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
infrared_brute_force_set_db_filename(brute_force, remote_file);
|
||||
infrared_brute_force_add_record(brute_force, i++, furi_string_get_cstr(signal));
|
||||
|
||||
success = infrared_brute_force_calculate_messages(brute_force);
|
||||
if(success) {
|
||||
uint32_t record_count;
|
||||
uint32_t index = 0;
|
||||
int records_sent = 0;
|
||||
bool running = false;
|
||||
|
||||
running = infrared_brute_force_start(brute_force, index, &record_count);
|
||||
if(record_count <= 0) {
|
||||
printf("Invalid signal.\n");
|
||||
infrared_brute_force_clear_records(brute_force);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Sending %ld codes to the tv.\r\n", record_count);
|
||||
printf("Press Ctrl-C to stop.\r\n");
|
||||
while(running) {
|
||||
running = infrared_brute_force_send_next(brute_force);
|
||||
|
||||
if(cli_cmd_interrupt_received(cli)) break;
|
||||
|
||||
printf("\r%d%% complete.", (int)((float)records_sent++ / (float)record_count * 100));
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
infrared_brute_force_stop(brute_force);
|
||||
} else {
|
||||
printf("Invalid signal.\r\n");
|
||||
}
|
||||
|
||||
infrared_brute_force_clear_records(brute_force);
|
||||
infrared_brute_force_free(brute_force);
|
||||
}
|
||||
|
||||
static void infrared_cli_start_ir(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(context);
|
||||
if(furi_hal_infrared_is_busy()) {
|
||||
printf("INFRARED is busy. Exiting.");
|
||||
return;
|
||||
}
|
||||
|
||||
string_t command;
|
||||
string_init(command);
|
||||
FuriString* command;
|
||||
command = furi_string_alloc();
|
||||
args_read_string_and_trim(args, command);
|
||||
|
||||
size_t i = 0;
|
||||
for(; i < COUNT_OF(infrared_cli_commands); ++i) {
|
||||
size_t cmd_len = strlen(infrared_cli_commands[i].cmd);
|
||||
if(!strncmp(string_get_cstr(command), infrared_cli_commands[i].cmd, cmd_len)) {
|
||||
if(!strncmp(furi_string_get_cstr(command), infrared_cli_commands[i].cmd, cmd_len)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -346,7 +531,7 @@ static void infrared_cli_start_ir(Cli* cli, string_t args, void* context) {
|
||||
infrared_cli_print_usage();
|
||||
}
|
||||
|
||||
string_clear(command);
|
||||
furi_string_free(command);
|
||||
}
|
||||
void infrared_on_system_start() {
|
||||
#ifdef SRV_CLI
|
||||
|
||||
@@ -96,7 +96,7 @@ struct Infrared {
|
||||
Loading* loading;
|
||||
InfraredProgressView* progress;
|
||||
|
||||
string_t file_path;
|
||||
FuriString* file_path;
|
||||
char text_store[INFRARED_TEXT_STORE_NUM][INFRARED_TEXT_STORE_SIZE + 1];
|
||||
InfraredAppState app_state;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <m-string.h>
|
||||
#include <m-array.h>
|
||||
#include <toolbox/path.h>
|
||||
#include <storage/storage.h>
|
||||
@@ -15,8 +14,8 @@ ARRAY_DEF(InfraredButtonArray, InfraredRemoteButton*, M_PTR_OPLIST);
|
||||
|
||||
struct InfraredRemote {
|
||||
InfraredButtonArray_t buttons;
|
||||
string_t name;
|
||||
string_t path;
|
||||
FuriString* name;
|
||||
FuriString* path;
|
||||
};
|
||||
|
||||
static void infrared_remote_clear_buttons(InfraredRemote* remote) {
|
||||
@@ -31,39 +30,39 @@ static void infrared_remote_clear_buttons(InfraredRemote* remote) {
|
||||
InfraredRemote* infrared_remote_alloc() {
|
||||
InfraredRemote* remote = malloc(sizeof(InfraredRemote));
|
||||
InfraredButtonArray_init(remote->buttons);
|
||||
string_init(remote->name);
|
||||
string_init(remote->path);
|
||||
remote->name = furi_string_alloc();
|
||||
remote->path = furi_string_alloc();
|
||||
return remote;
|
||||
}
|
||||
|
||||
void infrared_remote_free(InfraredRemote* remote) {
|
||||
infrared_remote_clear_buttons(remote);
|
||||
InfraredButtonArray_clear(remote->buttons);
|
||||
string_clear(remote->path);
|
||||
string_clear(remote->name);
|
||||
furi_string_free(remote->path);
|
||||
furi_string_free(remote->name);
|
||||
free(remote);
|
||||
}
|
||||
|
||||
void infrared_remote_reset(InfraredRemote* remote) {
|
||||
infrared_remote_clear_buttons(remote);
|
||||
string_reset(remote->name);
|
||||
string_reset(remote->path);
|
||||
furi_string_reset(remote->name);
|
||||
furi_string_reset(remote->path);
|
||||
}
|
||||
|
||||
void infrared_remote_set_name(InfraredRemote* remote, const char* name) {
|
||||
string_set_str(remote->name, name);
|
||||
furi_string_set(remote->name, name);
|
||||
}
|
||||
|
||||
const char* infrared_remote_get_name(InfraredRemote* remote) {
|
||||
return string_get_cstr(remote->name);
|
||||
return furi_string_get_cstr(remote->name);
|
||||
}
|
||||
|
||||
void infrared_remote_set_path(InfraredRemote* remote, const char* path) {
|
||||
string_set_str(remote->path, path);
|
||||
furi_string_set(remote->path, path);
|
||||
}
|
||||
|
||||
const char* infrared_remote_get_path(InfraredRemote* remote) {
|
||||
return string_get_cstr(remote->path);
|
||||
return furi_string_get_cstr(remote->path);
|
||||
}
|
||||
|
||||
size_t infrared_remote_get_button_count(InfraredRemote* remote) {
|
||||
@@ -112,7 +111,7 @@ bool infrared_remote_delete_button(InfraredRemote* remote, size_t index) {
|
||||
bool infrared_remote_store(InfraredRemote* remote) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* ff = flipper_format_file_alloc(storage);
|
||||
const char* path = string_get_cstr(remote->path);
|
||||
const char* path = furi_string_get_cstr(remote->path);
|
||||
|
||||
FURI_LOG_I(TAG, "store file: \'%s\'", path);
|
||||
|
||||
@@ -138,33 +137,33 @@ bool infrared_remote_store(InfraredRemote* remote) {
|
||||
return success;
|
||||
}
|
||||
|
||||
bool infrared_remote_load(InfraredRemote* remote, string_t path) {
|
||||
bool infrared_remote_load(InfraredRemote* remote, FuriString* path) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* ff = flipper_format_buffered_file_alloc(storage);
|
||||
|
||||
string_t buf;
|
||||
string_init(buf);
|
||||
FuriString* buf;
|
||||
buf = furi_string_alloc();
|
||||
|
||||
FURI_LOG_I(TAG, "load file: \'%s\'", string_get_cstr(path));
|
||||
bool success = flipper_format_buffered_file_open_existing(ff, string_get_cstr(path));
|
||||
FURI_LOG_I(TAG, "load file: \'%s\'", furi_string_get_cstr(path));
|
||||
bool success = flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(path));
|
||||
|
||||
if(success) {
|
||||
uint32_t version;
|
||||
success = flipper_format_read_header(ff, buf, &version) &&
|
||||
!string_cmp_str(buf, "IR signals file") && (version == 1);
|
||||
!furi_string_cmp(buf, "IR signals file") && (version == 1);
|
||||
}
|
||||
|
||||
if(success) {
|
||||
path_extract_filename(path, buf, true);
|
||||
infrared_remote_clear_buttons(remote);
|
||||
infrared_remote_set_name(remote, string_get_cstr(buf));
|
||||
infrared_remote_set_path(remote, string_get_cstr(path));
|
||||
infrared_remote_set_name(remote, furi_string_get_cstr(buf));
|
||||
infrared_remote_set_path(remote, furi_string_get_cstr(path));
|
||||
|
||||
for(bool can_read = true; can_read;) {
|
||||
InfraredRemoteButton* button = infrared_remote_button_alloc();
|
||||
can_read = infrared_signal_read(infrared_remote_button_get_signal(button), ff, buf);
|
||||
if(can_read) {
|
||||
infrared_remote_button_set_name(button, string_get_cstr(buf));
|
||||
infrared_remote_button_set_name(button, furi_string_get_cstr(buf));
|
||||
InfraredButtonArray_push_back(remote->buttons, button);
|
||||
} else {
|
||||
infrared_remote_button_free(button);
|
||||
@@ -172,7 +171,7 @@ bool infrared_remote_load(InfraredRemote* remote, string_t path) {
|
||||
}
|
||||
}
|
||||
|
||||
string_clear(buf);
|
||||
furi_string_free(buf);
|
||||
flipper_format_free(ff);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
return success;
|
||||
@@ -181,7 +180,7 @@ bool infrared_remote_load(InfraredRemote* remote, string_t path) {
|
||||
bool infrared_remote_remove(InfraredRemote* remote) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
FS_Error status = storage_common_remove(storage, string_get_cstr(remote->path));
|
||||
FS_Error status = storage_common_remove(storage, furi_string_get_cstr(remote->path));
|
||||
infrared_remote_reset(remote);
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
@@ -25,5 +25,5 @@ bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name,
|
||||
bool infrared_remote_delete_button(InfraredRemote* remote, size_t index);
|
||||
|
||||
bool infrared_remote_store(InfraredRemote* remote);
|
||||
bool infrared_remote_load(InfraredRemote* remote, string_t path);
|
||||
bool infrared_remote_load(InfraredRemote* remote, FuriString* path);
|
||||
bool infrared_remote_remove(InfraredRemote* remote);
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
#include "infrared_remote_button.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <m-string.h>
|
||||
|
||||
struct InfraredRemoteButton {
|
||||
string_t name;
|
||||
FuriString* name;
|
||||
InfraredSignal* signal;
|
||||
};
|
||||
|
||||
InfraredRemoteButton* infrared_remote_button_alloc() {
|
||||
InfraredRemoteButton* button = malloc(sizeof(InfraredRemoteButton));
|
||||
string_init(button->name);
|
||||
button->name = furi_string_alloc();
|
||||
button->signal = infrared_signal_alloc();
|
||||
return button;
|
||||
}
|
||||
|
||||
void infrared_remote_button_free(InfraredRemoteButton* button) {
|
||||
string_clear(button->name);
|
||||
furi_string_free(button->name);
|
||||
infrared_signal_free(button->signal);
|
||||
free(button);
|
||||
}
|
||||
|
||||
void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name) {
|
||||
string_set_str(button->name, name);
|
||||
furi_string_set(button->name, name);
|
||||
}
|
||||
|
||||
const char* infrared_remote_button_get_name(InfraredRemoteButton* button) {
|
||||
return string_get_cstr(button->name);
|
||||
return furi_string_get_cstr(button->name);
|
||||
}
|
||||
|
||||
void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal) {
|
||||
|
||||
@@ -61,7 +61,7 @@ static bool infrared_signal_is_raw_valid(InfraredRawSignal* raw) {
|
||||
if((raw->frequency > INFRARED_MAX_FREQUENCY) || (raw->frequency < INFRARED_MIN_FREQUENCY)) {
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"Frequency is out of range (%lX - %lX): %lX",
|
||||
"Frequency is out of range (%X - %X): %lX",
|
||||
INFRARED_MIN_FREQUENCY,
|
||||
INFRARED_MAX_FREQUENCY,
|
||||
raw->frequency);
|
||||
@@ -74,7 +74,7 @@ static bool infrared_signal_is_raw_valid(InfraredRawSignal* raw) {
|
||||
} else if((raw->timings_size <= 0) || (raw->timings_size > MAX_TIMINGS_AMOUNT)) {
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"Timings amount is out of range (0 - %lX): %lX",
|
||||
"Timings amount is out of range (0 - %X): %X",
|
||||
MAX_TIMINGS_AMOUNT,
|
||||
raw->timings_size);
|
||||
return false;
|
||||
@@ -100,15 +100,15 @@ static inline bool infrared_signal_save_raw(InfraredRawSignal* raw, FlipperForma
|
||||
}
|
||||
|
||||
static inline bool infrared_signal_read_message(InfraredSignal* signal, FlipperFormat* ff) {
|
||||
string_t buf;
|
||||
string_init(buf);
|
||||
FuriString* buf;
|
||||
buf = furi_string_alloc();
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!flipper_format_read_string(ff, "protocol", buf)) break;
|
||||
|
||||
InfraredMessage message;
|
||||
message.protocol = infrared_get_protocol_by_name(string_get_cstr(buf));
|
||||
message.protocol = infrared_get_protocol_by_name(furi_string_get_cstr(buf));
|
||||
|
||||
success = flipper_format_read_hex(ff, "address", (uint8_t*)&message.address, 4) &&
|
||||
flipper_format_read_hex(ff, "command", (uint8_t*)&message.command, 4) &&
|
||||
@@ -119,7 +119,7 @@ static inline bool infrared_signal_read_message(InfraredSignal* signal, FlipperF
|
||||
infrared_signal_set_message(signal, &message);
|
||||
} while(0);
|
||||
|
||||
string_clear(buf);
|
||||
furi_string_free(buf);
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -146,6 +146,26 @@ static inline bool infrared_signal_read_raw(InfraredSignal* signal, FlipperForma
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool infrared_signal_read_body(InfraredSignal* signal, FlipperFormat* ff) {
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!flipper_format_read_string(ff, "type", tmp)) break;
|
||||
if(furi_string_equal(tmp, "raw")) {
|
||||
success = infrared_signal_read_raw(signal, ff);
|
||||
} else if(furi_string_equal(tmp, "parsed")) {
|
||||
success = infrared_signal_read_message(signal, ff);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unknown signal type");
|
||||
}
|
||||
} while(false);
|
||||
|
||||
furi_string_free(tmp);
|
||||
return success;
|
||||
}
|
||||
|
||||
InfraredSignal* infrared_signal_alloc() {
|
||||
InfraredSignal* signal = malloc(sizeof(InfraredSignal));
|
||||
|
||||
@@ -226,25 +246,41 @@ bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char*
|
||||
}
|
||||
}
|
||||
|
||||
bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name) {
|
||||
string_t buf;
|
||||
string_init(buf);
|
||||
bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name) {
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!flipper_format_read_string(ff, "name", buf)) break;
|
||||
string_set(name, buf);
|
||||
if(!flipper_format_read_string(ff, "type", buf)) break;
|
||||
if(!string_cmp_str(buf, "raw")) {
|
||||
success = infrared_signal_read_raw(signal, ff);
|
||||
} else if(!string_cmp_str(buf, "parsed")) {
|
||||
success = infrared_signal_read_message(signal, ff);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unknown type of signal (allowed - raw/parsed) ");
|
||||
}
|
||||
if(!flipper_format_read_string(ff, "name", tmp)) break;
|
||||
furi_string_set(name, tmp);
|
||||
if(!infrared_signal_read_body(signal, ff)) break;
|
||||
success = true;
|
||||
} while(0);
|
||||
|
||||
string_clear(buf);
|
||||
furi_string_free(tmp);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool infrared_signal_search_and_read(
|
||||
InfraredSignal* signal,
|
||||
FlipperFormat* ff,
|
||||
const FuriString* name) {
|
||||
bool success = false;
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
|
||||
do {
|
||||
bool is_name_found = false;
|
||||
while(flipper_format_read_string(ff, "name", tmp)) {
|
||||
is_name_found = furi_string_equal(name, tmp);
|
||||
if(is_name_found) break;
|
||||
}
|
||||
if(!is_name_found) break;
|
||||
if(!infrared_signal_read_body(signal, ff)) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
furi_string_free(tmp);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,10 @@ void infrared_signal_set_message(InfraredSignal* signal, const InfraredMessage*
|
||||
InfraredMessage* infrared_signal_get_message(InfraredSignal* signal);
|
||||
|
||||
bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name);
|
||||
bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, string_t name);
|
||||
bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name);
|
||||
bool infrared_signal_search_and_read(
|
||||
InfraredSignal* signal,
|
||||
FlipperFormat* ff,
|
||||
const FuriString* name);
|
||||
|
||||
void infrared_signal_transmit(InfraredSignal* signal);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -72,7 +70,7 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e
|
||||
uint32_t record_count;
|
||||
if(infrared_brute_force_start(
|
||||
brute_force, infrared_custom_event_get_value(event.event), &record_count)) {
|
||||
DOLPHIN_DEED(DolphinDeedIrBruteForce);
|
||||
DOLPHIN_DEED(DolphinDeedIrSend);
|
||||
infrared_scene_universal_common_show_popup(infrared, record_count);
|
||||
} else {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneErrorDatabases);
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -29,20 +29,20 @@ void infrared_scene_edit_rename_on_enter(void* context) {
|
||||
enter_name_length = INFRARED_MAX_REMOTE_NAME_LENGTH;
|
||||
strncpy(infrared->text_store[0], infrared_remote_get_name(remote), enter_name_length);
|
||||
|
||||
string_t folder_path;
|
||||
string_init(folder_path);
|
||||
FuriString* folder_path;
|
||||
folder_path = furi_string_alloc();
|
||||
|
||||
if(string_end_with_str_p(infrared->file_path, INFRARED_APP_EXTENSION)) {
|
||||
path_extract_dirname(string_get_cstr(infrared->file_path), folder_path);
|
||||
if(furi_string_end_with(infrared->file_path, INFRARED_APP_EXTENSION)) {
|
||||
path_extract_dirname(furi_string_get_cstr(infrared->file_path), folder_path);
|
||||
}
|
||||
|
||||
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
|
||||
string_get_cstr(folder_path),
|
||||
furi_string_get_cstr(folder_path),
|
||||
INFRARED_APP_EXTENSION,
|
||||
infrared_remote_get_name(remote));
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
|
||||
string_clear(folder_path);
|
||||
furi_string_free(folder_path);
|
||||
} else {
|
||||
furi_assert(0);
|
||||
}
|
||||
|
||||
@@ -50,8 +50,10 @@ bool infrared_scene_learn_enter_name_on_event(void* context, SceneManagerEvent e
|
||||
if(success) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneLearnDone);
|
||||
} else {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
scene_manager, InfraredSceneRemoteList);
|
||||
dialog_message_show_storage_error(infrared->dialogs, "Failed to save file");
|
||||
const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart};
|
||||
scene_manager_search_and_switch_to_previous_scene_one_of(
|
||||
scene_manager, possible_scenes, COUNT_OF(possible_scenes));
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
bool result = false;
|
||||
const char* arg = rpc_system_app_get_data(infrared->rpc_ctx);
|
||||
if(arg && (state == InfraredRpcStateIdle)) {
|
||||
string_set_str(infrared->file_path, arg);
|
||||
furi_string_set(infrared->file_path, arg);
|
||||
result = infrared_remote_load(infrared->remote, infrared->file_path);
|
||||
if(result) {
|
||||
scene_manager_set_scene_state(
|
||||
|
||||
@@ -66,7 +66,7 @@ bool infrared_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneLearn);
|
||||
consumed = true;
|
||||
} else if(submenu_index == SubmenuIndexSavedRemotes) {
|
||||
string_set_str(infrared->file_path, INFRARED_APP_FOLDER);
|
||||
furi_string_set(infrared->file_path, INFRARED_APP_FOLDER);
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneRemoteList);
|
||||
consumed = true;
|
||||
} else if(submenu_index == SubmenuIndexDebug) {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "gui/canvas.h"
|
||||
#include "gui/view.h"
|
||||
#include "input/input.h"
|
||||
#include "m-string.h"
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
#include "infrared_progress_view.h"
|
||||
|
||||
@@ -36,9 +36,9 @@ static LfRfid* lfrfid_alloc() {
|
||||
lfrfid->storage = furi_record_open(RECORD_STORAGE);
|
||||
lfrfid->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
string_init(lfrfid->file_name);
|
||||
string_init(lfrfid->raw_file_name);
|
||||
string_init_set_str(lfrfid->file_path, LFRFID_APP_FOLDER);
|
||||
lfrfid->file_name = furi_string_alloc();
|
||||
lfrfid->raw_file_name = furi_string_alloc();
|
||||
lfrfid->file_path = furi_string_alloc_set(LFRFID_APP_FOLDER);
|
||||
|
||||
lfrfid->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
|
||||
|
||||
@@ -104,9 +104,9 @@ static LfRfid* lfrfid_alloc() {
|
||||
static void lfrfid_free(LfRfid* lfrfid) {
|
||||
furi_assert(lfrfid);
|
||||
|
||||
string_clear(lfrfid->raw_file_name);
|
||||
string_clear(lfrfid->file_name);
|
||||
string_clear(lfrfid->file_path);
|
||||
furi_string_free(lfrfid->raw_file_name);
|
||||
furi_string_free(lfrfid->file_name);
|
||||
furi_string_free(lfrfid->file_path);
|
||||
protocol_dict_free(lfrfid->dict);
|
||||
|
||||
lfrfid_worker_free(lfrfid->lfworker);
|
||||
@@ -183,7 +183,7 @@ int32_t lfrfid_app(void* p) {
|
||||
app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc);
|
||||
} else {
|
||||
string_set_str(app->file_path, args);
|
||||
furi_string_set(app->file_path, args);
|
||||
lfrfid_load_key_data(app, app->file_path, true);
|
||||
view_dispatcher_attach_to_gui(
|
||||
app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
@@ -210,13 +210,13 @@ bool lfrfid_save_key(LfRfid* app) {
|
||||
|
||||
lfrfid_make_app_folder(app);
|
||||
|
||||
if(string_end_with_str_p(app->file_path, LFRFID_APP_EXTENSION)) {
|
||||
size_t filename_start = string_search_rchar(app->file_path, '/');
|
||||
string_left(app->file_path, filename_start);
|
||||
if(furi_string_end_with(app->file_path, LFRFID_APP_EXTENSION)) {
|
||||
size_t filename_start = furi_string_search_rchar(app->file_path, '/');
|
||||
furi_string_left(app->file_path, filename_start);
|
||||
}
|
||||
|
||||
string_cat_printf(
|
||||
app->file_path, "/%s%s", string_get_cstr(app->file_name), LFRFID_APP_EXTENSION);
|
||||
furi_string_cat_printf(
|
||||
app->file_path, "/%s%s", furi_string_get_cstr(app->file_name), LFRFID_APP_EXTENSION);
|
||||
|
||||
result = lfrfid_save_key_data(app, app->file_path);
|
||||
return result;
|
||||
@@ -242,14 +242,14 @@ bool lfrfid_load_key_from_file_select(LfRfid* app) {
|
||||
bool lfrfid_delete_key(LfRfid* app) {
|
||||
furi_assert(app);
|
||||
|
||||
return storage_simply_remove(app->storage, string_get_cstr(app->file_path));
|
||||
return storage_simply_remove(app->storage, furi_string_get_cstr(app->file_path));
|
||||
}
|
||||
|
||||
bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog) {
|
||||
bool lfrfid_load_key_data(LfRfid* app, FuriString* path, bool show_dialog) {
|
||||
bool result = false;
|
||||
|
||||
do {
|
||||
app->protocol_id = lfrfid_dict_file_load(app->dict, string_get_cstr(path));
|
||||
app->protocol_id = lfrfid_dict_file_load(app->dict, furi_string_get_cstr(path));
|
||||
if(app->protocol_id == PROTOCOL_NO) break;
|
||||
|
||||
path_extract_filename(path, app->file_name, true);
|
||||
@@ -263,8 +263,8 @@ bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool lfrfid_save_key_data(LfRfid* app, string_t path) {
|
||||
bool result = lfrfid_dict_file_save(app->dict, app->protocol_id, string_get_cstr(path));
|
||||
bool lfrfid_save_key_data(LfRfid* app, FuriString* path) {
|
||||
bool result = lfrfid_dict_file_save(app->dict, app->protocol_id, furi_string_get_cstr(path));
|
||||
|
||||
if(!result) {
|
||||
dialog_message_show_storage_error(app->dialogs, "Cannot save\nkey file");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user