mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-13 05:06:30 +04:00
Compare commits
118 Commits
unlshd-062
...
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 | ||
|
|
535bf35e23 | ||
|
|
d7a579e713 | ||
|
|
2458cb2b96 | ||
|
|
3da9cb1b81 | ||
|
|
5cfc8fc536 | ||
|
|
0af8bd1e8b |
@@ -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",
|
||||
|
||||
59
CHANGELOG.md
59
CHANGELOG.md
@@ -1,11 +1,41 @@
|
||||
## New changes
|
||||
* !!! **Warning! After installing, Desktop settings (Favoutite apps, PIN Code, AutoLock time..) will be resetted to default due to settings changes, Please set your PIN code, Favourite apps again in Settings->Desktop** !!!
|
||||
* Desktop: **New way to set favourite apps and fully configurable dummy mode** (now you can set up to 4 favourite apps!) (port of OFW PR 2972 by nminaylov) (by @gid9798 | PR #578)
|
||||
* Desktop: Fix lock timer after rebooting (by @gid9798 | PR #578)
|
||||
* Infrared: Updated universal assets (by @amec0e | PR #581)
|
||||
* Core: Added proper error message on out of memory crash (by @Willy-JL)
|
||||
* SubGHz: Fix FAAC SLH add manually issues and fix sending signals with unknown seed
|
||||
* SubGHz: Temporarily reverted changes from OFW PR 2984: SubGhz: fix todo (by Skorpionm) - Fixes Enhanced Sub-GHz Chat app and various issues related to receiving signals that was found in 061 release
|
||||
* **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
|
||||
|
||||
----
|
||||
|
||||
@@ -16,6 +46,7 @@
|
||||
## Please support development of the project
|
||||
|Service|Remark|Link/Wallet|
|
||||
|-|-|-|
|
||||
|**Patreon**||https://patreon.com/mmxdev|
|
||||
|**Boosty**|patreon alternative|https://boosty.to/mmxdev|
|
||||
|cloudtips|only RU payments accepted|https://pay.cloudtips.ru/p/7b3e9d65|
|
||||
|YooMoney|only RU payments accepted|https://yoomoney.ru/fundraise/XA49mgQLPA0.221209|
|
||||
@@ -41,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 (base pack)<br>
|
||||
`c` = this build comes with 3 custom animations, and only main apps (Clean build like latest OFW)<br>
|
||||
`n` = this build comes without our custom animations (we have only 3 of them), only official flipper animations, and base pack apps<br>
|
||||
`e` = build has 🎲 [extra apps pack](https://github.com/xMasterX/all-the-plugins) preinstalled, our custom animations, and base pack apps too<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>
|
||||
|
||||
118
ReadMe.md
118
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)
|
||||
@@ -33,9 +41,9 @@ Our Discord Community:
|
||||
|
||||
# What's changed
|
||||
- **Sub-GHz** *lib & hal*
|
||||
- regional TX restrictions removed
|
||||
- Regional TX restrictions removed
|
||||
- Extra Sub-GHz frequencies
|
||||
- frequency range can be extended in settings file (Warning: It can damage Flipper's hardware)
|
||||
- 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)
|
||||
@@ -45,12 +53,12 @@ Our Discord Community:
|
||||
- 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 (scrolling text, + shows time when signal was received) (by @wosk)
|
||||
- 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
|
||||
- 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)
|
||||
- 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
|
||||
|
||||
@@ -84,7 +92,7 @@ Our Discord Community:
|
||||
- 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.
|
||||
@@ -112,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)
|
||||
|
||||
@@ -140,6 +148,7 @@ Also, regarding our releases, every build has and always will be free and open-s
|
||||
You can support us by using links or addresses below:
|
||||
|Service|Remark|Link/Wallet|
|
||||
|-|-|-|
|
||||
|**Patreon**||https://patreon.com/mmxdev|
|
||||
|**Boosty**|patreon alternative|https://boosty.to/mmxdev|
|
||||
|cloudtips|only RU payments accepted|https://pay.cloudtips.ru/p/7b3e9d65|
|
||||
|YooMoney|only RU payments accepted|https://yoomoney.ru/fundraise/XA49mgQLPA0.221209|
|
||||
@@ -152,75 +161,84 @@ You can support us by using links or addresses below:
|
||||
|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>
|
||||
@@ -234,12 +252,6 @@ 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: [docs.flipper.net](https://docs.flipper.net/)
|
||||
* Official Forum: [forum.flipperzero.one](https://forum.flipperzero.one/)
|
||||
|
||||
|
||||
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
|
||||
|
||||
@@ -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!");
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
@@ -45,13 +45,6 @@ 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(seed == 0) {
|
||||
furi_string_set(subghz->error_str, "Seed value\ncan not be 0.");
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
generated_protocol = subghz_txrx_gen_keeloq_bft_protocol(
|
||||
subghz->txrx,
|
||||
"AM650",
|
||||
@@ -69,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];
|
||||
|
||||
@@ -80,13 +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(seed == 0) {
|
||||
furi_string_set(subghz->error_str, "Seed value\ncan not be 0.");
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
if(state == SubmenuIndexFaacSLH_433) {
|
||||
if(state == SubmenuIndexFaacSLH_Manual_433) {
|
||||
generated_protocol = subghz_txrx_gen_faac_slh_protocol(
|
||||
subghz->txrx,
|
||||
"AM650",
|
||||
@@ -96,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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -341,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
|
||||
@@ -415,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
|
||||
|
||||
@@ -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,8 +125,6 @@ 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);
|
||||
@@ -224,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);
|
||||
@@ -382,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(
|
||||
@@ -478,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");
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_rtc.h>
|
||||
#include <stdint.h>
|
||||
#include <u8g2_glue.h>
|
||||
|
||||
|
||||
@@ -236,11 +236,11 @@ static size_t
|
||||
}
|
||||
|
||||
if(len_px > px_left) {
|
||||
uint8_t excess_symbols_approximately =
|
||||
roundf((float)(len_px - px_left) / ((float)len_px / (float)text_size));
|
||||
size_t excess_symbols_approximately =
|
||||
ceilf((float)(len_px - px_left) / ((float)len_px / (float)text_size));
|
||||
// reduce to 5 to be sure dash fit, and next line will be at least 5 symbols long
|
||||
if(excess_symbols_approximately > 0) {
|
||||
excess_symbols_approximately = MAX(excess_symbols_approximately, 5);
|
||||
excess_symbols_approximately = MAX(excess_symbols_approximately, 5u);
|
||||
result = text_size - excess_symbols_approximately - 1;
|
||||
} else {
|
||||
result = text_size;
|
||||
@@ -290,7 +290,8 @@ void elements_multiline_text_aligned(
|
||||
} else if((y + font_height) > canvas_height(canvas)) {
|
||||
line = furi_string_alloc_printf("%.*s...\n", chars_fit, start);
|
||||
} else {
|
||||
line = furi_string_alloc_printf("%.*s-\n", chars_fit, start);
|
||||
// Account for the added "-" in length
|
||||
line = furi_string_alloc_printf("%.*s-\n", chars_fit - 1, start);
|
||||
}
|
||||
canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, furi_string_get_cstr(line));
|
||||
furi_string_free(line);
|
||||
|
||||
@@ -361,10 +361,11 @@ void gui_add_view_port(Gui* gui, ViewPort* view_port, GuiLayer layer) {
|
||||
furi_assert(view_port);
|
||||
furi_check(layer < GuiLayerMAX);
|
||||
// Only fullscreen supports Vertical orientation for now
|
||||
furi_assert(
|
||||
ViewPortOrientation view_port_orientation = view_port_get_orientation(view_port);
|
||||
furi_check(
|
||||
(layer == GuiLayerFullscreen) ||
|
||||
((view_port->orientation != ViewPortOrientationVertical) &&
|
||||
(view_port->orientation != ViewPortOrientationVerticalFlip)));
|
||||
((view_port_orientation != ViewPortOrientationVertical) &&
|
||||
(view_port_orientation != ViewPortOrientationVerticalFlip)));
|
||||
|
||||
gui_lock(gui);
|
||||
// Verify that view port is not yet added
|
||||
|
||||
@@ -29,6 +29,9 @@ typedef struct {
|
||||
const Icon* name_selected;
|
||||
} IconElement;
|
||||
|
||||
LIST_DEF(IconList, IconElement, M_POD_OPLIST)
|
||||
#define M_OPL_IconList_t() LIST_OPLIST(IconList)
|
||||
|
||||
typedef struct ButtonItem {
|
||||
uint32_t index;
|
||||
ButtonItemCallback callback;
|
||||
@@ -47,6 +50,7 @@ struct ButtonPanel {
|
||||
|
||||
typedef struct {
|
||||
ButtonMatrix_t button_matrix;
|
||||
IconList_t icons;
|
||||
LabelList_t labels;
|
||||
uint16_t reserve_x;
|
||||
uint16_t reserve_y;
|
||||
@@ -114,7 +118,6 @@ void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t re
|
||||
ButtonArray_t* array = ButtonMatrix_get(model->button_matrix, i);
|
||||
ButtonArray_init(*array);
|
||||
ButtonArray_reserve(*array, reserve_x);
|
||||
// TODO: do we need to clear allocated memory of ptr-s to ButtonItem ??
|
||||
}
|
||||
LabelList_init(model->labels);
|
||||
},
|
||||
@@ -158,6 +161,7 @@ void button_panel_reset(ButtonPanel* button_panel) {
|
||||
model->selected_item_x = 0;
|
||||
model->selected_item_y = 0;
|
||||
LabelList_reset(model->labels);
|
||||
IconList_reset(model->icons);
|
||||
ButtonMatrix_reset(model->button_matrix);
|
||||
},
|
||||
true);
|
||||
@@ -220,9 +224,17 @@ static void button_panel_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
for
|
||||
M_EACH(icon, model->icons, IconList_t) {
|
||||
canvas_draw_icon(canvas, icon->x, icon->y, icon->name);
|
||||
}
|
||||
|
||||
for(size_t x = 0; x < model->reserve_x; ++x) {
|
||||
for(size_t y = 0; y < model->reserve_y; ++y) {
|
||||
ButtonItem* button_item = *button_panel_get_item(model, x, y);
|
||||
if(!button_item) {
|
||||
continue;
|
||||
}
|
||||
const Icon* icon_name = button_item->icon.name;
|
||||
if((model->selected_item_x == x) && (model->selected_item_y == y)) {
|
||||
icon_name = button_item->icon.name_selected;
|
||||
@@ -418,3 +430,24 @@ void button_panel_add_label(
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
// Draw an icon but don't make it a button.
|
||||
void button_panel_add_icon(
|
||||
ButtonPanel* button_panel,
|
||||
uint16_t x,
|
||||
uint16_t y,
|
||||
const Icon* icon_name) {
|
||||
furi_assert(button_panel);
|
||||
|
||||
with_view_model( //-V773
|
||||
button_panel->view,
|
||||
ButtonPanelModel * model,
|
||||
{
|
||||
IconElement* icon = IconList_push_raw(model->icons);
|
||||
icon->x = x;
|
||||
icon->y = y;
|
||||
icon->name = icon_name;
|
||||
icon->name_selected = icon_name;
|
||||
},
|
||||
true);
|
||||
}
|
||||
@@ -106,6 +106,19 @@ void button_panel_add_label(
|
||||
Font font,
|
||||
const char* label_str);
|
||||
|
||||
/** Add a non-button icon to button_panel module.
|
||||
*
|
||||
* @param button_panel ButtonPanel instance
|
||||
* @param x x-coordinate to place icon
|
||||
* @param y y-coordinate to place icon
|
||||
* @param icon_name name of the icon to draw
|
||||
*/
|
||||
void button_panel_add_icon(
|
||||
ButtonPanel* button_panel,
|
||||
uint16_t x,
|
||||
uint16_t y,
|
||||
const Icon* icon_name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -325,6 +325,7 @@ static void text_input_handle_down(TextInput* text_input, TextInputModel* model)
|
||||
static void text_input_handle_left(TextInput* text_input, TextInputModel* model) {
|
||||
UNUSED(text_input);
|
||||
if(model->cursor_select) {
|
||||
model->clear_default_text = false;
|
||||
if(model->cursor_pos > 0) {
|
||||
model->cursor_pos = CLAMP(model->cursor_pos - 1, strlen(model->text_buffer), 0u);
|
||||
}
|
||||
@@ -338,6 +339,7 @@ static void text_input_handle_left(TextInput* text_input, TextInputModel* model)
|
||||
static void text_input_handle_right(TextInput* text_input, TextInputModel* model) {
|
||||
UNUSED(text_input);
|
||||
if(model->cursor_select) {
|
||||
model->clear_default_text = false;
|
||||
model->cursor_pos = CLAMP(model->cursor_pos + 1, strlen(model->text_buffer), 0u);
|
||||
} else if(model->selected_column < get_row_size(model->selected_row) - 1) {
|
||||
model->selected_column++;
|
||||
@@ -347,7 +349,10 @@ static void text_input_handle_right(TextInput* text_input, TextInputModel* model
|
||||
}
|
||||
|
||||
static void text_input_handle_ok(TextInput* text_input, TextInputModel* model, InputType type) {
|
||||
if(model->cursor_select) return;
|
||||
if(model->cursor_select) {
|
||||
model->clear_default_text = !model->clear_default_text;
|
||||
return;
|
||||
}
|
||||
bool shift = type == InputTypeLong;
|
||||
bool repeat = type == InputTypeRepeat;
|
||||
char selected = get_selected_char(model);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user