mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 20:49:49 +04:00
Compare commits
139 Commits
unlshd-061
...
readme_upd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
226e300a16 | ||
|
|
d49246048d | ||
|
|
a90ebd7b53 | ||
|
|
b1b35e87f9 | ||
|
|
1df2fc035f | ||
|
|
45fd5ef9d8 | ||
|
|
cfa95c757e | ||
|
|
600b2ce627 | ||
|
|
fdb9748acc | ||
|
|
d40f664342 | ||
|
|
8cbb757533 | ||
|
|
452e27b05e | ||
|
|
b3cce2351a | ||
|
|
1859b06b6a | ||
|
|
1653abe0ef | ||
|
|
c7b2e85e13 | ||
|
|
b24fba6ad7 | ||
|
|
ffc6f726f0 | ||
|
|
0eb06ba2b7 | ||
|
|
2a789ae1c1 | ||
|
|
062faa4a84 | ||
|
|
1cafa9a46b | ||
|
|
654b3245c2 | ||
|
|
99eb10d6e7 | ||
|
|
e878ed7547 | ||
|
|
ac4177c248 | ||
|
|
e6f9563bbc | ||
|
|
2b383ebcee | ||
|
|
cfc5caca63 | ||
|
|
9c6e20356f | ||
|
|
0b806c2360 | ||
|
|
ce89240f6f | ||
|
|
686fab7296 | ||
|
|
7d2deb5939 | ||
|
|
06a528f497 | ||
|
|
265d2592e7 | ||
|
|
72e6f5f59e | ||
|
|
3898e6e71d | ||
|
|
17269a5386 | ||
|
|
a2bcf67f7f | ||
|
|
bd2cfb55df | ||
|
|
0c7689831e | ||
|
|
ec9df8711a | ||
|
|
15c480b68a | ||
|
|
a8456208da | ||
|
|
7ecd5684cb | ||
|
|
832d861b9d | ||
|
|
7a0c896626 | ||
|
|
52b5966262 | ||
|
|
e5fdb2e069 | ||
|
|
5eeb672dd4 | ||
|
|
d8d2b360cb | ||
|
|
7531e18020 | ||
|
|
f218c41d83 | ||
|
|
7aa55ebc6c | ||
|
|
809418b9da | ||
|
|
b91f8d009e | ||
|
|
aa1c1fd905 | ||
|
|
cb5c5c08f6 | ||
|
|
c6be6f487a | ||
|
|
5eb045e25f | ||
|
|
04b2771e3b | ||
|
|
5bd868665e | ||
|
|
46e74b3823 | ||
|
|
a772408ee6 | ||
|
|
416a02fc5b | ||
|
|
cf74dd2599 | ||
|
|
66d26c16cd | ||
|
|
c3aa151712 | ||
|
|
ce1336c0ed | ||
|
|
32fb94f5db | ||
|
|
f93aab9b22 | ||
|
|
742c4ae834 | ||
|
|
6609a64307 | ||
|
|
09aabff55b | ||
|
|
0660329ae5 | ||
|
|
b5426197f5 | ||
|
|
940ec36a0b | ||
|
|
60182aa2cd | ||
|
|
56b5b35236 | ||
|
|
b368660d48 | ||
|
|
091d32ed7a | ||
|
|
52654d018e | ||
|
|
8df9947d42 | ||
|
|
d808884b97 | ||
|
|
6042254861 | ||
|
|
beeeb9bbdc | ||
|
|
4ade0fc76d | ||
|
|
15f92f765d | ||
|
|
821f03b230 | ||
|
|
ad723217e6 | ||
|
|
df5b2cbddd | ||
|
|
dc7517e5fd | ||
|
|
20593d56c0 | ||
|
|
27b2808ade | ||
|
|
ace0901125 | ||
|
|
991e58e405 | ||
|
|
e353433cd8 | ||
|
|
200c44bdca | ||
|
|
67a0136e81 | ||
|
|
2b5ad4f5af | ||
|
|
35cdefa1ca | ||
|
|
f14ed73dfd | ||
|
|
9bf1433334 | ||
|
|
35c413b8a6 | ||
|
|
34712b0c3b | ||
|
|
486542fe14 | ||
|
|
69debc36a0 | ||
|
|
2fabb0b589 | ||
|
|
c05a766651 | ||
|
|
ac9234563a | ||
|
|
b07b6dc857 | ||
|
|
c70edf6dc9 | ||
|
|
8a3d8bdee7 | ||
|
|
535bf35e23 | ||
|
|
362aa68038 | ||
|
|
f17b941f7d | ||
|
|
830eb0e5f6 | ||
|
|
38607d8dbe | ||
|
|
fe095df06a | ||
|
|
d728c140d8 | ||
|
|
4f6fd2e9bc | ||
|
|
d7a579e713 | ||
|
|
26e5ae7476 | ||
|
|
2458cb2b96 | ||
|
|
3da9cb1b81 | ||
|
|
5924c3dd2c | ||
|
|
5cfc8fc536 | ||
|
|
03d3482357 | ||
|
|
0af8bd1e8b | ||
|
|
6330012b1d | ||
|
|
b1b00d4fa7 | ||
|
|
7a80aaa5c8 | ||
|
|
3584e0da46 | ||
|
|
e1c83692c3 | ||
|
|
3507c89dbb | ||
|
|
6e2bcd9d00 | ||
|
|
f73f369952 | ||
|
|
3990c93013 |
@@ -47,6 +47,7 @@ steps:
|
||||
- cp -R base_pack_build/artifacts-base/* assets/resources/apps/
|
||||
- rm -rf base_pack_build
|
||||
- rm -rf all-the-apps-base.tgz
|
||||
- rm -f build/f7-firmware-C/toolbox/version.*
|
||||
- ./fbt COMPACT=1 DEBUG=0 updater_package
|
||||
- mkdir artifacts-default
|
||||
- mv dist/f7-C/* artifacts-default/
|
||||
@@ -414,6 +415,7 @@ steps:
|
||||
- cp -R base_pack_build/artifacts-base/* assets/resources/apps/
|
||||
- rm -rf base_pack_build
|
||||
- rm -rf all-the-apps-base.tgz
|
||||
- rm -f build/f7-firmware-C/toolbox/version.*
|
||||
- ./fbt COMPACT=1 DEBUG=0 updater_package
|
||||
- mkdir artifacts-default
|
||||
- mv dist/f7-C/* artifacts-default/
|
||||
|
||||
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@@ -1,3 +1,4 @@
|
||||
patreon: mmxdev
|
||||
custom:
|
||||
[
|
||||
"https://boosty.to/mmxdev",
|
||||
|
||||
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -38,3 +38,7 @@
|
||||
[submodule "lib/stm32wb_copro"]
|
||||
path = lib/stm32wb_copro
|
||||
url = https://github.com/flipperdevices/stm32wb_copro.git
|
||||
[submodule "subghz_remote"]
|
||||
path = applications/main/subghz_remote
|
||||
url = https://github.com/DarkFlippers/SubGHz_Remote.git
|
||||
branch = ufw_main_app
|
||||
|
||||
16
.vscode/example/tasks.json
vendored
16
.vscode/example/tasks.json
vendored
@@ -28,29 +28,17 @@
|
||||
"command": "./fbt -c"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (ST-Link)",
|
||||
"label": "[Release] Flash (SWD)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Flash (ST-Link)",
|
||||
"label": "[Debug] Flash (SWD)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FORCE=1 flash"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (blackmagic)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_blackmagic"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Flash (blackmagic)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FORCE=1 flash_blackmagic"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (JLink)",
|
||||
"group": "build",
|
||||
|
||||
103
CHANGELOG.md
103
CHANGELOG.md
@@ -1,31 +1,41 @@
|
||||
## New changes
|
||||
* NFC: Add manually MF Classic with custom UID (by @gid9798 | PR #571)
|
||||
* Infrared: Fix crash when frequency is outside of supported range, allow sending broken files by setting frequency to nearest border
|
||||
* Infrared: Updated AC universal asset (Legion LE-F30RH-IN added and other changes) (by @Leptopt1los | PR #577)
|
||||
* SubGHz: Fix Somfy Telis wrong frequency in add manually
|
||||
* SubGHz: Fix frequency out of bounds check causing crash/freeze
|
||||
* RGB Patch: Fix colors
|
||||
* Builds: New build (clean) `c` - comes only with main apps, use in case you don't want preinstalled apps pack
|
||||
* Plugins: Moved into one repo - https://github.com/xMasterX/all-the-plugins
|
||||
* OFW PR 2984: (only buffer changes was merged, other will be later) SubGhz: fix todo (by Skorpionm)
|
||||
* OFW PR 2980: Properly reset the NFC device data (by Astrrra)
|
||||
* OFW: SubGhz: add timeout to subghz_hal_async_tx_test_run
|
||||
* OFW: Improve vscode clangd experience
|
||||
* OFW: Add the Sad song animation
|
||||
* OFW: ufbt: fixed FAP_SRC_DIR
|
||||
* OFW: UI: Clock on Desktop -> Refactoring of our desktop clock
|
||||
* OFW: uFBT: devboard_flash to update WiFi devboard
|
||||
* OFW: FBT: devboard_flash to update WiFi devboard
|
||||
* OFW: Scripts: OB recovery
|
||||
* OFW: Expose additional functions of the crypto engine to user -> **Breaking API change 34.x -> 35.x**
|
||||
* OFW: External apps removed -> In our case - moved into extra plugins repo to separate plugins and firmware
|
||||
* OFW: BadUSB: qFlipper install script for MacOS
|
||||
* OFW: Add compressor.h to the SDK
|
||||
* OFW: fbt: Fix building using path with space
|
||||
* OFW: RPC: md5 in storage list
|
||||
* OFW: Fixes 2957 - subghz decode_raw
|
||||
* OFW: FDX-B temperature in system units
|
||||
* OFW: Infrared: buttons move feature rework
|
||||
* **Apple BLE Spam app** (by @Willy-JL | Plus research from ECTO-1A, xMasterX and techryptic) -> (app can be found in builds ` `, `e`, `n`, `r`)
|
||||
* SubGHz: **FAAC SLH - Programming mode** (by @xMasterX & @Eng1n33r (full research and PoC by @Skorpionm)| PR #585) -> [How to use](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
* SubGHz: FAAC SLH -> Add manually new options
|
||||
* SubGHz: Fix 0xFFFF counter value being skipped
|
||||
* SubGHz: Fix path reset on save name scene exit
|
||||
* SubGHz: Various fixes
|
||||
* SubGHz Remote: Fix Sub-GHz Remote folder name (by @OperKH | PR #583)
|
||||
* SubGHz Remote: submodule (by @gid9798 | PR #592)
|
||||
* Infrared: Updated universal assets (by @amec0e | PR #594)
|
||||
* Infrared: Remake custom universal remotes to use new design (New icons by @Svaarich)
|
||||
* UI: Keyboard ok to toggle select all in cursor mode (by @Willy-JL)
|
||||
* CI/CD: Fixed regular builds having `c` in version name in the device info while not being actual `c` build
|
||||
* Docs: New FAAC SLH instructions
|
||||
* Docs: Readme & Changelog fixes (by @gid9798 | PR #586)
|
||||
* OFW: iButton: Return to the file selection if file is corrupted
|
||||
* OFW: Account for the "-" in line carry-over
|
||||
* OFW: github: workflow improvements
|
||||
* OFW: Storage: force mount
|
||||
* OFW: Add File Naming setting for more detailed naming -> **Breaking API change, API 35.x -> API 36.x** - **Update your apps!**
|
||||
* OFW: Disconnect from BLE on protobuf error
|
||||
* OFW: Add support for Mifare Classic 4k SAK 0x38 ATQA 0x02, 0x04, 0x08
|
||||
* OFW: Undo some TODO
|
||||
* OFW: Check the filetype of the update manifest
|
||||
* OFW: StorageListRequest: size filter
|
||||
* OFW: SubGhz: heap overflow text error
|
||||
* OFW: nfc: add rfal wrong state error handling
|
||||
* OFW: Rfid: fix crash on broken key launch from archive (fix was already done in UL in similar way)
|
||||
* OFW: AC OFF button
|
||||
* OFW: New IR universal remote graphics
|
||||
* OFW: Intelligent probing with warnings for fwflash.py
|
||||
* OFW: FuriHal: explicitly pull display pins at early init stage, move PUPD config to early stage
|
||||
* OFW: Fix display last symbol in multiline text
|
||||
* OFW: Properly reset the NFC device data
|
||||
* OFW: fbt: various improvements and bug fixes
|
||||
* OFW: Littlefs updated to v2.7.0
|
||||
* OFW: loader: restored support for debug apps
|
||||
* OFW: Removed explicit dependency on scons for external scripting
|
||||
|
||||
----
|
||||
|
||||
@@ -34,17 +44,20 @@
|
||||
[-> Download qFlipper (official link)](https://flipperzero.one/update)
|
||||
|
||||
## Please support development of the project
|
||||
* **Boosty** (patreon alternative): https://boosty.to/mmxdev
|
||||
* cloudtips (only RU payments accepted): https://pay.cloudtips.ru/p/7b3e9d65
|
||||
* YooMoney (only RU payments accepted): https://yoomoney.ru/fundraise/XA49mgQLPA0.221209
|
||||
* USDT(TRC20): `TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`
|
||||
* BCH: `qquxfyzntuqufy2dx0hrfr4sndp0tucvky4sw8qyu3`
|
||||
* ETH/BSC/ERC20-Tokens: `darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)
|
||||
* BTC: `bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`
|
||||
* DOGE: `D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`
|
||||
* LTC: `ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`
|
||||
* XMR (Monero): `41xUz92suUu1u5Mu4qkrcs52gtfpu9rnZRdBpCJ244KRHf6xXSvVFevdf2cnjS7RAeYr5hn9MsEfxKoFDRSctFjG5fv1Mhn`
|
||||
* TON: `EQCOqcnYkvzOZUV_9bPE_8oTbOrOF03MnF-VcJyjisTZmpGf`
|
||||
|Service|Remark|Link/Wallet|
|
||||
|-|-|-|
|
||||
|**Patreon**||https://patreon.com/mmxdev|
|
||||
|**Boosty**|patreon alternative|https://boosty.to/mmxdev|
|
||||
|cloudtips|only RU payments accepted|https://pay.cloudtips.ru/p/7b3e9d65|
|
||||
|YooMoney|only RU payments accepted|https://yoomoney.ru/fundraise/XA49mgQLPA0.221209|
|
||||
|USDT|(TRC20)|`TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`|
|
||||
|BCH||`qquxfyzntuqufy2dx0hrfr4sndp0tucvky4sw8qyu3`|
|
||||
|ETH|(BSC/ERC20-Tokens)|`darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)|
|
||||
|BTC||`bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`|
|
||||
|DOGE||`D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`|
|
||||
|LTC||`ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`|
|
||||
|XMR|(Monero)| `41xUz92suUu1u5Mu4qkrcs52gtfpu9rnZRdBpCJ244KRHf6xXSvVFevdf2cnjS7RAeYr5hn9MsEfxKoFDRSctFjG5fv1Mhn`|
|
||||
|TON||`EQCOqcnYkvzOZUV_9bPE_8oTbOrOF03MnF-VcJyjisTZmpGf`|
|
||||
|
||||
#### Thanks to our sponsors:
|
||||
callmezimbra, Quen0n, MERRON, grvpvl (lvpvrg), art_col, ThurstonWaffles, Moneron, UterGrooll, LUCFER, Northpirate, zloepuzo, T.Rat, Alexey B., ionelife, ...
|
||||
@@ -59,11 +72,15 @@ What build I should download and what this name means - `flipper-z-f7-update-(ve
|
||||
`f7` = Hardware version - same for all flipper zero devices<br>
|
||||
`update` = Update package, contains updater, all assets (plugins, IR libs, etc.), and firmware itself<br>
|
||||
`(version)` = Firmware version<br>
|
||||
` ` = this build comes with 3 custom animations, and default apps preinstalled<br>
|
||||
`c` = this build comes with 3 custom animations, and only main apps (Clean build)<br>
|
||||
`n` = this build comes without our custom animations (we have only 3 of them), only official flipper animations<br>
|
||||
`e` = build has 🎲 [extra apps pack](https://github.com/xMasterX/all-the-plugins) preinstalled<br>
|
||||
`r` = RGB patch (+ extra apps) for flippers with rgb backlight mod (this is hardware mod!) (Works only on modded flippers!) (do not install on non modded device!)
|
||||
| Designation | 3 Custom Animation | [Base Apps](https://github.com/xMasterX/all-the-plugins#default-pack) | [Extra Apps](https://github.com/xMasterX/all-the-plugins#extra-pack) | ⚠️RGB mode* |
|
||||
|-----|:---:|:---:|:---:|:---:|
|
||||
| ` ` | ✅ | ✅ | | |
|
||||
| `c` | ✅ | | | |
|
||||
| `n` | | ✅ | | |
|
||||
| `e` | ✅ | ✅ | ✅ | |
|
||||
| `r` | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
⚠️This is [hardware mod](https://github.com/quen0n/flipperzero-firmware-rgb#readme), works only on modded flippers! do not install on non modded device!
|
||||
|
||||
Firmware Self-update package (update from microSD) - `flipper-z-f7-update-(version).tgz` for mobile app / qFlipper / web<br>
|
||||
Archive of `scripts` folder (contains scripts for FW/plugins development) - `flipper-z-any-scripts-(version).tgz`<br>
|
||||
|
||||
224
ReadMe.md
224
ReadMe.md
@@ -3,6 +3,20 @@
|
||||
<img src="https://user-images.githubusercontent.com/10697207/186202043-26947e28-b1cc-459a-8f20-ffcc7fc0c71c.png" align="center" alt="fzCUSTOM" border="0">
|
||||
</a>
|
||||
</h3>
|
||||
<div align="center" id="badges">
|
||||
<a href="https://discord.unleashedflip.com">
|
||||
<img src="https://img.shields.io/discord/937479784148115456?style=flat-square&logo=discord&label=Discord&color=%237289DA&link=https%3A%2F%2Fdiscord.unleashedflip.com%2F" alt="Discord server"/>
|
||||
</a>
|
||||
<a href="https://t.me/flipperzero_unofficial">
|
||||
<img src="https://img.shields.io/endpoint?label=EN%20Channel&style=flat-square&url=https%3A%2F%2Fmogyo.ro%2Fquart-apis%2Ftgmembercount%3Fchat_id%3Dflipperzero_unofficial" alt="EN TG channel"/>
|
||||
</a>
|
||||
<a href="https://t.me/flipperzero_unofficial_ru">
|
||||
<img src="https://img.shields.io/endpoint?label=RU%20Channel&style=flat-square&url=https%3A%2F%2Fmogyo.ro%2Fquart-apis%2Ftgmembercount%3Fchat_id%3Dflipperzero_unofficial_ru" alt="RU TG channel"/>
|
||||
</a>
|
||||
<a href="https://t.me/flipperzero_unofficial_ua">
|
||||
<img src="https://img.shields.io/endpoint?label=UA%20Channel&style=flat-square&url=https%3A%2F%2Fmogyo.ro%2Fquart-apis%2Ftgmembercount%3Fchat_id%3Dflipperzero_unofficial_ua" alt="UA TG channel"/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Welcome to the Flipper Zero Unleashed Firmware repo!
|
||||
|
||||
@@ -16,13 +30,7 @@
|
||||
|
||||
##### This software is for experimental purposes only and is not meant for any illegal activity/purposes. <br> We do not condone illegal activity and strongly encourage keeping transmissions to legal/valid uses allowed by law. <br> Also, this software is made without any support from Flipper Devices and is in no way related to the official devs.
|
||||
|
||||
<br>
|
||||
Our Discord Community:
|
||||
<br>
|
||||
<a href="https://discord.unleashedflip.com"><img src="https://discordapp.com/api/guilds/937479784148115456/widget.png?style=banner4" alt="Unofficial Discord Community" target="_blank"></a>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Dev builds (unstable)
|
||||
@@ -32,45 +40,59 @@ Our Discord Community:
|
||||
- https://t.me/unleashed_fw
|
||||
|
||||
# What's changed
|
||||
* Sub-GHz regional TX restrictions removed
|
||||
* Sub-GHz frequency range can be extended in settings file (Warning: It can damage Flipper's hardware)
|
||||
* Many rolling code protocols now have the ability to save & send captured signals
|
||||
* FAAC SLH (Spa) & BFT Mitto (keeloq secure with seed) manual creation
|
||||
* Sub-GHz static code brute-force plugin
|
||||
* LFRFID Fuzzer plugin
|
||||
* Custom community plugins and games added + all known working apps can be downloaded in extra pack in every release
|
||||
* Extra Sub-GHz frequencies + extra Mifare Classic keys
|
||||
* Picopass/iClass plugin included in releases
|
||||
* Recompiled IR TV Universal Remote for ALL buttons
|
||||
* Universal remote for Projectors, Fans, A/Cs and Audio(soundbars, etc.)
|
||||
* Customizable Flipper name **Update! Now can be changed in Settings->Desktop** (by @xMasterX and @Willy-JL)
|
||||
* Text Input UI element -> Cursor feature (by @Willy-JL)
|
||||
- **BadBT** plugin (BT version of BadKB) [(by Willy-JL, ClaraCrazy, XFW contributors)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/main/bad_kb) - (See in Applications->Tools) - (aka BadUSB via Bluetooth)
|
||||
- BadUSB -> Keyboard layouts [(by rien > dummy-decoy)](https://github.com/dummy-decoy/flipperzero-firmware/tree/dummy_decoy/bad_usb_keyboard_layout)
|
||||
- Sub-GHz -> External CC1101 module support - [(by quen0n)](https://github.com/DarkFlippers/unleashed-firmware/pull/307)
|
||||
- Sub-GHz -> `Add manually` menu extended with new protocols
|
||||
- Sub-GHz -> New frequency analyzer - [(by ClusterM)](https://github.com/DarkFlippers/unleashed-firmware/pull/43)
|
||||
- Sub-GHz -> Save last used frequency [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
|
||||
- Sub-GHz -> Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
|
||||
- Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79)
|
||||
- Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107)
|
||||
* Sub-GHz -> Short press OK in frequency analyzer to save detected frequency for usage in Read modes
|
||||
* Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu and automatically use selected frequency
|
||||
* SubGHz -> New option to use timestamps + protocol name when you saving file, instead of random name - Enable in `Radio Settings -> Time in names = ON`
|
||||
* SubGHz Bruteforcer plugin -> Time delay (between signals) setting (hold Up in main screen(says Up to Save)) + configure repeats in protocols list by pressing right button on selected protocol
|
||||
* SubGHz -> Read mode UI improvements (scrolling text, + shows time when signal was received) (by @wosk)
|
||||
* Sub-GHz -> External CC1101 module support (Hardware SPI used)
|
||||
* SubGHz -> **Hold right in received signal list to delete selected signal**
|
||||
* SubGHz -> **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S / Somfy Telis / Security+ 2.0 / CAME Atomo** - now you can use arrow buttons to send signal with different button code
|
||||
* SubGHz -> BFT Mitto / Somfy Telis / Nice Flor S / CAME Atomo, etc.. manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis)
|
||||
* SubGHz -> Debug mode counter increase settings (+1 -> +5, +10, default: +1)
|
||||
* SubGHz -> Debug PIN output settings for protocol development
|
||||
* Infrared -> `RCA` Protocol
|
||||
* Infrared -> Debug TX PIN output settings
|
||||
* Other small fixes and changes throughout
|
||||
* See other changes in readme below
|
||||
- **Sub-GHz** *lib & hal*
|
||||
- Regional TX restrictions removed
|
||||
- Extra Sub-GHz frequencies
|
||||
- Frequency range can be extended in settings file (Warning: It can damage Flipper's hardware)
|
||||
- Many rolling code [protocols](https://github.com/DarkFlippers/unleashed-firmware#current-modified-and-new-sub-ghz-protocols-list) now have the ability to save & send captured signals
|
||||
- FAAC SLH (Spa) & BFT Mitto (keeloq secure with seed) manual creation
|
||||
- External CC1101 module support [(by quen0n)](https://github.com/DarkFlippers/unleashed-firmware/pull/307)
|
||||
- **Sub-GHz** *Main App*
|
||||
- Save last used frequency [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
|
||||
- New frequency analyzer [(by ClusterM)](https://github.com/DarkFlippers/unleashed-firmware/pull/43)
|
||||
- Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
|
||||
- Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79)
|
||||
- New option to use timestamps + protocol name when you saving file, instead of random name - Enable in `Radio Settings -> Time in names = ON`
|
||||
- Read mode UI improvements (shows time when signal was received) (by @wosk)
|
||||
- External CC1101 module support (Hardware SPI used)
|
||||
- **Hold right in received signal list to delete selected signal**
|
||||
- **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S / Somfy Telis / Security+ 2.0 / CAME Atomo** - now you can use arrow buttons to send signal with different button code
|
||||
- `Add manually` menu extended with new protocols
|
||||
- FAAC SLH, BFT Mitto / Somfy Telis / Nice Flor S / CAME Atomo, etc.. manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis)
|
||||
- Debug mode counter increase settings (+1 -> +5, +10, default: +1)
|
||||
- Debug PIN output settings for protocol development
|
||||
|
||||
- **Sub-GHz apps** *by unleashed team*
|
||||
- Sub-GHz Bruteforce - static code brute-force plugin |
|
||||
- Time delay (between signals) setting (hold Up in main screen(says Up to Save)) + configure repeats in protocols list by pressing right button on selected protocol
|
||||
- Load your own file and select bytes you want to bruteforce or use preconfigured options in protocols list
|
||||
- Sub-GHz Remote - remote control for 5 sub-ghz files | bind one file for each button
|
||||
- use the built-in constructor or make config file by following this [instruction](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)
|
||||
- **Infrared**
|
||||
- Recompiled IR TV Universal Remote for ALL buttons
|
||||
- Universal remotes for Projectors, Fans, A/Cs and Audio(soundbars, etc.) -> Also always updated and verified by our team
|
||||
- Infrared -> `RCA` Protocol
|
||||
- Infrared -> Debug TX PIN output settings
|
||||
- **NFC/RFID/iButton**
|
||||
* LFRFID/iButton Fuzzer plugins
|
||||
* Extra Mifare Classic keys
|
||||
* `Add manually` -> Mifare Classic with custom UID
|
||||
* Picopass/iClass plugin (now with emulation support!) included in releases
|
||||
- **Quality of life & other features**
|
||||
- Customizable Flipper name **Update! Now can be changed in Settings->Desktop** (by @xMasterX and @Willy-JL)
|
||||
- Text Input UI element -> Cursor feature (by @Willy-JL)
|
||||
- Byte Input Mini editor -> **Press UP** multiple times until the nibble editor appears
|
||||
- Clock on Desktop -> `Settings -> Desktop -> Show Clock`
|
||||
- Battery percentage display with different styles `Settings -> Desktop -> Battery View`
|
||||
- More games in Dummy Mode -> click or hold any of arrow buttons
|
||||
- Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107)
|
||||
- **BadBT** plugin (BT version of BadKB) [(by Willy-JL, ClaraCrazy, XFW contributors)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/main/bad_kb) - (See in Applications->Tools) - (aka BadUSB via Bluetooth)
|
||||
- BadUSB -> Keyboard layouts [(by rien > dummy-decoy)](https://github.com/dummy-decoy/flipperzero-firmware/tree/dummy_decoy/bad_usb_keyboard_layout)
|
||||
- Custom community plugins and games added + all known working apps can be downloaded in extra pack in every release
|
||||
- Other small fixes and changes throughout
|
||||
- See other changes in readme below
|
||||
|
||||
Also check the changelog in releases for latest updates!
|
||||
Also check the [changelog in releases](https://github.com/DarkFlippers/unleashed-firmware/releases) for latest updates!
|
||||
|
||||
### Current modified and new Sub-GHz protocols list:
|
||||
Thanks to Official team (to their SubGHz Developer, Skorp) for implementing decoders for these protocols in OFW.
|
||||
@@ -98,8 +120,8 @@ Encoders or sending made by @xMasterX:
|
||||
Encoders or sending made by @Eng1n33r(first implementation in Q2 2022) & @xMasterX (current version):
|
||||
- CAME Atomo -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
- Nice Flor S -> How to create new remote - [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
- FAAC SLH (Spa) [External seed calculation required (For info contact me in Discord: @mmx7)]
|
||||
- Keeloq: BFT Mitto -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
- FAAC SLH (Spa) -> Update!!! Check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
- Keeloq: BFT Mitto -> Update! Check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
- Star Line
|
||||
- Security+ v1 & v2 (encoders was made in OFW)
|
||||
|
||||
@@ -124,87 +146,99 @@ Our team is small and the guys are working on this project as much as they can s
|
||||
The amount of work done on this project is huge and we need your support, no matter how large or small. Even if you just say, "Thank you Unleashed firmware developers!" somewhere. Doing so will help us continue our work and will help drive us to make the firmware better every time.
|
||||
Also, regarding our releases, every build has and always will be free and open-source. There will be no paywall releases or closed-source apps within the firmware. As long as I am working on this project it will never happen.
|
||||
You can support us by using links or addresses below:
|
||||
* **Boosty** (patreon alternative): https://boosty.to/mmxdev
|
||||
* cloudtips (only RU payments accepted): https://pay.cloudtips.ru/p/7b3e9d65
|
||||
* YooMoney (only RU payments accepted): https://yoomoney.ru/fundraise/XA49mgQLPA0.221209
|
||||
* USDT(TRC20): `TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`
|
||||
* BCH: `qquxfyzntuqufy2dx0hrfr4sndp0tucvky4sw8qyu3`
|
||||
* ETH/BSC/ERC20-Tokens: `darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)
|
||||
* BTC: `bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`
|
||||
* DOGE: `D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`
|
||||
* LTC: `ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`
|
||||
* XMR (Monero): `41xUz92suUu1u5Mu4qkrcs52gtfpu9rnZRdBpCJ244KRHf6xXSvVFevdf2cnjS7RAeYr5hn9MsEfxKoFDRSctFjG5fv1Mhn`
|
||||
* TON: `EQCOqcnYkvzOZUV_9bPE_8oTbOrOF03MnF-VcJyjisTZmpGf`
|
||||
|Service|Remark|Link/Wallet|
|
||||
|-|-|-|
|
||||
|**Patreon**||https://patreon.com/mmxdev|
|
||||
|**Boosty**|patreon alternative|https://boosty.to/mmxdev|
|
||||
|cloudtips|only RU payments accepted|https://pay.cloudtips.ru/p/7b3e9d65|
|
||||
|YooMoney|only RU payments accepted|https://yoomoney.ru/fundraise/XA49mgQLPA0.221209|
|
||||
|USDT|(TRC20)|`TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`|
|
||||
|BCH||`qquxfyzntuqufy2dx0hrfr4sndp0tucvky4sw8qyu3`|
|
||||
|ETH|(BSC/ERC20-Tokens)|`darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)|
|
||||
|BTC||`bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`|
|
||||
|DOGE||`D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`|
|
||||
|LTC||`ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`|
|
||||
|XMR|(Monero)| `41xUz92suUu1u5Mu4qkrcs52gtfpu9rnZRdBpCJ244KRHf6xXSvVFevdf2cnjS7RAeYr5hn9MsEfxKoFDRSctFjG5fv1Mhn`|
|
||||
|TON||`EQCOqcnYkvzOZUV_9bPE_8oTbOrOF03MnF-VcJyjisTZmpGf`|
|
||||
|
||||
### Community apps included:
|
||||
## Community apps included
|
||||
|
||||
#### See full list and sources here: https://github.com/xMasterX/all-the-plugins/tree/dev
|
||||
### [🎲 Download Extra plugins for Unleashed](https://github.com/xMasterX/all-the-plugins/releases/latest)
|
||||
### [List of Extra pack](https://github.com/xMasterX/all-the-plugins/tree/dev#extra-pack) | [List of Base *(Deafult)* pack](https://github.com/xMasterX/all-the-plugins/tree/dev#default-pack)
|
||||
|
||||
See full list and sources here: [xMasterX/all-the-plugin](https://github.com/xMasterX/all-the-plugins/tree/dev)
|
||||
|
||||
### Official Flipper Zero Apps Catalog [web version](https://lab.flipper.net/apps) or mobile app
|
||||
|
||||
# Instructions
|
||||
## [- How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)
|
||||
## First lock official docs [docs.flipper.net](https://docs.flipper.net/)
|
||||
## [How to install](/documentation/HowToInstall.md) - [versions info](/CHANGELOG.md#what-n-r-e--c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater): `n`,` `,`e`...
|
||||
## Firmware & Development
|
||||
|
||||
## [- How to build firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToBuild.md)
|
||||
### - **[How to build](/documentation/HowToBuild.md#how-to-build-by-yourself) | [Project-structure](#project-structure)**
|
||||
|
||||
## [- How to connect external CC1101 module](https://github.com/quen0n/flipperzero-ext-cc1101)
|
||||
### - **CLion IDE** - How to setup workspace for flipper firmware development [by Savely Krasovsky](https://krasovs.ky/2022/11/01/flipper-zero-clion.html)
|
||||
|
||||
## [- BadUSB: how to add new keyboard layouts](https://github.com/dummy-decoy/flipperzero_badusb_kl)
|
||||
### - **"Hello world!"** - plugin tutorial [English<sub> by DroomOne</sub> ](https://github.com/DroomOne/Flipper-Plugin-Tutorial) | [Russian<sub> by Pavel Yakovlev</sub>](https://yakovlev.me/hello-flipper-zero/)
|
||||
|
||||
## [- How to change Flipper name](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/CustomFlipperName.md)
|
||||
### - [How to write your own app](https://flipper.atmanos.com/docs/overview/intro). Docs by atmanos **⚠️outdated API**
|
||||
|
||||
## [- How to use Mifare Nested plugin to recover keys](https://github.com/AloneLiberty/FlipperNested#how-to-use-it)
|
||||
## Firmware & main Apps feature
|
||||
|
||||
## [- How to make captures to add them into Universal IR remotes](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/InfraredCaptures.md)
|
||||
### - System: [How to change Flipper name](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/CustomFlipperName.md)
|
||||
|
||||
### **Sub-GHz**
|
||||
### - BadUSB: [How to add new keyboard layouts](https://github.com/dummy-decoy/flipperzero_badusb_kl)
|
||||
|
||||
## [- Transmission is blocked? - How to extend Sub-GHz frequency range](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md)
|
||||
### - Infrared: [How to make captures to add them into Universal IR remotes](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/InfraredCaptures.md)
|
||||
|
||||
## [- How to add extra Sub-GHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md)
|
||||
## **Sub-GHz**
|
||||
|
||||
## [- How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis, Aprimatic, AN-Motors, etc..)](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
### - External Radio: [How to connect CC1101 module](https://github.com/quen0n/flipperzero-ext-cc1101)
|
||||
|
||||
## [- Configure Sub-GHz Remote App](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)
|
||||
### - Transmission is blocked? [How to extend Sub-GHz frequency range](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md)
|
||||
|
||||
### **Plugins**
|
||||
### - [How to add extra Sub-GHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md)
|
||||
|
||||
## [- 🎲 Download Extra plugins for Unleashed](https://github.com/xMasterX/all-the-plugins)
|
||||
### - [How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis, Aprimatic, AN-Motors, etc..)](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
|
||||
## [- TOTP (Authenticator) config description](https://github.com/akopachov/flipper-zero_authenticator/blob/master/docs/conf-file_description.md)
|
||||
### - [~~Configure Sub-GHz Remote App~~](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md) Not recomeded, please use embedded configurator
|
||||
|
||||
## [- Barcode Generator](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/BarcodeGenerator.md)
|
||||
## **Plugins**
|
||||
|
||||
## [- Multi Converter](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/MultiConverter.md)
|
||||
### - TOTP (Authenticator): [config description](https://github.com/akopachov/flipper-zero_authenticator/blob/master/docs/conf-file_description.md)
|
||||
|
||||
## [- WAV Player sample files & how to convert](https://github.com/UberGuidoZ/Flipper/tree/main/Wav_Player#readme)
|
||||
### - Mifare Nested plugin: [How to recover keys](https://github.com/AloneLiberty/FlipperNested#how-to-use-it)
|
||||
|
||||
## [- Sub-GHz playlist generator script](https://github.com/darmiel/flipper-scripts/blob/main/playlist/playlist_creator_by_chunk.py)
|
||||
### - Barcode Generator: [How to use](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/BarcodeGenerator.md)
|
||||
|
||||
### **Plugins that works with external hardware**
|
||||
### - Multi Converter: [How to use](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/MultiConverter.md)
|
||||
|
||||
## [- How to use: Unitemp - Temperature sensors reader](https://github.com/quen0n/unitemp-flipperzero#readme)
|
||||
### - WAV Player: [sample files & how to convert](https://github.com/UberGuidoZ/Flipper/tree/main/Wav_Player#readme)
|
||||
|
||||
## [- How to use: [NMEA] GPS](https://github.com/xMasterX/all-the-plugins/blob/dev/base_pack/gps_nmea_uart/README.md)
|
||||
### - Sub-GHz playlist: [generator script](https://github.com/darmiel/flipper-scripts/blob/main/playlist/playlist_creator_by_chunk.py)
|
||||
|
||||
## [- How to use: i2c Tools](https://github.com/xMasterX/all-the-plugins/blob/dev/base_pack/flipper_i2ctools/README.md)
|
||||
## **Plugins that works with external hardware** [GPIO]
|
||||
|
||||
## [- How to use: [NRF24] plugins](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/NRF24.md)
|
||||
### - Unitemp - Temperature sensors reader: [How to use & supported sensors](https://github.com/quen0n/unitemp-flipperzero#readme)
|
||||
|
||||
## [- How to use: [WiFi] Scanner](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module#readme)
|
||||
### - [NMEA] GPS: [How to use](https://github.com/xMasterX/all-the-plugins/blob/dev/base_pack/gps_nmea_uart/README.md)
|
||||
|
||||
## [- How to use: [ESP8266] Deauther](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module#readme)
|
||||
### - i2c Tools [How to use](https://github.com/xMasterX/all-the-plugins/blob/dev/base_pack/flipper_i2ctools/README.md)
|
||||
|
||||
## [- How to use: [ESP32] WiFi Marauder](https://github.com/UberGuidoZ/Flipper/tree/main/Wifi_DevBoard)
|
||||
### - [NRF24] plugins: [How to use](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/NRF24.md)
|
||||
|
||||
## [- How to use: [ESP32-CAM] Camera Suite](https://github.com/CodyTolene/Flipper-Zero-Camera-Suite)
|
||||
|
||||
## [- [WiFi] Scanner - Web Flasher for module firmware](https://sequoiasan.github.io/FlipperZero-WiFi-Scanner_Module/)
|
||||
### - [WiFi] Scanner: [How to use](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module#readme) | [Web Flasher](https://sequoiasan.github.io/FlipperZero-WiFi-Scanner_Module/)
|
||||
|
||||
## [- [ESP8266] Deauther - Web Flasher for module firmware](https://sequoiasan.github.io/FlipperZero-Wifi-ESP8266-Deauther-Module/)
|
||||
### - [ESP8266] Deauther: [How to use](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module#readme) | [Web Flasher](https://sequoiasan.github.io/FlipperZero-Wifi-ESP8266-Deauther-Module/)
|
||||
|
||||
## [- Windows: How to Upload .bin to ESP32/ESP8266](https://github.com/SequoiaSan/Guide-How-To-Upload-bin-to-ESP8266-ESP32)
|
||||
### - [ESP32] WiFi Marauder: [How to use](https://github.com/UberGuidoZ/Flipper/tree/main/Wifi_DevBoard)<sub> docs by UberGuidoZ</sub> | [Marauder repo](https://github.com/justcallmekoko/ESP32Marauder)
|
||||
|
||||
## [- How to use: [GPIO] SentrySafe plugin](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SentrySafe.md)
|
||||
### - [ESP32-CAM] Camera Suite: [How to use](https://github.com/CodyTolene/Flipper-Zero-Camera-Suite)
|
||||
|
||||
### - How to Upload `.bin` to ESP32/ESP8266: [Windows](https://github.com/SequoiaSan/Guide-How-To-Upload-bin-to-ESP8266-ESP32) | [FAP "ESP flasher"](https://github.com/0xchocolate/flipperzero-esp-flasher)
|
||||
|
||||
### - [GPIO] SentrySafe plugin: [How to use](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SentrySafe.md)
|
||||
|
||||
<br>
|
||||
<br>
|
||||
@@ -218,13 +252,7 @@ You can support us by using links or addresses below:
|
||||
|
||||
# Links
|
||||
|
||||
* Unofficial Discord: [discord.unleashedflip.com](https://discord.unleashedflip.com)
|
||||
* Hello world - plugin tutorial (English): [https://github.com/DroomOne/Flipper-Plugin-Tutorial](https://github.com/DroomOne/Flipper-Plugin-Tutorial)
|
||||
* Hello world - plugin tutorial (in Russian): [https://yakovlev.me/hello-flipper-zero/](https://yakovlev.me/hello-flipper-zero/)
|
||||
* CLion IDE - How to setup workspace for flipper firmware development: [https://krasovs.ky/2022/11/01/flipper-zero-clion.html](https://krasovs.ky/2022/11/01/flipper-zero-clion.html)
|
||||
* 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)
|
||||
* Official Docs: [docs.flipper.net](https://docs.flipper.net/)
|
||||
* Official Forum: [forum.flipperzero.one](https://forum.flipperzero.one/)
|
||||
|
||||
# Project structure
|
||||
|
||||
20
SConstruct
20
SConstruct
@@ -185,27 +185,15 @@ copro_dist = distenv.CoproBuilder(
|
||||
distenv.AlwaysBuild(copro_dist)
|
||||
distenv.Alias("copro_dist", copro_dist)
|
||||
|
||||
firmware_flash = distenv.AddOpenOCDFlashTarget(firmware_env)
|
||||
|
||||
firmware_flash = distenv.AddFwFlashTarget(firmware_env)
|
||||
distenv.Alias("flash", firmware_flash)
|
||||
|
||||
# To be implemented in fwflash.py
|
||||
firmware_jflash = distenv.AddJFlashTarget(firmware_env)
|
||||
distenv.Alias("jflash", firmware_jflash)
|
||||
|
||||
firmware_bm_flash = distenv.PhonyTarget(
|
||||
"flash_blackmagic",
|
||||
"$GDB $GDBOPTS $SOURCES $GDBFLASH",
|
||||
source=firmware_env["FW_ELF"],
|
||||
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
||||
GDBREMOTE="${BLACKMAGIC_ADDR}",
|
||||
GDBFLASH=[
|
||||
"-ex",
|
||||
"load",
|
||||
"-ex",
|
||||
"quit",
|
||||
],
|
||||
)
|
||||
|
||||
gdb_backtrace_all_threads = distenv.PhonyTarget(
|
||||
distenv.PhonyTarget(
|
||||
"gdb_trace_all",
|
||||
"$GDB $GDBOPTS $SOURCES $GDBFLASH",
|
||||
source=firmware_env["FW_ELF"],
|
||||
|
||||
@@ -174,7 +174,7 @@ bool WIEGAND::DoWiegandConversion() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Handle validation failure case!
|
||||
// TODO FL-3490: Handle validation failure case!
|
||||
} else if(4 == _bitCount) {
|
||||
// 4-bit Wiegand codes have no data integrity check so we just
|
||||
// read the LOW nibble.
|
||||
|
||||
@@ -56,7 +56,6 @@ static void subghz_test_packet_rx_callback(bool level, uint32_t duration, void*
|
||||
subghz_decoder_princeton_for_testing_parse(instance->decoder, level, duration);
|
||||
}
|
||||
|
||||
//todo
|
||||
static void subghz_test_packet_rx_pt_callback(SubGhzDecoderPrinceton* parser, void* context) {
|
||||
UNUSED(parser);
|
||||
furi_assert(context);
|
||||
|
||||
@@ -26,7 +26,6 @@ void test_furi_memmgr() {
|
||||
mu_assert_int_eq(66, ((uint8_t*)ptr)[i]);
|
||||
}
|
||||
|
||||
// TODO: fix realloc to copy only old size, and write testcase that leftover of reallocated memory is zero-initialized
|
||||
free(ptr);
|
||||
|
||||
// allocate and zero-initialize array (calloc)
|
||||
|
||||
@@ -69,7 +69,7 @@ MU_TEST(mu_test_furi_string_mem) {
|
||||
mu_check(string != NULL);
|
||||
mu_check(!furi_string_empty(string));
|
||||
|
||||
// TODO: how to test furi_string_reserve?
|
||||
// TODO FL-3493: how to test furi_string_reserve?
|
||||
|
||||
// test furi_string_reset
|
||||
furi_string_reset(string);
|
||||
|
||||
@@ -311,7 +311,7 @@ MU_TEST(test_bit_lib_test_parity) {
|
||||
}
|
||||
|
||||
MU_TEST(test_bit_lib_remove_bit_every_nth) {
|
||||
// TODO: more tests
|
||||
// TODO FL-3494: more tests
|
||||
uint8_t data_i[1] = {0b00001111};
|
||||
uint8_t data_o[1] = {0b00011111};
|
||||
size_t length;
|
||||
|
||||
@@ -67,7 +67,6 @@ static RpcSessionContext rpc_session[TEST_RPC_SESSIONS];
|
||||
} while(0)
|
||||
|
||||
static void output_bytes_callback(void* ctx, uint8_t* got_bytes, size_t got_size);
|
||||
static void clean_directory(Storage* fs_api, const char* clean_dir);
|
||||
static void
|
||||
test_rpc_add_empty_to_list(MsgList_t msg_list, PB_CommandStatus status, uint32_t command_id);
|
||||
static void test_rpc_encode_and_feed(MsgList_t msg_list, uint8_t session);
|
||||
@@ -149,11 +148,41 @@ static void test_rpc_teardown_second_session(void) {
|
||||
rpc_session[1].session = NULL;
|
||||
}
|
||||
|
||||
static void test_rpc_storage_clean_directory(Storage* fs_api, const char* clean_dir) {
|
||||
furi_check(fs_api);
|
||||
furi_check(clean_dir);
|
||||
storage_simply_remove_recursive(fs_api, clean_dir);
|
||||
FS_Error error = storage_common_mkdir(fs_api, clean_dir);
|
||||
furi_check(error == FSE_OK);
|
||||
}
|
||||
|
||||
static void test_rpc_storage_create_file(Storage* fs_api, const char* path, size_t size) {
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
bool success = false;
|
||||
do {
|
||||
if(!storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) break;
|
||||
if(!storage_file_seek(file, size, true)) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
|
||||
furi_check(success);
|
||||
}
|
||||
|
||||
static void test_rpc_storage_setup(void) {
|
||||
test_rpc_setup();
|
||||
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
clean_directory(fs_api, TEST_DIR_NAME);
|
||||
test_rpc_storage_clean_directory(fs_api, TEST_DIR_NAME);
|
||||
test_rpc_storage_create_file(fs_api, TEST_DIR_NAME "/file100", 100);
|
||||
test_rpc_storage_create_file(fs_api, TEST_DIR_NAME "/file250", 250);
|
||||
test_rpc_storage_create_file(fs_api, TEST_DIR_NAME "/file500", 200);
|
||||
test_rpc_storage_create_file(fs_api, TEST_DIR_NAME "/file1000", 1000);
|
||||
test_rpc_storage_create_file(fs_api, TEST_DIR_NAME "/file2500", 2500);
|
||||
test_rpc_storage_create_file(fs_api, TEST_DIR_NAME "/file5000", 5000);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
@@ -161,7 +190,7 @@ static void test_rpc_storage_teardown(void) {
|
||||
test_rpc_teardown();
|
||||
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
clean_directory(fs_api, TEST_DIR_NAME);
|
||||
test_rpc_storage_clean_directory(fs_api, TEST_DIR_NAME);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
@@ -179,36 +208,6 @@ static void test_rpc_session_terminated_callback(void* context) {
|
||||
xSemaphoreGive(callbacks_context->terminate_semaphore);
|
||||
}
|
||||
|
||||
static void clean_directory(Storage* fs_api, const char* clean_dir) {
|
||||
furi_check(fs_api);
|
||||
furi_check(clean_dir);
|
||||
|
||||
File* dir = storage_file_alloc(fs_api);
|
||||
if(storage_dir_open(dir, clean_dir)) {
|
||||
FileInfo fileinfo;
|
||||
char* name = malloc(MAX_NAME_LENGTH + 1);
|
||||
while(storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH)) {
|
||||
size_t size = strlen(clean_dir) + strlen(name) + 1 + 1;
|
||||
char* fullname = malloc(size);
|
||||
snprintf(fullname, size, "%s/%s", clean_dir, name);
|
||||
if(file_info_is_dir(&fileinfo)) {
|
||||
clean_directory(fs_api, fullname);
|
||||
}
|
||||
FS_Error error = storage_common_remove(fs_api, fullname);
|
||||
furi_check(error == FSE_OK);
|
||||
free(fullname);
|
||||
}
|
||||
free(name);
|
||||
} else {
|
||||
FS_Error error = storage_common_mkdir(fs_api, clean_dir);
|
||||
(void)error;
|
||||
furi_check(error == FSE_OK);
|
||||
}
|
||||
|
||||
storage_dir_close(dir);
|
||||
storage_file_free(dir);
|
||||
}
|
||||
|
||||
static void test_rpc_print_message_list(MsgList_t msg_list) {
|
||||
#if DEBUG_PRINT
|
||||
MsgList_reverse(msg_list);
|
||||
@@ -282,24 +281,40 @@ static void test_rpc_add_ping_to_list(MsgList_t msg_list, bool request, uint32_t
|
||||
response->which_content = (request == PING_REQUEST) ? PB_Main_system_ping_request_tag :
|
||||
PB_Main_system_ping_response_tag;
|
||||
}
|
||||
static void test_rpc_fill_basic_message(PB_Main* message, uint16_t tag, uint32_t command_id) {
|
||||
message->command_id = command_id;
|
||||
message->command_status = PB_CommandStatus_OK;
|
||||
message->cb_content.funcs.encode = NULL;
|
||||
message->which_content = tag;
|
||||
message->has_next = false;
|
||||
}
|
||||
|
||||
static void test_rpc_create_storage_list_request(
|
||||
PB_Main* message,
|
||||
const char* path,
|
||||
bool include_md5,
|
||||
uint32_t command_id,
|
||||
uint32_t filter_max_size) {
|
||||
furi_check(message);
|
||||
furi_check(path);
|
||||
test_rpc_fill_basic_message(message, PB_Main_storage_list_request_tag, command_id);
|
||||
message->content.storage_list_request.path = strdup(path);
|
||||
message->content.storage_list_request.include_md5 = include_md5;
|
||||
message->content.storage_list_request.filter_max_size = filter_max_size;
|
||||
}
|
||||
|
||||
static void test_rpc_create_simple_message(
|
||||
PB_Main* message,
|
||||
uint16_t tag,
|
||||
const char* str,
|
||||
uint32_t command_id,
|
||||
bool flag) {
|
||||
uint32_t command_id) {
|
||||
furi_check(message);
|
||||
|
||||
char* str_copy = NULL;
|
||||
if(str) {
|
||||
str_copy = strdup(str);
|
||||
}
|
||||
message->command_id = command_id;
|
||||
message->command_status = PB_CommandStatus_OK;
|
||||
message->cb_content.funcs.encode = NULL;
|
||||
message->which_content = tag;
|
||||
message->has_next = false;
|
||||
test_rpc_fill_basic_message(message, tag, command_id);
|
||||
switch(tag) {
|
||||
case PB_Main_storage_info_request_tag:
|
||||
message->content.storage_info_request.path = str_copy;
|
||||
@@ -307,10 +322,6 @@ static void test_rpc_create_simple_message(
|
||||
case PB_Main_storage_stat_request_tag:
|
||||
message->content.storage_stat_request.path = str_copy;
|
||||
break;
|
||||
case PB_Main_storage_list_request_tag:
|
||||
message->content.storage_list_request.path = str_copy;
|
||||
message->content.storage_list_request.include_md5 = flag;
|
||||
break;
|
||||
case PB_Main_storage_mkdir_request_tag:
|
||||
message->content.storage_mkdir_request.path = str_copy;
|
||||
break;
|
||||
@@ -573,11 +584,29 @@ static void
|
||||
message->content.storage_list_response.file[2].name = str;
|
||||
}
|
||||
|
||||
static bool test_rpc_system_storage_list_filter(
|
||||
const FileInfo* fileinfo,
|
||||
const char* name,
|
||||
size_t filter_max_size) {
|
||||
bool result = false;
|
||||
|
||||
do {
|
||||
if(!path_contains_only_ascii(name)) break;
|
||||
if(filter_max_size) {
|
||||
if(fileinfo->size > filter_max_size) break;
|
||||
}
|
||||
result = true;
|
||||
} while(false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void test_rpc_storage_list_create_expected_list(
|
||||
MsgList_t msg_list,
|
||||
const char* path,
|
||||
uint32_t command_id,
|
||||
bool append_md5) {
|
||||
bool append_md5,
|
||||
size_t filter_max_size) {
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
File* dir = storage_file_alloc(fs_api);
|
||||
|
||||
@@ -615,7 +644,7 @@ static void test_rpc_storage_list_create_expected_list(
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if(path_contains_only_ascii(name)) {
|
||||
if(test_rpc_system_storage_list_filter(&fileinfo, name, filter_max_size)) {
|
||||
list->file[i].type = file_info_is_dir(&fileinfo) ? PB_Storage_File_FileType_DIR :
|
||||
PB_Storage_File_FileType_FILE;
|
||||
list->file[i].size = fileinfo.size;
|
||||
@@ -698,17 +727,21 @@ static void test_rpc_free_msg_list(MsgList_t msg_list) {
|
||||
MsgList_clear(msg_list);
|
||||
}
|
||||
|
||||
static void test_rpc_storage_list_run(const char* path, uint32_t command_id, bool md5) {
|
||||
static void test_rpc_storage_list_run(
|
||||
const char* path,
|
||||
uint32_t command_id,
|
||||
bool md5,
|
||||
size_t filter_max_size) {
|
||||
PB_Main request;
|
||||
MsgList_t expected_msg_list;
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_list_request_tag, path, command_id, md5);
|
||||
test_rpc_create_storage_list_request(&request, path, md5, command_id, filter_max_size);
|
||||
if(!strcmp(path, "/")) {
|
||||
test_rpc_storage_list_create_expected_list_root(expected_msg_list, command_id);
|
||||
} else {
|
||||
test_rpc_storage_list_create_expected_list(expected_msg_list, path, command_id, md5);
|
||||
test_rpc_storage_list_create_expected_list(
|
||||
expected_msg_list, path, command_id, md5, filter_max_size);
|
||||
}
|
||||
test_rpc_encode_and_feed_one(&request, 0);
|
||||
test_rpc_decode_and_compare(expected_msg_list, 0);
|
||||
@@ -718,25 +751,32 @@ static void test_rpc_storage_list_run(const char* path, uint32_t command_id, boo
|
||||
}
|
||||
|
||||
MU_TEST(test_storage_list) {
|
||||
test_rpc_storage_list_run("/", ++command_id, false);
|
||||
test_rpc_storage_list_run(EXT_PATH("nfc"), ++command_id, false);
|
||||
test_rpc_storage_list_run(STORAGE_INT_PATH_PREFIX, ++command_id, false);
|
||||
test_rpc_storage_list_run(STORAGE_EXT_PATH_PREFIX, ++command_id, false);
|
||||
test_rpc_storage_list_run(EXT_PATH("infrared"), ++command_id, false);
|
||||
test_rpc_storage_list_run(EXT_PATH("ibutton"), ++command_id, false);
|
||||
test_rpc_storage_list_run(EXT_PATH("lfrfid"), ++command_id, false);
|
||||
test_rpc_storage_list_run("error_path", ++command_id, false);
|
||||
test_rpc_storage_list_run("/", ++command_id, false, 0);
|
||||
test_rpc_storage_list_run(EXT_PATH("nfc"), ++command_id, false, 0);
|
||||
test_rpc_storage_list_run(STORAGE_INT_PATH_PREFIX, ++command_id, false, 0);
|
||||
test_rpc_storage_list_run(STORAGE_EXT_PATH_PREFIX, ++command_id, false, 0);
|
||||
test_rpc_storage_list_run(EXT_PATH("infrared"), ++command_id, false, 0);
|
||||
test_rpc_storage_list_run(EXT_PATH("ibutton"), ++command_id, false, 0);
|
||||
test_rpc_storage_list_run(EXT_PATH("lfrfid"), ++command_id, false, 0);
|
||||
test_rpc_storage_list_run("error_path", ++command_id, false, 0);
|
||||
}
|
||||
|
||||
MU_TEST(test_storage_list_md5) {
|
||||
test_rpc_storage_list_run("/", ++command_id, true);
|
||||
test_rpc_storage_list_run(EXT_PATH("nfc"), ++command_id, true);
|
||||
test_rpc_storage_list_run(STORAGE_INT_PATH_PREFIX, ++command_id, true);
|
||||
test_rpc_storage_list_run(STORAGE_EXT_PATH_PREFIX, ++command_id, true);
|
||||
test_rpc_storage_list_run(EXT_PATH("infrared"), ++command_id, true);
|
||||
test_rpc_storage_list_run(EXT_PATH("ibutton"), ++command_id, true);
|
||||
test_rpc_storage_list_run(EXT_PATH("lfrfid"), ++command_id, true);
|
||||
test_rpc_storage_list_run("error_path", ++command_id, true);
|
||||
test_rpc_storage_list_run("/", ++command_id, true, 0);
|
||||
test_rpc_storage_list_run(EXT_PATH("nfc"), ++command_id, true, 0);
|
||||
test_rpc_storage_list_run(STORAGE_INT_PATH_PREFIX, ++command_id, true, 0);
|
||||
test_rpc_storage_list_run(STORAGE_EXT_PATH_PREFIX, ++command_id, true, 0);
|
||||
test_rpc_storage_list_run(EXT_PATH("infrared"), ++command_id, true, 0);
|
||||
test_rpc_storage_list_run(EXT_PATH("ibutton"), ++command_id, true, 0);
|
||||
test_rpc_storage_list_run(EXT_PATH("lfrfid"), ++command_id, true, 0);
|
||||
test_rpc_storage_list_run("error_path", ++command_id, true, 0);
|
||||
}
|
||||
|
||||
MU_TEST(test_storage_list_size) {
|
||||
test_rpc_storage_list_run(TEST_DIR_NAME, ++command_id, false, 0);
|
||||
test_rpc_storage_list_run(TEST_DIR_NAME, ++command_id, false, 1);
|
||||
test_rpc_storage_list_run(TEST_DIR_NAME, ++command_id, false, 1000);
|
||||
test_rpc_storage_list_run(TEST_DIR_NAME, ++command_id, false, 2500);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -804,8 +844,7 @@ static void test_storage_read_run(const char* path, uint32_t command_id) {
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_add_read_to_list_by_reading_real_file(expected_msg_list, path, command_id);
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_read_request_tag, path, command_id, false);
|
||||
test_rpc_create_simple_message(&request, PB_Main_storage_read_request_tag, path, command_id);
|
||||
test_rpc_encode_and_feed_one(&request, 0);
|
||||
test_rpc_decode_and_compare(expected_msg_list, 0);
|
||||
|
||||
@@ -859,8 +898,7 @@ static void test_rpc_storage_info_run(const char* path, uint32_t command_id) {
|
||||
MsgList_t expected_msg_list;
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_info_request_tag, path, command_id, false);
|
||||
test_rpc_create_simple_message(&request, PB_Main_storage_info_request_tag, path, command_id);
|
||||
|
||||
PB_Main* response = MsgList_push_new(expected_msg_list);
|
||||
response->command_id = command_id;
|
||||
@@ -892,8 +930,7 @@ static void test_rpc_storage_stat_run(const char* path, uint32_t command_id) {
|
||||
MsgList_t expected_msg_list;
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_stat_request_tag, path, command_id, false);
|
||||
test_rpc_create_simple_message(&request, PB_Main_storage_stat_request_tag, path, command_id);
|
||||
|
||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
||||
FileInfo fileinfo;
|
||||
@@ -1005,11 +1042,7 @@ static void test_storage_write_read_run(
|
||||
test_rpc_add_empty_to_list(expected_msg_list, PB_CommandStatus_OK, *command_id);
|
||||
|
||||
test_rpc_create_simple_message(
|
||||
MsgList_push_raw(input_msg_list),
|
||||
PB_Main_storage_read_request_tag,
|
||||
path,
|
||||
++*command_id,
|
||||
false);
|
||||
MsgList_push_raw(input_msg_list), PB_Main_storage_read_request_tag, path, ++*command_id);
|
||||
test_rpc_add_read_or_write_to_list(
|
||||
expected_msg_list,
|
||||
READ_RESPONSE,
|
||||
@@ -1082,8 +1115,7 @@ MU_TEST(test_storage_interrupt_continuous_same_system) {
|
||||
MsgList_push_new(input_msg_list),
|
||||
PB_Main_storage_mkdir_request_tag,
|
||||
TEST_DIR "dir1",
|
||||
command_id + 1,
|
||||
false);
|
||||
command_id + 1);
|
||||
test_rpc_add_read_or_write_to_list(
|
||||
input_msg_list,
|
||||
WRITE_REQUEST,
|
||||
@@ -1163,8 +1195,7 @@ static void test_storage_delete_run(
|
||||
MsgList_t expected_msg_list;
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_delete_request_tag, path, command_id, false);
|
||||
test_rpc_create_simple_message(&request, PB_Main_storage_delete_request_tag, path, command_id);
|
||||
request.content.storage_delete_request.recursive = recursive;
|
||||
test_rpc_add_empty_to_list(expected_msg_list, status, command_id);
|
||||
|
||||
@@ -1245,8 +1276,7 @@ static void test_storage_mkdir_run(const char* path, size_t command_id, PB_Comma
|
||||
MsgList_t expected_msg_list;
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_mkdir_request_tag, path, command_id, false);
|
||||
test_rpc_create_simple_message(&request, PB_Main_storage_mkdir_request_tag, path, command_id);
|
||||
test_rpc_add_empty_to_list(expected_msg_list, status, command_id);
|
||||
|
||||
test_rpc_encode_and_feed_one(&request, 0);
|
||||
@@ -1297,12 +1327,11 @@ static void test_storage_md5sum_run(
|
||||
MsgList_t expected_msg_list;
|
||||
MsgList_init(expected_msg_list);
|
||||
|
||||
test_rpc_create_simple_message(
|
||||
&request, PB_Main_storage_md5sum_request_tag, path, command_id, false);
|
||||
test_rpc_create_simple_message(&request, PB_Main_storage_md5sum_request_tag, path, command_id);
|
||||
if(status == PB_CommandStatus_OK) {
|
||||
PB_Main* response = MsgList_push_new(expected_msg_list);
|
||||
test_rpc_create_simple_message(
|
||||
response, PB_Main_storage_md5sum_response_tag, md5sum, command_id, false);
|
||||
response, PB_Main_storage_md5sum_response_tag, md5sum, command_id);
|
||||
response->command_status = status;
|
||||
} else {
|
||||
test_rpc_add_empty_to_list(expected_msg_list, status, command_id);
|
||||
@@ -1461,6 +1490,7 @@ MU_TEST_SUITE(test_rpc_storage) {
|
||||
MU_RUN_TEST(test_storage_stat);
|
||||
MU_RUN_TEST(test_storage_list);
|
||||
MU_RUN_TEST(test_storage_list_md5);
|
||||
MU_RUN_TEST(test_storage_list_size);
|
||||
MU_RUN_TEST(test_storage_read);
|
||||
MU_RUN_TEST(test_storage_write_read);
|
||||
MU_RUN_TEST(test_storage_write);
|
||||
@@ -1759,8 +1789,7 @@ MU_TEST(test_rpc_multisession_storage) {
|
||||
MsgList_push_raw(input_0),
|
||||
PB_Main_storage_read_request_tag,
|
||||
TEST_DIR "file0.txt",
|
||||
++command_id,
|
||||
false);
|
||||
++command_id);
|
||||
test_rpc_add_read_or_write_to_list(
|
||||
expected_0, READ_RESPONSE, TEST_DIR "file0.txt", pattern, sizeof(pattern), 1, command_id);
|
||||
|
||||
@@ -1768,8 +1797,7 @@ MU_TEST(test_rpc_multisession_storage) {
|
||||
MsgList_push_raw(input_1),
|
||||
PB_Main_storage_read_request_tag,
|
||||
TEST_DIR "file1.txt",
|
||||
++command_id,
|
||||
false);
|
||||
++command_id);
|
||||
test_rpc_add_read_or_write_to_list(
|
||||
expected_1, READ_RESPONSE, TEST_DIR "file1.txt", pattern, sizeof(pattern), 1, command_id);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <lib/subghz/devices/devices.h>
|
||||
#include <lib/subghz/devices/cc1101_configs.h>
|
||||
|
||||
#define TAG "SubGhz TEST"
|
||||
#define TAG "SubGhzTest"
|
||||
#define KEYSTORE_DIR_NAME EXT_PATH("subghz/assets/keeloq_mfcodes")
|
||||
#define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo")
|
||||
#define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s")
|
||||
@@ -42,8 +42,6 @@ static void subghz_test_rx_callback(
|
||||
|
||||
static void subghz_test_init(void) {
|
||||
environment_handler = subghz_environment_alloc();
|
||||
subghz_environment_set_came_atomo_rainbow_table_file_name(
|
||||
environment_handler, CAME_ATOMO_DIR_NAME);
|
||||
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
|
||||
environment_handler, NICE_FLOR_S_DIR_NAME);
|
||||
subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
|
||||
|
||||
@@ -90,7 +90,7 @@ void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
|
||||
Loader* loader = furi_record_open(RECORD_LOADER);
|
||||
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
// TODO: lock device while test running
|
||||
// TODO FL-3491: lock device while test running
|
||||
if(loader_is_locked(loader)) {
|
||||
printf("RPC: stop all applications to run tests\r\n");
|
||||
notification_message(notification, &sequence_blink_magenta_100);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <cc1101.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define TAG "SubGhz_Device_CC1101_Ext"
|
||||
#define TAG "SubGhzDeviceCc1101Ext"
|
||||
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO &gpio_ext_pb2
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO &gpio_ext_pc3
|
||||
@@ -357,7 +357,7 @@ bool subghz_device_cc1101_ext_rx_pipe_not_empty() {
|
||||
(CC1101_STATUS_RXBYTES) | CC1101_BURST,
|
||||
(uint8_t*)status);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
// TODO: you can add a buffer overflow flag if needed
|
||||
// TODO: Find reason why RXFIFO_OVERFLOW doesnt work correctly
|
||||
if(status->NUM_RXBYTES > 0) {
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "cc1101_ext.h"
|
||||
#include <lib/subghz/devices/cc1101_configs.h>
|
||||
|
||||
#define TAG "SubGhzDeviceCC1101Ext"
|
||||
#define TAG "SubGhzDeviceCc1101Ext"
|
||||
|
||||
static bool subghz_device_cc1101_ext_interconnect_is_frequency_valid(uint32_t frequency) {
|
||||
bool ret = subghz_device_cc1101_ext_is_frequency_valid(frequency);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
|
||||
// Define log tag
|
||||
#define TAG "example_apps_assets"
|
||||
#define TAG "ExampleAppsAssets"
|
||||
|
||||
static void example_apps_data_print_file_content(Storage* storage, const char* path) {
|
||||
Stream* stream = file_stream_alloc(storage);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <storage/storage.h>
|
||||
|
||||
// Define log tag
|
||||
#define TAG "example_apps_data"
|
||||
#define TAG "ExampleAppsData"
|
||||
|
||||
// Application entry point
|
||||
int32_t example_apps_data_main(void* p) {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <loader/firmware_api/firmware_api.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
#define TAG "example_plugins"
|
||||
#define TAG "ExamplePlugins"
|
||||
|
||||
int32_t example_plugins_app(void* p) {
|
||||
UNUSED(p);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "example_plugins"
|
||||
#define TAG "ExamplePlugins"
|
||||
|
||||
int32_t example_plugins_multi_app(void* p) {
|
||||
UNUSED(p);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <loader/firmware_api/firmware_api.h>
|
||||
|
||||
#define TAG "example_advanced_plugins"
|
||||
#define TAG "ExampleAdvancedPlugins"
|
||||
|
||||
int32_t example_advanced_plugins_app(void* p) {
|
||||
UNUSED(p);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "ducky_script_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define TAG "BadUSB"
|
||||
#define TAG "BadUsb"
|
||||
#define WORKER_TAG TAG "Worker"
|
||||
|
||||
#define BADUSB_ASCII_TO_KEY(script, x) \
|
||||
|
||||
@@ -171,7 +171,7 @@ static const DuckyCmd ducky_commands[] = {
|
||||
{"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1},
|
||||
};
|
||||
|
||||
#define TAG "BadUSB"
|
||||
#define TAG "BadUsb"
|
||||
#define WORKER_TAG TAG "Worker"
|
||||
|
||||
int32_t ducky_execute_cmd(BadUsbScript* bad_usb, const char* line) {
|
||||
|
||||
@@ -18,10 +18,12 @@ GPIOItems* gpio_items_alloc() {
|
||||
}
|
||||
|
||||
items->pins = malloc(sizeof(GpioPinRecord) * items->count);
|
||||
for(size_t i = 0; i < items->count; i++) {
|
||||
size_t index = 0;
|
||||
for(size_t i = 0; i < gpio_pins_count; i++) {
|
||||
if(!gpio_pins[i].debug) {
|
||||
items->pins[i].pin = gpio_pins[i].pin;
|
||||
items->pins[i].name = gpio_pins[i].name;
|
||||
items->pins[index].pin = gpio_pins[i].pin;
|
||||
items->pins[index].name = gpio_pins[i].name;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return items;
|
||||
|
||||
@@ -19,7 +19,7 @@ void gpio_scene_usb_uart_on_enter(void* context) {
|
||||
uint32_t prev_state = scene_manager_get_scene_state(app->scene_manager, GpioAppViewUsbUart);
|
||||
if(prev_state == 0) {
|
||||
scene_usb_uart = malloc(sizeof(SceneUsbUartBridge));
|
||||
scene_usb_uart->cfg.vcp_ch = 0; // TODO: settings load
|
||||
scene_usb_uart->cfg.vcp_ch = 0;
|
||||
scene_usb_uart->cfg.uart_ch = 0;
|
||||
scene_usb_uart->cfg.flow_pins = 0;
|
||||
scene_usb_uart->cfg.baudrate_mode = 0;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <toolbox/path.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define TAG "iButtonApp"
|
||||
#define TAG "IButtonApp"
|
||||
|
||||
static const NotificationSequence sequence_blink_set_yellow = {
|
||||
&message_blink_set_color_yellow,
|
||||
@@ -195,16 +195,23 @@ bool ibutton_load_key(iButton* ibutton) {
|
||||
|
||||
bool ibutton_select_and_load_key(iButton* ibutton) {
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, IBUTTON_APP_EXTENSION, &I_ibutt_10px);
|
||||
bool success = false;
|
||||
dialog_file_browser_set_basic_options(
|
||||
&browser_options, IBUTTON_APP_FILENAME_EXTENSION, &I_ibutt_10px);
|
||||
browser_options.base_path = IBUTTON_APP_FOLDER;
|
||||
|
||||
if(furi_string_empty(ibutton->file_path)) {
|
||||
furi_string_set(ibutton->file_path, browser_options.base_path);
|
||||
}
|
||||
|
||||
return dialog_file_browser_show(
|
||||
ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options) &&
|
||||
ibutton_load_key(ibutton);
|
||||
do {
|
||||
if(!dialog_file_browser_show(
|
||||
ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options))
|
||||
break;
|
||||
success = ibutton_load_key(ibutton);
|
||||
} while(!success);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ibutton_save_key(iButton* ibutton) {
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
#include "scenes/ibutton_scene.h"
|
||||
|
||||
#define IBUTTON_APP_FOLDER ANY_PATH("ibutton")
|
||||
#define IBUTTON_APP_EXTENSION ".ibtn"
|
||||
#define IBUTTON_APP_FILENAME_PREFIX "iBtn"
|
||||
#define IBUTTON_APP_FILENAME_EXTENSION ".ibtn"
|
||||
|
||||
#define IBUTTON_KEY_NAME_SIZE 22
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../ibutton_i.h"
|
||||
|
||||
#include <toolbox/random_name.h>
|
||||
#include <toolbox/name_generator.h>
|
||||
#include <toolbox/path.h>
|
||||
|
||||
#include <dolphin/dolphin.h>
|
||||
@@ -17,7 +17,8 @@ void ibutton_scene_save_name_on_enter(void* context) {
|
||||
const bool is_new_file = furi_string_empty(ibutton->file_path);
|
||||
|
||||
if(is_new_file) {
|
||||
set_random_name(ibutton->key_name, IBUTTON_KEY_NAME_SIZE);
|
||||
name_generator_make_auto(
|
||||
ibutton->key_name, IBUTTON_KEY_NAME_SIZE, IBUTTON_APP_FILENAME_PREFIX);
|
||||
}
|
||||
|
||||
text_input_set_header_text(text_input, "Name the key");
|
||||
@@ -29,8 +30,8 @@ void ibutton_scene_save_name_on_enter(void* context) {
|
||||
IBUTTON_KEY_NAME_SIZE,
|
||||
is_new_file);
|
||||
|
||||
ValidatorIsFile* validator_is_file =
|
||||
validator_is_file_alloc_init(IBUTTON_APP_FOLDER, IBUTTON_APP_EXTENSION, ibutton->key_name);
|
||||
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
|
||||
IBUTTON_APP_FOLDER, IBUTTON_APP_FILENAME_EXTENSION, ibutton->key_name);
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewTextInput);
|
||||
@@ -48,7 +49,7 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
||||
"%s/%s%s",
|
||||
IBUTTON_APP_FOLDER,
|
||||
ibutton->key_name,
|
||||
IBUTTON_APP_EXTENSION);
|
||||
IBUTTON_APP_FILENAME_EXTENSION);
|
||||
|
||||
if(ibutton_save_key(ibutton)) {
|
||||
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveSuccess);
|
||||
|
||||
@@ -85,7 +85,7 @@ static void infrared_cli_print_usage(void) {
|
||||
printf("\tir decode <input_file> [<output_file>]\r\n");
|
||||
printf("\tir universal <remote_name> <signal_name>\r\n");
|
||||
printf("\tir universal list <remote_name>\r\n");
|
||||
// TODO: Do not hardcode universal remote names
|
||||
// TODO FL-3496: Do not hardcode universal remote names
|
||||
printf("\tAvailable universal remotes: tv audio ac projector\r\n");
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ static bool infrared_cli_decode_raw_signal(
|
||||
|
||||
size_t i;
|
||||
for(i = 0; i < raw_signal->timings_size; ++i) {
|
||||
// TODO: Any infrared_check_decoder_ready() magic?
|
||||
// TODO FL-3523: Any infrared_check_decoder_ready() magic?
|
||||
const InfraredMessage* message = infrared_decode(decoder, level, raw_signal->timings[i]);
|
||||
|
||||
if(message) {
|
||||
|
||||
@@ -18,24 +18,26 @@ void infrared_scene_universal_ac_on_enter(void* context) {
|
||||
i,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
22,
|
||||
&I_Off_25x27,
|
||||
&I_Off_hvr_25x27,
|
||||
6,
|
||||
15,
|
||||
&I_off_19x20,
|
||||
&I_off_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 10, 37, &I_off_text_12x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Off");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
0,
|
||||
36,
|
||||
22,
|
||||
&I_Dehumidify_25x27,
|
||||
&I_Dehumidify_hvr_25x27,
|
||||
39,
|
||||
15,
|
||||
&I_dry_19x20,
|
||||
&I_dry_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 41, 37, &I_dry_text_15x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Dh");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
@@ -43,9 +45,9 @@ void infrared_scene_universal_ac_on_enter(void* context) {
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
59,
|
||||
&I_CoolHi_25x27,
|
||||
&I_CoolHi_hvr_25x27,
|
||||
49,
|
||||
&I_max_24x23,
|
||||
&I_max_hover_24x23,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Cool_hi");
|
||||
@@ -54,39 +56,71 @@ void infrared_scene_universal_ac_on_enter(void* context) {
|
||||
i,
|
||||
1,
|
||||
1,
|
||||
36,
|
||||
59,
|
||||
&I_HeatHi_25x27,
|
||||
&I_HeatHi_hvr_25x27,
|
||||
37,
|
||||
49,
|
||||
&I_max_24x23,
|
||||
&I_max_hover_24x23,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Heat_hi");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
91,
|
||||
&I_CoolLo_25x27,
|
||||
&I_CoolLo_hvr_25x27,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
if(furi_hal_rtc_get_locale_units() == FuriHalRtcLocaleUnitsMetric) {
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
100,
|
||||
&I_celsius_24x23,
|
||||
&I_celsius_hover_24x23,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
} else {
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
100,
|
||||
&I_fahren_24x23,
|
||||
&I_fahren_hover_24x23,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
}
|
||||
infrared_brute_force_add_record(brute_force, i++, "Cool_lo");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
2,
|
||||
36,
|
||||
91,
|
||||
&I_HeatLo_25x27,
|
||||
&I_HeatLo_hvr_25x27,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
|
||||
if(furi_hal_rtc_get_locale_units() == FuriHalRtcLocaleUnitsMetric) {
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
2,
|
||||
37,
|
||||
100,
|
||||
&I_celsius_24x23,
|
||||
&I_celsius_hover_24x23,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
} else {
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
2,
|
||||
37,
|
||||
100,
|
||||
&I_fahren_24x23,
|
||||
&I_fahren_hover_24x23,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
}
|
||||
infrared_brute_force_add_record(brute_force, i++, "Heat_lo");
|
||||
|
||||
button_panel_add_label(button_panel, 6, 10, FontPrimary, "AC remote");
|
||||
button_panel_add_icon(button_panel, 0, 60, &I_cool_30x51);
|
||||
button_panel_add_icon(button_panel, 34, 60, &I_heat_30x51);
|
||||
|
||||
button_panel_add_label(button_panel, 4, 10, FontPrimary, "AC remote");
|
||||
|
||||
view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical);
|
||||
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack);
|
||||
|
||||
@@ -18,82 +18,88 @@ void infrared_scene_universal_audio_on_enter(void* context) {
|
||||
i,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
11,
|
||||
&I_Power_25x27,
|
||||
&I_Power_hvr_25x27,
|
||||
6,
|
||||
13,
|
||||
&I_power_19x20,
|
||||
&I_power_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 4, 35, &I_power_text_24x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Power");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
0,
|
||||
36,
|
||||
11,
|
||||
&I_Mute_25x27,
|
||||
&I_Mute_hvr_25x27,
|
||||
39,
|
||||
13,
|
||||
&I_mute_19x20,
|
||||
&I_mute_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 39, 35, &I_mute_text_19x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Mute");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
41,
|
||||
&I_Play_25x27,
|
||||
&I_Play_hvr_25x27,
|
||||
6,
|
||||
42,
|
||||
&I_play_19x20,
|
||||
&I_play_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 6, 64, &I_play_text_19x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Play");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
1,
|
||||
36,
|
||||
41,
|
||||
&I_Pause_25x27,
|
||||
&I_Pause_hvr_25x27,
|
||||
0,
|
||||
2,
|
||||
6,
|
||||
71,
|
||||
&I_pause_19x20,
|
||||
&I_pause_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 4, 93, &I_pause_text_23x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Pause");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
71,
|
||||
&I_TrackPrev_25x27,
|
||||
&I_TrackPrev_hvr_25x27,
|
||||
6,
|
||||
101,
|
||||
&I_prev_19x20,
|
||||
&I_prev_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 6, 123, &I_prev_text_19x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Prev");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
2,
|
||||
36,
|
||||
71,
|
||||
&I_TrackNext_25x27,
|
||||
&I_TrackNext_hvr_25x27,
|
||||
3,
|
||||
39,
|
||||
101,
|
||||
&I_next_19x20,
|
||||
&I_next_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 39, 123, &I_next_text_19x6);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Next");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
3,
|
||||
3,
|
||||
101,
|
||||
&I_Vol_down_25x27,
|
||||
&I_Vol_down_hvr_25x27,
|
||||
1,
|
||||
2,
|
||||
37,
|
||||
77,
|
||||
&I_voldown_24x21,
|
||||
&I_voldown_hover_24x21,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Vol_dn");
|
||||
@@ -101,16 +107,17 @@ void infrared_scene_universal_audio_on_enter(void* context) {
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
3,
|
||||
36,
|
||||
101,
|
||||
&I_Vol_up_25x27,
|
||||
&I_Vol_up_hvr_25x27,
|
||||
1,
|
||||
37,
|
||||
43,
|
||||
&I_volup_24x21,
|
||||
&I_volup_hover_24x21,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Vol_up");
|
||||
|
||||
button_panel_add_label(button_panel, 1, 8, FontPrimary, "Mus. remote");
|
||||
button_panel_add_label(button_panel, 1, 10, FontPrimary, "Mus. remote");
|
||||
button_panel_add_icon(button_panel, 34, 56, &I_vol_ac_text_30x30);
|
||||
|
||||
view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical);
|
||||
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack);
|
||||
|
||||
@@ -19,34 +19,38 @@ void infrared_scene_universal_fan_on_enter(void* context) {
|
||||
i,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
6,
|
||||
24,
|
||||
&I_Power_25x27,
|
||||
&I_Power_hvr_25x27,
|
||||
&I_power_19x20,
|
||||
&I_power_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Power");
|
||||
button_panel_add_icon(button_panel, 4, 46, &I_power_text_24x5);
|
||||
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
0,
|
||||
36,
|
||||
39,
|
||||
24,
|
||||
&I_Mode_25x27,
|
||||
&I_Mode_hvr_25x27,
|
||||
&I_mode_19x20,
|
||||
&I_mode_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Mode");
|
||||
button_panel_add_icon(button_panel, 39, 46, &I_mode_text_20x5);
|
||||
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
66,
|
||||
&I_Vol_up_25x27,
|
||||
&I_Vol_up_hvr_25x27,
|
||||
1,
|
||||
37,
|
||||
55,
|
||||
&I_volup_24x21,
|
||||
&I_volup_hover_24x21,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Speed_up");
|
||||
@@ -54,11 +58,11 @@ void infrared_scene_universal_fan_on_enter(void* context) {
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
1,
|
||||
36,
|
||||
66,
|
||||
&I_Vol_down_25x27,
|
||||
&I_Vol_down_hvr_25x27,
|
||||
2,
|
||||
37,
|
||||
89,
|
||||
&I_voldown_24x21,
|
||||
&I_voldown_hover_24x21,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Speed_dn");
|
||||
@@ -66,31 +70,32 @@ void infrared_scene_universal_fan_on_enter(void* context) {
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
98,
|
||||
&I_Rotate_25x27,
|
||||
&I_Rotate_hvr_25x27,
|
||||
1,
|
||||
6,
|
||||
58,
|
||||
&I_rotate_19x20,
|
||||
&I_rotate_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Rotate");
|
||||
button_panel_add_icon(button_panel, 4, 80, &I_rotate_text_24x5);
|
||||
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
36,
|
||||
98,
|
||||
&I_Timer_25x27,
|
||||
&I_Timer_hvr_25x27,
|
||||
6,
|
||||
87,
|
||||
&I_timer_19x20,
|
||||
&I_timer_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Timer");
|
||||
button_panel_add_icon(button_panel, 4, 109, &I_timer_text_23x5);
|
||||
|
||||
button_panel_add_label(button_panel, 5, 11, FontPrimary, "Fan remote");
|
||||
button_panel_add_label(button_panel, 20, 63, FontSecondary, "Speed");
|
||||
button_panel_add_label(button_panel, 8, 23, FontSecondary, "Pwr");
|
||||
button_panel_add_label(button_panel, 40, 23, FontSecondary, "Mod");
|
||||
button_panel_add_icon(button_panel, 34, 68, &I_speed_text_30x30);
|
||||
|
||||
view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical);
|
||||
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack);
|
||||
|
||||
@@ -18,46 +18,49 @@ void infrared_scene_universal_projector_on_enter(void* context) {
|
||||
i,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
19,
|
||||
&I_Power_25x27,
|
||||
&I_Power_hvr_25x27,
|
||||
6,
|
||||
24,
|
||||
&I_power_19x20,
|
||||
&I_power_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 4, 46, &I_power_text_24x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Power");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
0,
|
||||
36,
|
||||
19,
|
||||
&I_Mute_25x27,
|
||||
&I_Mute_hvr_25x27,
|
||||
39,
|
||||
24,
|
||||
&I_mute_19x20,
|
||||
&I_mute_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 39, 46, &I_mute_text_19x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Mute");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
64,
|
||||
&I_Vol_up_25x27,
|
||||
&I_Vol_up_hvr_25x27,
|
||||
1,
|
||||
37,
|
||||
55,
|
||||
&I_volup_24x21,
|
||||
&I_volup_hover_24x21,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Vol_up");
|
||||
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
1,
|
||||
36,
|
||||
64,
|
||||
&I_Vol_down_25x27,
|
||||
&I_Vol_down_hvr_25x27,
|
||||
2,
|
||||
37,
|
||||
89,
|
||||
&I_voldown_24x21,
|
||||
&I_voldown_hover_24x21,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Vol_dn");
|
||||
@@ -65,29 +68,31 @@ void infrared_scene_universal_projector_on_enter(void* context) {
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
101,
|
||||
&I_Play_25x27,
|
||||
&I_Play_hvr_25x27,
|
||||
1,
|
||||
6,
|
||||
58,
|
||||
&I_play_19x20,
|
||||
&I_play_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Play");
|
||||
button_panel_add_icon(button_panel, 6, 80, &I_play_text_19x5);
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
36,
|
||||
101,
|
||||
&I_Pause_25x27,
|
||||
&I_Pause_hvr_25x27,
|
||||
6,
|
||||
87,
|
||||
&I_pause_19x20,
|
||||
&I_pause_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Pause");
|
||||
button_panel_add_icon(button_panel, 4, 109, &I_pause_text_23x5);
|
||||
|
||||
button_panel_add_label(button_panel, 10, 11, FontPrimary, "Projector");
|
||||
button_panel_add_label(button_panel, 17, 60, FontSecondary, "Volume");
|
||||
button_panel_add_label(button_panel, 3, 11, FontPrimary, "Proj. remote");
|
||||
button_panel_add_icon(button_panel, 34, 68, &I_vol_ac_text_30x30);
|
||||
|
||||
view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical);
|
||||
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack);
|
||||
|
||||
@@ -18,77 +18,82 @@ void infrared_scene_universal_tv_on_enter(void* context) {
|
||||
i,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
19,
|
||||
&I_Power_25x27,
|
||||
&I_Power_hvr_25x27,
|
||||
6,
|
||||
16,
|
||||
&I_power_19x20,
|
||||
&I_power_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 4, 38, &I_power_text_24x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Power");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
0,
|
||||
36,
|
||||
19,
|
||||
&I_Mute_25x27,
|
||||
&I_Mute_hvr_25x27,
|
||||
39,
|
||||
16,
|
||||
&I_mute_19x20,
|
||||
&I_mute_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 39, 38, &I_mute_text_19x5);
|
||||
|
||||
button_panel_add_icon(button_panel, 0, 66, &I_ch_text_31x34);
|
||||
button_panel_add_icon(button_panel, 35, 66, &I_vol_tv_text_29x34);
|
||||
|
||||
infrared_brute_force_add_record(brute_force, i++, "Mute");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
1,
|
||||
38,
|
||||
53,
|
||||
&I_volup_24x21,
|
||||
&I_volup_hover_24x21,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
|
||||
infrared_brute_force_add_record(brute_force, i++, "Vol_up");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
66,
|
||||
&I_Vol_up_25x27,
|
||||
&I_Vol_up_hvr_25x27,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Vol_up");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
1,
|
||||
36,
|
||||
66,
|
||||
&I_Up_25x27,
|
||||
&I_Up_hvr_25x27,
|
||||
53,
|
||||
&I_ch_up_24x21,
|
||||
&I_ch_up_hover_24x21,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Ch_next");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
98,
|
||||
&I_Vol_down_25x27,
|
||||
&I_Vol_down_hvr_25x27,
|
||||
38,
|
||||
91,
|
||||
&I_voldown_24x21,
|
||||
&I_voldown_hover_24x21,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Vol_dn");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
36,
|
||||
98,
|
||||
&I_Down_25x27,
|
||||
&I_Down_hvr_25x27,
|
||||
3,
|
||||
91,
|
||||
&I_ch_down_24x21,
|
||||
&I_ch_down_hover_24x21,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Ch_prev");
|
||||
|
||||
button_panel_add_label(button_panel, 6, 11, FontPrimary, "TV remote");
|
||||
button_panel_add_label(button_panel, 9, 64, FontSecondary, "Vol");
|
||||
button_panel_add_label(button_panel, 43, 64, FontSecondary, "Ch");
|
||||
button_panel_add_label(button_panel, 5, 10, FontPrimary, "TV remote");
|
||||
|
||||
view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical);
|
||||
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack);
|
||||
|
||||
@@ -192,12 +192,9 @@ int32_t lfrfid_app(void* p) {
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
|
||||
dolphin_deed(DolphinDeedRfidEmulate);
|
||||
} else {
|
||||
// TODO: exit properly
|
||||
lfrfid_free(app);
|
||||
return 0;
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
view_dispatcher_attach_to_gui(
|
||||
app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
@@ -218,13 +215,16 @@ bool lfrfid_save_key(LfRfid* app) {
|
||||
|
||||
lfrfid_make_app_folder(app);
|
||||
|
||||
if(furi_string_end_with(app->file_path, LFRFID_APP_EXTENSION)) {
|
||||
if(furi_string_end_with(app->file_path, LFRFID_APP_FILENAME_EXTENSION)) {
|
||||
size_t filename_start = furi_string_search_rchar(app->file_path, '/');
|
||||
furi_string_left(app->file_path, filename_start);
|
||||
}
|
||||
|
||||
furi_string_cat_printf(
|
||||
app->file_path, "/%s%s", furi_string_get_cstr(app->file_name), LFRFID_APP_EXTENSION);
|
||||
app->file_path,
|
||||
"/%s%s",
|
||||
furi_string_get_cstr(app->file_name),
|
||||
LFRFID_APP_FILENAME_EXTENSION);
|
||||
|
||||
result = lfrfid_save_key_data(app, app->file_path);
|
||||
return result;
|
||||
@@ -234,7 +234,8 @@ bool lfrfid_load_key_from_file_select(LfRfid* app) {
|
||||
furi_assert(app);
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, LFRFID_APP_EXTENSION, &I_125_10px);
|
||||
dialog_file_browser_set_basic_options(
|
||||
&browser_options, LFRFID_APP_FILENAME_EXTENSION, &I_125_10px);
|
||||
browser_options.base_path = LFRFID_APP_FOLDER;
|
||||
|
||||
// Input events and views are managed by file_browser
|
||||
|
||||
@@ -40,8 +40,9 @@
|
||||
|
||||
#define LFRFID_APP_FOLDER ANY_PATH("lfrfid")
|
||||
#define LFRFID_SD_FOLDER EXT_PATH("lfrfid")
|
||||
#define LFRFID_APP_EXTENSION ".rfid"
|
||||
#define LFRFID_APP_SHADOW_EXTENSION ".shd"
|
||||
#define LFRFID_APP_FILENAME_PREFIX "RFID"
|
||||
#define LFRFID_APP_FILENAME_EXTENSION ".rfid"
|
||||
#define LFRFID_APP_SHADOW_FILENAME_EXTENSION ".shd"
|
||||
|
||||
#define LFRFID_APP_RAW_ASK_EXTENSION ".ask.raw"
|
||||
#define LFRFID_APP_RAW_PSK_EXTENSION ".psk.raw"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <lib/toolbox/random_name.h>
|
||||
#include "../lfrfid_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <toolbox/name_generator.h>
|
||||
|
||||
void lfrfid_scene_save_name_on_enter(void* context) {
|
||||
LfRfid* app = context;
|
||||
@@ -11,7 +11,10 @@ void lfrfid_scene_save_name_on_enter(void* context) {
|
||||
bool key_name_is_empty = furi_string_empty(app->file_name);
|
||||
if(key_name_is_empty) {
|
||||
furi_string_set(app->file_path, LFRFID_APP_FOLDER);
|
||||
set_random_name(app->text_store, LFRFID_TEXT_STORE_SIZE);
|
||||
|
||||
name_generator_make_auto(
|
||||
app->text_store, LFRFID_TEXT_STORE_SIZE, LFRFID_APP_FILENAME_PREFIX);
|
||||
|
||||
furi_string_set(folder_path, LFRFID_APP_FOLDER);
|
||||
} else {
|
||||
lfrfid_text_store_set(app, "%s", furi_string_get_cstr(app->file_name));
|
||||
@@ -31,7 +34,7 @@ void lfrfid_scene_save_name_on_enter(void* context) {
|
||||
|
||||
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
|
||||
furi_string_get_cstr(folder_path),
|
||||
LFRFID_APP_EXTENSION,
|
||||
LFRFID_APP_FILENAME_EXTENSION,
|
||||
furi_string_get_cstr(app->file_name));
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
|
||||
|
||||
@@ -223,7 +223,11 @@ void nfc_blink_stop(Nfc* nfc) {
|
||||
|
||||
bool nfc_save_file(Nfc* nfc) {
|
||||
furi_string_printf(
|
||||
nfc->dev->load_path, "%s/%s%s", NFC_APP_FOLDER, nfc->dev->dev_name, NFC_APP_EXTENSION);
|
||||
nfc->dev->load_path,
|
||||
"%s/%s%s",
|
||||
NFC_APP_FOLDER,
|
||||
nfc->dev->dev_name,
|
||||
NFC_APP_FILENAME_EXTENSION);
|
||||
bool file_saved = nfc_device_save(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
|
||||
return file_saved;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "../nfc_i.h"
|
||||
#include <lib/toolbox/random_name.h>
|
||||
#include <lib/toolbox/name_generator.h>
|
||||
#include <gui/modules/validators.h>
|
||||
#include <toolbox/path.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
@@ -17,7 +17,7 @@ void nfc_scene_save_name_on_enter(void* context) {
|
||||
TextInput* text_input = nfc->text_input;
|
||||
bool dev_name_empty = false;
|
||||
if(!strcmp(nfc->dev->dev_name, "")) {
|
||||
set_random_name(nfc->text_store, sizeof(nfc->text_store));
|
||||
name_generator_make_auto(nfc->text_store, NFC_DEV_NAME_MAX_LEN, NFC_APP_FILENAME_PREFIX);
|
||||
dev_name_empty = true;
|
||||
} else {
|
||||
nfc_text_store_set(nfc, nfc->dev->dev_name);
|
||||
@@ -34,14 +34,14 @@ void nfc_scene_save_name_on_enter(void* context) {
|
||||
FuriString* folder_path;
|
||||
folder_path = furi_string_alloc();
|
||||
|
||||
if(furi_string_end_with(nfc->dev->load_path, NFC_APP_EXTENSION)) {
|
||||
if(furi_string_end_with(nfc->dev->load_path, NFC_APP_FILENAME_EXTENSION)) {
|
||||
path_extract_dirname(furi_string_get_cstr(nfc->dev->load_path), folder_path);
|
||||
} else {
|
||||
furi_string_set(folder_path, NFC_APP_FOLDER);
|
||||
}
|
||||
|
||||
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
|
||||
furi_string_get_cstr(folder_path), NFC_APP_EXTENSION, nfc->dev->dev_name);
|
||||
furi_string_get_cstr(folder_path), NFC_APP_FILENAME_EXTENSION, nfc->dev->dev_name);
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
|
||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput);
|
||||
|
||||
@@ -6,6 +6,8 @@ typedef enum {
|
||||
SubGhzCustomEventManagerSetRAW,
|
||||
|
||||
//SubmenuIndex
|
||||
SubmenuIndexFaacSLH_Manual_433,
|
||||
SubmenuIndexFaacSLH_Manual_868,
|
||||
SubmenuIndexFaacSLH_433,
|
||||
SubmenuIndexFaacSLH_868,
|
||||
SubmenuIndexBFTClone,
|
||||
|
||||
@@ -46,8 +46,6 @@ SubGhzTxRx* subghz_txrx_alloc() {
|
||||
instance->is_database_loaded =
|
||||
subghz_environment_load_keystore(instance->environment, SUBGHZ_KEYSTORE_DIR_NAME);
|
||||
subghz_environment_load_keystore(instance->environment, SUBGHZ_KEYSTORE_DIR_USER_NAME);
|
||||
subghz_environment_set_came_atomo_rainbow_table_file_name(
|
||||
instance->environment, SUBGHZ_CAME_ATOMO_DIR_NAME);
|
||||
subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
|
||||
instance->environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME);
|
||||
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
|
||||
@@ -336,7 +334,6 @@ static void subghz_txrx_tx_stop(SubGhzTxRx* instance) {
|
||||
}
|
||||
subghz_txrx_idle(instance);
|
||||
subghz_txrx_speaker_off(instance);
|
||||
//Todo: Show message
|
||||
}
|
||||
|
||||
FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) {
|
||||
@@ -666,6 +663,8 @@ void subghz_txrx_reset_dynamic_and_custom_btns(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
subghz_environment_reset_keeloq(instance->environment);
|
||||
|
||||
faac_slh_reset_prog_mode();
|
||||
|
||||
subghz_custom_btns_reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ bool subghz_txrx_gen_data_protocol(
|
||||
subghz_receiver_search_decoder_base_by_name(instance->receiver, protocol_name);
|
||||
|
||||
if(instance->decoder_result == NULL) {
|
||||
//TODO: Error
|
||||
//TODO FL-3502: Error
|
||||
// furi_string_set(error_str, "Protocol not\nfound!");
|
||||
// scene_manager_next_scene(scene_manager, SubGhzSceneShowErrorSub);
|
||||
FURI_LOG_E(TAG, "Protocol not found!");
|
||||
@@ -199,7 +199,7 @@ bool subghz_txrx_gen_faac_slh_protocol(
|
||||
uint32_t frequency,
|
||||
uint32_t serial,
|
||||
uint8_t btn,
|
||||
uint16_t cnt,
|
||||
uint32_t cnt,
|
||||
uint32_t seed,
|
||||
const char* manufacture_name) {
|
||||
SubGhzTxRx* txrx = context;
|
||||
@@ -228,7 +228,9 @@ bool subghz_txrx_gen_faac_slh_protocol(
|
||||
seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF;
|
||||
}
|
||||
|
||||
bool tmp_allow_zero_seed = true;
|
||||
flipper_format_write_hex(txrx->fff_data, "Seed", seed_data, sizeof(uint32_t));
|
||||
flipper_format_write_bool(txrx->fff_data, "AllowZeroSeed", &tmp_allow_zero_seed, 1);
|
||||
}
|
||||
|
||||
subghz_transmitter_free(txrx->transmitter);
|
||||
|
||||
@@ -88,7 +88,7 @@ bool subghz_txrx_gen_faac_slh_protocol(
|
||||
uint32_t frequency,
|
||||
uint32_t serial,
|
||||
uint8_t btn,
|
||||
uint16_t cnt,
|
||||
uint32_t cnt,
|
||||
uint32_t seed,
|
||||
const char* manufacture_name);
|
||||
|
||||
|
||||
@@ -23,4 +23,4 @@ ADD_SCENE(subghz, more_raw, MoreRAW)
|
||||
ADD_SCENE(subghz, decode_raw, DecodeRAW)
|
||||
ADD_SCENE(subghz, delete_raw, DeleteRAW)
|
||||
ADD_SCENE(subghz, need_saving, NeedSaving)
|
||||
ADD_SCENE(subghz, rpc, Rpc)
|
||||
ADD_SCENE(subghz, rpc, Rpc)
|
||||
@@ -32,7 +32,7 @@ const char* const debug_pin_text[DEBUG_P_COUNT] = {
|
||||
"17(1W)",
|
||||
};
|
||||
|
||||
#define DEBUG_COUNTER_COUNT 6
|
||||
#define DEBUG_COUNTER_COUNT 13
|
||||
const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = {
|
||||
"+1",
|
||||
"+2",
|
||||
@@ -40,6 +40,13 @@ const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = {
|
||||
"+4",
|
||||
"+5",
|
||||
"+10",
|
||||
"0",
|
||||
"-1",
|
||||
"-2",
|
||||
"-3",
|
||||
"-4",
|
||||
"-5",
|
||||
"-10",
|
||||
};
|
||||
const uint32_t debug_counter_val[DEBUG_COUNTER_COUNT] = {
|
||||
1,
|
||||
@@ -48,6 +55,13 @@ const uint32_t debug_counter_val[DEBUG_COUNTER_COUNT] = {
|
||||
4,
|
||||
5,
|
||||
10,
|
||||
0,
|
||||
-1,
|
||||
-2,
|
||||
-3,
|
||||
-4,
|
||||
-5,
|
||||
-10,
|
||||
};
|
||||
|
||||
static void subghz_scene_radio_settings_set_device(VariableItem* item) {
|
||||
|
||||
@@ -248,7 +248,11 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
furi_string_printf(
|
||||
temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION);
|
||||
temp_str,
|
||||
"%s/%s%s",
|
||||
SUBGHZ_RAW_FOLDER,
|
||||
RAW_FILE_NAME,
|
||||
SUBGHZ_APP_FILENAME_EXTENSION);
|
||||
subghz_protocol_raw_gen_fff_data(
|
||||
subghz_txrx_get_fff_data(subghz->txrx),
|
||||
furi_string_get_cstr(temp_str),
|
||||
|
||||
@@ -167,7 +167,6 @@ void subghz_scene_receiver_on_enter(void* context) {
|
||||
}
|
||||
furi_string_free(item_name);
|
||||
furi_string_free(item_time);
|
||||
subghz_scene_receiver_update_statusbar(subghz);
|
||||
subghz_view_receiver_set_callback(
|
||||
subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
|
||||
subghz_txrx_set_rx_calback(subghz->txrx, subghz_scene_add_to_history_callback, subghz);
|
||||
@@ -182,6 +181,8 @@ void subghz_scene_receiver_on_enter(void* context) {
|
||||
furi_check(
|
||||
subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_BIN_RAW_NAME));
|
||||
|
||||
subghz_scene_receiver_update_statusbar(subghz);
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ static bool subghz_scene_receiver_info_update_parser(void* context) {
|
||||
if(subghz_txrx_load_decoder_by_name_protocol(
|
||||
subghz->txrx,
|
||||
subghz_history_get_protocol_name(subghz->history, subghz->idx_menu_chosen))) {
|
||||
//todo we are trying to deserialize without checking for errors, since it is assumed that we just received this signal
|
||||
// we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal
|
||||
subghz_protocol_decoder_base_deserialize(
|
||||
subghz_txrx_get_decoder(subghz->txrx),
|
||||
subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen));
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "../subghz_i.h"
|
||||
#include "subghz/types.h"
|
||||
#include <lib/toolbox/random_name.h>
|
||||
#include "../helpers/subghz_custom_event.h"
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
#include <gui/modules/validators.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <toolbox/name_generator.h>
|
||||
|
||||
#define MAX_TEXT_INPUT_LEN 23
|
||||
|
||||
@@ -79,7 +79,8 @@ void subghz_scene_save_name_on_enter(void* context) {
|
||||
subghz_scene_save_name_get_timefilename(file_name, "S", true);
|
||||
}
|
||||
} else {
|
||||
set_random_name(file_name_buf, SUBGHZ_MAX_LEN_NAME);
|
||||
name_generator_make_auto(
|
||||
file_name_buf, SUBGHZ_MAX_LEN_NAME, SUBGHZ_APP_FILENAME_PREFIX);
|
||||
furi_string_set(file_name, file_name_buf);
|
||||
}
|
||||
furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER);
|
||||
@@ -112,7 +113,7 @@ void subghz_scene_save_name_on_enter(void* context) {
|
||||
dev_name_empty);
|
||||
|
||||
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
|
||||
furi_string_get_cstr(subghz->file_path), SUBGHZ_APP_EXTENSION, "");
|
||||
furi_string_get_cstr(subghz->file_path), SUBGHZ_APP_FILENAME_EXTENSION, "");
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
|
||||
furi_string_free(file_name);
|
||||
@@ -131,13 +132,24 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_string_set(subghz->file_path, subghz->file_path_tmp);
|
||||
}
|
||||
}
|
||||
scene_manager_previous_scene(subghz->scene_manager);
|
||||
if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSetSeed)) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneSetType);
|
||||
} else {
|
||||
scene_manager_previous_scene(subghz->scene_manager);
|
||||
}
|
||||
// Set file path to default
|
||||
furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER);
|
||||
|
||||
return true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubGhzCustomEventSceneSaveName) {
|
||||
if(strcmp(subghz->file_name_tmp, "") != 0) {
|
||||
furi_string_cat_printf(
|
||||
subghz->file_path, "/%s%s", subghz->file_name_tmp, SUBGHZ_APP_EXTENSION);
|
||||
subghz->file_path,
|
||||
"/%s%s",
|
||||
subghz->file_name_tmp,
|
||||
SUBGHZ_APP_FILENAME_EXTENSION);
|
||||
if(subghz_path_is_file(subghz->file_path_tmp)) {
|
||||
if(!subghz_rename_file(subghz)) {
|
||||
return false;
|
||||
|
||||
@@ -19,7 +19,7 @@ void subghz_scene_saved_menu_on_enter(void* context) {
|
||||
SubmenuIndexEmulate,
|
||||
subghz_scene_saved_menu_submenu_callback,
|
||||
subghz);
|
||||
|
||||
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Rename",
|
||||
|
||||
@@ -18,7 +18,7 @@ void subghz_scene_set_cnt_on_enter(void* context) {
|
||||
|
||||
switch(state) {
|
||||
case SubmenuIndexBFTClone:
|
||||
byte_input_set_header_text(byte_input, "Enter COUNTER in hex");
|
||||
byte_input_set_header_text(byte_input, "Enter COUNTER in Hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
subghz_scene_set_cnt_byte_input_callback,
|
||||
@@ -27,9 +27,9 @@ void subghz_scene_set_cnt_on_enter(void* context) {
|
||||
subghz->secure_data->cnt,
|
||||
2);
|
||||
break;
|
||||
case SubmenuIndexFaacSLH_433:
|
||||
case SubmenuIndexFaacSLH_868:
|
||||
byte_input_set_header_text(byte_input, "Enter COUNTER in hex, 20bits");
|
||||
case SubmenuIndexFaacSLH_Manual_433:
|
||||
case SubmenuIndexFaacSLH_Manual_868:
|
||||
byte_input_set_header_text(byte_input, "Enter COUNTER in Hex 20 bits");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
subghz_scene_set_cnt_byte_input_callback,
|
||||
|
||||
@@ -13,7 +13,7 @@ void subghz_scene_set_fix_on_enter(void* context) {
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = subghz->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter FIX in hex");
|
||||
byte_input_set_header_text(byte_input, "Enter FIX in Hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
subghz_scene_set_fix_byte_input_callback,
|
||||
|
||||
@@ -14,7 +14,7 @@ void subghz_scene_set_seed_on_enter(void* context) {
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = subghz->byte_input;
|
||||
byte_input_set_header_text(byte_input, "Enter SEED in hex");
|
||||
byte_input_set_header_text(byte_input, "Enter SEED in Hex");
|
||||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
subghz_scene_set_seed_byte_input_callback,
|
||||
@@ -62,8 +62,8 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
case SubmenuIndexFaacSLH_433:
|
||||
case SubmenuIndexFaacSLH_868:
|
||||
case SubmenuIndexFaacSLH_Manual_433:
|
||||
case SubmenuIndexFaacSLH_Manual_868:
|
||||
fix_part = subghz->secure_data->fix[0] << 24 | subghz->secure_data->fix[1] << 16 |
|
||||
subghz->secure_data->fix[2] << 8 | subghz->secure_data->fix[3];
|
||||
|
||||
@@ -73,7 +73,7 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) {
|
||||
seed = subghz->secure_data->seed[0] << 24 | subghz->secure_data->seed[1] << 16 |
|
||||
subghz->secure_data->seed[2] << 8 | subghz->secure_data->seed[3];
|
||||
|
||||
if(state == SubmenuIndexFaacSLH_433) {
|
||||
if(state == SubmenuIndexFaacSLH_Manual_433) {
|
||||
generated_protocol = subghz_txrx_gen_faac_slh_protocol(
|
||||
subghz->txrx,
|
||||
"AM650",
|
||||
@@ -83,7 +83,7 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) {
|
||||
(cnt & 0xFFFFF),
|
||||
seed,
|
||||
"FAAC_SLH");
|
||||
} else if(state == SubmenuIndexFaacSLH_868) {
|
||||
} else if(state == SubmenuIndexFaacSLH_Manual_868) {
|
||||
generated_protocol = subghz_txrx_gen_faac_slh_protocol(
|
||||
subghz->txrx,
|
||||
"AM650",
|
||||
@@ -108,8 +108,14 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
}
|
||||
|
||||
// Reset Seed, Fix, Cnt in secure data after successful or unsuccessful generation
|
||||
memset(subghz->secure_data->seed, 0, sizeof(subghz->secure_data->seed));
|
||||
memset(subghz->secure_data->cnt, 0, sizeof(subghz->secure_data->cnt));
|
||||
memset(subghz->secure_data->fix, 0, sizeof(subghz->secure_data->fix));
|
||||
|
||||
if(generated_protocol) {
|
||||
subghz_file_name_clear(subghz);
|
||||
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet);
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
||||
|
||||
@@ -15,14 +15,14 @@ void subghz_scene_set_type_on_enter(void* context) {
|
||||
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Faac SLH 868MHz",
|
||||
SubmenuIndexFaacSLH_868,
|
||||
"FAAC SLH [Man.] 868MHz",
|
||||
SubmenuIndexFaacSLH_Manual_868,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"Faac SLH 433MHz",
|
||||
SubmenuIndexFaacSLH_433,
|
||||
"FAAC SLH [Man.] 433MHz",
|
||||
SubmenuIndexFaacSLH_Manual_433,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
@@ -31,6 +31,18 @@ void subghz_scene_set_type_on_enter(void* context) {
|
||||
SubmenuIndexBFTClone,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"FAAC SLH 868MHz",
|
||||
SubmenuIndexFaacSLH_868,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"FAAC SLH 433MHz",
|
||||
SubmenuIndexFaacSLH_433,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"BFT Mitto 433MHz",
|
||||
@@ -319,10 +331,10 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
uint32_t key = (uint32_t)rand();
|
||||
switch(event.event) {
|
||||
case SubmenuIndexFaacSLH_868:
|
||||
case SubmenuIndexFaacSLH_Manual_868:
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFix);
|
||||
break;
|
||||
case SubmenuIndexFaacSLH_433:
|
||||
case SubmenuIndexFaacSLH_Manual_433:
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFix);
|
||||
break;
|
||||
case SubmenuIndexBFTClone:
|
||||
@@ -390,6 +402,38 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||
generated_protocol = subghz_txrx_gen_data_protocol(
|
||||
subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24);
|
||||
break;
|
||||
case SubmenuIndexFaacSLH_433:
|
||||
generated_protocol = subghz_txrx_gen_faac_slh_protocol(
|
||||
subghz->txrx,
|
||||
"AM650",
|
||||
433920000,
|
||||
((key & 0x00FFFFF0) | 0xA0000006) >> 4,
|
||||
0x6,
|
||||
0x00002,
|
||||
key,
|
||||
"FAAC_SLH");
|
||||
if(!generated_protocol) {
|
||||
furi_string_set(
|
||||
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
}
|
||||
break;
|
||||
case SubmenuIndexFaacSLH_868:
|
||||
generated_protocol = subghz_txrx_gen_faac_slh_protocol(
|
||||
subghz->txrx,
|
||||
"AM650",
|
||||
868350000,
|
||||
((key & 0x00FFFFF0) | 0xA0000006) >> 4,
|
||||
0x6,
|
||||
0x00002,
|
||||
key,
|
||||
"FAAC_SLH");
|
||||
if(!generated_protocol) {
|
||||
furi_string_set(
|
||||
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
}
|
||||
break;
|
||||
case SubmenuIndexBeninca433:
|
||||
generated_protocol = subghz_txrx_gen_keeloq_protocol(
|
||||
subghz->txrx,
|
||||
|
||||
@@ -77,11 +77,15 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz_txrx_stop(subghz->txrx);
|
||||
if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) {
|
||||
subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK);
|
||||
uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult();
|
||||
int8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult();
|
||||
furi_hal_subghz_set_rolling_counter_mult(0);
|
||||
// Calling restore!
|
||||
subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx));
|
||||
subghz_txrx_stop(subghz->txrx);
|
||||
// Calling restore 2nd time special for FAAC SLH!
|
||||
// TODO: Find better way to restore after custom button is used!!!
|
||||
subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx));
|
||||
subghz_txrx_stop(subghz->txrx);
|
||||
furi_hal_subghz_set_rolling_counter_mult(tmp_counter);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
// Rx RAW | only internal module
|
||||
// Chat | both
|
||||
|
||||
#define TAG "SubGhz CLI"
|
||||
#define TAG "SubGhzCli"
|
||||
|
||||
static void subghz_cli_radio_device_power_on() {
|
||||
uint8_t attempts = 5;
|
||||
@@ -326,8 +326,6 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) {
|
||||
SubGhzEnvironment* environment = subghz_environment_alloc();
|
||||
subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_NAME);
|
||||
subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_USER_NAME);
|
||||
subghz_environment_set_came_atomo_rainbow_table_file_name(
|
||||
environment, SUBGHZ_CAME_ATOMO_DIR_NAME);
|
||||
subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
|
||||
environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME);
|
||||
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
|
||||
@@ -526,8 +524,6 @@ void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) {
|
||||
printf(
|
||||
"SubGhz decode_raw: Load_keystore keeloq_mfcodes_user \033[0;31mERROR\033[0m\r\n");
|
||||
}
|
||||
subghz_environment_set_came_atomo_rainbow_table_file_name(
|
||||
environment, SUBGHZ_CAME_ATOMO_DIR_NAME);
|
||||
subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
|
||||
environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME);
|
||||
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
|
||||
|
||||
@@ -142,7 +142,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
|
||||
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
|
||||
|
||||
if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) {
|
||||
//Todo add Custom_preset_module
|
||||
//TODO FL-3551: add Custom_preset_module
|
||||
//delete preset if it already exists
|
||||
subghz_setting_delete_custom_preset(setting, furi_string_get_cstr(temp_str));
|
||||
//load custom preset from file
|
||||
@@ -258,7 +258,7 @@ bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) {
|
||||
storage,
|
||||
furi_string_get_cstr(file_path),
|
||||
furi_string_get_cstr(file_name),
|
||||
SUBGHZ_APP_EXTENSION,
|
||||
SUBGHZ_APP_FILENAME_EXTENSION,
|
||||
file_name,
|
||||
max_len);
|
||||
|
||||
@@ -267,7 +267,7 @@ bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) {
|
||||
"%s/%s%s",
|
||||
furi_string_get_cstr(file_path),
|
||||
furi_string_get_cstr(file_name),
|
||||
SUBGHZ_APP_EXTENSION);
|
||||
SUBGHZ_APP_FILENAME_EXTENSION);
|
||||
furi_string_set(subghz->file_path, temp_str);
|
||||
res = true;
|
||||
}
|
||||
@@ -309,10 +309,14 @@ bool subghz_save_protocol_to_file(
|
||||
if(!storage_simply_remove(storage, dev_file_name)) {
|
||||
break;
|
||||
}
|
||||
//ToDo check Write
|
||||
|
||||
stream_seek(flipper_format_stream, 0, StreamOffsetFromStart);
|
||||
stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS);
|
||||
|
||||
if(storage_common_stat(storage, dev_file_name, NULL) != FSE_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
saved = true;
|
||||
} while(0);
|
||||
furi_string_free(file_dir);
|
||||
@@ -337,7 +341,8 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) {
|
||||
FuriString* file_path = furi_string_alloc();
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px);
|
||||
dialog_file_browser_set_basic_options(
|
||||
&browser_options, SUBGHZ_APP_FILENAME_EXTENSION, &I_sub1_10px);
|
||||
browser_options.base_path = SUBGHZ_APP_FOLDER;
|
||||
|
||||
// Input events and views are managed by file_select
|
||||
@@ -411,7 +416,7 @@ void subghz_file_name_clear(SubGhz* subghz) {
|
||||
}
|
||||
|
||||
bool subghz_path_is_file(FuriString* path) {
|
||||
return furi_string_end_with(path, SUBGHZ_APP_EXTENSION);
|
||||
return furi_string_end_with(path, SUBGHZ_APP_FILENAME_EXTENSION);
|
||||
}
|
||||
|
||||
void subghz_lock(SubGhz* subghz) {
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
typedef struct {
|
||||
uint8_t fix[4];
|
||||
uint8_t cnt[3];
|
||||
uint8_t cnt[4];
|
||||
uint8_t seed[4];
|
||||
} SecureData;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <assets_icons.h>
|
||||
#define SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE 100
|
||||
#define TAG "SubGhzReadRAW"
|
||||
#define TAG "SubGhzReadRaw"
|
||||
|
||||
struct SubGhzReadRAW {
|
||||
View* view;
|
||||
|
||||
1
applications/main/subghz_remote
Submodule
1
applications/main/subghz_remote
Submodule
Submodule applications/main/subghz_remote added at a905d701ee
@@ -1,17 +0,0 @@
|
||||
App(
|
||||
appid="subghz_remote",
|
||||
name="Sub-GHz Remote",
|
||||
apptype=FlipperAppType.MENUEXTERNAL,
|
||||
entry_point="subghz_remote_app",
|
||||
icon="A_SubGHzRemote_14",
|
||||
requires=[
|
||||
"gui",
|
||||
"dialogs",
|
||||
],
|
||||
stack_size=2 * 1024,
|
||||
order=11,
|
||||
fap_libs=["assets",],
|
||||
fap_icon="icon.png",
|
||||
fap_description="SubGhz Remote, uses up to 5 .sub files",
|
||||
fap_category="Sub-Ghz",
|
||||
)
|
||||
@@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
SubRemEditMenuStateUP = 0,
|
||||
SubRemEditMenuStateDOWN,
|
||||
SubRemEditMenuStateLEFT,
|
||||
SubRemEditMenuStateRIGHT,
|
||||
SubRemEditMenuStateOK,
|
||||
} SubRemEditMenuState;
|
||||
|
||||
typedef enum {
|
||||
// StartSubmenuIndex
|
||||
SubmenuIndexSubRemOpenMapFile = 0,
|
||||
SubmenuIndexSubRemEditMapFile,
|
||||
SubmenuIndexSubRemNewMapFile,
|
||||
#if FURI_DEBUG
|
||||
SubmenuIndexSubRemRemoteView,
|
||||
#endif
|
||||
// SubmenuIndexSubRemAbout,
|
||||
|
||||
// EditSubmenuIndex
|
||||
EditSubmenuIndexEditLabel,
|
||||
EditSubmenuIndexEditFile,
|
||||
|
||||
// SubRemCustomEvent
|
||||
SubRemCustomEventViewRemoteStartUP = 100,
|
||||
SubRemCustomEventViewRemoteStartDOWN,
|
||||
SubRemCustomEventViewRemoteStartLEFT,
|
||||
SubRemCustomEventViewRemoteStartRIGHT,
|
||||
SubRemCustomEventViewRemoteStartOK,
|
||||
SubRemCustomEventViewRemoteBack,
|
||||
SubRemCustomEventViewRemoteStop,
|
||||
SubRemCustomEventViewRemoteForcedStop,
|
||||
|
||||
SubRemCustomEventViewEditMenuBack,
|
||||
SubRemCustomEventViewEditMenuUP,
|
||||
SubRemCustomEventViewEditMenuDOWN,
|
||||
SubRemCustomEventViewEditMenuEdit,
|
||||
SubRemCustomEventViewEditMenuSave,
|
||||
|
||||
SubRemCustomEventSceneEditsubmenu,
|
||||
SubRemCustomEventSceneEditLabelInputDone,
|
||||
SubRemCustomEventSceneEditLabelWidgetAcces,
|
||||
SubRemCustomEventSceneEditLabelWidgetBack,
|
||||
|
||||
SubRemCustomEventSceneEditOpenSubErrorPopup,
|
||||
|
||||
SubRemCustomEventSceneEditPreviewSaved,
|
||||
|
||||
SubRemCustomEventSceneNewName,
|
||||
} SubRemCustomEvent;
|
||||
@@ -1,181 +0,0 @@
|
||||
#include "subrem_presets.h"
|
||||
|
||||
#define TAG "SubRemPresets"
|
||||
|
||||
SubRemSubFilePreset* subrem_sub_file_preset_alloc() {
|
||||
SubRemSubFilePreset* sub_preset = malloc(sizeof(SubRemSubFilePreset));
|
||||
|
||||
sub_preset->fff_data = flipper_format_string_alloc();
|
||||
sub_preset->file_path = furi_string_alloc();
|
||||
sub_preset->protocaol_name = furi_string_alloc();
|
||||
sub_preset->label = furi_string_alloc();
|
||||
|
||||
sub_preset->freq_preset.name = furi_string_alloc();
|
||||
|
||||
sub_preset->type = SubGhzProtocolTypeUnknown;
|
||||
sub_preset->load_state = SubRemLoadSubStateNotSet;
|
||||
|
||||
return sub_preset;
|
||||
}
|
||||
|
||||
void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) {
|
||||
furi_assert(sub_preset);
|
||||
|
||||
furi_string_free(sub_preset->label);
|
||||
furi_string_free(sub_preset->protocaol_name);
|
||||
furi_string_free(sub_preset->file_path);
|
||||
flipper_format_free(sub_preset->fff_data);
|
||||
|
||||
furi_string_free(sub_preset->freq_preset.name);
|
||||
|
||||
free(sub_preset);
|
||||
}
|
||||
|
||||
void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) {
|
||||
furi_assert(sub_preset);
|
||||
|
||||
furi_string_set_str(sub_preset->label, "");
|
||||
furi_string_reset(sub_preset->protocaol_name);
|
||||
furi_string_reset(sub_preset->file_path);
|
||||
|
||||
Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data);
|
||||
stream_clean(fff_data_stream);
|
||||
|
||||
sub_preset->type = SubGhzProtocolTypeUnknown;
|
||||
sub_preset->load_state = SubRemLoadSubStateNotSet;
|
||||
}
|
||||
|
||||
SubRemLoadSubState subrem_sub_preset_load(
|
||||
SubRemSubFilePreset* sub_preset,
|
||||
SubGhzTxRx* txrx,
|
||||
FlipperFormat* fff_data_file) {
|
||||
furi_assert(sub_preset);
|
||||
furi_assert(txrx);
|
||||
furi_assert(fff_data_file);
|
||||
|
||||
Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data);
|
||||
|
||||
SubRemLoadSubState ret;
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
uint32_t temp_data32;
|
||||
uint32_t repeat = 200;
|
||||
|
||||
ret = SubRemLoadSubStateError;
|
||||
|
||||
do {
|
||||
stream_clean(fff_data_stream);
|
||||
if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect header");
|
||||
break;
|
||||
}
|
||||
|
||||
if(((!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) ||
|
||||
(!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) &&
|
||||
temp_data32 == SUBGHZ_KEY_FILE_VERSION) {
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Type or version mismatch");
|
||||
break;
|
||||
}
|
||||
|
||||
SubGhzSetting* setting = subghz_txrx_get_setting(txrx);
|
||||
|
||||
//Load frequency or using default from settings
|
||||
ret = SubRemLoadSubStateErrorFreq;
|
||||
if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) {
|
||||
FURI_LOG_W(TAG, "Cannot read frequency. Set default frequency");
|
||||
sub_preset->freq_preset.frequency = subghz_setting_get_default_frequency(setting);
|
||||
} else if(!subghz_txrx_radio_device_is_frequency_valid(txrx, temp_data32)) {
|
||||
FURI_LOG_E(TAG, "Frequency not supported on chosen radio module");
|
||||
break;
|
||||
}
|
||||
sub_preset->freq_preset.frequency = temp_data32;
|
||||
|
||||
//Load preset
|
||||
ret = SubRemLoadSubStateErrorMod;
|
||||
if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing Preset");
|
||||
break;
|
||||
}
|
||||
|
||||
furi_string_set_str(
|
||||
temp_str, subghz_txrx_get_preset_name(txrx, furi_string_get_cstr(temp_str)));
|
||||
if(!strcmp(furi_string_get_cstr(temp_str), "")) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) {
|
||||
FURI_LOG_E(TAG, "CUSTOM preset is not supported");
|
||||
break;
|
||||
// TODO Custom preset loading logic if need
|
||||
// sub_preset->freq_preset.preset_index =
|
||||
// subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str));
|
||||
}
|
||||
|
||||
furi_string_set(sub_preset->freq_preset.name, temp_str);
|
||||
|
||||
// Load protocol
|
||||
ret = SubRemLoadSubStateErrorProtocol;
|
||||
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing Protocol");
|
||||
break;
|
||||
}
|
||||
|
||||
FlipperFormat* fff_data = sub_preset->fff_data;
|
||||
if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) {
|
||||
//if RAW
|
||||
subghz_protocol_raw_gen_fff_data(
|
||||
fff_data,
|
||||
furi_string_get_cstr(sub_preset->file_path),
|
||||
subghz_txrx_radio_device_get_name(txrx));
|
||||
} else {
|
||||
stream_copy_full(
|
||||
flipper_format_get_raw_stream(fff_data_file),
|
||||
flipper_format_get_raw_stream(fff_data));
|
||||
}
|
||||
|
||||
if(subghz_txrx_load_decoder_by_name_protocol(txrx, furi_string_get_cstr(temp_str))) {
|
||||
SubGhzProtocolStatus status =
|
||||
subghz_protocol_decoder_base_deserialize(subghz_txrx_get_decoder(txrx), fff_data);
|
||||
if(status != SubGhzProtocolStatusOk) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Protocol not found");
|
||||
break;
|
||||
}
|
||||
|
||||
const SubGhzProtocol* protocol = subghz_txrx_get_decoder(txrx)->protocol;
|
||||
|
||||
if(protocol->flag & SubGhzProtocolFlag_Send) {
|
||||
if((protocol->type == SubGhzProtocolTypeStatic) ||
|
||||
(protocol->type == SubGhzProtocolTypeDynamic) ||
|
||||
(protocol->type == SubGhzProtocolTypeBinRAW) ||
|
||||
(protocol->type == SubGhzProtocolTypeRAW)) {
|
||||
sub_preset->type = protocol->type;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unsuported Protocol");
|
||||
break;
|
||||
}
|
||||
|
||||
furi_string_set(sub_preset->protocaol_name, temp_str);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Protocol does not support transmission");
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_insert_or_update_uint32(fff_data, "Repeat", &repeat, 1)) {
|
||||
FURI_LOG_E(TAG, "Unable Repeat");
|
||||
break;
|
||||
}
|
||||
|
||||
ret = SubRemLoadSubStateOK;
|
||||
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label));
|
||||
#endif
|
||||
} while(false);
|
||||
|
||||
furi_string_free(temp_str);
|
||||
sub_preset->load_state = ret;
|
||||
return ret;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "subrem_types.h"
|
||||
#include "txrx/subghz_txrx.h"
|
||||
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
#include <lib/subghz/types.h>
|
||||
|
||||
typedef struct {
|
||||
FuriString* name;
|
||||
uint32_t frequency;
|
||||
// size_t preset_index; // Need for custom preset
|
||||
} FreqPreset;
|
||||
|
||||
// Sub File preset
|
||||
typedef struct {
|
||||
FlipperFormat* fff_data;
|
||||
FreqPreset freq_preset;
|
||||
FuriString* file_path;
|
||||
FuriString* protocaol_name;
|
||||
FuriString* label;
|
||||
SubGhzProtocolType type;
|
||||
SubRemLoadSubState load_state;
|
||||
} SubRemSubFilePreset;
|
||||
|
||||
typedef struct {
|
||||
SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount];
|
||||
} SubRemMapPreset;
|
||||
|
||||
SubRemSubFilePreset* subrem_sub_file_preset_alloc();
|
||||
|
||||
void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset);
|
||||
|
||||
void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset);
|
||||
|
||||
SubRemLoadSubState subrem_sub_preset_load(
|
||||
SubRemSubFilePreset* sub_preset,
|
||||
SubGhzTxRx* txrx,
|
||||
FlipperFormat* fff_data_file);
|
||||
@@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#define SUBREM_APP_APP_FILE_VERSION 1
|
||||
#define SUBREM_APP_APP_FILE_TYPE "Flipper SubRem Map file"
|
||||
#define SUBREM_APP_EXTENSION ".txt"
|
||||
|
||||
typedef enum {
|
||||
SubRemSubKeyNameUp = (0U),
|
||||
SubRemSubKeyNameDown,
|
||||
SubRemSubKeyNameLeft,
|
||||
SubRemSubKeyNameRight,
|
||||
SubRemSubKeyNameOk,
|
||||
SubRemSubKeyNameMaxCount,
|
||||
} SubRemSubKeyName;
|
||||
|
||||
typedef enum {
|
||||
SubRemViewIDSubmenu,
|
||||
SubRemViewIDWidget,
|
||||
SubRemViewIDPopup,
|
||||
SubRemViewIDTextInput,
|
||||
SubRemViewIDRemote,
|
||||
SubRemViewIDEditMenu,
|
||||
} SubRemViewID;
|
||||
|
||||
typedef enum {
|
||||
SubRemLoadSubStateNotSet = 0,
|
||||
SubRemLoadSubStatePreloaded,
|
||||
SubRemLoadSubStateError,
|
||||
SubRemLoadSubStateErrorIncorectPath,
|
||||
SubRemLoadSubStateErrorNoFile,
|
||||
SubRemLoadSubStateErrorFreq,
|
||||
SubRemLoadSubStateErrorMod,
|
||||
SubRemLoadSubStateErrorProtocol,
|
||||
SubRemLoadSubStateOK,
|
||||
} SubRemLoadSubState;
|
||||
|
||||
typedef enum {
|
||||
SubRemLoadMapStateBack = 0,
|
||||
SubRemLoadMapStateError,
|
||||
SubRemLoadMapStateErrorOpenError,
|
||||
SubRemLoadMapStateErrorStorage,
|
||||
SubRemLoadMapStateErrorBrokenFile,
|
||||
SubRemLoadMapStateNotAllOK,
|
||||
SubRemLoadMapStateOK,
|
||||
} SubRemLoadMapState;
|
||||
@@ -1,4 +0,0 @@
|
||||
This is part of the official `SubGhz` app from [flipperzero-firmware](https://github.com/flipperdevices/flipperzero-firmware/tree/3217f286f03da119398586daf94c0723d28b872a/applications/main/subghz)
|
||||
|
||||
With changes from [unleashed-firmware
|
||||
](https://github.com/DarkFlippers/unleashed-firmware/tree/3eac6ccd48a3851cf5d63bf7899b387a293e5319/applications/main/subghz)
|
||||
@@ -1,670 +0,0 @@
|
||||
#include "subghz_txrx_i.h"
|
||||
|
||||
#include <lib/subghz/protocols/protocol_items.h>
|
||||
#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
|
||||
#include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
|
||||
|
||||
#include <lib/subghz/blocks/custom_btn.h>
|
||||
|
||||
#define TAG "SubGhz"
|
||||
|
||||
static void subghz_txrx_radio_device_power_on(SubGhzTxRx* instance) {
|
||||
UNUSED(instance);
|
||||
uint8_t attempts = 0;
|
||||
while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
|
||||
furi_hal_power_enable_otg();
|
||||
//CC1101 power-up time
|
||||
furi_delay_ms(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void subghz_txrx_radio_device_power_off(SubGhzTxRx* instance) {
|
||||
UNUSED(instance);
|
||||
if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg();
|
||||
}
|
||||
|
||||
SubGhzTxRx* subghz_txrx_alloc() {
|
||||
SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx));
|
||||
instance->setting = subghz_setting_alloc();
|
||||
subghz_setting_load(instance->setting, EXT_PATH("subghz/assets/setting_user"));
|
||||
|
||||
instance->preset = malloc(sizeof(SubGhzRadioPreset));
|
||||
instance->preset->name = furi_string_alloc();
|
||||
subghz_txrx_set_preset(
|
||||
instance, "AM650", subghz_setting_get_default_frequency(instance->setting), NULL, 0);
|
||||
|
||||
instance->txrx_state = SubGhzTxRxStateSleep;
|
||||
|
||||
subghz_txrx_hopper_set_state(instance, SubGhzHopperStateOFF);
|
||||
subghz_txrx_speaker_set_state(instance, SubGhzSpeakerStateDisable);
|
||||
subghz_txrx_set_debug_pin_state(instance, false);
|
||||
|
||||
instance->worker = subghz_worker_alloc();
|
||||
instance->fff_data = flipper_format_string_alloc();
|
||||
|
||||
instance->environment = subghz_environment_alloc();
|
||||
instance->is_database_loaded =
|
||||
subghz_environment_load_keystore(instance->environment, SUBGHZ_KEYSTORE_DIR_NAME);
|
||||
subghz_environment_load_keystore(instance->environment, SUBGHZ_KEYSTORE_DIR_USER_NAME);
|
||||
subghz_environment_set_came_atomo_rainbow_table_file_name(
|
||||
instance->environment, SUBGHZ_CAME_ATOMO_DIR_NAME);
|
||||
subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
|
||||
instance->environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME);
|
||||
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
|
||||
instance->environment, SUBGHZ_NICE_FLOR_S_DIR_NAME);
|
||||
subghz_environment_set_protocol_registry(
|
||||
instance->environment, (void*)&subghz_protocol_registry);
|
||||
instance->receiver = subghz_receiver_alloc_init(instance->environment);
|
||||
|
||||
subghz_worker_set_overrun_callback(
|
||||
instance->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
|
||||
subghz_worker_set_pair_callback(
|
||||
instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
|
||||
subghz_worker_set_context(instance->worker, instance->receiver);
|
||||
|
||||
//set default device Internal
|
||||
subghz_devices_init();
|
||||
instance->radio_device_type = SubGhzRadioDeviceTypeInternal;
|
||||
instance->radio_device_type =
|
||||
subghz_txrx_radio_device_set(instance, SubGhzRadioDeviceTypeExternalCC1101);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void subghz_txrx_free(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
if(instance->radio_device_type != SubGhzRadioDeviceTypeInternal) {
|
||||
subghz_txrx_radio_device_power_off(instance);
|
||||
subghz_devices_end(instance->radio_device);
|
||||
}
|
||||
|
||||
subghz_devices_deinit();
|
||||
|
||||
subghz_worker_free(instance->worker);
|
||||
subghz_receiver_free(instance->receiver);
|
||||
subghz_environment_free(instance->environment);
|
||||
flipper_format_free(instance->fff_data);
|
||||
furi_string_free(instance->preset->name);
|
||||
subghz_setting_free(instance->setting);
|
||||
|
||||
free(instance->preset);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->is_database_loaded;
|
||||
}
|
||||
|
||||
void subghz_txrx_set_preset(
|
||||
SubGhzTxRx* instance,
|
||||
const char* preset_name,
|
||||
uint32_t frequency,
|
||||
uint8_t* preset_data,
|
||||
size_t preset_data_size) {
|
||||
furi_assert(instance);
|
||||
furi_string_set(instance->preset->name, preset_name);
|
||||
SubGhzRadioPreset* preset = instance->preset;
|
||||
preset->frequency = frequency;
|
||||
preset->data = preset_data;
|
||||
preset->data_size = preset_data_size;
|
||||
}
|
||||
|
||||
const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) {
|
||||
UNUSED(instance);
|
||||
const char* preset_name = "";
|
||||
if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
|
||||
preset_name = "AM270";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
|
||||
preset_name = "AM650";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
|
||||
preset_name = "FM238";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
|
||||
preset_name = "FM476";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) {
|
||||
preset_name = "CUSTOM";
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unknown preset");
|
||||
}
|
||||
return preset_name;
|
||||
}
|
||||
|
||||
SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return *instance->preset;
|
||||
}
|
||||
|
||||
void subghz_txrx_get_frequency_and_modulation(
|
||||
SubGhzTxRx* instance,
|
||||
FuriString* frequency,
|
||||
FuriString* modulation,
|
||||
bool long_name) {
|
||||
furi_assert(instance);
|
||||
SubGhzRadioPreset* preset = instance->preset;
|
||||
if(frequency != NULL) {
|
||||
furi_string_printf(
|
||||
frequency,
|
||||
"%03ld.%02ld",
|
||||
preset->frequency / 1000000 % 1000,
|
||||
preset->frequency / 10000 % 100);
|
||||
}
|
||||
if(modulation != NULL) {
|
||||
if(long_name) {
|
||||
furi_string_printf(modulation, "%s", furi_string_get_cstr(preset->name));
|
||||
} else {
|
||||
furi_string_printf(modulation, "%.2s", furi_string_get_cstr(preset->name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) {
|
||||
furi_assert(instance);
|
||||
subghz_devices_reset(instance->radio_device);
|
||||
subghz_devices_idle(instance->radio_device);
|
||||
subghz_devices_load_preset(instance->radio_device, FuriHalSubGhzPresetCustom, preset_data);
|
||||
instance->txrx_state = SubGhzTxRxStateIDLE;
|
||||
}
|
||||
|
||||
static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) {
|
||||
furi_assert(instance);
|
||||
furi_assert(
|
||||
instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep);
|
||||
|
||||
subghz_devices_idle(instance->radio_device);
|
||||
|
||||
uint32_t value = subghz_devices_set_frequency(instance->radio_device, frequency);
|
||||
subghz_devices_flush_rx(instance->radio_device);
|
||||
subghz_txrx_speaker_on(instance);
|
||||
|
||||
subghz_devices_start_async_rx(
|
||||
instance->radio_device, subghz_worker_rx_callback, instance->worker);
|
||||
subghz_worker_start(instance->worker);
|
||||
instance->txrx_state = SubGhzTxRxStateRx;
|
||||
return value;
|
||||
}
|
||||
|
||||
static void subghz_txrx_idle(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
|
||||
subghz_devices_idle(instance->radio_device);
|
||||
subghz_txrx_speaker_off(instance);
|
||||
instance->txrx_state = SubGhzTxRxStateIDLE;
|
||||
}
|
||||
|
||||
static void subghz_txrx_rx_end(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->txrx_state == SubGhzTxRxStateRx);
|
||||
|
||||
if(subghz_worker_is_running(instance->worker)) {
|
||||
subghz_worker_stop(instance->worker);
|
||||
subghz_devices_stop_async_rx(instance->radio_device);
|
||||
}
|
||||
subghz_devices_idle(instance->radio_device);
|
||||
subghz_txrx_speaker_off(instance);
|
||||
instance->txrx_state = SubGhzTxRxStateIDLE;
|
||||
}
|
||||
|
||||
void subghz_txrx_sleep(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
subghz_devices_sleep(instance->radio_device);
|
||||
instance->txrx_state = SubGhzTxRxStateSleep;
|
||||
}
|
||||
|
||||
static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
|
||||
|
||||
subghz_devices_idle(instance->radio_device);
|
||||
subghz_devices_set_frequency(instance->radio_device, frequency);
|
||||
|
||||
bool ret = subghz_devices_set_tx(instance->radio_device);
|
||||
if(ret) {
|
||||
subghz_txrx_speaker_on(instance);
|
||||
instance->txrx_state = SubGhzTxRxStateTx;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) {
|
||||
furi_assert(instance);
|
||||
furi_assert(flipper_format);
|
||||
|
||||
subghz_txrx_stop(instance);
|
||||
|
||||
SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
uint32_t repeat = 200;
|
||||
do {
|
||||
if(!flipper_format_rewind(flipper_format)) {
|
||||
FURI_LOG_E(TAG, "Rewind error");
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing Protocol");
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) {
|
||||
FURI_LOG_E(TAG, "Unable Repeat");
|
||||
break;
|
||||
}
|
||||
ret = SubGhzTxRxStartTxStateOk;
|
||||
|
||||
SubGhzRadioPreset* preset = instance->preset;
|
||||
instance->transmitter =
|
||||
subghz_transmitter_alloc_init(instance->environment, furi_string_get_cstr(temp_str));
|
||||
|
||||
if(instance->transmitter) {
|
||||
if(subghz_transmitter_deserialize(instance->transmitter, flipper_format) ==
|
||||
SubGhzProtocolStatusOk) {
|
||||
if(strcmp(furi_string_get_cstr(preset->name), "") != 0) {
|
||||
subghz_txrx_begin(
|
||||
instance,
|
||||
subghz_setting_get_preset_data_by_name(
|
||||
instance->setting, furi_string_get_cstr(preset->name)));
|
||||
if(preset->frequency) {
|
||||
if(!subghz_txrx_tx(instance, preset->frequency)) {
|
||||
FURI_LOG_E(TAG, "Only Rx");
|
||||
ret = SubGhzTxRxStartTxStateErrorOnlyRx;
|
||||
}
|
||||
} else {
|
||||
ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||
}
|
||||
|
||||
} else {
|
||||
FURI_LOG_E(
|
||||
TAG, "Unknown name preset \" %s \"", furi_string_get_cstr(preset->name));
|
||||
ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||
}
|
||||
|
||||
if(ret == SubGhzTxRxStartTxStateOk) {
|
||||
//Start TX
|
||||
subghz_devices_start_async_tx(
|
||||
instance->radio_device, subghz_transmitter_yield, instance->transmitter);
|
||||
}
|
||||
} else {
|
||||
ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||
}
|
||||
} else {
|
||||
ret = SubGhzTxRxStartTxStateErrorParserOthers;
|
||||
}
|
||||
if(ret != SubGhzTxRxStartTxStateOk) {
|
||||
subghz_transmitter_free(instance->transmitter);
|
||||
if(instance->txrx_state != SubGhzTxRxStateIDLE) {
|
||||
subghz_txrx_idle(instance);
|
||||
}
|
||||
}
|
||||
|
||||
} while(false);
|
||||
furi_string_free(temp_str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void subghz_txrx_rx_start(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
subghz_txrx_stop(instance);
|
||||
subghz_txrx_begin(
|
||||
instance,
|
||||
subghz_setting_get_preset_data_by_name(
|
||||
subghz_txrx_get_setting(instance), furi_string_get_cstr(instance->preset->name)));
|
||||
subghz_txrx_rx(instance, instance->preset->frequency);
|
||||
}
|
||||
|
||||
void subghz_txrx_set_need_save_callback(
|
||||
SubGhzTxRx* instance,
|
||||
SubGhzTxRxNeedSaveCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
instance->need_save_callback = callback;
|
||||
instance->need_save_context = context;
|
||||
}
|
||||
|
||||
static void subghz_txrx_tx_stop(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->txrx_state == SubGhzTxRxStateTx);
|
||||
//Stop TX
|
||||
subghz_devices_stop_async_tx(instance->radio_device);
|
||||
subghz_transmitter_stop(instance->transmitter);
|
||||
subghz_transmitter_free(instance->transmitter);
|
||||
|
||||
//if protocol dynamic then we save the last upload
|
||||
if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) {
|
||||
if(instance->need_save_callback) {
|
||||
instance->need_save_callback(instance->need_save_context);
|
||||
}
|
||||
}
|
||||
subghz_txrx_idle(instance);
|
||||
subghz_txrx_speaker_off(instance);
|
||||
//Todo: Show message
|
||||
}
|
||||
|
||||
FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->fff_data;
|
||||
}
|
||||
|
||||
SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->setting;
|
||||
}
|
||||
|
||||
void subghz_txrx_stop(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
switch(instance->txrx_state) {
|
||||
case SubGhzTxRxStateTx:
|
||||
subghz_txrx_tx_stop(instance);
|
||||
subghz_txrx_speaker_unmute(instance);
|
||||
break;
|
||||
case SubGhzTxRxStateRx:
|
||||
subghz_txrx_rx_end(instance);
|
||||
subghz_txrx_speaker_mute(instance);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_hopper_update(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
switch(instance->hopper_state) {
|
||||
case SubGhzHopperStateOFF:
|
||||
case SubGhzHopperStatePause:
|
||||
return;
|
||||
case SubGhzHopperStateRSSITimeOut:
|
||||
if(instance->hopper_timeout != 0) {
|
||||
instance->hopper_timeout--;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
float rssi = -127.0f;
|
||||
if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) {
|
||||
// See RSSI Calculation timings in CC1101 17.3 RSSI
|
||||
rssi = subghz_devices_get_rssi(instance->radio_device);
|
||||
|
||||
// Stay if RSSI is high enough
|
||||
if(rssi > -90.0f) {
|
||||
instance->hopper_timeout = 10;
|
||||
instance->hopper_state = SubGhzHopperStateRSSITimeOut;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
instance->hopper_state = SubGhzHopperStateRunning;
|
||||
}
|
||||
// Select next frequency
|
||||
if(instance->hopper_idx_frequency <
|
||||
subghz_setting_get_hopper_frequency_count(instance->setting) - 1) {
|
||||
instance->hopper_idx_frequency++;
|
||||
} else {
|
||||
instance->hopper_idx_frequency = 0;
|
||||
}
|
||||
|
||||
if(instance->txrx_state == SubGhzTxRxStateRx) {
|
||||
subghz_txrx_rx_end(instance);
|
||||
};
|
||||
if(instance->txrx_state == SubGhzTxRxStateIDLE) {
|
||||
subghz_receiver_reset(instance->receiver);
|
||||
instance->preset->frequency =
|
||||
subghz_setting_get_hopper_frequency(instance->setting, instance->hopper_idx_frequency);
|
||||
subghz_txrx_rx(instance, instance->preset->frequency);
|
||||
}
|
||||
}
|
||||
|
||||
SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->hopper_state;
|
||||
}
|
||||
|
||||
void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state) {
|
||||
furi_assert(instance);
|
||||
instance->hopper_state = state;
|
||||
}
|
||||
|
||||
void subghz_txrx_hopper_unpause(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->hopper_state == SubGhzHopperStatePause) {
|
||||
instance->hopper_state = SubGhzHopperStateRunning;
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_hopper_pause(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->hopper_state == SubGhzHopperStateRunning) {
|
||||
instance->hopper_state = SubGhzHopperStatePause;
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_speaker_on(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->debug_pin_state) {
|
||||
subghz_devices_set_async_mirror_pin(instance->radio_device, &gpio_ibutton);
|
||||
}
|
||||
|
||||
if(instance->speaker_state == SubGhzSpeakerStateEnable) {
|
||||
if(furi_hal_speaker_acquire(30)) {
|
||||
if(!instance->debug_pin_state) {
|
||||
subghz_devices_set_async_mirror_pin(instance->radio_device, &gpio_speaker);
|
||||
}
|
||||
} else {
|
||||
instance->speaker_state = SubGhzSpeakerStateDisable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_speaker_off(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->debug_pin_state) {
|
||||
subghz_devices_set_async_mirror_pin(instance->radio_device, NULL);
|
||||
}
|
||||
if(instance->speaker_state != SubGhzSpeakerStateDisable) {
|
||||
if(furi_hal_speaker_is_mine()) {
|
||||
if(!instance->debug_pin_state) {
|
||||
subghz_devices_set_async_mirror_pin(instance->radio_device, NULL);
|
||||
}
|
||||
furi_hal_speaker_release();
|
||||
if(instance->speaker_state == SubGhzSpeakerStateShutdown)
|
||||
instance->speaker_state = SubGhzSpeakerStateDisable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_speaker_mute(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->debug_pin_state) {
|
||||
subghz_devices_set_async_mirror_pin(instance->radio_device, NULL);
|
||||
}
|
||||
if(instance->speaker_state == SubGhzSpeakerStateEnable) {
|
||||
if(furi_hal_speaker_is_mine()) {
|
||||
if(!instance->debug_pin_state) {
|
||||
subghz_devices_set_async_mirror_pin(instance->radio_device, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
if(instance->debug_pin_state) {
|
||||
subghz_devices_set_async_mirror_pin(instance->radio_device, &gpio_ibutton);
|
||||
}
|
||||
if(instance->speaker_state == SubGhzSpeakerStateEnable) {
|
||||
if(furi_hal_speaker_is_mine()) {
|
||||
if(!instance->debug_pin_state) {
|
||||
subghz_devices_set_async_mirror_pin(instance->radio_device, &gpio_speaker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state) {
|
||||
furi_assert(instance);
|
||||
instance->speaker_state = state;
|
||||
}
|
||||
|
||||
SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->speaker_state;
|
||||
}
|
||||
|
||||
bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol) {
|
||||
furi_assert(instance);
|
||||
furi_assert(name_protocol);
|
||||
bool res = false;
|
||||
instance->decoder_result =
|
||||
subghz_receiver_search_decoder_base_by_name(instance->receiver, name_protocol);
|
||||
if(instance->decoder_result) {
|
||||
res = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->decoder_result;
|
||||
}
|
||||
|
||||
bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return (
|
||||
(instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
|
||||
SubGhzProtocolFlag_Save);
|
||||
}
|
||||
|
||||
bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type) {
|
||||
furi_assert(instance);
|
||||
const SubGhzProtocol* protocol = instance->decoder_result->protocol;
|
||||
if(check_type) {
|
||||
return (
|
||||
((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
|
||||
protocol->encoder->deserialize && protocol->type == SubGhzProtocolTypeStatic);
|
||||
}
|
||||
return (
|
||||
((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
|
||||
protocol->encoder->deserialize);
|
||||
}
|
||||
|
||||
void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter) {
|
||||
furi_assert(instance);
|
||||
subghz_receiver_set_filter(instance->receiver, filter);
|
||||
}
|
||||
|
||||
void subghz_txrx_set_rx_calback(
|
||||
SubGhzTxRx* instance,
|
||||
SubGhzReceiverCallback callback,
|
||||
void* context) {
|
||||
subghz_receiver_set_rx_callback(instance->receiver, callback, context);
|
||||
}
|
||||
|
||||
void subghz_txrx_set_raw_file_encoder_worker_callback_end(
|
||||
SubGhzTxRx* instance,
|
||||
SubGhzProtocolEncoderRAWCallbackEnd callback,
|
||||
void* context) {
|
||||
subghz_protocol_raw_file_encoder_worker_set_callback_end(
|
||||
(SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(instance->transmitter),
|
||||
callback,
|
||||
context);
|
||||
}
|
||||
|
||||
bool subghz_txrx_radio_device_is_external_connected(SubGhzTxRx* instance, const char* name) {
|
||||
furi_assert(instance);
|
||||
|
||||
bool is_connect = false;
|
||||
bool is_otg_enabled = furi_hal_power_is_otg_enabled();
|
||||
|
||||
if(!is_otg_enabled) {
|
||||
subghz_txrx_radio_device_power_on(instance);
|
||||
}
|
||||
|
||||
const SubGhzDevice* device = subghz_devices_get_by_name(name);
|
||||
if(device) {
|
||||
is_connect = subghz_devices_is_connect(device);
|
||||
}
|
||||
|
||||
if(!is_otg_enabled) {
|
||||
subghz_txrx_radio_device_power_off(instance);
|
||||
}
|
||||
return is_connect;
|
||||
}
|
||||
|
||||
SubGhzRadioDeviceType
|
||||
subghz_txrx_radio_device_set(SubGhzTxRx* instance, SubGhzRadioDeviceType radio_device_type) {
|
||||
furi_assert(instance);
|
||||
|
||||
if(radio_device_type == SubGhzRadioDeviceTypeExternalCC1101 &&
|
||||
subghz_txrx_radio_device_is_external_connected(instance, SUBGHZ_DEVICE_CC1101_EXT_NAME)) {
|
||||
subghz_txrx_radio_device_power_on(instance);
|
||||
instance->radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_EXT_NAME);
|
||||
subghz_devices_begin(instance->radio_device);
|
||||
instance->radio_device_type = SubGhzRadioDeviceTypeExternalCC1101;
|
||||
} else {
|
||||
subghz_txrx_radio_device_power_off(instance);
|
||||
if(instance->radio_device_type != SubGhzRadioDeviceTypeInternal) {
|
||||
subghz_devices_end(instance->radio_device);
|
||||
}
|
||||
instance->radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME);
|
||||
instance->radio_device_type = SubGhzRadioDeviceTypeInternal;
|
||||
}
|
||||
|
||||
return instance->radio_device_type;
|
||||
}
|
||||
|
||||
SubGhzRadioDeviceType subghz_txrx_radio_device_get(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->radio_device_type;
|
||||
}
|
||||
|
||||
float subghz_txrx_radio_device_get_rssi(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return subghz_devices_get_rssi(instance->radio_device);
|
||||
}
|
||||
|
||||
const char* subghz_txrx_radio_device_get_name(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return subghz_devices_get_name(instance->radio_device);
|
||||
}
|
||||
|
||||
bool subghz_txrx_radio_device_is_frequency_valid(SubGhzTxRx* instance, uint32_t frequency) {
|
||||
furi_assert(instance);
|
||||
return subghz_devices_is_frequency_valid(instance->radio_device, frequency);
|
||||
}
|
||||
|
||||
bool subghz_txrx_radio_device_is_tx_allowed(SubGhzTxRx* instance, uint32_t frequency) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
|
||||
|
||||
subghz_devices_idle(instance->radio_device);
|
||||
subghz_devices_set_frequency(instance->radio_device, frequency);
|
||||
|
||||
bool ret = subghz_devices_set_tx(instance->radio_device);
|
||||
subghz_devices_idle(instance->radio_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void subghz_txrx_set_debug_pin_state(SubGhzTxRx* instance, bool state) {
|
||||
furi_assert(instance);
|
||||
instance->debug_pin_state = state;
|
||||
}
|
||||
|
||||
bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->debug_pin_state;
|
||||
}
|
||||
|
||||
void subghz_txrx_reset_dynamic_and_custom_btns(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
subghz_environment_reset_keeloq(instance->environment);
|
||||
|
||||
subghz_custom_btns_reset();
|
||||
}
|
||||
|
||||
SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->receiver;
|
||||
}
|
||||
@@ -1,375 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <lib/subghz/subghz_worker.h>
|
||||
#include <lib/subghz/subghz_setting.h>
|
||||
#include <lib/subghz/receiver.h>
|
||||
#include <lib/subghz/transmitter.h>
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
#include <lib/subghz/devices/devices.h>
|
||||
|
||||
typedef struct SubGhzTxRx SubGhzTxRx;
|
||||
|
||||
typedef void (*SubGhzTxRxNeedSaveCallback)(void* context);
|
||||
|
||||
typedef enum {
|
||||
SubGhzTxRxStartTxStateOk,
|
||||
SubGhzTxRxStartTxStateErrorOnlyRx,
|
||||
SubGhzTxRxStartTxStateErrorParserOthers,
|
||||
} SubGhzTxRxStartTxState;
|
||||
|
||||
// Type from subghz_types.h need for txrx working
|
||||
/** SubGhzTxRx state */
|
||||
typedef enum {
|
||||
SubGhzTxRxStateIDLE,
|
||||
SubGhzTxRxStateRx,
|
||||
SubGhzTxRxStateTx,
|
||||
SubGhzTxRxStateSleep,
|
||||
} SubGhzTxRxState;
|
||||
|
||||
/** SubGhzHopperState state */
|
||||
typedef enum {
|
||||
SubGhzHopperStateOFF,
|
||||
SubGhzHopperStateRunning,
|
||||
SubGhzHopperStatePause,
|
||||
SubGhzHopperStateRSSITimeOut,
|
||||
} SubGhzHopperState;
|
||||
|
||||
/** SubGhzSpeakerState state */
|
||||
typedef enum {
|
||||
SubGhzSpeakerStateDisable,
|
||||
SubGhzSpeakerStateShutdown,
|
||||
SubGhzSpeakerStateEnable,
|
||||
} SubGhzSpeakerState;
|
||||
|
||||
/** SubGhzRadioDeviceType */
|
||||
typedef enum {
|
||||
SubGhzRadioDeviceTypeAuto,
|
||||
SubGhzRadioDeviceTypeInternal,
|
||||
SubGhzRadioDeviceTypeExternalCC1101,
|
||||
} SubGhzRadioDeviceType;
|
||||
|
||||
/**
|
||||
* Allocate SubGhzTxRx
|
||||
*
|
||||
* @return SubGhzTxRx* pointer to SubGhzTxRx
|
||||
*/
|
||||
SubGhzTxRx* subghz_txrx_alloc();
|
||||
|
||||
/**
|
||||
* Free SubGhzTxRx
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_free(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Check if the database is loaded
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return bool True if the database is loaded
|
||||
*/
|
||||
bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Set preset
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param preset_name Name of preset
|
||||
* @param frequency Frequency in Hz
|
||||
* @param preset_data Data of preset
|
||||
* @param preset_data_size Size of preset data
|
||||
*/
|
||||
void subghz_txrx_set_preset(
|
||||
SubGhzTxRx* instance,
|
||||
const char* preset_name,
|
||||
uint32_t frequency,
|
||||
uint8_t* preset_data,
|
||||
size_t preset_data_size);
|
||||
|
||||
/**
|
||||
* Get name of preset
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param preset String of preset
|
||||
* @return const char* Name of preset
|
||||
*/
|
||||
const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset);
|
||||
|
||||
/**
|
||||
* Get of preset
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return SubGhzRadioPreset Preset
|
||||
*/
|
||||
SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Get string frequency and modulation
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param frequency Pointer to a string frequency
|
||||
* @param modulation Pointer to a string modulation
|
||||
*/
|
||||
void subghz_txrx_get_frequency_and_modulation(
|
||||
SubGhzTxRx* instance,
|
||||
FuriString* frequency,
|
||||
FuriString* modulation,
|
||||
bool long_name);
|
||||
|
||||
/**
|
||||
* Start TX CC1101
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param flipper_format Pointer to a FlipperFormat
|
||||
* @return SubGhzTxRxStartTxState
|
||||
*/
|
||||
SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format);
|
||||
|
||||
/**
|
||||
* Start RX CC1101
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_rx_start(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Stop TX/RX CC1101
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_stop(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Set sleep mode CC1101
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_sleep(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Update frequency CC1101 in automatic mode (hopper)
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_hopper_update(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Get state hopper
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return SubGhzHopperState
|
||||
*/
|
||||
SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Set state hopper
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param state State hopper
|
||||
*/
|
||||
void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state);
|
||||
|
||||
/**
|
||||
* Unpause hopper
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_hopper_unpause(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Set pause hopper
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_hopper_pause(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Speaker on
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_speaker_on(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Speaker off
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_speaker_off(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Speaker mute
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_speaker_mute(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Speaker unmute
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
*/
|
||||
void subghz_txrx_speaker_unmute(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Set state speaker
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param state State speaker
|
||||
*/
|
||||
void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state);
|
||||
|
||||
/**
|
||||
* Get state speaker
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return SubGhzSpeakerState
|
||||
*/
|
||||
SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* load decoder by name protocol
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param name_protocol Name protocol
|
||||
* @return bool True if the decoder is loaded
|
||||
*/
|
||||
bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol);
|
||||
|
||||
/**
|
||||
* Get decoder
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return SubGhzProtocolDecoderBase* Pointer to a SubGhzProtocolDecoderBase
|
||||
*/
|
||||
SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Set callback for save data
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param callback Callback for save data
|
||||
* @param context Context for callback
|
||||
*/
|
||||
void subghz_txrx_set_need_save_callback(
|
||||
SubGhzTxRx* instance,
|
||||
SubGhzTxRxNeedSaveCallback callback,
|
||||
void* context);
|
||||
|
||||
/**
|
||||
* Get pointer to a load data key
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return FlipperFormat*
|
||||
*/
|
||||
FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Get pointer to a SugGhzSetting
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return SubGhzSetting*
|
||||
*/
|
||||
SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Is it possible to save this protocol
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return bool True if it is possible to save this protocol
|
||||
*/
|
||||
bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance);
|
||||
|
||||
/**
|
||||
* Is it possible to send this protocol
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return bool True if it is possible to send this protocol
|
||||
*/
|
||||
bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type);
|
||||
|
||||
/**
|
||||
* Set filter, what types of decoder to use
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param filter Filter
|
||||
*/
|
||||
void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter);
|
||||
|
||||
/**
|
||||
* Set callback for receive data
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param callback Callback for receive data
|
||||
* @param context Context for callback
|
||||
*/
|
||||
void subghz_txrx_set_rx_calback(
|
||||
SubGhzTxRx* instance,
|
||||
SubGhzReceiverCallback callback,
|
||||
void* context);
|
||||
|
||||
/**
|
||||
* Set callback for Raw decoder, end of data transfer
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param callback Callback for Raw decoder, end of data transfer
|
||||
* @param context Context for callback
|
||||
*/
|
||||
void subghz_txrx_set_raw_file_encoder_worker_callback_end(
|
||||
SubGhzTxRx* instance,
|
||||
SubGhzProtocolEncoderRAWCallbackEnd callback,
|
||||
void* context);
|
||||
|
||||
/* Checking if an external radio device is connected
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param name Name of external radio device
|
||||
* @return bool True if is connected to the external radio device
|
||||
*/
|
||||
bool subghz_txrx_radio_device_is_external_connected(SubGhzTxRx* instance, const char* name);
|
||||
|
||||
/* Set the selected radio device to use
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @param radio_device_type Radio device type
|
||||
* @return SubGhzRadioDeviceType Type of installed radio device
|
||||
*/
|
||||
SubGhzRadioDeviceType
|
||||
subghz_txrx_radio_device_set(SubGhzTxRx* instance, SubGhzRadioDeviceType radio_device_type);
|
||||
|
||||
/* Get the selected radio device to use
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return SubGhzRadioDeviceType Type of installed radio device
|
||||
*/
|
||||
SubGhzRadioDeviceType subghz_txrx_radio_device_get(SubGhzTxRx* instance);
|
||||
|
||||
/* Get RSSI the selected radio device to use
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return float RSSI
|
||||
*/
|
||||
float subghz_txrx_radio_device_get_rssi(SubGhzTxRx* instance);
|
||||
|
||||
/* Get name the selected radio device to use
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return const char* Name of installed radio device
|
||||
*/
|
||||
const char* subghz_txrx_radio_device_get_name(SubGhzTxRx* instance);
|
||||
|
||||
/* Get get intelligence whether frequency the selected radio device to use
|
||||
*
|
||||
* @param instance Pointer to a SubGhzTxRx
|
||||
* @return bool True if the frequency is valid
|
||||
*/
|
||||
bool subghz_txrx_radio_device_is_frequency_valid(SubGhzTxRx* instance, uint32_t frequency);
|
||||
|
||||
bool subghz_txrx_radio_device_is_tx_allowed(SubGhzTxRx* instance, uint32_t frequency);
|
||||
|
||||
void subghz_txrx_set_debug_pin_state(SubGhzTxRx* instance, bool state);
|
||||
bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance);
|
||||
|
||||
void subghz_txrx_reset_dynamic_and_custom_btns(SubGhzTxRx* instance);
|
||||
|
||||
SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance); // TODO use only in DecodeRaw
|
||||
@@ -1,31 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "subghz_txrx.h"
|
||||
|
||||
struct SubGhzTxRx {
|
||||
SubGhzWorker* worker;
|
||||
|
||||
SubGhzEnvironment* environment;
|
||||
SubGhzReceiver* receiver;
|
||||
SubGhzTransmitter* transmitter;
|
||||
SubGhzProtocolDecoderBase* decoder_result;
|
||||
FlipperFormat* fff_data;
|
||||
|
||||
SubGhzRadioPreset* preset;
|
||||
SubGhzSetting* setting;
|
||||
|
||||
uint8_t hopper_timeout;
|
||||
uint8_t hopper_idx_frequency;
|
||||
bool is_database_loaded;
|
||||
SubGhzHopperState hopper_state;
|
||||
|
||||
SubGhzTxRxState txrx_state;
|
||||
SubGhzSpeakerState speaker_state;
|
||||
const SubGhzDevice* radio_device;
|
||||
SubGhzRadioDeviceType radio_device_type;
|
||||
|
||||
SubGhzTxRxNeedSaveCallback need_save_callback;
|
||||
void* need_save_context;
|
||||
|
||||
bool debug_pin_state;
|
||||
};
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.9 KiB |
@@ -1,30 +0,0 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const subrem_scene_on_enter_handlers[])(void*) = {
|
||||
#include "subrem_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const subrem_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "subrem_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const subrem_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "subrem_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers subrem_scene_handlers = {
|
||||
.on_enter_handlers = subrem_scene_on_enter_handlers,
|
||||
.on_event_handlers = subrem_scene_on_event_handlers,
|
||||
.on_exit_handlers = subrem_scene_on_exit_handlers,
|
||||
.scene_num = SubRemSceneNum,
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) SubRemScene##id,
|
||||
typedef enum {
|
||||
#include "subrem_scene_config.h"
|
||||
SubRemSceneNum,
|
||||
} SubRemScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers subrem_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "subrem_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) \
|
||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||
#include "subrem_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||
#include "subrem_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -1,9 +0,0 @@
|
||||
ADD_SCENE(subrem, start, Start)
|
||||
ADD_SCENE(subrem, open_map_file, OpenMapFile)
|
||||
ADD_SCENE(subrem, remote, Remote)
|
||||
ADD_SCENE(subrem, edit_menu, EditMenu)
|
||||
ADD_SCENE(subrem, edit_submenu, EditSubMenu)
|
||||
ADD_SCENE(subrem, edit_label, EditLabel)
|
||||
ADD_SCENE(subrem, open_sub_file, OpenSubFile)
|
||||
ADD_SCENE(subrem, edit_preview, EditPreview)
|
||||
ADD_SCENE(subrem, enter_new_name, EnterNewName)
|
||||
@@ -1,133 +0,0 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
|
||||
#include <lib/toolbox/path.h>
|
||||
|
||||
typedef enum {
|
||||
SubRemSceneEditLabelStateTextInput,
|
||||
SubRemSceneEditLabelStateWidget,
|
||||
} SubRemSceneEditLabelState;
|
||||
|
||||
void subrem_scene_edit_label_text_input_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, SubRemCustomEventSceneEditLabelInputDone);
|
||||
}
|
||||
|
||||
void subrem_scene_edit_label_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
if((result == GuiButtonTypeCenter) && (type == InputTypeShort)) {
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, SubRemCustomEventSceneEditLabelWidgetAcces);
|
||||
} else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, SubRemCustomEventSceneEditLabelWidgetBack);
|
||||
}
|
||||
}
|
||||
|
||||
void subrem_scene_edit_label_on_enter(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub];
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
|
||||
if(furi_string_empty(sub_preset->label)) {
|
||||
if(furi_string_empty(sub_preset->file_path)) {
|
||||
path_extract_filename(sub_preset->file_path, temp_str, true);
|
||||
strcpy(app->file_name_tmp, furi_string_get_cstr(temp_str));
|
||||
} else {
|
||||
strcpy(app->file_name_tmp, "");
|
||||
}
|
||||
} else {
|
||||
strcpy(app->file_name_tmp, furi_string_get_cstr(sub_preset->label));
|
||||
}
|
||||
|
||||
TextInput* text_input = app->text_input;
|
||||
text_input_set_header_text(text_input, "Label name");
|
||||
text_input_set_result_callback(
|
||||
text_input,
|
||||
subrem_scene_edit_label_text_input_callback,
|
||||
app,
|
||||
app->file_name_tmp,
|
||||
25,
|
||||
false);
|
||||
|
||||
text_input_set_minimum_length(app->text_input, 0);
|
||||
|
||||
widget_add_string_element(
|
||||
app->widget, 63, 12, AlignCenter, AlignCenter, FontPrimary, "Empty Label Name");
|
||||
widget_add_string_element(
|
||||
app->widget, 63, 32, AlignCenter, AlignCenter, FontSecondary, "Continue?");
|
||||
|
||||
widget_add_button_element(
|
||||
app->widget, GuiButtonTypeCenter, "Ok", subrem_scene_edit_label_widget_callback, app);
|
||||
widget_add_button_element(
|
||||
app->widget, GuiButtonTypeLeft, "Back", subrem_scene_edit_label_widget_callback, app);
|
||||
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, SubRemSceneEditLabel, SubRemSceneEditLabelStateTextInput);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDTextInput);
|
||||
|
||||
furi_string_free(temp_str);
|
||||
}
|
||||
|
||||
bool subrem_scene_edit_label_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
FuriString* label = app->map_preset->subs_preset[app->chusen_sub]->label;
|
||||
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
if(scene_manager_get_scene_state(app->scene_manager, SubRemSceneEditLabel) ==
|
||||
SubRemSceneEditLabelStateWidget) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, SubRemSceneEditLabel, SubRemSceneEditLabelStateTextInput);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDTextInput);
|
||||
return true;
|
||||
} else if(
|
||||
scene_manager_get_scene_state(app->scene_manager, SubRemSceneEditLabel) ==
|
||||
SubRemSceneEditLabelStateTextInput) {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
return true;
|
||||
}
|
||||
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
return true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubRemCustomEventSceneEditLabelInputDone) {
|
||||
if(strcmp(app->file_name_tmp, "") == 0) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, SubRemSceneEditLabel, SubRemSceneEditLabelStateWidget);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDWidget);
|
||||
|
||||
} else {
|
||||
furi_string_set(label, app->file_name_tmp);
|
||||
app->map_not_saved = true;
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
}
|
||||
return true;
|
||||
} else if(event.event == SubRemCustomEventSceneEditLabelWidgetAcces) {
|
||||
furi_string_set(label, app->file_name_tmp);
|
||||
app->map_not_saved = true;
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
|
||||
return true;
|
||||
} else if(event.event == SubRemCustomEventSceneEditLabelWidgetBack) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, SubRemSceneEditLabel, SubRemSceneEditLabelStateTextInput);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDTextInput);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void subrem_scene_edit_label_on_exit(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
// Clear view
|
||||
text_input_reset(app->text_input);
|
||||
widget_reset(app->widget);
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
|
||||
void subrem_scene_edit_menu_callback(SubRemCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void subrem_scene_edit_menu_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
|
||||
app->map_not_saved = false;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventViewEditMenuBack);
|
||||
} else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDEditMenu);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t subrem_scene_edit_menu_state_to_index(SubRemEditMenuState event_id) {
|
||||
uint8_t ret = 0;
|
||||
|
||||
if(event_id == SubRemEditMenuStateUP) {
|
||||
ret = SubRemSubKeyNameUp;
|
||||
} else if(event_id == SubRemEditMenuStateDOWN) {
|
||||
ret = SubRemSubKeyNameDown;
|
||||
} else if(event_id == SubRemEditMenuStateLEFT) {
|
||||
ret = SubRemSubKeyNameLeft;
|
||||
} else if(event_id == SubRemEditMenuStateRIGHT) {
|
||||
ret = SubRemSubKeyNameRight;
|
||||
} else if(event_id == SubRemEditMenuStateOK) {
|
||||
ret = SubRemSubKeyNameOk;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void subrem_scene_edit_menu_update_data(SubGhzRemoteApp* app) {
|
||||
furi_assert(app);
|
||||
uint8_t index = subrem_scene_edit_menu_state_to_index(
|
||||
scene_manager_get_scene_state(app->scene_manager, SubRemSceneEditMenu));
|
||||
|
||||
subrem_view_edit_menu_add_data_to_show(
|
||||
app->subrem_edit_menu,
|
||||
index,
|
||||
app->map_preset->subs_preset[index]->label,
|
||||
app->map_preset->subs_preset[index]->file_path,
|
||||
app->map_preset->subs_preset[index]->load_state);
|
||||
}
|
||||
|
||||
void subrem_scene_edit_menu_on_enter(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
subrem_view_edit_menu_set_callback(
|
||||
app->subrem_edit_menu, subrem_scene_edit_menu_callback, app);
|
||||
|
||||
subrem_scene_edit_menu_update_data(app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDEditMenu);
|
||||
|
||||
Widget* widget = app->widget;
|
||||
|
||||
widget_add_string_element(
|
||||
widget, 63, 12, AlignCenter, AlignBottom, FontPrimary, "Changes are not saved");
|
||||
widget_add_string_element(
|
||||
widget, 63, 32, AlignCenter, AlignBottom, FontPrimary, "do you want to exit?");
|
||||
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeRight, "Yes", subrem_scene_edit_menu_widget_callback, app);
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeLeft, "No", subrem_scene_edit_menu_widget_callback, app);
|
||||
}
|
||||
|
||||
bool subrem_scene_edit_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
// Catch widget backEvent
|
||||
return true;
|
||||
}
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubRemCustomEventViewEditMenuBack) {
|
||||
if(app->map_not_saved) {
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDWidget);
|
||||
} else if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SubRemSceneStart)) {
|
||||
scene_manager_stop(app->scene_manager);
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if(
|
||||
event.event == SubRemCustomEventViewEditMenuUP ||
|
||||
event.event == SubRemCustomEventViewEditMenuDOWN) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager,
|
||||
SubRemSceneEditMenu,
|
||||
subrem_view_edit_menu_get_index(app->subrem_edit_menu));
|
||||
subrem_scene_edit_menu_update_data(app);
|
||||
|
||||
return true;
|
||||
} else if(event.event == SubRemCustomEventViewEditMenuEdit) {
|
||||
app->chusen_sub = subrem_view_edit_menu_get_index(app->subrem_edit_menu);
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, SubRemSceneEditSubMenu, EditSubmenuIndexEditLabel);
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneEditSubMenu);
|
||||
|
||||
return true;
|
||||
} else if(event.event == SubRemCustomEventViewEditMenuSave) {
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneEditPreview);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void subrem_scene_edit_menu_on_exit(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
#include "../views/remote.h"
|
||||
|
||||
#define TAG "SubRemScenRemote"
|
||||
|
||||
void subghz_scene_edit_preview_save_popup_callback(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, SubRemCustomEventSceneEditPreviewSaved);
|
||||
}
|
||||
|
||||
void subrem_scene_edit_preview_callback(SubRemCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void subrem_scene_edit_preview_on_enter(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
// Setup view
|
||||
Popup* popup = app->popup;
|
||||
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
|
||||
popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_callback(popup, subghz_scene_edit_preview_save_popup_callback);
|
||||
popup_enable_timeout(popup);
|
||||
|
||||
subrem_view_remote_update_data_labels(app->subrem_remote_view, app->map_preset->subs_preset);
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateOFF, 0);
|
||||
|
||||
subrem_view_remote_set_callback(
|
||||
app->subrem_remote_view, subrem_scene_edit_preview_callback, app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDRemote);
|
||||
}
|
||||
|
||||
bool subrem_scene_edit_preview_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
if(event.type == SceneManagerEventTypeBack ||
|
||||
(event.type == SceneManagerEventTypeCustom &&
|
||||
(event.event == SubRemCustomEventViewRemoteStartLEFT ||
|
||||
event.event == SubRemCustomEventViewRemoteForcedStop))) {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
return true;
|
||||
} else if(
|
||||
event.type == SceneManagerEventTypeCustom &&
|
||||
(event.event == SubRemCustomEventViewRemoteStartRIGHT ||
|
||||
event.event == SubRemCustomEventViewRemoteStartOK)) {
|
||||
if(subrem_save_map_to_file(app)) {
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDPopup);
|
||||
app->map_not_saved = false;
|
||||
return true;
|
||||
}
|
||||
// TODO error screen
|
||||
return true;
|
||||
} else if(
|
||||
event.type == SceneManagerEventTypeCustom &&
|
||||
event.event == SubRemCustomEventSceneEditPreviewSaved) {
|
||||
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SubRemSceneEditMenu);
|
||||
}
|
||||
// } else if(event.type == SceneManagerEventTypeTick) {
|
||||
// }
|
||||
return false;
|
||||
}
|
||||
|
||||
void subrem_scene_edit_preview_on_exit(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle, 0);
|
||||
popup_reset(app->popup);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
#include "../helpers/subrem_custom_event.h"
|
||||
|
||||
void subrem_scene_edit_submenu_text_input_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventSceneEditsubmenu);
|
||||
}
|
||||
|
||||
void subrem_scene_edit_submenu_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void subrem_scene_edit_submenu_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
submenu_add_item(
|
||||
submenu, "Edit Label", EditSubmenuIndexEditLabel, subrem_scene_edit_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
submenu, "Edit File", EditSubmenuIndexEditFile, subrem_scene_edit_submenu_callback, app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDSubmenu);
|
||||
}
|
||||
|
||||
bool subrem_scene_edit_submenu_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == EditSubmenuIndexEditLabel) {
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneEditLabel);
|
||||
consumed = true;
|
||||
} else if(event.event == EditSubmenuIndexEditFile) {
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneOpenSubFile);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subrem_scene_edit_submenu_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
#include "../helpers/subrem_custom_event.h"
|
||||
|
||||
#include <gui/modules/validators.h>
|
||||
|
||||
void subrem_scene_enter_new_name_text_input_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventSceneNewName);
|
||||
}
|
||||
|
||||
void subrem_scene_enter_new_name_on_enter(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
// Setup view
|
||||
TextInput* text_input = app->text_input;
|
||||
|
||||
//strncpy(app->file_name_tmp, "subrem_", SUBREM_MAX_LEN_NAME);
|
||||
text_input_set_header_text(text_input, "Map file Name");
|
||||
text_input_set_result_callback(
|
||||
text_input,
|
||||
subrem_scene_enter_new_name_text_input_callback,
|
||||
app,
|
||||
app->file_name_tmp,
|
||||
25,
|
||||
false);
|
||||
|
||||
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
|
||||
furi_string_get_cstr(app->file_path), SUBREM_APP_EXTENSION, "");
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDTextInput);
|
||||
}
|
||||
|
||||
bool subrem_scene_enter_new_name_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubRemCustomEventSceneNewName) {
|
||||
if(strcmp(app->file_name_tmp, "") != 0) {
|
||||
furi_string_set(app->file_path, SUBREM_APP_FOLDER);
|
||||
furi_string_cat_printf(
|
||||
app->file_path, "/%s%s", app->file_name_tmp, SUBREM_APP_EXTENSION);
|
||||
|
||||
subrem_map_preset_reset(app->map_preset);
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneEditMenu);
|
||||
} else { //error
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subrem_scene_enter_new_name_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
|
||||
// Clear validator & view
|
||||
void* validator_context = text_input_get_validator_callback_context(app->text_input);
|
||||
text_input_set_validator(app->text_input, NULL, NULL);
|
||||
validator_is_file_free(validator_context);
|
||||
text_input_reset(app->text_input);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
|
||||
void subrem_scene_open_map_file_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
SubRemLoadMapState load_state = subrem_load_from_file(app);
|
||||
uint32_t start_scene_state =
|
||||
scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart);
|
||||
|
||||
if(load_state == SubRemLoadMapStateBack) {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
} else if(start_scene_state == SubmenuIndexSubRemEditMapFile) {
|
||||
scene_manager_set_scene_state(app->scene_manager, SubRemSceneEditMenu, SubRemSubKeyNameUp);
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneEditMenu);
|
||||
} else if(start_scene_state == SubmenuIndexSubRemOpenMapFile) {
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneRemote);
|
||||
}
|
||||
}
|
||||
|
||||
bool subrem_scene_open_map_file_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
void subrem_scene_open_map_file_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
|
||||
void subrem_scene_open_sub_file_error_popup_callback(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, SubRemCustomEventSceneEditOpenSubErrorPopup);
|
||||
}
|
||||
|
||||
SubRemLoadSubState subrem_scene_open_sub_file_dialog(SubGhzRemoteApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
SubRemSubFilePreset* sub = app->map_preset->subs_preset[app->chusen_sub];
|
||||
|
||||
FuriString* temp_file_path = furi_string_alloc();
|
||||
|
||||
if(furi_string_empty(sub->file_path)) {
|
||||
furi_string_set(temp_file_path, SUBGHZ_RAW_FOLDER);
|
||||
} else {
|
||||
furi_string_set(temp_file_path, sub->file_path);
|
||||
}
|
||||
|
||||
SubRemLoadSubState ret = SubRemLoadSubStateNotSet;
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
|
||||
dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px);
|
||||
browser_options.base_path = SUBGHZ_RAW_FOLDER;
|
||||
|
||||
// Input events and views are managed by file_select
|
||||
if(!dialog_file_browser_show(app->dialogs, temp_file_path, temp_file_path, &browser_options)) {
|
||||
} else {
|
||||
// Check sub file
|
||||
SubRemSubFilePreset* sub_candidate = subrem_sub_file_preset_alloc();
|
||||
furi_string_set(sub_candidate->label, sub->label);
|
||||
furi_string_set(sub_candidate->file_path, temp_file_path);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* fff_file = flipper_format_file_alloc(storage);
|
||||
|
||||
if(flipper_format_file_open_existing(
|
||||
fff_file, furi_string_get_cstr(sub_candidate->file_path))) {
|
||||
ret = subrem_sub_preset_load(sub_candidate, app->txrx, fff_file);
|
||||
}
|
||||
|
||||
flipper_format_file_close(fff_file);
|
||||
flipper_format_free(fff_file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
if(ret == SubRemLoadSubStateOK) {
|
||||
subrem_sub_file_preset_free(app->map_preset->subs_preset[app->chusen_sub]);
|
||||
app->map_preset->subs_preset[app->chusen_sub] = sub_candidate;
|
||||
app->map_not_saved = true;
|
||||
} else {
|
||||
subrem_sub_file_preset_free(sub_candidate);
|
||||
}
|
||||
}
|
||||
|
||||
furi_string_free(temp_file_path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void subrem_scene_open_sub_file_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
SubRemLoadSubState load_state = subrem_scene_open_sub_file_dialog(app);
|
||||
|
||||
Popup* popup = app->popup;
|
||||
// popup_set_icon();
|
||||
popup_set_header(popup, "ERROR", 63, 16, AlignCenter, AlignBottom);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_callback(popup, subrem_scene_open_sub_file_error_popup_callback);
|
||||
popup_enable_timeout(popup);
|
||||
|
||||
if(load_state == SubRemLoadSubStateOK) {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
} else if(load_state == SubRemLoadSubStateNotSet) {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
} else {
|
||||
switch(load_state) {
|
||||
case SubRemLoadSubStateErrorFreq:
|
||||
|
||||
popup_set_text(popup, "Bad frequency", 63, 30, AlignCenter, AlignBottom);
|
||||
break;
|
||||
case SubRemLoadSubStateErrorMod:
|
||||
|
||||
popup_set_text(popup, "Bad modulation", 63, 30, AlignCenter, AlignBottom);
|
||||
break;
|
||||
case SubRemLoadSubStateErrorProtocol:
|
||||
|
||||
popup_set_text(popup, "Unsupported protocol", 63, 30, AlignCenter, AlignBottom);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDPopup);
|
||||
}
|
||||
}
|
||||
|
||||
bool subrem_scene_open_sub_file_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom &&
|
||||
event.event == SubRemCustomEventSceneEditOpenSubErrorPopup) {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void subrem_scene_open_sub_file_on_exit(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
popup_reset(app->popup);
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
#include "../views/remote.h"
|
||||
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
|
||||
#define TAG "SubRemScenRemote"
|
||||
|
||||
void subrem_scene_remote_callback(SubRemCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void subrem_scene_remote_raw_callback_end_tx(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventViewRemoteForcedStop);
|
||||
}
|
||||
|
||||
static uint8_t subrem_scene_remote_event_to_index(SubRemCustomEvent event_id) {
|
||||
uint8_t ret = 0;
|
||||
|
||||
if(event_id == SubRemCustomEventViewRemoteStartUP) {
|
||||
ret = SubRemSubKeyNameUp;
|
||||
} else if(event_id == SubRemCustomEventViewRemoteStartDOWN) {
|
||||
ret = SubRemSubKeyNameDown;
|
||||
} else if(event_id == SubRemCustomEventViewRemoteStartLEFT) {
|
||||
ret = SubRemSubKeyNameLeft;
|
||||
} else if(event_id == SubRemCustomEventViewRemoteStartRIGHT) {
|
||||
ret = SubRemSubKeyNameRight;
|
||||
} else if(event_id == SubRemCustomEventViewRemoteStartOK) {
|
||||
ret = SubRemSubKeyNameOk;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void subrem_scene_remote_on_enter(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
subrem_view_remote_update_data_labels(app->subrem_remote_view, app->map_preset->subs_preset);
|
||||
subrem_view_remote_set_radio(
|
||||
app->subrem_remote_view,
|
||||
subghz_txrx_radio_device_get(app->txrx) != SubGhzRadioDeviceTypeInternal);
|
||||
|
||||
subrem_view_remote_set_callback(app->subrem_remote_view, subrem_scene_remote_callback, app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDRemote);
|
||||
}
|
||||
|
||||
bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubRemCustomEventViewRemoteBack) {
|
||||
if(!scene_manager_previous_scene(app->scene_manager)) {
|
||||
scene_manager_stop(app->scene_manager);
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
return true;
|
||||
} else if(
|
||||
event.event == SubRemCustomEventViewRemoteStartUP ||
|
||||
event.event == SubRemCustomEventViewRemoteStartDOWN ||
|
||||
event.event == SubRemCustomEventViewRemoteStartLEFT ||
|
||||
event.event == SubRemCustomEventViewRemoteStartRIGHT ||
|
||||
event.event == SubRemCustomEventViewRemoteStartOK) {
|
||||
// Start sending sub
|
||||
subrem_tx_stop_sub(app, true);
|
||||
|
||||
uint8_t chusen_sub = subrem_scene_remote_event_to_index(event.event);
|
||||
app->chusen_sub = chusen_sub;
|
||||
|
||||
subrem_view_remote_set_state(
|
||||
app->subrem_remote_view, SubRemViewRemoteStateLoading, chusen_sub);
|
||||
|
||||
if(subrem_tx_start_sub(app, app->map_preset->subs_preset[chusen_sub])) {
|
||||
if(app->map_preset->subs_preset[chusen_sub]->type == SubGhzProtocolTypeRAW) {
|
||||
subghz_txrx_set_raw_file_encoder_worker_callback_end(
|
||||
app->txrx, subrem_scene_remote_raw_callback_end_tx, app);
|
||||
}
|
||||
subrem_view_remote_set_state(
|
||||
app->subrem_remote_view, SubRemViewRemoteStateSending, chusen_sub);
|
||||
notification_message(app->notifications, &sequence_blink_start_magenta);
|
||||
} else {
|
||||
subrem_view_remote_set_state(
|
||||
app->subrem_remote_view, SubRemViewRemoteStateIdle, 0);
|
||||
notification_message(app->notifications, &sequence_blink_red_100);
|
||||
}
|
||||
return true;
|
||||
} else if(event.event == SubRemCustomEventViewRemoteForcedStop) {
|
||||
subrem_tx_stop_sub(app, true);
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle, 0);
|
||||
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
return true;
|
||||
} else if(event.event == SubRemCustomEventViewRemoteStop) {
|
||||
if(subrem_tx_stop_sub(app, false)) {
|
||||
subrem_view_remote_set_state(
|
||||
app->subrem_remote_view, SubRemViewRemoteStateIdle, 0);
|
||||
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// } else if(event.type == SceneManagerEventTypeTick) {
|
||||
// }
|
||||
return false;
|
||||
}
|
||||
|
||||
void subrem_scene_remote_on_exit(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
subrem_tx_stop_sub(app, true);
|
||||
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle, 0);
|
||||
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
#include "../helpers/subrem_custom_event.h"
|
||||
|
||||
void subrem_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void subrem_scene_start_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Open Map File",
|
||||
SubmenuIndexSubRemOpenMapFile,
|
||||
subrem_scene_start_submenu_callback,
|
||||
app);
|
||||
#if FURI_DEBUG
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Remote_Debug",
|
||||
SubmenuIndexSubRemRemoteView,
|
||||
subrem_scene_start_submenu_callback,
|
||||
app);
|
||||
#endif
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Edit Map File",
|
||||
SubmenuIndexSubRemEditMapFile,
|
||||
subrem_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"New Map File",
|
||||
SubmenuIndexSubRemNewMapFile,
|
||||
subrem_scene_start_submenu_callback,
|
||||
app);
|
||||
// submenu_add_item(
|
||||
// submenu,
|
||||
// "About",
|
||||
// SubmenuIndexSubGhzRemoteAbout,
|
||||
// subrem_scene_start_submenu_callback,
|
||||
// app);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDSubmenu);
|
||||
}
|
||||
|
||||
bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexSubRemOpenMapFile) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemOpenMapFile);
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile);
|
||||
consumed = true;
|
||||
}
|
||||
#if FURI_DEBUG
|
||||
else if(event.event == SubmenuIndexSubRemRemoteView) {
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneRemote);
|
||||
consumed = true;
|
||||
}
|
||||
#endif
|
||||
else if(event.event == SubmenuIndexSubRemEditMapFile) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemEditMapFile);
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexSubRemNewMapFile) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemNewMapFile);
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneEnterNewName);
|
||||
consumed = true;
|
||||
}
|
||||
// } else if(event.event == SubmenuIndexSubRemAbout) {
|
||||
// scene_manager_next_scene(app->scene_manager, SubRemSceneAbout);
|
||||
// consumed = true;
|
||||
// }
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subrem_scene_start_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
#include "subghz_remote_app_i.h"
|
||||
|
||||
static bool subghz_remote_app_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool subghz_remote_app_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void subghz_remote_app_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void subghz_remote_make_app_folder(SubGhzRemoteApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
// Migrate old users data
|
||||
storage_common_migrate(storage, EXT_PATH("unirf"), SUBREM_APP_FOLDER);
|
||||
|
||||
if(!storage_simply_mkdir(storage, SUBREM_APP_FOLDER)) {
|
||||
// FURI_LOG_E(TAG, "Could not create folder %s", SUBREM_APP_FOLDER);
|
||||
dialog_message_show_storage_error(app->dialogs, "Cannot create\napp folder");
|
||||
}
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
SubGhzRemoteApp* subghz_remote_app_alloc() {
|
||||
SubGhzRemoteApp* app = malloc(sizeof(SubGhzRemoteApp));
|
||||
|
||||
furi_hal_power_suppress_charge_enter();
|
||||
|
||||
app->file_path = furi_string_alloc();
|
||||
furi_string_set(app->file_path, SUBREM_APP_FOLDER);
|
||||
|
||||
// GUI
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
// View Dispatcher
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
|
||||
app->scene_manager = scene_manager_alloc(&subrem_scene_handlers, app);
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
app->view_dispatcher, subghz_remote_app_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, subghz_remote_app_back_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, subghz_remote_app_tick_event_callback, 100);
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
// Open Notification record
|
||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
// SubMenu
|
||||
app->submenu = submenu_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, SubRemViewIDSubmenu, submenu_get_view(app->submenu));
|
||||
|
||||
// Dialog
|
||||
app->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
// TextInput
|
||||
app->text_input = text_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, SubRemViewIDTextInput, text_input_get_view(app->text_input));
|
||||
|
||||
// Widget
|
||||
app->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, SubRemViewIDWidget, widget_get_view(app->widget));
|
||||
|
||||
// Popup
|
||||
app->popup = popup_alloc();
|
||||
view_dispatcher_add_view(app->view_dispatcher, SubRemViewIDPopup, popup_get_view(app->popup));
|
||||
|
||||
// Remote view
|
||||
app->subrem_remote_view = subrem_view_remote_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
SubRemViewIDRemote,
|
||||
subrem_view_remote_get_view(app->subrem_remote_view));
|
||||
|
||||
// Edit Menu view
|
||||
app->subrem_edit_menu = subrem_view_edit_menu_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
SubRemViewIDEditMenu,
|
||||
subrem_view_edit_menu_get_view(app->subrem_edit_menu));
|
||||
|
||||
app->map_preset = malloc(sizeof(SubRemMapPreset));
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
app->map_preset->subs_preset[i] = subrem_sub_file_preset_alloc();
|
||||
}
|
||||
|
||||
app->txrx = subghz_txrx_alloc();
|
||||
|
||||
subghz_txrx_set_need_save_callback(app->txrx, subrem_save_active_sub, app);
|
||||
|
||||
app->map_not_saved = false;
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void subghz_remote_app_free(SubGhzRemoteApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
furi_hal_power_suppress_charge_exit();
|
||||
|
||||
// Submenu
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDSubmenu);
|
||||
submenu_free(app->submenu);
|
||||
|
||||
// Dialog
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
|
||||
// TextInput
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDTextInput);
|
||||
text_input_free(app->text_input);
|
||||
|
||||
// Widget
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDWidget);
|
||||
widget_free(app->widget);
|
||||
|
||||
// Popup
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDPopup);
|
||||
popup_free(app->popup);
|
||||
|
||||
// Remote view
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDRemote);
|
||||
subrem_view_remote_free(app->subrem_remote_view);
|
||||
|
||||
// Edit view
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDEditMenu);
|
||||
subrem_view_edit_menu_free(app->subrem_edit_menu);
|
||||
|
||||
scene_manager_free(app->scene_manager);
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
|
||||
subghz_txrx_free(app->txrx);
|
||||
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
subrem_sub_file_preset_free(app->map_preset->subs_preset[i]);
|
||||
}
|
||||
free(app->map_preset);
|
||||
|
||||
// Notifications
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
app->notifications = NULL;
|
||||
|
||||
// Close records
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
// Path strings
|
||||
furi_string_free(app->file_path);
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t subghz_remote_app(void* arg) {
|
||||
SubGhzRemoteApp* subghz_remote_app = subghz_remote_app_alloc();
|
||||
|
||||
subghz_remote_make_app_folder(subghz_remote_app);
|
||||
|
||||
bool map_loaded = false;
|
||||
|
||||
if((arg != NULL) && (strlen(arg) != 0)) {
|
||||
furi_string_set(subghz_remote_app->file_path, (const char*)arg);
|
||||
SubRemLoadMapState load_state = subrem_map_file_load(
|
||||
subghz_remote_app, furi_string_get_cstr(subghz_remote_app->file_path));
|
||||
|
||||
if(load_state == SubRemLoadMapStateOK || load_state == SubRemLoadMapStateNotAllOK) {
|
||||
map_loaded = true;
|
||||
} else {
|
||||
// TODO Replace
|
||||
dialog_message_show_storage_error(subghz_remote_app->dialogs, "Cannot load\nmap file");
|
||||
}
|
||||
}
|
||||
|
||||
if(map_loaded) {
|
||||
scene_manager_next_scene(subghz_remote_app->scene_manager, SubRemSceneRemote);
|
||||
} else {
|
||||
furi_string_set(subghz_remote_app->file_path, SUBREM_APP_FOLDER);
|
||||
scene_manager_next_scene(subghz_remote_app->scene_manager, SubRemSceneStart);
|
||||
scene_manager_next_scene(subghz_remote_app->scene_manager, SubRemSceneOpenMapFile);
|
||||
}
|
||||
|
||||
view_dispatcher_run(subghz_remote_app->view_dispatcher);
|
||||
|
||||
subghz_remote_app_free(subghz_remote_app);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,320 +0,0 @@
|
||||
#include "subghz_remote_app_i.h"
|
||||
#include <lib/toolbox/path.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
#include "helpers/txrx/subghz_txrx.h"
|
||||
|
||||
// #include <lib/subghz/protocols/keeloq.h>
|
||||
// #include <lib/subghz/protocols/star_line.h>
|
||||
|
||||
#include <lib/subghz/protocols/protocol_items.h>
|
||||
#include <lib/subghz/blocks/custom_btn.h>
|
||||
|
||||
#define TAG "SubGhzRemote"
|
||||
|
||||
static const char* map_file_labels[SubRemSubKeyNameMaxCount][2] = {
|
||||
[SubRemSubKeyNameUp] = {"UP", "ULABEL"},
|
||||
[SubRemSubKeyNameDown] = {"DOWN", "DLABEL"},
|
||||
[SubRemSubKeyNameLeft] = {"LEFT", "LLABEL"},
|
||||
[SubRemSubKeyNameRight] = {"RIGHT", "RLABEL"},
|
||||
[SubRemSubKeyNameOk] = {"OK", "OKLABEL"},
|
||||
};
|
||||
|
||||
void subrem_map_preset_reset(SubRemMapPreset* map_preset) {
|
||||
furi_assert(map_preset);
|
||||
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
subrem_sub_file_preset_reset(map_preset->subs_preset[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static SubRemLoadMapState subrem_map_preset_check(
|
||||
SubRemMapPreset* map_preset,
|
||||
SubGhzTxRx* txrx,
|
||||
FlipperFormat* fff_data_file) {
|
||||
furi_assert(map_preset);
|
||||
furi_assert(txrx);
|
||||
|
||||
bool all_loaded = true;
|
||||
SubRemLoadMapState ret = SubRemLoadMapStateErrorBrokenFile;
|
||||
|
||||
SubRemLoadSubState sub_loadig_state;
|
||||
SubRemSubFilePreset* sub_preset;
|
||||
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
sub_preset = map_preset->subs_preset[i];
|
||||
|
||||
sub_loadig_state = SubRemLoadSubStateErrorNoFile;
|
||||
|
||||
if(furi_string_empty(sub_preset->file_path)) {
|
||||
// FURI_LOG_I(TAG, "Empty file path");
|
||||
} else if(!flipper_format_file_open_existing(
|
||||
fff_data_file, furi_string_get_cstr(sub_preset->file_path))) {
|
||||
sub_preset->load_state = SubRemLoadSubStateErrorNoFile;
|
||||
FURI_LOG_W(TAG, "Error open file %s", furi_string_get_cstr(sub_preset->file_path));
|
||||
} else {
|
||||
sub_loadig_state = subrem_sub_preset_load(sub_preset, txrx, fff_data_file);
|
||||
}
|
||||
|
||||
if(sub_loadig_state != SubRemLoadSubStateOK) {
|
||||
all_loaded = false;
|
||||
} else {
|
||||
ret = SubRemLoadMapStateNotAllOK;
|
||||
}
|
||||
|
||||
if(ret != SubRemLoadMapStateErrorBrokenFile && all_loaded) {
|
||||
ret = SubRemLoadMapStateOK;
|
||||
}
|
||||
|
||||
flipper_format_file_close(fff_data_file);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool subrem_map_preset_load(SubRemMapPreset* map_preset, FlipperFormat* fff_data_file) {
|
||||
furi_assert(map_preset);
|
||||
bool ret = false;
|
||||
SubRemSubFilePreset* sub_preset;
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
sub_preset = map_preset->subs_preset[i];
|
||||
if(!flipper_format_read_string(
|
||||
fff_data_file, map_file_labels[i][0], sub_preset->file_path)) {
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_W(TAG, "No file patch for %s", map_file_labels[i][0]);
|
||||
#endif
|
||||
sub_preset->type = SubGhzProtocolTypeUnknown;
|
||||
} else if(!path_contains_only_ascii(furi_string_get_cstr(sub_preset->file_path))) {
|
||||
FURI_LOG_E(TAG, "Incorrect characters in [%s] file path", map_file_labels[i][0]);
|
||||
sub_preset->type = SubGhzProtocolTypeUnknown;
|
||||
} else if(!flipper_format_rewind(fff_data_file)) {
|
||||
// Rewind error
|
||||
} else if(!flipper_format_read_string(
|
||||
fff_data_file, map_file_labels[i][1], sub_preset->label)) {
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_W(TAG, "No Label for %s", map_file_labels[i][0]);
|
||||
#endif
|
||||
ret = true;
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
if(ret) {
|
||||
// Preload seccesful
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"%-5s: %s %s",
|
||||
map_file_labels[i][0],
|
||||
furi_string_get_cstr(sub_preset->label),
|
||||
furi_string_get_cstr(sub_preset->file_path));
|
||||
sub_preset->load_state = SubRemLoadSubStatePreloaded;
|
||||
}
|
||||
|
||||
flipper_format_rewind(fff_data_file);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) {
|
||||
furi_assert(app);
|
||||
furi_assert(file_path);
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "Load Map File Start");
|
||||
#endif
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
SubRemLoadMapState ret = SubRemLoadMapStateErrorOpenError;
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "Open Map File..");
|
||||
#endif
|
||||
subrem_map_preset_reset(app->map_preset);
|
||||
|
||||
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
|
||||
FURI_LOG_E(TAG, "Could not open MAP file %s", file_path);
|
||||
ret = SubRemLoadMapStateErrorOpenError;
|
||||
} else {
|
||||
if(!subrem_map_preset_load(app->map_preset, fff_data_file)) {
|
||||
FURI_LOG_E(TAG, "Could no Sub file path in MAP file");
|
||||
// ret = // error for popup
|
||||
} else if(!flipper_format_file_close(fff_data_file)) {
|
||||
ret = SubRemLoadMapStateErrorOpenError;
|
||||
} else {
|
||||
ret = subrem_map_preset_check(app->map_preset, app->txrx, fff_data_file);
|
||||
}
|
||||
}
|
||||
|
||||
if(ret == SubRemLoadMapStateOK) {
|
||||
FURI_LOG_I(TAG, "Load Map File Seccesful");
|
||||
} else if(ret == SubRemLoadMapStateNotAllOK) {
|
||||
FURI_LOG_I(TAG, "Load Map File Seccesful [Not all files]");
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Broken Map File");
|
||||
}
|
||||
|
||||
flipper_format_file_close(fff_data_file);
|
||||
flipper_format_free(fff_data_file);
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* sub_file_name) {
|
||||
furi_assert(flipper_format);
|
||||
furi_assert(sub_file_name);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format);
|
||||
|
||||
bool saved = false;
|
||||
uint32_t repeat = 200;
|
||||
FuriString* file_dir = furi_string_alloc();
|
||||
|
||||
path_extract_dirname(sub_file_name, file_dir);
|
||||
do {
|
||||
// removing additional fields
|
||||
flipper_format_delete_key(flipper_format, "Repeat");
|
||||
// flipper_format_delete_key(flipper_format, "Manufacture");
|
||||
|
||||
if(!storage_simply_remove(storage, sub_file_name)) {
|
||||
break;
|
||||
}
|
||||
|
||||
//ToDo check Write
|
||||
stream_seek(flipper_format_stream, 0, StreamOffsetFromStart);
|
||||
stream_save_to_file(flipper_format_stream, storage, sub_file_name, FSOM_CREATE_ALWAYS);
|
||||
|
||||
if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) {
|
||||
FURI_LOG_E(TAG, "Unable Repeat");
|
||||
break;
|
||||
}
|
||||
|
||||
saved = true;
|
||||
} while(0);
|
||||
|
||||
furi_string_free(file_dir);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
return saved;
|
||||
}
|
||||
|
||||
void subrem_save_active_sub(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub];
|
||||
subrem_save_protocol_to_file(
|
||||
sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path));
|
||||
}
|
||||
|
||||
bool subrem_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) {
|
||||
furi_assert(app);
|
||||
furi_assert(sub_preset);
|
||||
bool ret = false;
|
||||
|
||||
subrem_tx_stop_sub(app, true);
|
||||
|
||||
if(sub_preset->type == SubGhzProtocolTypeUnknown) {
|
||||
ret = false;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label));
|
||||
|
||||
subghz_txrx_load_decoder_by_name_protocol(
|
||||
app->txrx, furi_string_get_cstr(sub_preset->protocaol_name));
|
||||
|
||||
subghz_txrx_set_preset(
|
||||
app->txrx,
|
||||
furi_string_get_cstr(sub_preset->freq_preset.name),
|
||||
sub_preset->freq_preset.frequency,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
subghz_custom_btns_reset();
|
||||
|
||||
if(subghz_txrx_tx_start(app->txrx, sub_preset->fff_data) == SubGhzTxRxStartTxStateOk) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) {
|
||||
furi_assert(app);
|
||||
SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub];
|
||||
|
||||
if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) {
|
||||
subghz_txrx_stop(app->txrx);
|
||||
|
||||
if(sub_preset->type == SubGhzProtocolTypeDynamic) {
|
||||
subghz_txrx_reset_dynamic_and_custom_btns(app->txrx);
|
||||
}
|
||||
subghz_custom_btns_reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
FuriString* file_path = furi_string_alloc();
|
||||
SubRemLoadMapState ret = SubRemLoadMapStateBack;
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, SUBREM_APP_EXTENSION, &I_subrem_10px);
|
||||
browser_options.base_path = SUBREM_APP_FOLDER;
|
||||
|
||||
// Input events and views are managed by file_select
|
||||
if(!dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options)) {
|
||||
} else {
|
||||
ret = subrem_map_file_load(app, furi_string_get_cstr(app->file_path));
|
||||
}
|
||||
|
||||
furi_string_free(file_path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool subrem_save_map_to_file(SubGhzRemoteApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
const char* file_name = furi_string_get_cstr(app->file_path);
|
||||
bool saved = false;
|
||||
FlipperFormat* fff_data = flipper_format_string_alloc();
|
||||
|
||||
SubRemSubFilePreset* sub_preset;
|
||||
|
||||
flipper_format_write_header_cstr(
|
||||
fff_data, SUBREM_APP_APP_FILE_TYPE, SUBREM_APP_APP_FILE_VERSION);
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
sub_preset = app->map_preset->subs_preset[i];
|
||||
if(!furi_string_empty(sub_preset->file_path)) {
|
||||
flipper_format_write_string(fff_data, map_file_labels[i][0], sub_preset->file_path);
|
||||
}
|
||||
}
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
sub_preset = app->map_preset->subs_preset[i];
|
||||
if(!furi_string_empty(sub_preset->file_path)) {
|
||||
flipper_format_write_string(fff_data, map_file_labels[i][1], sub_preset->label);
|
||||
}
|
||||
}
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
Stream* flipper_format_stream = flipper_format_get_raw_stream(fff_data);
|
||||
|
||||
do {
|
||||
if(!storage_simply_remove(storage, file_name)) {
|
||||
break;
|
||||
}
|
||||
//ToDo check Write
|
||||
stream_seek(flipper_format_stream, 0, StreamOffsetFromStart);
|
||||
stream_save_to_file(flipper_format_stream, storage, file_name, FSOM_CREATE_ALWAYS);
|
||||
|
||||
saved = true;
|
||||
} while(0);
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
flipper_format_free(fff_data);
|
||||
|
||||
return saved;
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers/subrem_types.h"
|
||||
#include "helpers/subrem_presets.h"
|
||||
#include "scenes/subrem_scene.h"
|
||||
|
||||
#include "helpers/txrx/subghz_txrx.h"
|
||||
|
||||
#include <assets_icons.h>
|
||||
|
||||
#include "views/remote.h"
|
||||
#include "views/edit_menu.h"
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
#define SUBREM_APP_FOLDER EXT_PATH("subghz_remote")
|
||||
#define SUBREM_MAX_LEN_NAME 64
|
||||
|
||||
typedef struct {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
NotificationApp* notifications;
|
||||
DialogsApp* dialogs;
|
||||
Widget* widget;
|
||||
Popup* popup;
|
||||
TextInput* text_input;
|
||||
Submenu* submenu;
|
||||
|
||||
FuriString* file_path;
|
||||
char file_name_tmp[SUBREM_MAX_LEN_NAME];
|
||||
|
||||
SubRemViewRemote* subrem_remote_view;
|
||||
SubRemViewEditMenu* subrem_edit_menu;
|
||||
|
||||
SubRemMapPreset* map_preset;
|
||||
|
||||
SubGhzTxRx* txrx;
|
||||
|
||||
bool map_not_saved;
|
||||
|
||||
uint8_t chusen_sub;
|
||||
} SubGhzRemoteApp;
|
||||
|
||||
SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app);
|
||||
|
||||
bool subrem_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset);
|
||||
|
||||
bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced);
|
||||
|
||||
SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path);
|
||||
|
||||
void subrem_map_preset_reset(SubRemMapPreset* map_preset);
|
||||
|
||||
bool subrem_save_map_to_file(SubGhzRemoteApp* app);
|
||||
|
||||
void subrem_save_active_sub(void* context);
|
||||
@@ -1,290 +0,0 @@
|
||||
#include "edit_menu.h"
|
||||
#include "../subghz_remote_app_i.h"
|
||||
|
||||
#include <input/input.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
#define subrem_view_edit_menu_MAX_LABEL_LENGTH 12
|
||||
|
||||
#define FRAME_HEIGHT 12
|
||||
|
||||
struct SubRemViewEditMenu {
|
||||
View* view;
|
||||
SubRemViewEditMenuCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
FuriString* label;
|
||||
FuriString* file_path;
|
||||
SubRemLoadSubState sub_state;
|
||||
|
||||
uint8_t chusen;
|
||||
} SubRemViewEditMenuModel;
|
||||
|
||||
void subrem_view_edit_menu_set_callback(
|
||||
SubRemViewEditMenu* subrem_view_edit_menu,
|
||||
SubRemViewEditMenuCallback callback,
|
||||
void* context) {
|
||||
furi_assert(subrem_view_edit_menu);
|
||||
|
||||
subrem_view_edit_menu->callback = callback;
|
||||
subrem_view_edit_menu->context = context;
|
||||
}
|
||||
|
||||
void subrem_view_edit_menu_add_data_to_show(
|
||||
SubRemViewEditMenu* subrem_view_edit_remote,
|
||||
uint8_t index,
|
||||
FuriString* label,
|
||||
FuriString* path,
|
||||
SubRemLoadSubState state) {
|
||||
furi_assert(subrem_view_edit_remote);
|
||||
|
||||
with_view_model(
|
||||
subrem_view_edit_remote->view,
|
||||
SubRemViewEditMenuModel * model,
|
||||
{
|
||||
model->chusen = index;
|
||||
if(!furi_string_empty(label)) {
|
||||
furi_string_set(model->label, label);
|
||||
} else {
|
||||
furi_string_set(model->label, "Empty label");
|
||||
}
|
||||
furi_string_set(model->file_path, path);
|
||||
model->sub_state = state;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
uint8_t subrem_view_edit_menu_get_index(SubRemViewEditMenu* subrem_view_edit_remote) {
|
||||
furi_assert(subrem_view_edit_remote);
|
||||
uint8_t index;
|
||||
|
||||
with_view_model(
|
||||
subrem_view_edit_remote->view,
|
||||
SubRemViewEditMenuModel * model,
|
||||
{ index = model->chusen; },
|
||||
true);
|
||||
return index;
|
||||
}
|
||||
|
||||
void subrem_view_edit_menu_draw(Canvas* canvas, SubRemViewEditMenuModel* model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
canvas_clear(canvas);
|
||||
|
||||
// Draw bottom btn
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_button_left(canvas, "Back");
|
||||
elements_button_center(canvas, "Edit");
|
||||
elements_button_right(canvas, "Save");
|
||||
|
||||
// Draw top frame
|
||||
canvas_draw_line(canvas, 1, 0, 125, 0);
|
||||
canvas_draw_box(canvas, 0, 1, 127, FRAME_HEIGHT - 2);
|
||||
canvas_draw_line(canvas, 1, FRAME_HEIGHT - 1, 125, FRAME_HEIGHT - 1);
|
||||
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
|
||||
// Draw btn name
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
switch(model->chusen) {
|
||||
case SubRemSubKeyNameUp:
|
||||
canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "UP");
|
||||
break;
|
||||
|
||||
case SubRemSubKeyNameDown:
|
||||
canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "DOWN");
|
||||
break;
|
||||
|
||||
case SubRemSubKeyNameLeft:
|
||||
canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "LEFT");
|
||||
break;
|
||||
|
||||
case SubRemSubKeyNameRight:
|
||||
canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "RIGHT");
|
||||
break;
|
||||
|
||||
case SubRemSubKeyNameOk:
|
||||
canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "OK");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw Label
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_text_box(
|
||||
canvas,
|
||||
38,
|
||||
2,
|
||||
127 - 38,
|
||||
FRAME_HEIGHT,
|
||||
AlignCenter,
|
||||
AlignBottom,
|
||||
furi_string_empty(model->label) ? "Empty label" : furi_string_get_cstr(model->label),
|
||||
true);
|
||||
|
||||
// Draw arrow
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
if(model->chusen != 0) {
|
||||
canvas_draw_icon(canvas, 119, 13, &I_Pin_arrow_up_7x9);
|
||||
}
|
||||
if(model->chusen != 4) {
|
||||
canvas_draw_icon_ex(canvas, 119, 42, &I_Pin_arrow_up_7x9, IconRotation180);
|
||||
}
|
||||
|
||||
// Draw file_path
|
||||
if(model->sub_state == SubRemLoadSubStateOK) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_text_box(
|
||||
canvas,
|
||||
1,
|
||||
FRAME_HEIGHT + 1,
|
||||
118,
|
||||
(63 - FRAME_HEIGHT * 2),
|
||||
AlignLeft,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(model->file_path),
|
||||
false);
|
||||
} else if(furi_string_empty(model->file_path)) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 1, FRAME_HEIGHT * 2 - 2, "Button not set");
|
||||
} else {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 1, FRAME_HEIGHT * 2 - 2, "ERR:");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
switch(model->sub_state) {
|
||||
case SubRemLoadSubStateErrorNoFile:
|
||||
canvas_draw_str(canvas, 26, FRAME_HEIGHT * 2 - 2, "File not found");
|
||||
break;
|
||||
case SubRemLoadSubStateErrorFreq:
|
||||
canvas_draw_str(canvas, 26, FRAME_HEIGHT * 2 - 2, "Bad frequency");
|
||||
break;
|
||||
case SubRemLoadSubStateErrorMod:
|
||||
canvas_draw_str(canvas, 26, FRAME_HEIGHT * 2 - 2, "Bad modulation");
|
||||
break;
|
||||
case SubRemLoadSubStateErrorProtocol:
|
||||
canvas_draw_str(canvas, 26, FRAME_HEIGHT * 2 - 2, "Unsupported protocol");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
elements_text_box(
|
||||
canvas,
|
||||
1,
|
||||
FRAME_HEIGHT * 2,
|
||||
118,
|
||||
30,
|
||||
AlignLeft,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(model->file_path),
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
bool subrem_view_edit_menu_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
SubRemViewEditMenu* subrem_view_edit_menu = context;
|
||||
|
||||
if((event->key == InputKeyBack || event->key == InputKeyLeft) &&
|
||||
event->type == InputTypeShort) {
|
||||
subrem_view_edit_menu->callback(
|
||||
SubRemCustomEventViewEditMenuBack, subrem_view_edit_menu->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyUp && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
subrem_view_edit_menu->view,
|
||||
SubRemViewEditMenuModel * model,
|
||||
{
|
||||
if(model->chusen > 0) {
|
||||
model->chusen -= 1;
|
||||
};
|
||||
},
|
||||
true);
|
||||
subrem_view_edit_menu->callback(
|
||||
SubRemCustomEventViewEditMenuUP, subrem_view_edit_menu->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyDown && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
subrem_view_edit_menu->view,
|
||||
SubRemViewEditMenuModel * model,
|
||||
{
|
||||
if(model->chusen < 4) {
|
||||
model->chusen += 1;
|
||||
};
|
||||
},
|
||||
true);
|
||||
subrem_view_edit_menu->callback(
|
||||
SubRemCustomEventViewEditMenuDOWN, subrem_view_edit_menu->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
||||
subrem_view_edit_menu->callback(
|
||||
SubRemCustomEventViewEditMenuEdit, subrem_view_edit_menu->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyRight && event->type == InputTypeShort) {
|
||||
subrem_view_edit_menu->callback(
|
||||
SubRemCustomEventViewEditMenuSave, subrem_view_edit_menu->context);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void subrem_view_edit_menu_enter(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
void subrem_view_edit_menu_exit(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
SubRemViewEditMenu* subrem_view_edit_menu_alloc() {
|
||||
SubRemViewEditMenu* subrem_view_edit_menu = malloc(sizeof(SubRemViewEditMenu));
|
||||
|
||||
// View allocation and configuration
|
||||
subrem_view_edit_menu->view = view_alloc();
|
||||
view_allocate_model(
|
||||
subrem_view_edit_menu->view, ViewModelTypeLocking, sizeof(SubRemViewEditMenuModel));
|
||||
view_set_context(subrem_view_edit_menu->view, subrem_view_edit_menu);
|
||||
view_set_draw_callback(
|
||||
subrem_view_edit_menu->view, (ViewDrawCallback)subrem_view_edit_menu_draw);
|
||||
view_set_input_callback(subrem_view_edit_menu->view, subrem_view_edit_menu_input);
|
||||
view_set_enter_callback(subrem_view_edit_menu->view, subrem_view_edit_menu_enter);
|
||||
view_set_exit_callback(subrem_view_edit_menu->view, subrem_view_edit_menu_exit);
|
||||
|
||||
with_view_model(
|
||||
subrem_view_edit_menu->view,
|
||||
SubRemViewEditMenuModel * model,
|
||||
{
|
||||
model->label = furi_string_alloc(); // furi_string_alloc_set_str("LABEL");
|
||||
model->file_path = furi_string_alloc(); // furi_string_alloc_set_str("FILE_PATH");
|
||||
|
||||
model->chusen = 0;
|
||||
},
|
||||
true);
|
||||
return subrem_view_edit_menu;
|
||||
}
|
||||
|
||||
void subrem_view_edit_menu_free(SubRemViewEditMenu* subghz_edit_menu) {
|
||||
furi_assert(subghz_edit_menu);
|
||||
|
||||
with_view_model(
|
||||
subghz_edit_menu->view,
|
||||
SubRemViewEditMenuModel * model,
|
||||
{
|
||||
furi_string_free(model->label);
|
||||
furi_string_free(model->file_path);
|
||||
},
|
||||
true);
|
||||
view_free(subghz_edit_menu->view);
|
||||
free(subghz_edit_menu);
|
||||
}
|
||||
|
||||
View* subrem_view_edit_menu_get_view(SubRemViewEditMenu* subrem_view_edit_menu) {
|
||||
furi_assert(subrem_view_edit_menu);
|
||||
return subrem_view_edit_menu->view;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../helpers/subrem_custom_event.h"
|
||||
#include "../helpers/subrem_presets.h"
|
||||
|
||||
typedef struct SubRemViewEditMenu SubRemViewEditMenu;
|
||||
|
||||
typedef void (*SubRemViewEditMenuCallback)(SubRemCustomEvent event, void* context);
|
||||
|
||||
void subrem_view_edit_menu_set_callback(
|
||||
SubRemViewEditMenu* subrem_view_edit_menu,
|
||||
SubRemViewEditMenuCallback callback,
|
||||
void* context);
|
||||
|
||||
SubRemViewEditMenu* subrem_view_edit_menu_alloc();
|
||||
|
||||
void subrem_view_edit_menu_free(SubRemViewEditMenu* subrem_view_edit_menu);
|
||||
|
||||
View* subrem_view_edit_menu_get_view(SubRemViewEditMenu* subrem_view_edit_menu);
|
||||
|
||||
void subrem_view_edit_menu_add_data_to_show(
|
||||
SubRemViewEditMenu* subrem_view_edit_remote,
|
||||
uint8_t index,
|
||||
FuriString* label,
|
||||
FuriString* path,
|
||||
SubRemLoadSubState state);
|
||||
|
||||
uint8_t subrem_view_edit_menu_get_index(SubRemViewEditMenu* subrem_view_edit_remote);
|
||||
@@ -1,307 +0,0 @@
|
||||
#include "remote.h"
|
||||
#include "../subghz_remote_app_i.h"
|
||||
|
||||
#include <input/input.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
#include <lib/toolbox/path.h>
|
||||
|
||||
#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 30
|
||||
#define SUBREM_VIEW_REMOTE_LEFT_OFFSET 10
|
||||
#define SUBREM_VIEW_REMOTE_RIGHT_OFFSET 22
|
||||
|
||||
struct SubRemViewRemote {
|
||||
View* view;
|
||||
SubRemViewRemoteCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char* labels[SubRemSubKeyNameMaxCount];
|
||||
|
||||
SubRemViewRemoteState state;
|
||||
|
||||
uint8_t pressed_btn;
|
||||
bool is_external;
|
||||
} SubRemViewRemoteModel;
|
||||
|
||||
void subrem_view_remote_set_callback(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemViewRemoteCallback callback,
|
||||
void* context) {
|
||||
furi_assert(subrem_view_remote);
|
||||
|
||||
subrem_view_remote->callback = callback;
|
||||
subrem_view_remote->context = context;
|
||||
}
|
||||
|
||||
void subrem_view_remote_update_data_labels(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemSubFilePreset** subs_presets) {
|
||||
furi_assert(subrem_view_remote);
|
||||
furi_assert(subs_presets);
|
||||
|
||||
FuriString* labels[SubRemSubKeyNameMaxCount];
|
||||
SubRemSubFilePreset* sub_preset;
|
||||
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
sub_preset = subs_presets[i];
|
||||
switch(sub_preset->load_state) {
|
||||
case SubRemLoadSubStateOK:
|
||||
if(!furi_string_empty(sub_preset->label)) {
|
||||
labels[i] = furi_string_alloc_set(sub_preset->label);
|
||||
} else if(!furi_string_empty(sub_preset->file_path)) {
|
||||
labels[i] = furi_string_alloc();
|
||||
path_extract_filename(sub_preset->file_path, labels[i], true);
|
||||
} else {
|
||||
labels[i] = furi_string_alloc_set("Empty Label");
|
||||
}
|
||||
break;
|
||||
|
||||
case SubRemLoadSubStateErrorNoFile:
|
||||
labels[i] = furi_string_alloc_set("[X] Can't open file");
|
||||
break;
|
||||
|
||||
case SubRemLoadSubStateErrorFreq:
|
||||
case SubRemLoadSubStateErrorMod:
|
||||
case SubRemLoadSubStateErrorProtocol:
|
||||
labels[i] = furi_string_alloc_set("[X] Error in .sub file");
|
||||
break;
|
||||
|
||||
default:
|
||||
labels[i] = furi_string_alloc_set("");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
strncpy(
|
||||
model->labels[i],
|
||||
furi_string_get_cstr(labels[i]),
|
||||
SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH);
|
||||
}
|
||||
},
|
||||
true);
|
||||
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
furi_string_free(labels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void subrem_view_remote_set_state(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemViewRemoteState state,
|
||||
uint8_t presed_btn) {
|
||||
furi_assert(subrem_view_remote);
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{
|
||||
model->state = state;
|
||||
model->pressed_btn = presed_btn;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void subrem_view_remote_set_radio(SubRemViewRemote* subrem_view_remote, bool external) {
|
||||
furi_assert(subrem_view_remote);
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{ model->is_external = external; },
|
||||
true);
|
||||
}
|
||||
|
||||
void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
canvas_clear(canvas);
|
||||
|
||||
//Icons for Labels
|
||||
//canvas_draw_icon(canvas, 0, 0, &I_SubGHzRemote_LeftAlignedButtons_9x64);
|
||||
canvas_draw_icon(canvas, 1, 5, &I_ButtonUp_7x4);
|
||||
canvas_draw_icon(canvas, 1, 15, &I_ButtonDown_7x4);
|
||||
canvas_draw_icon(canvas, 2, 23, &I_ButtonLeft_4x7);
|
||||
canvas_draw_icon(canvas, 2, 33, &I_ButtonRight_4x7);
|
||||
canvas_draw_icon(canvas, 0, 42, &I_Ok_btn_9x9);
|
||||
canvas_draw_icon(canvas, 0, 53, &I_back_10px);
|
||||
|
||||
//Labels
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
uint8_t y = 0;
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
elements_text_box(
|
||||
canvas,
|
||||
SUBREM_VIEW_REMOTE_LEFT_OFFSET,
|
||||
y + 2,
|
||||
126 - SUBREM_VIEW_REMOTE_LEFT_OFFSET - SUBREM_VIEW_REMOTE_RIGHT_OFFSET,
|
||||
12,
|
||||
AlignLeft,
|
||||
AlignBottom,
|
||||
model->labels[i],
|
||||
false);
|
||||
y += 10;
|
||||
}
|
||||
|
||||
if(model->state == SubRemViewRemoteStateOFF) {
|
||||
elements_button_left(canvas, "Back");
|
||||
elements_button_right(canvas, "Save");
|
||||
} else {
|
||||
canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit.");
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 126, 62, AlignRight, AlignBottom, ((model->is_external) ? "Ext" : "Int"));
|
||||
}
|
||||
|
||||
//Status text and indicator
|
||||
canvas_draw_icon(canvas, 113, 15, &I_Pin_cell_13x13);
|
||||
|
||||
if(model->state == SubRemViewRemoteStateIdle || model->state == SubRemViewRemoteStateOFF) {
|
||||
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Idle");
|
||||
} else {
|
||||
switch(model->state) {
|
||||
case SubRemViewRemoteStateSending:
|
||||
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Send");
|
||||
break;
|
||||
case SubRemViewRemoteStateLoading:
|
||||
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Load");
|
||||
break;
|
||||
default:
|
||||
#if FURI_DEBUG
|
||||
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Wrong_state");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
switch(model->pressed_btn) {
|
||||
case SubRemSubKeyNameUp:
|
||||
canvas_draw_icon(canvas, 116, 17, &I_Pin_arrow_up_7x9);
|
||||
break;
|
||||
case SubRemSubKeyNameDown:
|
||||
canvas_draw_icon_ex(canvas, 116, 17, &I_Pin_arrow_up_7x9, IconRotation180);
|
||||
break;
|
||||
case SubRemSubKeyNameLeft:
|
||||
canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation270);
|
||||
break;
|
||||
case SubRemSubKeyNameRight:
|
||||
canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation90);
|
||||
break;
|
||||
case SubRemSubKeyNameOk:
|
||||
canvas_draw_icon(canvas, 116, 18, &I_Pin_star_7x7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool subrem_view_remote_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
SubRemViewRemote* subrem_view_remote = context;
|
||||
|
||||
if(event->key == InputKeyBack && event->type == InputTypeLong) {
|
||||
subrem_view_remote->callback(SubRemCustomEventViewRemoteBack, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{ model->pressed_btn = 0; },
|
||||
true);
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteForcedStop, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
return true;
|
||||
}
|
||||
// BACK button processing end
|
||||
|
||||
if(event->key == InputKeyUp && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartUP, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyDown && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartDOWN, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyLeft && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartLEFT, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyRight && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartRIGHT, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyOk && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartOK, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
subrem_view_remote->callback(SubRemCustomEventViewRemoteStop, subrem_view_remote->context);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void subrem_view_remote_enter(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
void subrem_view_remote_exit(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
SubRemViewRemote* subrem_view_remote_alloc() {
|
||||
SubRemViewRemote* subrem_view_remote = malloc(sizeof(SubRemViewRemote));
|
||||
|
||||
// View allocation and configuration
|
||||
subrem_view_remote->view = view_alloc();
|
||||
view_allocate_model(
|
||||
subrem_view_remote->view, ViewModelTypeLocking, sizeof(SubRemViewRemoteModel));
|
||||
view_set_context(subrem_view_remote->view, subrem_view_remote);
|
||||
view_set_draw_callback(subrem_view_remote->view, (ViewDrawCallback)subrem_view_remote_draw);
|
||||
view_set_input_callback(subrem_view_remote->view, subrem_view_remote_input);
|
||||
view_set_enter_callback(subrem_view_remote->view, subrem_view_remote_enter);
|
||||
view_set_exit_callback(subrem_view_remote->view, subrem_view_remote_exit);
|
||||
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{
|
||||
model->state = SubRemViewRemoteStateIdle;
|
||||
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
model->labels[i] = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1);
|
||||
strcpy(model->labels[i], "");
|
||||
}
|
||||
|
||||
model->pressed_btn = 0;
|
||||
model->is_external = false;
|
||||
},
|
||||
true);
|
||||
return subrem_view_remote;
|
||||
}
|
||||
|
||||
void subrem_view_remote_free(SubRemViewRemote* subghz_remote) {
|
||||
furi_assert(subghz_remote);
|
||||
|
||||
with_view_model(
|
||||
subghz_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
free(model->labels[i]);
|
||||
}
|
||||
},
|
||||
true);
|
||||
view_free(subghz_remote->view);
|
||||
free(subghz_remote);
|
||||
}
|
||||
|
||||
View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote) {
|
||||
furi_assert(subrem_view_remote);
|
||||
return subrem_view_remote->view;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../helpers/subrem_custom_event.h"
|
||||
#include "../helpers/subrem_presets.h"
|
||||
|
||||
typedef enum {
|
||||
SubRemViewRemoteStateIdle,
|
||||
SubRemViewRemoteStateLoading,
|
||||
SubRemViewRemoteStateSending,
|
||||
SubRemViewRemoteStateOFF,
|
||||
} SubRemViewRemoteState;
|
||||
|
||||
typedef struct SubRemViewRemote SubRemViewRemote;
|
||||
|
||||
typedef void (*SubRemViewRemoteCallback)(SubRemCustomEvent event, void* context);
|
||||
|
||||
void subrem_view_remote_set_callback(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemViewRemoteCallback callback,
|
||||
void* context);
|
||||
|
||||
SubRemViewRemote* subrem_view_remote_alloc();
|
||||
|
||||
void subrem_view_remote_free(SubRemViewRemote* subrem_view_remote);
|
||||
|
||||
View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote);
|
||||
|
||||
void subrem_view_remote_update_data_labels(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemSubFilePreset** subs_presets);
|
||||
|
||||
void subrem_view_remote_set_state(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemViewRemoteState state,
|
||||
uint8_t presed_btn);
|
||||
|
||||
void subrem_view_remote_set_radio(SubRemViewRemote* subrem_view_remote, bool external);
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "hmac_sha256.h"
|
||||
#include "micro-ecc/uECC.h"
|
||||
|
||||
#define TAG "U2F"
|
||||
#define TAG "U2f"
|
||||
#define WORKER_TAG TAG "Worker"
|
||||
|
||||
#define U2F_CMD_REGISTER 0x01
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <furi_hal_random.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
|
||||
#define TAG "U2F"
|
||||
#define TAG "U2f"
|
||||
|
||||
#define U2F_DATA_FOLDER EXT_PATH("u2f/")
|
||||
#define U2F_CERT_FILE U2F_DATA_FOLDER "assets/cert.der"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <furi_hal_console.h>
|
||||
|
||||
#define TAG "U2FHID"
|
||||
#define TAG "U2fHid"
|
||||
#define WORKER_TAG TAG "Worker"
|
||||
|
||||
#define U2F_HID_MAX_PAYLOAD_LEN ((HID_U2F_PACKET_LEN - 7) + 128 * (HID_U2F_PACKET_LEN - 5))
|
||||
|
||||
@@ -51,6 +51,12 @@ extern const size_t FLIPPER_ON_SYSTEM_START_COUNT;
|
||||
extern const FlipperInternalApplication FLIPPER_SYSTEM_APPS[];
|
||||
extern const size_t FLIPPER_SYSTEM_APPS_COUNT;
|
||||
|
||||
/* Debug apps
|
||||
* Can only be spawned by loader by name
|
||||
*/
|
||||
extern const FlipperInternalApplication FLIPPER_DEBUG_APPS[];
|
||||
extern const size_t FLIPPER_DEBUG_APPS_COUNT;
|
||||
|
||||
extern const FlipperInternalApplication FLIPPER_ARCHIVE;
|
||||
|
||||
/* Settings list
|
||||
|
||||
@@ -65,8 +65,8 @@ static bool one_shot_view_input(InputEvent* event, void* context) {
|
||||
if(!consumed) {
|
||||
if(event->key == InputKeyRight) {
|
||||
/* Right button reserved for animation activation, so consume */
|
||||
consumed = true;
|
||||
if(event->type == InputTypeShort) {
|
||||
consumed = true;
|
||||
if(view->interact_callback) {
|
||||
view->interact_callback(view->interact_callback_context);
|
||||
}
|
||||
|
||||
@@ -101,7 +101,6 @@ static void desktop_clock_draw_callback(Canvas* canvas, void* context) {
|
||||
char buffer[20];
|
||||
snprintf(buffer, sizeof(buffer), "%02u:%02u", hour, desktop->time_minute);
|
||||
|
||||
// ToDo: never do that, may cause visual glitches
|
||||
view_port_set_width(
|
||||
desktop->clock_viewport,
|
||||
canvas_string_width(canvas, buffer) - 1 + (desktop->time_minute % 10 == 1));
|
||||
@@ -126,13 +125,12 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) {
|
||||
return true;
|
||||
case DesktopGlobalAfterAppFinished:
|
||||
animation_manager_load_and_continue_animation(desktop->animation_manager);
|
||||
// TODO: Implement a message mechanism for loading settings and (optionally)
|
||||
// locking and unlocking
|
||||
DESKTOP_SETTINGS_LOAD(&desktop->settings);
|
||||
|
||||
desktop_clock_reconfigure(desktop);
|
||||
|
||||
desktop_auto_lock_arm(desktop);
|
||||
if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
|
||||
desktop_auto_lock_arm(desktop);
|
||||
}
|
||||
return true;
|
||||
case DesktopGlobalAutoLock:
|
||||
if(!loader_is_locked(desktop->loader)) {
|
||||
@@ -223,7 +221,6 @@ void desktop_lock(Desktop* desktop) {
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
||||
notification_message(desktop->notification, &sequence_display_backlight_off_delay_1000);
|
||||
|
||||
DesktopStatus status = {.locked = true};
|
||||
furi_pubsub_publish(desktop->status_pubsub, &status);
|
||||
@@ -381,12 +378,7 @@ Desktop* desktop_alloc() {
|
||||
}
|
||||
gui_add_view_port(desktop->gui, desktop->stealth_mode_icon_viewport, GuiLayerStatusBarLeft);
|
||||
|
||||
// Special case: autostart application is already running
|
||||
desktop->loader = furi_record_open(RECORD_LOADER);
|
||||
if(loader_is_locked(desktop->loader) &&
|
||||
animation_manager_is_animation_loaded(desktop->animation_manager)) {
|
||||
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
||||
}
|
||||
|
||||
desktop->notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
desktop->app_start_stop_subscription = furi_pubsub_subscribe(
|
||||
@@ -477,6 +469,12 @@ int32_t desktop_srv(void* p) {
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneFault);
|
||||
}
|
||||
|
||||
// Special case: autostart application is already running
|
||||
if(loader_is_locked(desktop->loader) &&
|
||||
animation_manager_is_animation_loaded(desktop->animation_manager)) {
|
||||
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
||||
}
|
||||
|
||||
view_dispatcher_run(desktop->view_dispatcher);
|
||||
|
||||
furi_crash("That was unexpected");
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <toolbox/saved_struct.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
#define DESKTOP_SETTINGS_VER (12)
|
||||
#define DESKTOP_SETTINGS_VER (13)
|
||||
|
||||
#define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME)
|
||||
#define DESKTOP_SETTINGS_MAGIC (0x17)
|
||||
@@ -43,6 +43,29 @@
|
||||
#define DISPLAY_BATTERY_RETRO_5 4
|
||||
#define DISPLAY_BATTERY_BAR_PERCENT 5
|
||||
|
||||
typedef enum {
|
||||
FavoriteAppLeftShort = 0,
|
||||
FavoriteAppLeftLong,
|
||||
FavoriteAppRightShort,
|
||||
FavoriteAppRightLong,
|
||||
|
||||
FavoriteAppNumber,
|
||||
} FavoriteAppShortcut;
|
||||
|
||||
typedef enum {
|
||||
DummyAppLeft = 0,
|
||||
DummyAppLeftLong,
|
||||
DummyAppRight,
|
||||
DummyAppRightLong,
|
||||
DummyAppUpLong,
|
||||
DummyAppDown,
|
||||
DummyAppDownLong,
|
||||
DummyAppOk,
|
||||
DummyAppOkLong,
|
||||
|
||||
DummyAppNumber,
|
||||
} DummyAppShortcut;
|
||||
|
||||
typedef struct {
|
||||
InputKey data[MAX_PIN_SIZE];
|
||||
uint8_t length;
|
||||
@@ -53,12 +76,11 @@ typedef struct {
|
||||
} FavoriteApp;
|
||||
|
||||
typedef struct {
|
||||
FavoriteApp favorite_primary;
|
||||
FavoriteApp favorite_secondary;
|
||||
FavoriteApp favorite_tertiary;
|
||||
PinCode pin_code;
|
||||
uint32_t auto_lock_delay_ms;
|
||||
uint8_t displayBatteryPercentage;
|
||||
uint8_t dummy_mode;
|
||||
uint8_t display_clock;
|
||||
FavoriteApp favorite_apps[FavoriteAppNumber];
|
||||
FavoriteApp dummy_apps[DummyAppNumber];
|
||||
} DesktopSettings;
|
||||
|
||||
@@ -87,6 +87,10 @@ bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) {
|
||||
desktop_unlock(desktop);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopLockedEventDoorsClosed:
|
||||
notification_message(desktop->notification, &sequence_display_backlight_off);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopLockedEventUpdate:
|
||||
if(desktop_view_locked_is_locked_hint_visible(desktop->locked_view)) {
|
||||
notification_message(desktop->notification, &sequence_display_backlight_off);
|
||||
|
||||
@@ -61,17 +61,33 @@ static void
|
||||
}
|
||||
#endif
|
||||
|
||||
static void desktop_scene_main_open_app_or_profile(Desktop* desktop, const char* path) {
|
||||
if(loader_start_with_gui_error(desktop->loader, path, NULL) != LoaderStatusOk) {
|
||||
static inline bool desktop_scene_main_check_none(const char* str) {
|
||||
return (str[1] == '\0' && str[0] == '?');
|
||||
}
|
||||
|
||||
static void desktop_scene_main_open_app_or_profile(Desktop* desktop, FavoriteApp* application) {
|
||||
bool load_ok = false;
|
||||
if(strlen(application->name_or_path) > 0) {
|
||||
if(desktop_scene_main_check_none(application->name_or_path)) {
|
||||
// skip loading
|
||||
load_ok = true;
|
||||
} else if(
|
||||
loader_start(desktop->loader, application->name_or_path, NULL, NULL) ==
|
||||
LoaderStatusOk) {
|
||||
load_ok = true;
|
||||
}
|
||||
}
|
||||
if(!load_ok) {
|
||||
loader_start(desktop->loader, "Passport", NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void desktop_scene_main_start_favorite(Desktop* desktop, FavoriteApp* application) {
|
||||
if(strlen(application->name_or_path) > 2) {
|
||||
loader_start_with_gui_error(desktop->loader, application->name_or_path, NULL);
|
||||
} else if(
|
||||
(strlen(application->name_or_path) < 2) && (strcmp(application->name_or_path, "d") != 0)) {
|
||||
if(strlen(application->name_or_path) > 0) {
|
||||
if(!desktop_scene_main_check_none(application->name_or_path)) {
|
||||
loader_start_with_gui_error(desktop->loader, application->name_or_path, NULL);
|
||||
}
|
||||
} else {
|
||||
loader_start(desktop->loader, LOADER_APPLICATIONS_NAME, NULL, NULL);
|
||||
}
|
||||
}
|
||||
@@ -112,6 +128,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
consumed = true;
|
||||
} break;
|
||||
|
||||
case DesktopMainEventLock:
|
||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
|
||||
desktop_lock(desktop);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case DesktopMainEventOpenLockMenu:
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu);
|
||||
consumed = true;
|
||||
@@ -122,12 +144,6 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case DesktopMainEventLock:
|
||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
|
||||
desktop_lock(desktop);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case DesktopMainEventOpenArchive:
|
||||
#ifdef APP_ARCHIVE
|
||||
desktop_switch_to_app(desktop, &FLIPPER_ARCHIVE);
|
||||
@@ -141,21 +157,31 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
break;
|
||||
}
|
||||
|
||||
case DesktopMainEventOpenFavoritePrimary:
|
||||
case DesktopMainEventOpenFavoriteLeftShort:
|
||||
DESKTOP_SETTINGS_LOAD(&desktop->settings);
|
||||
desktop_scene_main_start_favorite(desktop, &desktop->settings.favorite_primary);
|
||||
desktop_scene_main_start_favorite(
|
||||
desktop, &desktop->settings.favorite_apps[FavoriteAppLeftShort]);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopMainEventOpenFavoriteSecondary:
|
||||
case DesktopMainEventOpenFavoriteLeftLong:
|
||||
DESKTOP_SETTINGS_LOAD(&desktop->settings);
|
||||
desktop_scene_main_start_favorite(desktop, &desktop->settings.favorite_secondary);
|
||||
desktop_scene_main_start_favorite(
|
||||
desktop, &desktop->settings.favorite_apps[FavoriteAppLeftLong]);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopMainEventOpenFavoriteTertiary:
|
||||
case DesktopMainEventOpenFavoriteRightShort:
|
||||
DESKTOP_SETTINGS_LOAD(&desktop->settings);
|
||||
desktop_scene_main_start_favorite(desktop, &desktop->settings.favorite_tertiary);
|
||||
desktop_scene_main_start_favorite(
|
||||
desktop, &desktop->settings.favorite_apps[FavoriteAppRightShort]);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopMainEventOpenFavoriteRightLong:
|
||||
DESKTOP_SETTINGS_LOAD(&desktop->settings);
|
||||
desktop_scene_main_start_favorite(
|
||||
desktop, &desktop->settings.favorite_apps[FavoriteAppRightLong]);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case DesktopAnimationEventCheckAnimation:
|
||||
animation_manager_check_blocking_process(desktop->animation_manager);
|
||||
consumed = true;
|
||||
@@ -166,39 +192,57 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
break;
|
||||
case DesktopAnimationEventInteractAnimation:
|
||||
if(!animation_manager_interact_process(desktop->animation_manager)) {
|
||||
loader_start(desktop->loader, "Passport", NULL, NULL);
|
||||
DESKTOP_SETTINGS_LOAD(&desktop->settings);
|
||||
if(!desktop->settings.dummy_mode) {
|
||||
desktop_scene_main_open_app_or_profile(
|
||||
desktop, &desktop->settings.favorite_apps[FavoriteAppRightShort]);
|
||||
} else {
|
||||
desktop_scene_main_open_app_or_profile(
|
||||
desktop, &desktop->settings.dummy_apps[DummyAppRight]);
|
||||
}
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopMainEventOpenPassport: {
|
||||
loader_start(desktop->loader, "Passport", NULL, NULL);
|
||||
break;
|
||||
}
|
||||
case DesktopMainEventOpenGameMenu: {
|
||||
desktop_scene_main_open_app_or_profile(desktop, EXT_PATH("/apps/Games/snake.fap"));
|
||||
break;
|
||||
}
|
||||
case DesktopMainEventOpenTetris: {
|
||||
desktop_scene_main_open_app_or_profile(desktop, EXT_PATH("/apps/Games/tetris.fap"));
|
||||
break;
|
||||
}
|
||||
case DesktopMainEventOpenArkanoid: {
|
||||
desktop_scene_main_open_app_or_profile(desktop, EXT_PATH("/apps/Games/arkanoid.fap"));
|
||||
break;
|
||||
}
|
||||
case DesktopMainEventOpenDOOM: {
|
||||
desktop_scene_main_open_app_or_profile(desktop, EXT_PATH("/apps/Games/doom.fap"));
|
||||
break;
|
||||
}
|
||||
case DesktopMainEventOpenZombiez: {
|
||||
desktop_scene_main_open_app_or_profile(desktop, EXT_PATH("/apps/Games/zombiez.fap"));
|
||||
break;
|
||||
}
|
||||
case DesktopMainEventOpenHeap: {
|
||||
|
||||
case DesktopDummyEventOpenLeft:
|
||||
desktop_scene_main_open_app_or_profile(
|
||||
desktop, EXT_PATH("/apps/Games/heap_defence.fap"));
|
||||
desktop, &desktop->settings.dummy_apps[DummyAppLeft]);
|
||||
break;
|
||||
}
|
||||
case DesktopDummyEventOpenDown:
|
||||
desktop_scene_main_open_app_or_profile(
|
||||
desktop, &desktop->settings.dummy_apps[DummyAppDown]);
|
||||
break;
|
||||
case DesktopDummyEventOpenOk:
|
||||
desktop_scene_main_open_app_or_profile(
|
||||
desktop, &desktop->settings.dummy_apps[DummyAppOk]);
|
||||
break;
|
||||
case DesktopDummyEventOpenUpLong:
|
||||
if(!desktop_scene_main_check_none(
|
||||
desktop->settings.dummy_apps[DummyAppUpLong].name_or_path)) {
|
||||
desktop_scene_main_open_app_or_profile(
|
||||
desktop, &desktop->settings.dummy_apps[DummyAppUpLong]);
|
||||
} else {
|
||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
|
||||
desktop_lock(desktop);
|
||||
}
|
||||
break;
|
||||
case DesktopDummyEventOpenDownLong:
|
||||
desktop_scene_main_open_app_or_profile(
|
||||
desktop, &desktop->settings.dummy_apps[DummyAppDownLong]);
|
||||
break;
|
||||
case DesktopDummyEventOpenLeftLong:
|
||||
desktop_scene_main_open_app_or_profile(
|
||||
desktop, &desktop->settings.dummy_apps[DummyAppLeftLong]);
|
||||
break;
|
||||
case DesktopDummyEventOpenRightLong:
|
||||
desktop_scene_main_open_app_or_profile(
|
||||
desktop, &desktop->settings.dummy_apps[DummyAppRightLong]);
|
||||
break;
|
||||
case DesktopDummyEventOpenOkLong:
|
||||
desktop_scene_main_open_app_or_profile(
|
||||
desktop, &desktop->settings.dummy_apps[DummyAppOkLong]);
|
||||
break;
|
||||
|
||||
case DesktopLockedEventUpdate:
|
||||
desktop_view_locked_update(desktop->locked_view);
|
||||
consumed = true;
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
DesktopMainEventLock,
|
||||
DesktopMainEventOpenLockMenu,
|
||||
DesktopMainEventOpenArchive,
|
||||
DesktopMainEventOpenFavoritePrimary,
|
||||
DesktopMainEventOpenFavoriteSecondary,
|
||||
DesktopMainEventOpenFavoriteTertiary,
|
||||
DesktopMainEventOpenFavoriteLeftShort,
|
||||
DesktopMainEventOpenFavoriteLeftLong,
|
||||
DesktopMainEventOpenFavoriteRightShort,
|
||||
DesktopMainEventOpenFavoriteRightLong,
|
||||
DesktopMainEventOpenMenu,
|
||||
DesktopMainEventOpenDebug,
|
||||
DesktopMainEventOpenPassport,
|
||||
DesktopMainEventOpenPowerOff,
|
||||
DesktopMainEventLock,
|
||||
|
||||
DesktopMainEventOpenGameMenu,
|
||||
DesktopMainEventOpenTetris,
|
||||
DesktopMainEventOpenArkanoid,
|
||||
DesktopMainEventOpenDOOM,
|
||||
DesktopMainEventOpenZombiez,
|
||||
DesktopMainEventOpenHeap,
|
||||
DesktopDummyEventOpenLeft,
|
||||
DesktopDummyEventOpenDown,
|
||||
DesktopDummyEventOpenOk,
|
||||
DesktopDummyEventOpenUpLong,
|
||||
DesktopDummyEventOpenDownLong,
|
||||
DesktopDummyEventOpenLeftLong,
|
||||
DesktopDummyEventOpenRightLong,
|
||||
DesktopDummyEventOpenOkLong,
|
||||
|
||||
DesktopLockedEventUnlocked,
|
||||
DesktopLockedEventUpdate,
|
||||
DesktopLockedEventShowPinInput,
|
||||
DesktopLockedEventDoorsClosed,
|
||||
|
||||
DesktopPinInputEventResetWrongPinLabel,
|
||||
DesktopPinInputEventUnlocked,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user