mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-25 05:50:20 +00:00
Merge branch 'dev' into release
This commit is contained in:
commit
5f866a5756
411 changed files with 23942 additions and 6424 deletions
22
.drone.yml
22
.drone.yml
|
@ -114,7 +114,7 @@ steps:
|
|||
from_secret: fbt_link
|
||||
|
||||
- name: "Bundle self-update packages"
|
||||
image: kramos/alpine-zip
|
||||
image: joshkeegan/zip
|
||||
commands:
|
||||
- cp artifacts-extra-apps/flipper-z-f7-update-${DRONE_TAG}e.tgz .
|
||||
- cp artifacts-rgb-patch/flipper-z-f7-update-${DRONE_TAG}r.tgz .
|
||||
|
@ -245,9 +245,11 @@ steps:
|
|||
- wget "https://raw.githubusercontent.com/fieu/discord.sh/2253303efc0e7211ac2777d2535054cbb872f1e0/discord.sh"
|
||||
- chmod +x ./discord.sh
|
||||
- sed -n '/## Main changes/,/## Other changes/p' CHANGELOG.md | sed -e 's/## Main changes//' -e 's/## Other changes//' > changelogcut.txt
|
||||
- truncate -s -1 changelogcut.txt
|
||||
- tail -c +2 changelogcut.txt > changelogready.txt
|
||||
- head -c 1544 changelogcut.txt > changelogcutfin.txt
|
||||
- truncate -s -1 changelogcutfin.txt
|
||||
- tail -c +2 changelogcutfin.txt > changelogready.txt
|
||||
- rm -f changelogcut.txt
|
||||
- rm -f changelogcutfin.txt
|
||||
- echo '' >> changelogready.txt
|
||||
- echo '## [Read full changelog](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')' >> changelogready.txt
|
||||
- sed -i 's/(releasever)/'${DRONE_TAG}'/g' .ci_files/release_msg_discord.txt
|
||||
|
@ -417,7 +419,7 @@ steps:
|
|||
from_secret: fbt_link
|
||||
|
||||
- name: "Bundle self-update packages"
|
||||
image: kramos/alpine-zip
|
||||
image: joshkeegan/zip
|
||||
commands:
|
||||
- cp artifacts-extra-apps/flipper-z-f7-update-${DRONE_BUILD_NUMBER}e.tgz .
|
||||
- cp artifacts-rgb-patch/flipper-z-f7-update-${DRONE_BUILD_NUMBER}r.tgz .
|
||||
|
@ -529,14 +531,20 @@ steps:
|
|||
commands:
|
||||
- wget "https://raw.githubusercontent.com/fieu/discord.sh/2253303efc0e7211ac2777d2535054cbb872f1e0/discord.sh"
|
||||
- chmod +x ./discord.sh
|
||||
- sed -n '/## Main changes/,/<br><br>/p' CHANGELOG.md | sed -e 's/<br><br>//' > changelogcut.txt
|
||||
- truncate -s -1 changelogcut.txt
|
||||
- sed -n '/## Main changes/,/## Other changes/p' CHANGELOG.md | sed -e 's/## Main changes//' -e 's/## Other changes//' > changelogcut.txt
|
||||
- head -c 1544 changelogcut.txt > changelogcutfin.txt
|
||||
- truncate -s -1 changelogcutfin.txt
|
||||
- tail -c +2 changelogcutfin.txt > changelogready.txt
|
||||
- rm -f changelogcut.txt
|
||||
- rm -f changelogcutfin.txt
|
||||
- echo '' >> changelogready.txt
|
||||
- echo '## [Read full changelog](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/CHANGELOG.md)' >> changelogready.txt
|
||||
- sed -i 's/(buildnum)/'${DRONE_BUILD_NUMBER}'/g' .ci_files/devbuild_msg_discord.txt
|
||||
- sed -i 's/(commitsha)/'${DRONE_COMMIT_SHA}'/g' .ci_files/devbuild_msg_discord.txt
|
||||
- sed -i 's/(buildnum)/'${DRONE_BUILD_NUMBER}'/g' .ci_files/devbuild_msg_telegram.txt
|
||||
- sed -i 's/(commitsha)/'${DRONE_COMMIT_SHA}'/g' .ci_files/devbuild_msg_telegram.txt
|
||||
- cp .ci_files/devbuild_msg_telegram.txt tg_dev_message.tpl
|
||||
- ./discord.sh --title "Changelog" --description "$(jq -Rs . <changelogcut.txt | cut -c 2- | rev | cut -c 2- | rev)" --timestamp --text "$(jq -Rs . <.ci_files/devbuild_msg_discord.txt | cut -c 2- | rev | cut -c 2- | rev)"
|
||||
- ./discord.sh --title "Changelog" --description "$(jq -Rs . <changelogready.txt | cut -c 2- | rev | cut -c 2- | rev)" --timestamp --text "$(jq -Rs . <.ci_files/devbuild_msg_discord.txt | cut -c 2- | rev | cut -c 2- | rev)"
|
||||
|
||||
- name: "Send message to telegram"
|
||||
image: appleboy/drone-telegram
|
||||
|
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -69,4 +69,7 @@ PVS-Studio.log
|
|||
|
||||
.gdbinit
|
||||
|
||||
/fbt_options_local.py
|
||||
/fbt_options_local.py
|
||||
|
||||
# JS packages
|
||||
node_modules/
|
||||
|
|
151
CHANGELOG.md
151
CHANGELOG.md
|
@ -1,46 +1,119 @@
|
|||
## Main changes
|
||||
- Current API: 78.1
|
||||
- SubGHz:
|
||||
- Add new protocols (by @xMasterX) (big thanks to @Skorpionm for help with GangQi and Hollarm protocols!):
|
||||
- Marantec24 (static 24 bit) with add manually support
|
||||
- GangQi (static 34 bit) with button parsing and add manually support (thanks to @mishamyte for captures and testing)
|
||||
- Hollarm (static 42 bit) with button parsing and add manually support (thanks to @mishamyte for captures)
|
||||
- Hay21 (dynamic 21 bit) with button parsing
|
||||
- Princeton custom buttons support (0x1, 0x2, 0x4, 0x8, 0xF)
|
||||
- 125kHz RFID:
|
||||
- OFW: Fix detection of GProx II cards and false detection of other cards (by @Astrrra)
|
||||
- OFW: Fix Guard GProxII False Positive and 36-bit Parsing (by @zinongli)
|
||||
- OFW: GProxII Fix Writing and Rendering Conflict
|
||||
- Frequency analyzer fixes and improvements:
|
||||
- **Enforce int module** (like in OFW) usage due to lack of required hardware on external boards (PathIsolate (+rf switch for multiple paths)) and incorrect usage and/or understanding the purpose of frequency analyzer app by users, it should be used only to get frequency of the remote placed around 1-10cm around flipper's left corner
|
||||
- **Fix possible GSM mobile towers signal interference** by limiting upper frequency to 920mhz max
|
||||
- Fix buttons logic, **fix crash**
|
||||
- Protocol improvements:
|
||||
- **Keeloq: Monarch full support, with add manually option** (thanks @ashphx !)
|
||||
- **Princeton support for second button encoding type** (8bit)
|
||||
- GangQi fix serial check and remove broken check from UI
|
||||
- Hollarm add more button codes (thanks to @mishamyte for captures)
|
||||
- Misc:
|
||||
- Add extra settings to disable GPIO pins control used for external modules amplifiers and/or LEDs (in radio settings menu with debug ON)
|
||||
- NFC:
|
||||
- Saflok parser improvements (by @zinongli & @xtruan & @zacharyweiss & @evilmog & @Arkwin)
|
||||
- OFW: Fix crash on Ultralight unlock (by @Astrrra)
|
||||
- OFW: FeliCa anti-collision fix
|
||||
* OFW: Rename 'Detect Reader' to 'Extract MF Keys'
|
||||
* OFW: Happy mode
|
||||
* OFW: Infrared: Universal AC - Add Airwell AW-HKD012-N91
|
||||
* OFW: Broken file interaction fixes
|
||||
* OFW: Add the Procrastination animation
|
||||
* OFW PR 3892: Fix USB-UART bridge exit screen stopping the bridge prematurely (by @portasynthinca3)
|
||||
- Read Ultralight block by block (**fix password protected MFUL reading issue**) (by @mishamyte | PR #825 #826)
|
||||
- **Update NDEF parser** (SLIX and MFC support) (by @luu176 and @jaylikesbunda and @Willy-JL)
|
||||
- OFW PR 3822: **MIFARE Classic Key Recovery Improvements** (by @noproto)
|
||||
- OFW PR 3930: NFC Emulation freeze fix (by @RebornedBrain)
|
||||
- OFW: H World Hotel Chain Room Key Parser
|
||||
- OFW: Parser for Tianjin Railway Transit
|
||||
- New keys in system dict
|
||||
- Infrared:
|
||||
- **Add LEDs universal remote** (DB by @amec0e)
|
||||
- Update universal remote assets (by @amec0e | PR #813 #816)
|
||||
- JS:
|
||||
- OFW: JS modules & SDK -> **Breaking API change**
|
||||
- **Backporting custom features** (read about most of the changes after other changes section) (by @xMasterX and @Willy-JL)
|
||||
- Add i2c & SPI module (by @jamisonderek)
|
||||
* OFW: FuriHal, drivers: rework gauge initialization routine -> **Downgrade to older releases may break battery UI percent indicator, upgrade to this or newer version to restore**
|
||||
* OFW: heap: increased size -> **More free RAM!!**
|
||||
* OFW: New layout for BadUSB (es-LA)
|
||||
* OFW: Require PIN on boot
|
||||
* Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev)
|
||||
## Other changes
|
||||
* Docs: Improved the description steps to create a new remote BFT Mitto with more detailed and accurate instructions (by @chrostino | PR #805)
|
||||
* OFW: FuriTimer: Use an event instead of a volatile bool to wait for deletion
|
||||
* OFW: Threading, Timers improvements
|
||||
* OFW: Replace all calls to strncpy with strlcpy, use strdup more, expose strlcat
|
||||
* OFW: feat: add linux/gnome badusb demo resource files
|
||||
* OFW: Exposed `view_dispatcher_get_event_loop`
|
||||
* OFW: Infrared button operation fails now shows more informative messages
|
||||
* OFW: Loader: Warn about missing SD card for main apps
|
||||
* OFW: Desktop: Sanity check PIN length for good measure
|
||||
* OFW: DialogEx: Fix NULL ptr crash
|
||||
* OFW: Debug: use proper hook for handle_exit in flipperapps
|
||||
* OFW: Clean up of LFS traces
|
||||
* OFW: Proper integer parsing
|
||||
* OFW: SubGhz: Fix RPC status for ButtonRelease event
|
||||
* OFW: CCID: App changes
|
||||
* OFW: 5V on GPIO control for ext. modules
|
||||
* OFW: Gui: Add up and down button drawing functions to GUI elements
|
||||
* OFW: Gui: change dialog_ex text ownership model
|
||||
* OFW: Publishing T5577 page 1 block count macro
|
||||
* SubGHz: Freq analyzer - Fix duplicated frequency lists and use user config for nearest frequency selector too
|
||||
* SubGHz: Code cleanup and fix for rare dupicated (Data) field cases
|
||||
* OFW: NFC TRT Parser: Additional checks to prevent false positives
|
||||
* OFW PR 3992: Loader: Fix BusFault in handling of OOM (by @Willy-JL)
|
||||
* OFW PR 3885: NFC: Add API to enforce ISO15693 mode (by @aaronjamt)
|
||||
* OFW: NFC: iso14443_4a improvements (by @RebornedBrain)
|
||||
* OFW: NFC: Plantain parser improvements (by @assasinfil) & fixes (by @mxcdoam)
|
||||
* OFW: NFC: Moscow social card parser (by @assasinfil)
|
||||
* OFW: fix: npm deps
|
||||
* OFW: 目覚め時計 (Added alarm option and clock settings)
|
||||
* OFW: JS: Backport and more additions & fixes
|
||||
* OFW: nfc: add Caltrain zones for Clipper
|
||||
* OFW: Update unit tests docs
|
||||
* OFW: Fix JS memory corruption (in gpio module)
|
||||
* OFW: Full-fledged JS SDK + npm packages
|
||||
* OFW: FurEventLoop: add support for FuriEventFlag, simplify API
|
||||
* OFW: lib: digital_signal: digital_sequence: add furi_hal.h wrapped in ifdefs
|
||||
* OFW: Add warning about stealth mode in vibro CLI
|
||||
* OFW: Small fixes in the wifi devboard docs
|
||||
* OFW: BadUSB - Improve ChromeOS and GNOME demo scripts
|
||||
* OFW: Small JS fixes
|
||||
* OFW: Canvas: extended icon draw.
|
||||
* OFW: Fixes Mouse Clicker Should have a "0" value setting for "as fast as possible"
|
||||
* OFW: Wi-Fi Devboard documentation rework
|
||||
* OFW: Furi: A Lot of Fixes
|
||||
* OFW PR 3933: furi_hal_random: Wait for ready state and no errors before sampling (by @n1kolasM)
|
||||
* OFW: nfc/clipper: Update BART station codes
|
||||
* OFW: FuriThread: Improve state callbacks
|
||||
* OFW: Documentation: update and cleanup
|
||||
* OFW: Improve bit_buffer.h docs
|
||||
* OFW: Prevent idle priority threads from potentially starving the FreeRTOS idle task
|
||||
* OFW: IR universal remote additions
|
||||
* OFW: Fix EM4100 T5577 writing block order (was already done in UL)
|
||||
* OFW: kerel typo
|
||||
* OFW: Folder rename fails
|
||||
* OFW: Put errno into TCB
|
||||
* OFW: Fix USB-UART bridge exit screen stopping the bridge prematurely
|
||||
**More details on JS changes** (js changelog written by @Willy-JL , thanks!):
|
||||
- Our custom JS SDK can be found on npm now: https://www.npmjs.com/org/darkflippers
|
||||
- Non-exhaustive list of changes to help you fix your scripts:
|
||||
- `badusb`:
|
||||
- `setup()`: `mfr_name`, `prod_name`, `layout_path` parameters renamed to `mfrName`, `prodName`, `layoutPath`
|
||||
- effort required to update old scripts using badusb: very minimal
|
||||
- `dialog`:
|
||||
- removed, now replaced by `gui/dialog` and `gui/file_picker` (see below)
|
||||
- `event_loop`:
|
||||
- new module, allows timer functionality, callbacks and event-driven programming, used heavily alongside gpio and gui modules
|
||||
- `gpio`:
|
||||
- fully overhauled, now you `get()` pin instances and perform actions on them like `.init()`
|
||||
- now supports interrupts, callbacks and more cool things
|
||||
- effort required to update old scripts using gpio: moderate
|
||||
- `gui`:
|
||||
- new module, fully overhauled, replaces dialog, keyboard, submenu, textbox modules
|
||||
- higher barrier to entry than older modules (requires usage of `event_loop` and `gui.viewDispatcher`), but much more flexible, powerful and easier to extend
|
||||
- includes all previously available js gui functionality (except `widget`), and also adds `gui/loading` and `gui/empty_screen` views
|
||||
- currently `gui/file_picker` works different than other new view objects, it is a simple `.pickFile()` synchronous function, but this [may change later](https://github.com/flipperdevices/flipperzero-firmware/pull/3961#discussion_r1805579153)
|
||||
- effort required to update old scripts using gui: extensive
|
||||
- `keyboard`:
|
||||
- removed, now replaced by `gui/text_input` and `gui/byte_input` (see above)
|
||||
- `math`:
|
||||
- `is_equal()` renamed to `isEqual()`
|
||||
- `storage`:
|
||||
- fully overhauled, now you `openFile()`s and perform actions on them like `.read()`
|
||||
- now supports many more operations including different open modes, directories and much more
|
||||
- effort required to update old scripts using storage: moderate
|
||||
- `submenu`:
|
||||
- removed, now replaced by `gui/submenu` (see above)
|
||||
- `textbox`:
|
||||
- removed, now replace by `gui/text_box` (see above)
|
||||
- `widget`:
|
||||
- only gui functionality not ported to new gui module, remains unchanged for now but likely to be ported later on
|
||||
- globals:
|
||||
- `__filepath` and `__dirpath` renamed to `__filename` and `__dirname` like in nodejs
|
||||
- `to_string()` renamed and moved to number class as `n.toString()`, now supports optional base parameter
|
||||
- `to_hex_string()` removed, now use `n.toString(16)`
|
||||
- `parse_int()` renamed to `parseInt()`, now supports optional base parameter
|
||||
- `to_upper_case()` and `to_lower_case()` renamed and moved to string class as `s.toUpperCase()` and `s.toLowerCase()`
|
||||
- effort required to update old scripts using these: minimal
|
||||
- Added type definitions (typescript files for type checking in IDE, Flipper does not run typescript)
|
||||
- Documentation is incomplete and deprecated, from now on you should refer to type definitions (`applications/system/js_app/types`), those will always be correct
|
||||
- Type definitions for extra modules we have that OFW doesn't will come later
|
||||
<br><br>
|
||||
#### Known NFC post-refactor regressions list:
|
||||
- Mifare Mini clones reading is broken (original mini working fine) (OFW)
|
||||
|
@ -60,7 +133,7 @@
|
|||
|cloudtips|only RU payments accepted|<div align="center"><a href="https://github.com/user-attachments/assets/5de31d6a-ef24-4d30-bd8e-c06af815332a"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|https://pay.cloudtips.ru/p/7b3e9d65|
|
||||
|YooMoney|only RU payments accepted|<div align="center"><a href="https://github.com/user-attachments/assets/33454f79-074b-4349-b453-f94fdadc3c68"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|https://yoomoney.ru/fundraise/XA49mgQLPA0.221209|
|
||||
|USDT|(TRC20)|<div align="center"><a href="https://github.com/user-attachments/assets/0500498d-18ed-412d-a1a4-8a66d0b6f057"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|`TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`|
|
||||
|ETH|(BSC/ERC20-Tokens)|<div align="center"><a href="https://github.com/user-attachments/assets/0f323e98-c524-4f41-abb2-f4f1cec83ab6"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|`darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)|
|
||||
|ETH|(BSC/ERC20-Tokens)|<div align="center"><a href="https://github.com/user-attachments/assets/0f323e98-c524-4f41-abb2-f4f1cec83ab6"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|`0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`|
|
||||
|BTC||<div align="center"><a href="https://github.com/user-attachments/assets/5a904d45-947e-4b92-9f0f-7fbaaa7b37f8"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|`bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`|
|
||||
|SOL|(Solana/Tokens)|<div align="center"><a href="https://github.com/user-attachments/assets/ab33c5e0-dd59-497b-9c91-ceb89c36b34d"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|`DSgwouAEgu8iP5yr7EHHDqMNYWZxAqXWsTEeqCAXGLj8`|
|
||||
|DOGE||<div align="center"><a href="https://github.com/user-attachments/assets/2937edd0-5c85-4465-a444-14d4edb481c0"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|`D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`|
|
||||
|
|
|
@ -36,9 +36,14 @@
|
|||
## FAQ (frequently asked questions)
|
||||
[Follow this link to find answers to most asked questions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/FAQ.md)
|
||||
|
||||
## Our official domains
|
||||
- https://flipperunleashed.com/ -> our main web page
|
||||
- https://unleashedflip.com/ -> update server, direct .tgz update links for web updater or direct download
|
||||
|
||||
## Dev builds (unstable) (built automatically from dev branch)
|
||||
- https://dev.unleashedflip.com/
|
||||
- https://t.me/kotnehleb
|
||||
|
||||
## Releases in Telegram
|
||||
- https://t.me/unleashed_fw
|
||||
|
||||
|
@ -112,7 +117,7 @@ Decoders/Encoders or emulation (+ programming mode) support made by @xMasterX:
|
|||
- Hay21 (dynamic 21 bit) with button parsing
|
||||
- Nero Radio 57bit (+ 56bit support)
|
||||
- CAME 12bit/24bit encoder fixes (Fixes are now merged in OFW)
|
||||
- Keeloq: Dea Mio, Genius Bravo, GSN, HCS101, AN-Motors, JCM Tech, MHouse, Nice Smilo, DTM Neo, FAAC RC,XT, Mutancode, Normstahl, Beninca + Allmatic, Stilmatic, CAME Space, Aprimatic (model TR and similar), Centurion Nova (thanks Carlos !), Hormann EcoStar, Novoferm, Sommer
|
||||
- Keeloq: Dea Mio, Genius Bravo, GSN, HCS101, AN-Motors, JCM Tech, MHouse, Nice Smilo, DTM Neo, FAAC RC,XT, Mutancode, Normstahl, Beninca + Allmatic, Stilmatic, CAME Space, Aprimatic (model TR and similar), Centurion Nova (thanks Carlos !), Hormann EcoStar, Novoferm, Sommer, Monarch (thanks @ashphx !)
|
||||
|
||||
Protocols support made by Skorp (original implementation) and @xMasterX (current version):
|
||||
- CAME Atomo -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
|
@ -150,7 +155,7 @@ You can support us by using links or addresses below:
|
|||
|cloudtips|only RU payments accepted|<div align="center"><a href="https://github.com/user-attachments/assets/5de31d6a-ef24-4d30-bd8e-c06af815332a"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|https://pay.cloudtips.ru/p/7b3e9d65|
|
||||
|YooMoney|only RU payments accepted|<div align="center"><a href="https://github.com/user-attachments/assets/33454f79-074b-4349-b453-f94fdadc3c68"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|https://yoomoney.ru/fundraise/XA49mgQLPA0.221209|
|
||||
|USDT|(TRC20)|<div align="center"><a href="https://github.com/user-attachments/assets/0500498d-18ed-412d-a1a4-8a66d0b6f057"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|`TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`|
|
||||
|ETH|(BSC/ERC20-Tokens)|<div align="center"><a href="https://github.com/user-attachments/assets/0f323e98-c524-4f41-abb2-f4f1cec83ab6"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|`darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)|
|
||||
|ETH|(BSC/ERC20-Tokens)|<div align="center"><a href="https://github.com/user-attachments/assets/0f323e98-c524-4f41-abb2-f4f1cec83ab6"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|`0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`|
|
||||
|BTC||<div align="center"><a href="https://github.com/user-attachments/assets/5a904d45-947e-4b92-9f0f-7fbaaa7b37f8"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|`bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`|
|
||||
|SOL|(Solana/Tokens)|<div align="center"><a href="https://github.com/user-attachments/assets/ab33c5e0-dd59-497b-9c91-ceb89c36b34d"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|`DSgwouAEgu8iP5yr7EHHDqMNYWZxAqXWsTEeqCAXGLj8`|
|
||||
|DOGE||<div align="center"><a href="https://github.com/user-attachments/assets/2937edd0-5c85-4465-a444-14d4edb481c0"><img src="https://github.com/user-attachments/assets/da3a864d-d1c7-42cc-8a86-6fcaf26663ec" alt="QR image"/></a></div>|`D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`|
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/canvas_i.h>
|
||||
#include <input/input.h>
|
||||
|
||||
#define BUFFER_SIZE (32U)
|
||||
|
@ -42,10 +41,11 @@ static DirectDraw* direct_draw_alloc(void) {
|
|||
static void direct_draw_free(DirectDraw* instance) {
|
||||
furi_pubsub_unsubscribe(instance->input, instance->input_subscription);
|
||||
|
||||
instance->canvas = NULL;
|
||||
gui_direct_draw_release(instance->gui);
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_INPUT_EVENTS);
|
||||
|
||||
free(instance);
|
||||
}
|
||||
|
||||
static void direct_draw_block(Canvas* canvas, uint32_t size, uint32_t counter) {
|
||||
|
|
|
@ -82,7 +82,7 @@ static void view_port_input_callback(InputEvent* input_event, void* context) {
|
|||
furi_message_queue_put(app->input_queue, input_event, 0);
|
||||
}
|
||||
|
||||
static bool input_queue_callback(FuriEventLoopObject* object, void* context) {
|
||||
static void input_queue_callback(FuriEventLoopObject* object, void* context) {
|
||||
FuriMessageQueue* queue = object;
|
||||
EventLoopBlinkTestApp* app = context;
|
||||
|
||||
|
@ -107,8 +107,6 @@ static bool input_queue_callback(FuriEventLoopObject* object, void* context) {
|
|||
furi_event_loop_stop(app->event_loop);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void blink_timer_callback(void* context) {
|
||||
|
|
|
@ -221,6 +221,14 @@ App(
|
|||
requires=["unit_tests"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="test_js",
|
||||
sources=["tests/common/*.c", "tests/js/*.c"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="get_api",
|
||||
requires=["unit_tests", "js_app"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="test_strint",
|
||||
sources=["tests/common/*.c", "tests/strint/*.c"],
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
let tests = require("tests");
|
||||
let flipper = require("flipper");
|
||||
|
||||
tests.assert_eq(1337, 1337);
|
||||
tests.assert_eq("hello", "hello");
|
||||
|
||||
tests.assert_eq("compatible", sdkCompatibilityStatus(0, 1));
|
||||
tests.assert_eq("firmwareTooOld", sdkCompatibilityStatus(100500, 0));
|
||||
tests.assert_eq("firmwareTooNew", sdkCompatibilityStatus(-100500, 0));
|
||||
tests.assert_eq(true, doesSdkSupport(["baseline"]));
|
||||
tests.assert_eq(false, doesSdkSupport(["abobus", "other-nonexistent-feature"]));
|
||||
|
||||
tests.assert_eq("flipperdevices", flipper.firmwareVendor);
|
||||
tests.assert_eq(0, flipper.jsSdkVersion[0]);
|
||||
tests.assert_eq(1, flipper.jsSdkVersion[1]);
|
|
@ -0,0 +1,30 @@
|
|||
let tests = require("tests");
|
||||
let event_loop = require("event_loop");
|
||||
|
||||
let ext = {
|
||||
i: 0,
|
||||
received: false,
|
||||
};
|
||||
|
||||
let queue = event_loop.queue(16);
|
||||
|
||||
event_loop.subscribe(queue.input, function (_, item, tests, ext) {
|
||||
tests.assert_eq(123, item);
|
||||
ext.received = true;
|
||||
}, tests, ext);
|
||||
|
||||
event_loop.subscribe(event_loop.timer("periodic", 1), function (_, _item, queue, counter, ext) {
|
||||
ext.i++;
|
||||
queue.send(123);
|
||||
if (counter === 10)
|
||||
event_loop.stop();
|
||||
return [queue, counter + 1, ext];
|
||||
}, queue, 1, ext);
|
||||
|
||||
event_loop.subscribe(event_loop.timer("oneshot", 1000), function (_, _item, tests) {
|
||||
tests.fail("event loop was not stopped");
|
||||
}, tests);
|
||||
|
||||
event_loop.run();
|
||||
tests.assert_eq(10, ext.i);
|
||||
tests.assert_eq(true, ext.received);
|
|
@ -0,0 +1,34 @@
|
|||
let tests = require("tests");
|
||||
let math = require("math");
|
||||
|
||||
// math.EPSILON on Flipper Zero is 2.22044604925031308085e-16
|
||||
|
||||
// basics
|
||||
tests.assert_float_close(5, math.abs(-5), math.EPSILON);
|
||||
tests.assert_float_close(0.5, math.abs(-0.5), math.EPSILON);
|
||||
tests.assert_float_close(5, math.abs(5), math.EPSILON);
|
||||
tests.assert_float_close(0.5, math.abs(0.5), math.EPSILON);
|
||||
tests.assert_float_close(3, math.cbrt(27), math.EPSILON);
|
||||
tests.assert_float_close(6, math.ceil(5.3), math.EPSILON);
|
||||
tests.assert_float_close(31, math.clz32(1), math.EPSILON);
|
||||
tests.assert_float_close(5, math.floor(5.7), math.EPSILON);
|
||||
tests.assert_float_close(5, math.max(3, 5), math.EPSILON);
|
||||
tests.assert_float_close(3, math.min(3, 5), math.EPSILON);
|
||||
tests.assert_float_close(-1, math.sign(-5), math.EPSILON);
|
||||
tests.assert_float_close(5, math.trunc(5.7), math.EPSILON);
|
||||
|
||||
// trig
|
||||
tests.assert_float_close(1.0471975511965976, math.acos(0.5), math.EPSILON);
|
||||
tests.assert_float_close(1.3169578969248166, math.acosh(2), math.EPSILON);
|
||||
tests.assert_float_close(0.5235987755982988, math.asin(0.5), math.EPSILON);
|
||||
tests.assert_float_close(1.4436354751788103, math.asinh(2), math.EPSILON);
|
||||
tests.assert_float_close(0.7853981633974483, math.atan(1), math.EPSILON);
|
||||
tests.assert_float_close(0.7853981633974483, math.atan2(1, 1), math.EPSILON);
|
||||
tests.assert_float_close(0.5493061443340549, math.atanh(0.5), math.EPSILON);
|
||||
tests.assert_float_close(-1, math.cos(math.PI), math.EPSILON * 18); // Error 3.77475828372553223744e-15
|
||||
tests.assert_float_close(1, math.sin(math.PI / 2), math.EPSILON * 4.5); // Error 9.99200722162640886381e-16
|
||||
|
||||
// powers
|
||||
tests.assert_float_close(5, math.sqrt(25), math.EPSILON);
|
||||
tests.assert_float_close(8, math.pow(2, 3), math.EPSILON);
|
||||
tests.assert_float_close(2.718281828459045, math.exp(1), math.EPSILON * 2); // Error 4.44089209850062616169e-16
|
136
applications/debug/unit_tests/resources/unit_tests/js/storage.js
Normal file
136
applications/debug/unit_tests/resources/unit_tests/js/storage.js
Normal file
|
@ -0,0 +1,136 @@
|
|||
let storage = require("storage");
|
||||
let tests = require("tests");
|
||||
|
||||
let baseDir = "/ext/.tmp/unit_tests";
|
||||
|
||||
tests.assert_eq(true, storage.rmrf(baseDir));
|
||||
tests.assert_eq(true, storage.makeDirectory(baseDir));
|
||||
|
||||
// write
|
||||
let file = storage.openFile(baseDir + "/helloworld", "w", "create_always");
|
||||
tests.assert_eq(true, !!file);
|
||||
tests.assert_eq(true, file.isOpen());
|
||||
tests.assert_eq(13, file.write("Hello, World!"));
|
||||
tests.assert_eq(true, file.close());
|
||||
tests.assert_eq(false, file.isOpen());
|
||||
|
||||
// read
|
||||
file = storage.openFile(baseDir + "/helloworld", "r", "open_existing");
|
||||
tests.assert_eq(true, !!file);
|
||||
tests.assert_eq(true, file.isOpen());
|
||||
tests.assert_eq(13, file.size());
|
||||
tests.assert_eq("Hello, World!", file.read("ascii", 128));
|
||||
tests.assert_eq(true, file.close());
|
||||
tests.assert_eq(false, file.isOpen());
|
||||
|
||||
// seek
|
||||
file = storage.openFile(baseDir + "/helloworld", "r", "open_existing");
|
||||
tests.assert_eq(true, !!file);
|
||||
tests.assert_eq(true, file.isOpen());
|
||||
tests.assert_eq(13, file.size());
|
||||
tests.assert_eq("Hello, World!", file.read("ascii", 128));
|
||||
tests.assert_eq(true, file.seekAbsolute(1));
|
||||
tests.assert_eq(true, file.seekRelative(2));
|
||||
tests.assert_eq(3, file.tell());
|
||||
tests.assert_eq(false, file.eof());
|
||||
tests.assert_eq("lo, World!", file.read("ascii", 128));
|
||||
tests.assert_eq(true, file.eof());
|
||||
tests.assert_eq(true, file.close());
|
||||
tests.assert_eq(false, file.isOpen());
|
||||
|
||||
// byte-level copy
|
||||
let src = storage.openFile(baseDir + "/helloworld", "r", "open_existing");
|
||||
let dst = storage.openFile(baseDir + "/helloworld2", "rw", "create_always");
|
||||
tests.assert_eq(true, !!src);
|
||||
tests.assert_eq(true, src.isOpen());
|
||||
tests.assert_eq(true, !!dst);
|
||||
tests.assert_eq(true, dst.isOpen());
|
||||
tests.assert_eq(true, src.copyTo(dst, 10));
|
||||
tests.assert_eq(true, dst.seekAbsolute(0));
|
||||
tests.assert_eq("Hello, Wor", dst.read("ascii", 128));
|
||||
tests.assert_eq(true, src.copyTo(dst, 3));
|
||||
tests.assert_eq(true, dst.seekAbsolute(0));
|
||||
tests.assert_eq("Hello, World!", dst.read("ascii", 128));
|
||||
tests.assert_eq(true, src.eof());
|
||||
tests.assert_eq(true, src.close());
|
||||
tests.assert_eq(false, src.isOpen());
|
||||
tests.assert_eq(true, dst.eof());
|
||||
tests.assert_eq(true, dst.close());
|
||||
tests.assert_eq(false, dst.isOpen());
|
||||
|
||||
// truncate
|
||||
tests.assert_eq(true, storage.copy(baseDir + "/helloworld", baseDir + "/helloworld2"));
|
||||
file = storage.openFile(baseDir + "/helloworld2", "w", "open_existing");
|
||||
tests.assert_eq(true, !!file);
|
||||
tests.assert_eq(true, file.seekAbsolute(5));
|
||||
tests.assert_eq(true, file.truncate());
|
||||
tests.assert_eq(true, file.close());
|
||||
file = storage.openFile(baseDir + "/helloworld2", "r", "open_existing");
|
||||
tests.assert_eq(true, !!file);
|
||||
tests.assert_eq("Hello", file.read("ascii", 128));
|
||||
tests.assert_eq(true, file.close());
|
||||
|
||||
// existence
|
||||
tests.assert_eq(true, storage.fileExists(baseDir + "/helloworld"));
|
||||
tests.assert_eq(true, storage.fileExists(baseDir + "/helloworld2"));
|
||||
tests.assert_eq(false, storage.fileExists(baseDir + "/sus_amogus_123"));
|
||||
tests.assert_eq(false, storage.directoryExists(baseDir + "/helloworld"));
|
||||
tests.assert_eq(false, storage.fileExists(baseDir));
|
||||
tests.assert_eq(true, storage.directoryExists(baseDir));
|
||||
tests.assert_eq(true, storage.fileOrDirExists(baseDir));
|
||||
tests.assert_eq(true, storage.remove(baseDir + "/helloworld2"));
|
||||
tests.assert_eq(false, storage.fileExists(baseDir + "/helloworld2"));
|
||||
|
||||
// stat
|
||||
let stat = storage.stat(baseDir + "/helloworld");
|
||||
tests.assert_eq(true, !!stat);
|
||||
tests.assert_eq(baseDir + "/helloworld", stat.path);
|
||||
tests.assert_eq(false, stat.isDirectory);
|
||||
tests.assert_eq(13, stat.size);
|
||||
|
||||
// rename
|
||||
tests.assert_eq(true, storage.fileExists(baseDir + "/helloworld"));
|
||||
tests.assert_eq(false, storage.fileExists(baseDir + "/helloworld123"));
|
||||
tests.assert_eq(true, storage.rename(baseDir + "/helloworld", baseDir + "/helloworld123"));
|
||||
tests.assert_eq(false, storage.fileExists(baseDir + "/helloworld"));
|
||||
tests.assert_eq(true, storage.fileExists(baseDir + "/helloworld123"));
|
||||
tests.assert_eq(true, storage.rename(baseDir + "/helloworld123", baseDir + "/helloworld"));
|
||||
tests.assert_eq(true, storage.fileExists(baseDir + "/helloworld"));
|
||||
tests.assert_eq(false, storage.fileExists(baseDir + "/helloworld123"));
|
||||
|
||||
// copy
|
||||
tests.assert_eq(true, storage.fileExists(baseDir + "/helloworld"));
|
||||
tests.assert_eq(false, storage.fileExists(baseDir + "/helloworld123"));
|
||||
tests.assert_eq(true, storage.copy(baseDir + "/helloworld", baseDir + "/helloworld123"));
|
||||
tests.assert_eq(true, storage.fileExists(baseDir + "/helloworld"));
|
||||
tests.assert_eq(true, storage.fileExists(baseDir + "/helloworld123"));
|
||||
|
||||
// next avail
|
||||
tests.assert_eq("helloworld1", storage.nextAvailableFilename(baseDir, "helloworld", "", 20));
|
||||
|
||||
// fs info
|
||||
let fsInfo = storage.fsInfo("/ext");
|
||||
tests.assert_eq(true, !!fsInfo);
|
||||
tests.assert_eq(true, fsInfo.freeSpace < fsInfo.totalSpace); // idk \(-_-)/
|
||||
fsInfo = storage.fsInfo("/int");
|
||||
tests.assert_eq(true, !!fsInfo);
|
||||
tests.assert_eq(true, fsInfo.freeSpace < fsInfo.totalSpace);
|
||||
|
||||
// path operations
|
||||
tests.assert_eq(true, storage.arePathsEqual("/ext/test", "/ext/Test"));
|
||||
tests.assert_eq(false, storage.arePathsEqual("/ext/test", "/ext/Testttt"));
|
||||
tests.assert_eq(true, storage.isSubpathOf("/ext/test", "/ext/test/sub"));
|
||||
tests.assert_eq(false, storage.isSubpathOf("/ext/test/sub", "/ext/test"));
|
||||
|
||||
// dir
|
||||
let entries = storage.readDirectory(baseDir);
|
||||
tests.assert_eq(true, !!entries);
|
||||
// FIXME: (-nofl) this test suite assumes that files are listed by
|
||||
// `readDirectory` in the exact order that they were created, which is not
|
||||
// something that is actually guaranteed.
|
||||
// Possible solution: sort and compare the array.
|
||||
tests.assert_eq("helloworld", entries[0].path);
|
||||
tests.assert_eq("helloworld123", entries[1].path);
|
||||
|
||||
tests.assert_eq(true, storage.rmrf(baseDir));
|
||||
tests.assert_eq(true, storage.makeDirectory(baseDir));
|
51
applications/debug/unit_tests/tests/furi/furi_errno_test.c
Normal file
51
applications/debug/unit_tests/tests/furi/furi_errno_test.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include <furi.h>
|
||||
#include <errno.h>
|
||||
#include "../test.h" // IWYU pragma: keep
|
||||
|
||||
#define TAG "ErrnoTest"
|
||||
#define THREAD_CNT 16
|
||||
#define ITER_CNT 1000
|
||||
|
||||
static int32_t errno_fuzzer(void* context) {
|
||||
int start_value = (int)context;
|
||||
int32_t fails = 0;
|
||||
|
||||
for(int i = start_value; i < start_value + ITER_CNT; i++) {
|
||||
errno = i;
|
||||
furi_thread_yield();
|
||||
if(errno != i) fails++;
|
||||
}
|
||||
|
||||
for(int i = 0; i < ITER_CNT; i++) {
|
||||
errno = 0;
|
||||
furi_thread_yield();
|
||||
UNUSED(strtol("123456", NULL, 10)); // -V530
|
||||
furi_thread_yield();
|
||||
if(errno != 0) fails++;
|
||||
|
||||
errno = 0;
|
||||
furi_thread_yield();
|
||||
UNUSED(strtol("123456123456123456123456123456123456123456123456", NULL, 10)); // -V530
|
||||
furi_thread_yield();
|
||||
if(errno != ERANGE) fails++;
|
||||
}
|
||||
|
||||
return fails;
|
||||
}
|
||||
|
||||
void test_errno_saving(void) {
|
||||
FuriThread* threads[THREAD_CNT];
|
||||
|
||||
for(int i = 0; i < THREAD_CNT; i++) {
|
||||
int start_value = i * ITER_CNT;
|
||||
threads[i] = furi_thread_alloc_ex("ErrnoFuzzer", 1024, errno_fuzzer, (void*)start_value);
|
||||
furi_thread_set_priority(threads[i], FuriThreadPriorityNormal);
|
||||
furi_thread_start(threads[i]);
|
||||
}
|
||||
|
||||
for(int i = 0; i < THREAD_CNT; i++) {
|
||||
furi_thread_join(threads[i]);
|
||||
mu_assert_int_eq(0, furi_thread_get_return_code(threads[i]));
|
||||
furi_thread_free(threads[i]);
|
||||
}
|
||||
}
|
|
@ -1,205 +0,0 @@
|
|||
#include "../test.h"
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
#define TAG "TestFuriEventLoop"
|
||||
|
||||
#define EVENT_LOOP_EVENT_COUNT (256u)
|
||||
|
||||
typedef struct {
|
||||
FuriMessageQueue* mq;
|
||||
|
||||
FuriEventLoop* producer_event_loop;
|
||||
uint32_t producer_counter;
|
||||
|
||||
FuriEventLoop* consumer_event_loop;
|
||||
uint32_t consumer_counter;
|
||||
} TestFuriData;
|
||||
|
||||
bool test_furi_event_loop_producer_mq_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_check(context);
|
||||
|
||||
TestFuriData* data = context;
|
||||
furi_check(data->mq == object, "Invalid queue");
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG, "producer_mq_callback: %lu %lu", data->producer_counter, data->consumer_counter);
|
||||
|
||||
if(data->producer_counter == EVENT_LOOP_EVENT_COUNT / 2) {
|
||||
furi_event_loop_unsubscribe(data->producer_event_loop, data->mq);
|
||||
furi_event_loop_subscribe_message_queue(
|
||||
data->producer_event_loop,
|
||||
data->mq,
|
||||
FuriEventLoopEventOut,
|
||||
test_furi_event_loop_producer_mq_callback,
|
||||
data);
|
||||
}
|
||||
|
||||
if(data->producer_counter == EVENT_LOOP_EVENT_COUNT) {
|
||||
furi_event_loop_stop(data->producer_event_loop);
|
||||
return false;
|
||||
}
|
||||
|
||||
data->producer_counter++;
|
||||
furi_check(
|
||||
furi_message_queue_put(data->mq, &data->producer_counter, 0) == FuriStatusOk,
|
||||
"furi_message_queue_put failed");
|
||||
furi_delay_us(furi_hal_random_get() % 1000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t test_furi_event_loop_producer(void* p) {
|
||||
furi_check(p);
|
||||
|
||||
TestFuriData* data = p;
|
||||
|
||||
FURI_LOG_I(TAG, "producer start 1st run");
|
||||
|
||||
data->producer_event_loop = furi_event_loop_alloc();
|
||||
furi_event_loop_subscribe_message_queue(
|
||||
data->producer_event_loop,
|
||||
data->mq,
|
||||
FuriEventLoopEventOut,
|
||||
test_furi_event_loop_producer_mq_callback,
|
||||
data);
|
||||
|
||||
furi_event_loop_run(data->producer_event_loop);
|
||||
|
||||
// 2 EventLoop index, 0xFFFFFFFF - all possible flags, emulate uncleared flags
|
||||
xTaskNotifyIndexed(xTaskGetCurrentTaskHandle(), 2, 0xFFFFFFFF, eSetBits);
|
||||
|
||||
furi_event_loop_unsubscribe(data->producer_event_loop, data->mq);
|
||||
furi_event_loop_free(data->producer_event_loop);
|
||||
|
||||
FURI_LOG_I(TAG, "producer start 2nd run");
|
||||
|
||||
data->producer_counter = 0;
|
||||
data->producer_event_loop = furi_event_loop_alloc();
|
||||
|
||||
furi_event_loop_subscribe_message_queue(
|
||||
data->producer_event_loop,
|
||||
data->mq,
|
||||
FuriEventLoopEventOut,
|
||||
test_furi_event_loop_producer_mq_callback,
|
||||
data);
|
||||
|
||||
furi_event_loop_run(data->producer_event_loop);
|
||||
|
||||
furi_event_loop_unsubscribe(data->producer_event_loop, data->mq);
|
||||
furi_event_loop_free(data->producer_event_loop);
|
||||
|
||||
FURI_LOG_I(TAG, "producer end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool test_furi_event_loop_consumer_mq_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_check(context);
|
||||
|
||||
TestFuriData* data = context;
|
||||
furi_check(data->mq == object);
|
||||
|
||||
furi_delay_us(furi_hal_random_get() % 1000);
|
||||
furi_check(furi_message_queue_get(data->mq, &data->consumer_counter, 0) == FuriStatusOk);
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG, "consumer_mq_callback: %lu %lu", data->producer_counter, data->consumer_counter);
|
||||
|
||||
if(data->consumer_counter == EVENT_LOOP_EVENT_COUNT / 2) {
|
||||
furi_event_loop_unsubscribe(data->consumer_event_loop, data->mq);
|
||||
furi_event_loop_subscribe_message_queue(
|
||||
data->consumer_event_loop,
|
||||
data->mq,
|
||||
FuriEventLoopEventIn,
|
||||
test_furi_event_loop_consumer_mq_callback,
|
||||
data);
|
||||
}
|
||||
|
||||
if(data->consumer_counter == EVENT_LOOP_EVENT_COUNT) {
|
||||
furi_event_loop_stop(data->consumer_event_loop);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t test_furi_event_loop_consumer(void* p) {
|
||||
furi_check(p);
|
||||
|
||||
TestFuriData* data = p;
|
||||
|
||||
FURI_LOG_I(TAG, "consumer start 1st run");
|
||||
|
||||
data->consumer_event_loop = furi_event_loop_alloc();
|
||||
furi_event_loop_subscribe_message_queue(
|
||||
data->consumer_event_loop,
|
||||
data->mq,
|
||||
FuriEventLoopEventIn,
|
||||
test_furi_event_loop_consumer_mq_callback,
|
||||
data);
|
||||
|
||||
furi_event_loop_run(data->consumer_event_loop);
|
||||
|
||||
// 2 EventLoop index, 0xFFFFFFFF - all possible flags, emulate uncleared flags
|
||||
xTaskNotifyIndexed(xTaskGetCurrentTaskHandle(), 2, 0xFFFFFFFF, eSetBits);
|
||||
|
||||
furi_event_loop_unsubscribe(data->consumer_event_loop, data->mq);
|
||||
furi_event_loop_free(data->consumer_event_loop);
|
||||
|
||||
FURI_LOG_I(TAG, "consumer start 2nd run");
|
||||
|
||||
data->consumer_counter = 0;
|
||||
data->consumer_event_loop = furi_event_loop_alloc();
|
||||
furi_event_loop_subscribe_message_queue(
|
||||
data->consumer_event_loop,
|
||||
data->mq,
|
||||
FuriEventLoopEventIn,
|
||||
test_furi_event_loop_consumer_mq_callback,
|
||||
data);
|
||||
|
||||
furi_event_loop_run(data->consumer_event_loop);
|
||||
|
||||
furi_event_loop_unsubscribe(data->consumer_event_loop, data->mq);
|
||||
furi_event_loop_free(data->consumer_event_loop);
|
||||
|
||||
FURI_LOG_I(TAG, "consumer end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_furi_event_loop(void) {
|
||||
TestFuriData data = {};
|
||||
|
||||
data.mq = furi_message_queue_alloc(16, sizeof(uint32_t));
|
||||
|
||||
FuriThread* producer_thread = furi_thread_alloc();
|
||||
furi_thread_set_name(producer_thread, "producer_thread");
|
||||
furi_thread_set_stack_size(producer_thread, 1 * 1024);
|
||||
furi_thread_set_callback(producer_thread, test_furi_event_loop_producer);
|
||||
furi_thread_set_context(producer_thread, &data);
|
||||
furi_thread_start(producer_thread);
|
||||
|
||||
FuriThread* consumer_thread = furi_thread_alloc();
|
||||
furi_thread_set_name(consumer_thread, "consumer_thread");
|
||||
furi_thread_set_stack_size(consumer_thread, 1 * 1024);
|
||||
furi_thread_set_callback(consumer_thread, test_furi_event_loop_consumer);
|
||||
furi_thread_set_context(consumer_thread, &data);
|
||||
furi_thread_start(consumer_thread);
|
||||
|
||||
// Wait for thread to complete their tasks
|
||||
furi_thread_join(producer_thread);
|
||||
furi_thread_join(consumer_thread);
|
||||
|
||||
// The test itself
|
||||
mu_assert_int_eq(data.producer_counter, data.consumer_counter);
|
||||
mu_assert_int_eq(data.producer_counter, EVENT_LOOP_EVENT_COUNT);
|
||||
|
||||
// Release memory
|
||||
furi_thread_free(consumer_thread);
|
||||
furi_thread_free(producer_thread);
|
||||
furi_message_queue_free(data.mq);
|
||||
}
|
490
applications/debug/unit_tests/tests/furi/furi_event_loop_test.c
Normal file
490
applications/debug/unit_tests/tests/furi/furi_event_loop_test.c
Normal file
|
@ -0,0 +1,490 @@
|
|||
#include "../test.h"
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
#define TAG "TestFuriEventLoop"
|
||||
|
||||
#define MESSAGE_COUNT (256UL)
|
||||
#define EVENT_FLAG_COUNT (23UL)
|
||||
#define PRIMITIVE_COUNT (4UL)
|
||||
#define RUN_COUNT (2UL)
|
||||
|
||||
typedef struct {
|
||||
FuriEventLoop* event_loop;
|
||||
uint32_t message_queue_count;
|
||||
uint32_t stream_buffer_count;
|
||||
uint32_t event_flag_count;
|
||||
uint32_t semaphore_count;
|
||||
uint32_t primitives_tested;
|
||||
} TestFuriEventLoopThread;
|
||||
|
||||
typedef struct {
|
||||
FuriMessageQueue* message_queue;
|
||||
FuriStreamBuffer* stream_buffer;
|
||||
FuriEventFlag* event_flag;
|
||||
FuriSemaphore* semaphore;
|
||||
|
||||
TestFuriEventLoopThread producer;
|
||||
TestFuriEventLoopThread consumer;
|
||||
} TestFuriEventLoopData;
|
||||
|
||||
static void test_furi_event_loop_pending_callback(void* context) {
|
||||
furi_check(context);
|
||||
|
||||
TestFuriEventLoopThread* test_thread = context;
|
||||
furi_check(test_thread->primitives_tested < PRIMITIVE_COUNT);
|
||||
|
||||
test_thread->primitives_tested++;
|
||||
FURI_LOG_I(TAG, "primitives tested: %lu", test_thread->primitives_tested);
|
||||
|
||||
if(test_thread->primitives_tested == PRIMITIVE_COUNT) {
|
||||
furi_event_loop_stop(test_thread->event_loop);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_furi_event_loop_thread_init(TestFuriEventLoopThread* test_thread) {
|
||||
memset(test_thread, 0, sizeof(TestFuriEventLoopThread));
|
||||
test_thread->event_loop = furi_event_loop_alloc();
|
||||
}
|
||||
|
||||
static void test_furi_event_loop_thread_run_and_cleanup(TestFuriEventLoopThread* test_thread) {
|
||||
furi_event_loop_run(test_thread->event_loop);
|
||||
// 2 EventLoop index, 0xFFFFFFFF - all possible flags, emulate uncleared flags
|
||||
xTaskNotifyIndexed(xTaskGetCurrentTaskHandle(), 2, 0xFFFFFFFF, eSetBits);
|
||||
furi_event_loop_free(test_thread->event_loop);
|
||||
}
|
||||
|
||||
static void test_furi_event_loop_producer_message_queue_callback(
|
||||
FuriEventLoopObject* object,
|
||||
void* context) {
|
||||
furi_check(context);
|
||||
|
||||
TestFuriEventLoopData* data = context;
|
||||
furi_check(data->message_queue == object);
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"producer MessageQueue: %lu %lu",
|
||||
data->producer.message_queue_count,
|
||||
data->consumer.message_queue_count);
|
||||
|
||||
if(data->producer.message_queue_count == MESSAGE_COUNT / 2) {
|
||||
furi_event_loop_unsubscribe(data->producer.event_loop, data->message_queue);
|
||||
furi_event_loop_subscribe_message_queue(
|
||||
data->producer.event_loop,
|
||||
data->message_queue,
|
||||
FuriEventLoopEventOut,
|
||||
test_furi_event_loop_producer_message_queue_callback,
|
||||
data);
|
||||
|
||||
} else if(data->producer.message_queue_count == MESSAGE_COUNT) {
|
||||
furi_event_loop_unsubscribe(data->producer.event_loop, data->message_queue);
|
||||
furi_event_loop_pend_callback(
|
||||
data->producer.event_loop, test_furi_event_loop_pending_callback, &data->producer);
|
||||
return;
|
||||
}
|
||||
|
||||
data->producer.message_queue_count++;
|
||||
|
||||
furi_check(
|
||||
furi_message_queue_put(data->message_queue, &data->producer.message_queue_count, 0) ==
|
||||
FuriStatusOk);
|
||||
|
||||
furi_delay_us(furi_hal_random_get() % 100);
|
||||
}
|
||||
|
||||
static void test_furi_event_loop_producer_stream_buffer_callback(
|
||||
FuriEventLoopObject* object,
|
||||
void* context) {
|
||||
furi_check(context);
|
||||
|
||||
TestFuriEventLoopData* data = context;
|
||||
furi_check(data->stream_buffer == object);
|
||||
|
||||
TestFuriEventLoopThread* producer = &data->producer;
|
||||
TestFuriEventLoopThread* consumer = &data->consumer;
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"producer StreamBuffer: %lu %lu",
|
||||
producer->stream_buffer_count,
|
||||
consumer->stream_buffer_count);
|
||||
|
||||
if(producer->stream_buffer_count == MESSAGE_COUNT / 2) {
|
||||
furi_event_loop_unsubscribe(producer->event_loop, data->stream_buffer);
|
||||
furi_event_loop_subscribe_stream_buffer(
|
||||
producer->event_loop,
|
||||
data->stream_buffer,
|
||||
FuriEventLoopEventOut,
|
||||
test_furi_event_loop_producer_stream_buffer_callback,
|
||||
data);
|
||||
|
||||
} else if(producer->stream_buffer_count == MESSAGE_COUNT) {
|
||||
furi_event_loop_unsubscribe(producer->event_loop, data->stream_buffer);
|
||||
furi_event_loop_pend_callback(
|
||||
producer->event_loop, test_furi_event_loop_pending_callback, producer);
|
||||
return;
|
||||
}
|
||||
|
||||
producer->stream_buffer_count++;
|
||||
|
||||
furi_check(
|
||||
furi_stream_buffer_send(
|
||||
data->stream_buffer, &producer->stream_buffer_count, sizeof(uint32_t), 0) ==
|
||||
sizeof(uint32_t));
|
||||
|
||||
furi_delay_us(furi_hal_random_get() % 100);
|
||||
}
|
||||
|
||||
static void
|
||||
test_furi_event_loop_producer_event_flag_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_check(context);
|
||||
|
||||
TestFuriEventLoopData* data = context;
|
||||
furi_check(data->event_flag == object);
|
||||
|
||||
const uint32_t producer_flags = (1UL << data->producer.event_flag_count);
|
||||
const uint32_t consumer_flags = (1UL << data->consumer.event_flag_count);
|
||||
|
||||
FURI_LOG_I(TAG, "producer EventFlag: 0x%06lX 0x%06lX", producer_flags, consumer_flags);
|
||||
|
||||
furi_check(furi_event_flag_set(data->event_flag, producer_flags) & producer_flags);
|
||||
|
||||
if(data->producer.event_flag_count == EVENT_FLAG_COUNT / 2) {
|
||||
furi_event_loop_unsubscribe(data->producer.event_loop, data->event_flag);
|
||||
furi_event_loop_subscribe_event_flag(
|
||||
data->producer.event_loop,
|
||||
data->event_flag,
|
||||
FuriEventLoopEventOut,
|
||||
test_furi_event_loop_producer_event_flag_callback,
|
||||
data);
|
||||
|
||||
} else if(data->producer.event_flag_count == EVENT_FLAG_COUNT) {
|
||||
furi_event_loop_unsubscribe(data->producer.event_loop, data->event_flag);
|
||||
furi_event_loop_pend_callback(
|
||||
data->producer.event_loop, test_furi_event_loop_pending_callback, &data->producer);
|
||||
return;
|
||||
}
|
||||
|
||||
data->producer.event_flag_count++;
|
||||
|
||||
furi_delay_us(furi_hal_random_get() % 100);
|
||||
}
|
||||
|
||||
static void
|
||||
test_furi_event_loop_producer_semaphore_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_check(context);
|
||||
|
||||
TestFuriEventLoopData* data = context;
|
||||
furi_check(data->semaphore == object);
|
||||
|
||||
TestFuriEventLoopThread* producer = &data->producer;
|
||||
TestFuriEventLoopThread* consumer = &data->consumer;
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG, "producer Semaphore: %lu %lu", producer->semaphore_count, consumer->semaphore_count);
|
||||
furi_check(furi_semaphore_release(data->semaphore) == FuriStatusOk);
|
||||
|
||||
if(producer->semaphore_count == MESSAGE_COUNT / 2) {
|
||||
furi_event_loop_unsubscribe(producer->event_loop, data->semaphore);
|
||||
furi_event_loop_subscribe_semaphore(
|
||||
producer->event_loop,
|
||||
data->semaphore,
|
||||
FuriEventLoopEventOut,
|
||||
test_furi_event_loop_producer_semaphore_callback,
|
||||
data);
|
||||
|
||||
} else if(producer->semaphore_count == MESSAGE_COUNT) {
|
||||
furi_event_loop_unsubscribe(producer->event_loop, data->semaphore);
|
||||
furi_event_loop_pend_callback(
|
||||
producer->event_loop, test_furi_event_loop_pending_callback, producer);
|
||||
return;
|
||||
}
|
||||
|
||||
data->producer.semaphore_count++;
|
||||
|
||||
furi_delay_us(furi_hal_random_get() % 100);
|
||||
}
|
||||
|
||||
static int32_t test_furi_event_loop_producer(void* p) {
|
||||
furi_check(p);
|
||||
|
||||
TestFuriEventLoopData* data = p;
|
||||
TestFuriEventLoopThread* producer = &data->producer;
|
||||
|
||||
for(uint32_t i = 0; i < RUN_COUNT; ++i) {
|
||||
FURI_LOG_I(TAG, "producer start run %lu", i);
|
||||
|
||||
test_furi_event_loop_thread_init(producer);
|
||||
|
||||
furi_event_loop_subscribe_message_queue(
|
||||
producer->event_loop,
|
||||
data->message_queue,
|
||||
FuriEventLoopEventOut,
|
||||
test_furi_event_loop_producer_message_queue_callback,
|
||||
data);
|
||||
furi_event_loop_subscribe_stream_buffer(
|
||||
producer->event_loop,
|
||||
data->stream_buffer,
|
||||
FuriEventLoopEventOut,
|
||||
test_furi_event_loop_producer_stream_buffer_callback,
|
||||
data);
|
||||
furi_event_loop_subscribe_event_flag(
|
||||
producer->event_loop,
|
||||
data->event_flag,
|
||||
FuriEventLoopEventOut,
|
||||
test_furi_event_loop_producer_event_flag_callback,
|
||||
data);
|
||||
furi_event_loop_subscribe_semaphore(
|
||||
producer->event_loop,
|
||||
data->semaphore,
|
||||
FuriEventLoopEventOut,
|
||||
test_furi_event_loop_producer_semaphore_callback,
|
||||
data);
|
||||
|
||||
test_furi_event_loop_thread_run_and_cleanup(producer);
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "producer end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_furi_event_loop_consumer_message_queue_callback(
|
||||
FuriEventLoopObject* object,
|
||||
void* context) {
|
||||
furi_check(context);
|
||||
|
||||
TestFuriEventLoopData* data = context;
|
||||
furi_check(data->message_queue == object);
|
||||
|
||||
furi_delay_us(furi_hal_random_get() % 100);
|
||||
|
||||
furi_check(
|
||||
furi_message_queue_get(data->message_queue, &data->consumer.message_queue_count, 0) ==
|
||||
FuriStatusOk);
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"consumer MessageQueue: %lu %lu",
|
||||
data->producer.message_queue_count,
|
||||
data->consumer.message_queue_count);
|
||||
|
||||
if(data->consumer.message_queue_count == MESSAGE_COUNT / 2) {
|
||||
furi_event_loop_unsubscribe(data->consumer.event_loop, data->message_queue);
|
||||
furi_event_loop_subscribe_message_queue(
|
||||
data->consumer.event_loop,
|
||||
data->message_queue,
|
||||
FuriEventLoopEventIn,
|
||||
test_furi_event_loop_consumer_message_queue_callback,
|
||||
data);
|
||||
|
||||
} else if(data->consumer.message_queue_count == MESSAGE_COUNT) {
|
||||
furi_event_loop_unsubscribe(data->consumer.event_loop, data->message_queue);
|
||||
furi_event_loop_pend_callback(
|
||||
data->consumer.event_loop, test_furi_event_loop_pending_callback, &data->consumer);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_furi_event_loop_consumer_stream_buffer_callback(
|
||||
FuriEventLoopObject* object,
|
||||
void* context) {
|
||||
furi_check(context);
|
||||
|
||||
TestFuriEventLoopData* data = context;
|
||||
furi_check(data->stream_buffer == object);
|
||||
|
||||
TestFuriEventLoopThread* producer = &data->producer;
|
||||
TestFuriEventLoopThread* consumer = &data->consumer;
|
||||
|
||||
furi_delay_us(furi_hal_random_get() % 100);
|
||||
|
||||
furi_check(
|
||||
furi_stream_buffer_receive(
|
||||
data->stream_buffer, &consumer->stream_buffer_count, sizeof(uint32_t), 0) ==
|
||||
sizeof(uint32_t));
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"consumer StreamBuffer: %lu %lu",
|
||||
producer->stream_buffer_count,
|
||||
consumer->stream_buffer_count);
|
||||
|
||||
if(consumer->stream_buffer_count == MESSAGE_COUNT / 2) {
|
||||
furi_event_loop_unsubscribe(consumer->event_loop, data->stream_buffer);
|
||||
furi_event_loop_subscribe_stream_buffer(
|
||||
consumer->event_loop,
|
||||
data->stream_buffer,
|
||||
FuriEventLoopEventIn,
|
||||
test_furi_event_loop_consumer_stream_buffer_callback,
|
||||
data);
|
||||
|
||||
} else if(consumer->stream_buffer_count == MESSAGE_COUNT) {
|
||||
furi_event_loop_unsubscribe(data->consumer.event_loop, data->stream_buffer);
|
||||
furi_event_loop_pend_callback(
|
||||
consumer->event_loop, test_furi_event_loop_pending_callback, consumer);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_furi_event_loop_consumer_event_flag_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_check(context);
|
||||
|
||||
TestFuriEventLoopData* data = context;
|
||||
furi_check(data->event_flag == object);
|
||||
|
||||
furi_delay_us(furi_hal_random_get() % 100);
|
||||
|
||||
const uint32_t producer_flags = (1UL << data->producer.event_flag_count);
|
||||
const uint32_t consumer_flags = (1UL << data->consumer.event_flag_count);
|
||||
|
||||
furi_check(
|
||||
furi_event_flag_wait(data->event_flag, consumer_flags, FuriFlagWaitAny, 0) &
|
||||
consumer_flags);
|
||||
|
||||
FURI_LOG_I(TAG, "consumer EventFlag: 0x%06lX 0x%06lX", producer_flags, consumer_flags);
|
||||
|
||||
if(data->consumer.event_flag_count == EVENT_FLAG_COUNT / 2) {
|
||||
furi_event_loop_unsubscribe(data->consumer.event_loop, data->event_flag);
|
||||
furi_event_loop_subscribe_event_flag(
|
||||
data->consumer.event_loop,
|
||||
data->event_flag,
|
||||
FuriEventLoopEventIn,
|
||||
test_furi_event_loop_consumer_event_flag_callback,
|
||||
data);
|
||||
|
||||
} else if(data->consumer.event_flag_count == EVENT_FLAG_COUNT) {
|
||||
furi_event_loop_unsubscribe(data->consumer.event_loop, data->event_flag);
|
||||
furi_event_loop_pend_callback(
|
||||
data->consumer.event_loop, test_furi_event_loop_pending_callback, &data->consumer);
|
||||
return;
|
||||
}
|
||||
|
||||
data->consumer.event_flag_count++;
|
||||
}
|
||||
|
||||
static void
|
||||
test_furi_event_loop_consumer_semaphore_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_check(context);
|
||||
|
||||
TestFuriEventLoopData* data = context;
|
||||
furi_check(data->semaphore == object);
|
||||
|
||||
furi_delay_us(furi_hal_random_get() % 100);
|
||||
|
||||
TestFuriEventLoopThread* producer = &data->producer;
|
||||
TestFuriEventLoopThread* consumer = &data->consumer;
|
||||
|
||||
furi_check(furi_semaphore_acquire(data->semaphore, 0) == FuriStatusOk);
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG, "consumer Semaphore: %lu %lu", producer->semaphore_count, consumer->semaphore_count);
|
||||
|
||||
if(consumer->semaphore_count == MESSAGE_COUNT / 2) {
|
||||
furi_event_loop_unsubscribe(consumer->event_loop, data->semaphore);
|
||||
furi_event_loop_subscribe_semaphore(
|
||||
consumer->event_loop,
|
||||
data->semaphore,
|
||||
FuriEventLoopEventIn,
|
||||
test_furi_event_loop_consumer_semaphore_callback,
|
||||
data);
|
||||
|
||||
} else if(consumer->semaphore_count == MESSAGE_COUNT) {
|
||||
furi_event_loop_unsubscribe(consumer->event_loop, data->semaphore);
|
||||
furi_event_loop_pend_callback(
|
||||
consumer->event_loop, test_furi_event_loop_pending_callback, consumer);
|
||||
return;
|
||||
}
|
||||
|
||||
data->consumer.semaphore_count++;
|
||||
}
|
||||
|
||||
static int32_t test_furi_event_loop_consumer(void* p) {
|
||||
furi_check(p);
|
||||
|
||||
TestFuriEventLoopData* data = p;
|
||||
TestFuriEventLoopThread* consumer = &data->consumer;
|
||||
|
||||
for(uint32_t i = 0; i < RUN_COUNT; ++i) {
|
||||
FURI_LOG_I(TAG, "consumer start run %lu", i);
|
||||
|
||||
test_furi_event_loop_thread_init(consumer);
|
||||
|
||||
furi_event_loop_subscribe_message_queue(
|
||||
consumer->event_loop,
|
||||
data->message_queue,
|
||||
FuriEventLoopEventIn,
|
||||
test_furi_event_loop_consumer_message_queue_callback,
|
||||
data);
|
||||
furi_event_loop_subscribe_stream_buffer(
|
||||
consumer->event_loop,
|
||||
data->stream_buffer,
|
||||
FuriEventLoopEventIn,
|
||||
test_furi_event_loop_consumer_stream_buffer_callback,
|
||||
data);
|
||||
furi_event_loop_subscribe_event_flag(
|
||||
consumer->event_loop,
|
||||
data->event_flag,
|
||||
FuriEventLoopEventIn,
|
||||
test_furi_event_loop_consumer_event_flag_callback,
|
||||
data);
|
||||
furi_event_loop_subscribe_semaphore(
|
||||
consumer->event_loop,
|
||||
data->semaphore,
|
||||
FuriEventLoopEventIn,
|
||||
test_furi_event_loop_consumer_semaphore_callback,
|
||||
data);
|
||||
|
||||
test_furi_event_loop_thread_run_and_cleanup(consumer);
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "consumer end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_furi_event_loop(void) {
|
||||
TestFuriEventLoopData data = {};
|
||||
|
||||
data.message_queue = furi_message_queue_alloc(16, sizeof(uint32_t));
|
||||
data.stream_buffer = furi_stream_buffer_alloc(16, sizeof(uint32_t));
|
||||
data.event_flag = furi_event_flag_alloc();
|
||||
data.semaphore = furi_semaphore_alloc(8, 0);
|
||||
|
||||
FuriThread* producer_thread =
|
||||
furi_thread_alloc_ex("producer_thread", 1 * 1024, test_furi_event_loop_producer, &data);
|
||||
furi_thread_start(producer_thread);
|
||||
|
||||
FuriThread* consumer_thread =
|
||||
furi_thread_alloc_ex("consumer_thread", 1 * 1024, test_furi_event_loop_consumer, &data);
|
||||
furi_thread_start(consumer_thread);
|
||||
|
||||
// Wait for thread to complete their tasks
|
||||
furi_thread_join(producer_thread);
|
||||
furi_thread_join(consumer_thread);
|
||||
|
||||
TestFuriEventLoopThread* producer = &data.producer;
|
||||
TestFuriEventLoopThread* consumer = &data.consumer;
|
||||
|
||||
// The test itself
|
||||
mu_assert_int_eq(producer->message_queue_count, consumer->message_queue_count);
|
||||
mu_assert_int_eq(producer->message_queue_count, MESSAGE_COUNT);
|
||||
mu_assert_int_eq(producer->stream_buffer_count, consumer->stream_buffer_count);
|
||||
mu_assert_int_eq(producer->stream_buffer_count, MESSAGE_COUNT);
|
||||
mu_assert_int_eq(producer->event_flag_count, consumer->event_flag_count);
|
||||
mu_assert_int_eq(producer->event_flag_count, EVENT_FLAG_COUNT);
|
||||
mu_assert_int_eq(producer->semaphore_count, consumer->semaphore_count);
|
||||
mu_assert_int_eq(producer->semaphore_count, MESSAGE_COUNT);
|
||||
|
||||
// Release memory
|
||||
furi_thread_free(consumer_thread);
|
||||
furi_thread_free(producer_thread);
|
||||
|
||||
furi_message_queue_free(data.message_queue);
|
||||
furi_stream_buffer_free(data.stream_buffer);
|
||||
furi_event_flag_free(data.event_flag);
|
||||
furi_semaphore_free(data.semaphore);
|
||||
}
|
103
applications/debug/unit_tests/tests/furi/furi_primitives_test.c
Normal file
103
applications/debug/unit_tests/tests/furi/furi_primitives_test.c
Normal file
|
@ -0,0 +1,103 @@
|
|||
#include <furi.h>
|
||||
#include "../test.h" // IWYU pragma: keep
|
||||
|
||||
#define MESSAGE_QUEUE_CAPACITY (16U)
|
||||
#define MESSAGE_QUEUE_ELEMENT_SIZE (sizeof(uint32_t))
|
||||
|
||||
#define STREAM_BUFFER_SIZE (32U)
|
||||
#define STREAM_BUFFER_TRG_LEVEL (STREAM_BUFFER_SIZE / 2U)
|
||||
|
||||
typedef struct {
|
||||
FuriMessageQueue* message_queue;
|
||||
FuriStreamBuffer* stream_buffer;
|
||||
} TestFuriPrimitivesData;
|
||||
|
||||
static void test_furi_message_queue(TestFuriPrimitivesData* data) {
|
||||
FuriMessageQueue* message_queue = data->message_queue;
|
||||
|
||||
mu_assert_int_eq(0, furi_message_queue_get_count(message_queue));
|
||||
mu_assert_int_eq(MESSAGE_QUEUE_CAPACITY, furi_message_queue_get_space(message_queue));
|
||||
mu_assert_int_eq(MESSAGE_QUEUE_CAPACITY, furi_message_queue_get_capacity(message_queue));
|
||||
mu_assert_int_eq(
|
||||
MESSAGE_QUEUE_ELEMENT_SIZE, furi_message_queue_get_message_size(message_queue));
|
||||
|
||||
for(uint32_t i = 0;; ++i) {
|
||||
mu_assert_int_eq(MESSAGE_QUEUE_CAPACITY - i, furi_message_queue_get_space(message_queue));
|
||||
mu_assert_int_eq(i, furi_message_queue_get_count(message_queue));
|
||||
|
||||
if(furi_message_queue_put(message_queue, &i, 0) != FuriStatusOk) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mu_assert_int_eq(0, furi_message_queue_get_space(message_queue));
|
||||
mu_assert_int_eq(MESSAGE_QUEUE_CAPACITY, furi_message_queue_get_count(message_queue));
|
||||
|
||||
for(uint32_t i = 0;; ++i) {
|
||||
mu_assert_int_eq(i, furi_message_queue_get_space(message_queue));
|
||||
mu_assert_int_eq(MESSAGE_QUEUE_CAPACITY - i, furi_message_queue_get_count(message_queue));
|
||||
|
||||
uint32_t value;
|
||||
if(furi_message_queue_get(message_queue, &value, 0) != FuriStatusOk) {
|
||||
break;
|
||||
}
|
||||
|
||||
mu_assert_int_eq(i, value);
|
||||
}
|
||||
|
||||
mu_assert_int_eq(0, furi_message_queue_get_count(message_queue));
|
||||
mu_assert_int_eq(MESSAGE_QUEUE_CAPACITY, furi_message_queue_get_space(message_queue));
|
||||
}
|
||||
|
||||
static void test_furi_stream_buffer(TestFuriPrimitivesData* data) {
|
||||
FuriStreamBuffer* stream_buffer = data->stream_buffer;
|
||||
|
||||
mu_assert(furi_stream_buffer_is_empty(stream_buffer), "Must be empty");
|
||||
mu_assert(!furi_stream_buffer_is_full(stream_buffer), "Must be not full");
|
||||
mu_assert_int_eq(0, furi_stream_buffer_bytes_available(stream_buffer));
|
||||
mu_assert_int_eq(STREAM_BUFFER_SIZE, furi_stream_buffer_spaces_available(stream_buffer));
|
||||
|
||||
for(uint8_t i = 0;; ++i) {
|
||||
mu_assert_int_eq(i, furi_stream_buffer_bytes_available(stream_buffer));
|
||||
mu_assert_int_eq(
|
||||
STREAM_BUFFER_SIZE - i, furi_stream_buffer_spaces_available(stream_buffer));
|
||||
|
||||
if(furi_stream_buffer_send(stream_buffer, &i, sizeof(uint8_t), 0) != sizeof(uint8_t)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mu_assert(!furi_stream_buffer_is_empty(stream_buffer), "Must be not empty");
|
||||
mu_assert(furi_stream_buffer_is_full(stream_buffer), "Must be full");
|
||||
mu_assert_int_eq(STREAM_BUFFER_SIZE, furi_stream_buffer_bytes_available(stream_buffer));
|
||||
mu_assert_int_eq(0, furi_stream_buffer_spaces_available(stream_buffer));
|
||||
|
||||
for(uint8_t i = 0;; ++i) {
|
||||
mu_assert_int_eq(
|
||||
STREAM_BUFFER_SIZE - i, furi_stream_buffer_bytes_available(stream_buffer));
|
||||
mu_assert_int_eq(i, furi_stream_buffer_spaces_available(stream_buffer));
|
||||
|
||||
uint8_t value;
|
||||
if(furi_stream_buffer_receive(stream_buffer, &value, sizeof(uint8_t), 0) !=
|
||||
sizeof(uint8_t)) {
|
||||
break;
|
||||
}
|
||||
|
||||
mu_assert_int_eq(i, value);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a stub that needs expanding
|
||||
void test_furi_primitives(void) {
|
||||
TestFuriPrimitivesData data = {
|
||||
.message_queue =
|
||||
furi_message_queue_alloc(MESSAGE_QUEUE_CAPACITY, MESSAGE_QUEUE_ELEMENT_SIZE),
|
||||
.stream_buffer = furi_stream_buffer_alloc(STREAM_BUFFER_SIZE, STREAM_BUFFER_TRG_LEVEL),
|
||||
};
|
||||
|
||||
test_furi_message_queue(&data);
|
||||
test_furi_stream_buffer(&data);
|
||||
|
||||
furi_message_queue_free(data.message_queue);
|
||||
furi_stream_buffer_free(data.stream_buffer);
|
||||
}
|
|
@ -8,6 +8,8 @@ void test_furi_concurrent_access(void);
|
|||
void test_furi_pubsub(void);
|
||||
void test_furi_memmgr(void);
|
||||
void test_furi_event_loop(void);
|
||||
void test_errno_saving(void);
|
||||
void test_furi_primitives(void);
|
||||
|
||||
static int foo = 0;
|
||||
|
||||
|
@ -42,6 +44,14 @@ MU_TEST(mu_test_furi_event_loop) {
|
|||
test_furi_event_loop();
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_errno_saving) {
|
||||
test_errno_saving();
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_primitives) {
|
||||
test_furi_primitives();
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_suite) {
|
||||
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||
MU_RUN_TEST(test_check);
|
||||
|
@ -51,6 +61,8 @@ MU_TEST_SUITE(test_suite) {
|
|||
MU_RUN_TEST(mu_test_furi_pubsub);
|
||||
MU_RUN_TEST(mu_test_furi_memmgr);
|
||||
MU_RUN_TEST(mu_test_furi_event_loop);
|
||||
MU_RUN_TEST(mu_test_errno_saving);
|
||||
MU_RUN_TEST(mu_test_furi_primitives);
|
||||
}
|
||||
|
||||
int run_minunit_test_furi(void) {
|
||||
|
|
88
applications/debug/unit_tests/tests/js/js_test.c
Normal file
88
applications/debug/unit_tests/tests/js/js_test.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
#include "../test.h" // IWYU pragma: keep
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_random.h>
|
||||
|
||||
#include <storage/storage.h>
|
||||
#include <applications/system/js_app/js_thread.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define JS_SCRIPT_PATH(name) EXT_PATH("unit_tests/js/" name ".js")
|
||||
|
||||
typedef enum {
|
||||
JsTestsFinished = 1,
|
||||
JsTestsError = 2,
|
||||
} JsTestFlag;
|
||||
|
||||
typedef struct {
|
||||
FuriEventFlag* event_flags;
|
||||
FuriString* error_string;
|
||||
} JsTestCallbackContext;
|
||||
|
||||
static void js_test_callback(JsThreadEvent event, const char* msg, void* param) {
|
||||
JsTestCallbackContext* context = param;
|
||||
if(event == JsThreadEventPrint) {
|
||||
FURI_LOG_I("js_test", "%s", msg);
|
||||
} else if(event == JsThreadEventError || event == JsThreadEventErrorTrace) {
|
||||
context->error_string = furi_string_alloc_set_str(msg);
|
||||
furi_event_flag_set(context->event_flags, JsTestsFinished | JsTestsError);
|
||||
} else if(event == JsThreadEventDone) {
|
||||
furi_event_flag_set(context->event_flags, JsTestsFinished);
|
||||
}
|
||||
}
|
||||
|
||||
static void js_test_run(const char* script_path) {
|
||||
JsTestCallbackContext* context = malloc(sizeof(JsTestCallbackContext));
|
||||
context->event_flags = furi_event_flag_alloc();
|
||||
|
||||
JsThread* thread = js_thread_run(script_path, js_test_callback, context);
|
||||
uint32_t flags = furi_event_flag_wait(
|
||||
context->event_flags, JsTestsFinished, FuriFlagWaitAny, FuriWaitForever);
|
||||
if(flags & FuriFlagError) {
|
||||
// getting the flags themselves should not fail
|
||||
furi_crash();
|
||||
}
|
||||
|
||||
FuriString* error_string = context->error_string;
|
||||
|
||||
js_thread_stop(thread);
|
||||
furi_event_flag_free(context->event_flags);
|
||||
free(context);
|
||||
|
||||
if(flags & JsTestsError) {
|
||||
// memory leak: not freeing the FuriString if the tests fail,
|
||||
// because mu_fail executes a return
|
||||
//
|
||||
// who cares tho?
|
||||
mu_fail(furi_string_get_cstr(error_string));
|
||||
}
|
||||
}
|
||||
|
||||
MU_TEST(js_test_basic) {
|
||||
js_test_run(JS_SCRIPT_PATH("basic"));
|
||||
}
|
||||
MU_TEST(js_test_math) {
|
||||
js_test_run(JS_SCRIPT_PATH("math"));
|
||||
}
|
||||
MU_TEST(js_test_event_loop) {
|
||||
js_test_run(JS_SCRIPT_PATH("event_loop"));
|
||||
}
|
||||
MU_TEST(js_test_storage) {
|
||||
js_test_run(JS_SCRIPT_PATH("storage"));
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_js) {
|
||||
MU_RUN_TEST(js_test_basic);
|
||||
MU_RUN_TEST(js_test_math);
|
||||
MU_RUN_TEST(js_test_event_loop);
|
||||
MU_RUN_TEST(js_test_storage);
|
||||
}
|
||||
|
||||
int run_minunit_test_js(void) {
|
||||
MU_RUN_SUITE(test_js);
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
|
||||
TEST_API_DEFINE(run_minunit_test_js)
|
|
@ -31,7 +31,7 @@ extern "C" {
|
|||
#include <Windows.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
#define __func__ __FUNCTION__
|
||||
#define __func__ __FUNCTION__ //-V1059
|
||||
#endif
|
||||
|
||||
#elif defined(__unix__) || defined(__unix) || defined(unix) || \
|
||||
|
@ -56,7 +56,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#if __GNUC__ >= 5 && !defined(__STDC_VERSION__)
|
||||
#define __func__ __extension__ __FUNCTION__
|
||||
#define __func__ __extension__ __FUNCTION__ //-V1059
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
@ -102,6 +102,7 @@ void minunit_printf_warning(const char* format, ...);
|
|||
MU__SAFE_BLOCK(minunit_setup = setup_fun; minunit_teardown = teardown_fun;)
|
||||
|
||||
/* Test runner */
|
||||
//-V:MU_RUN_TEST:550
|
||||
#define MU_RUN_TEST(test) \
|
||||
MU__SAFE_BLOCK( \
|
||||
if(minunit_real_timer == 0 && minunit_proc_timer == 0) { \
|
||||
|
|
|
@ -496,7 +496,7 @@ NfcCommand mf_classic_poller_send_frame_callback(NfcGenericEventEx event, void*
|
|||
MfClassicKey key = {
|
||||
.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
};
|
||||
error = mf_classic_poller_auth(instance, 0, &key, MfClassicKeyTypeA, NULL);
|
||||
error = mf_classic_poller_auth(instance, 0, &key, MfClassicKeyTypeA, NULL, false);
|
||||
frame_test->state = (error == MfClassicErrorNone) ?
|
||||
NfcTestMfClassicSendFrameTestStateReadBlock :
|
||||
NfcTestMfClassicSendFrameTestStateFail;
|
||||
|
|
|
@ -6,9 +6,10 @@
|
|||
// This is a hack to access internal storage functions and definitions
|
||||
#include <storage/storage_i.h>
|
||||
|
||||
#define UNIT_TESTS_PATH(path) EXT_PATH("unit_tests/" path)
|
||||
#define UNIT_TESTS_RESOURCES_PATH(path) EXT_PATH("unit_tests/" path)
|
||||
#define UNIT_TESTS_PATH(path) EXT_PATH(".tmp/unit_tests/" path)
|
||||
|
||||
#define STORAGE_LOCKED_FILE EXT_PATH("locked_file.test")
|
||||
#define STORAGE_LOCKED_FILE UNIT_TESTS_PATH("locked_file.test")
|
||||
#define STORAGE_LOCKED_DIR STORAGE_INT_PATH_PREFIX
|
||||
|
||||
#define STORAGE_TEST_DIR UNIT_TESTS_PATH("test_dir")
|
||||
|
@ -369,33 +370,78 @@ MU_TEST(storage_file_rename) {
|
|||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(storage);
|
||||
|
||||
mu_check(write_file_13DA(storage, EXT_PATH("file.old")));
|
||||
mu_check(check_file_13DA(storage, EXT_PATH("file.old")));
|
||||
mu_check(write_file_13DA(storage, UNIT_TESTS_PATH("file.old")));
|
||||
mu_check(check_file_13DA(storage, UNIT_TESTS_PATH("file.old")));
|
||||
mu_assert_int_eq(
|
||||
FSE_OK, storage_common_rename(storage, EXT_PATH("file.old"), EXT_PATH("file.new")));
|
||||
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, EXT_PATH("file.old"), NULL));
|
||||
mu_assert_int_eq(FSE_OK, storage_common_stat(storage, EXT_PATH("file.new"), NULL));
|
||||
mu_check(check_file_13DA(storage, EXT_PATH("file.new")));
|
||||
mu_assert_int_eq(FSE_OK, storage_common_remove(storage, EXT_PATH("file.new")));
|
||||
FSE_OK,
|
||||
storage_common_rename(storage, UNIT_TESTS_PATH("file.old"), UNIT_TESTS_PATH("file.new")));
|
||||
mu_assert_int_eq(
|
||||
FSE_NOT_EXIST, storage_common_stat(storage, UNIT_TESTS_PATH("file.old"), NULL));
|
||||
mu_assert_int_eq(FSE_OK, storage_common_stat(storage, UNIT_TESTS_PATH("file.new"), NULL));
|
||||
mu_check(check_file_13DA(storage, UNIT_TESTS_PATH("file.new")));
|
||||
mu_assert_int_eq(FSE_OK, storage_common_remove(storage, UNIT_TESTS_PATH("file.new")));
|
||||
|
||||
storage_file_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
static const char* dir_rename_tests[][2] = {
|
||||
{UNIT_TESTS_PATH("dir.old"), UNIT_TESTS_PATH("dir.new")},
|
||||
{UNIT_TESTS_PATH("test_dir"), UNIT_TESTS_PATH("test_dir-new")},
|
||||
{UNIT_TESTS_PATH("test"), UNIT_TESTS_PATH("test-test")},
|
||||
};
|
||||
|
||||
MU_TEST(storage_dir_rename) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
storage_dir_create(storage, EXT_PATH("dir.old"));
|
||||
for(size_t i = 0; i < COUNT_OF(dir_rename_tests); i++) {
|
||||
const char* old_path = dir_rename_tests[i][0];
|
||||
const char* new_path = dir_rename_tests[i][1];
|
||||
|
||||
mu_check(storage_dir_rename_check(storage, EXT_PATH("dir.old")));
|
||||
storage_dir_create(storage, old_path);
|
||||
mu_check(storage_dir_rename_check(storage, old_path));
|
||||
|
||||
mu_assert_int_eq(FSE_OK, storage_common_rename(storage, old_path, new_path));
|
||||
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, old_path, NULL));
|
||||
mu_check(storage_dir_rename_check(storage, new_path));
|
||||
|
||||
storage_dir_remove(storage, new_path);
|
||||
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, new_path, NULL));
|
||||
}
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
MU_TEST(storage_equiv_and_subdir) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
mu_assert_int_eq(
|
||||
FSE_OK, storage_common_rename(storage, EXT_PATH("dir.old"), EXT_PATH("dir.new")));
|
||||
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, EXT_PATH("dir.old"), NULL));
|
||||
mu_check(storage_dir_rename_check(storage, EXT_PATH("dir.new")));
|
||||
true,
|
||||
storage_common_equivalent_path(storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah")));
|
||||
mu_assert_int_eq(
|
||||
true,
|
||||
storage_common_equivalent_path(
|
||||
storage, UNIT_TESTS_PATH("blah/"), UNIT_TESTS_PATH("blah/")));
|
||||
mu_assert_int_eq(
|
||||
false,
|
||||
storage_common_equivalent_path(
|
||||
storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah-blah")));
|
||||
mu_assert_int_eq(
|
||||
false,
|
||||
storage_common_equivalent_path(
|
||||
storage, UNIT_TESTS_PATH("blah/"), UNIT_TESTS_PATH("blah-blah/")));
|
||||
|
||||
storage_dir_remove(storage, EXT_PATH("dir.new"));
|
||||
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, EXT_PATH("dir.new"), NULL));
|
||||
mu_assert_int_eq(
|
||||
true, storage_common_is_subdir(storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah")));
|
||||
mu_assert_int_eq(
|
||||
true,
|
||||
storage_common_is_subdir(storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah/blah")));
|
||||
mu_assert_int_eq(
|
||||
false,
|
||||
storage_common_is_subdir(storage, UNIT_TESTS_PATH("blah/blah"), UNIT_TESTS_PATH("blah")));
|
||||
mu_assert_int_eq(
|
||||
false,
|
||||
storage_common_is_subdir(storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah-blah")));
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
@ -403,10 +449,13 @@ MU_TEST(storage_dir_rename) {
|
|||
MU_TEST_SUITE(storage_rename) {
|
||||
MU_RUN_TEST(storage_file_rename);
|
||||
MU_RUN_TEST(storage_dir_rename);
|
||||
MU_RUN_TEST(storage_equiv_and_subdir);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
storage_dir_remove(storage, EXT_PATH("dir.old"));
|
||||
storage_dir_remove(storage, EXT_PATH("dir.new"));
|
||||
for(size_t i = 0; i < COUNT_OF(dir_rename_tests); i++) {
|
||||
storage_dir_remove(storage, dir_rename_tests[i][0]);
|
||||
storage_dir_remove(storage, dir_rename_tests[i][1]);
|
||||
}
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
|
@ -653,7 +702,7 @@ MU_TEST(test_md5_calc) {
|
|||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(storage);
|
||||
|
||||
const char* path = UNIT_TESTS_PATH("storage/md5.txt");
|
||||
const char* path = UNIT_TESTS_RESOURCES_PATH("storage/md5.txt");
|
||||
const char* md5_cstr = "2a456fa43e75088fdde41c93159d62a2";
|
||||
const uint8_t md5[MD5_HASH_SIZE] = {
|
||||
0x2a,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include <rpc/rpc_i.h>
|
||||
#include <flipper.pb.h>
|
||||
#include <core/event_loop.h>
|
||||
#include <applications/system/js_app/js_thread.h>
|
||||
|
||||
static constexpr auto unit_tests_api_table = sort(create_array_t<sym_entry>(
|
||||
API_METHOD(resource_manifest_reader_alloc, ResourceManifestReader*, (Storage*)),
|
||||
|
@ -33,13 +33,9 @@ static constexpr auto unit_tests_api_table = sort(create_array_t<sym_entry>(
|
|||
xQueueGenericSend,
|
||||
BaseType_t,
|
||||
(QueueHandle_t, const void* const, TickType_t, const BaseType_t)),
|
||||
API_METHOD(furi_event_loop_alloc, FuriEventLoop*, (void)),
|
||||
API_METHOD(furi_event_loop_free, void, (FuriEventLoop*)),
|
||||
API_METHOD(
|
||||
furi_event_loop_subscribe_message_queue,
|
||||
void,
|
||||
(FuriEventLoop*, FuriMessageQueue*, FuriEventLoopEvent, FuriEventLoopEventCallback, void*)),
|
||||
API_METHOD(furi_event_loop_unsubscribe, void, (FuriEventLoop*, FuriEventLoopObject*)),
|
||||
API_METHOD(furi_event_loop_run, void, (FuriEventLoop*)),
|
||||
API_METHOD(furi_event_loop_stop, void, (FuriEventLoop*)),
|
||||
js_thread_run,
|
||||
JsThread*,
|
||||
(const char* script_path, JsThreadCallback callback, void* context)),
|
||||
API_METHOD(js_thread_stop, void, (JsThread * worker)),
|
||||
API_VARIABLE(PB_Main_msg, PB_Main_msg_t)));
|
||||
|
|
|
@ -92,7 +92,7 @@ typedef struct {
|
|||
const GpioPin* g0_pin;
|
||||
SubGhzDeviceCC1101ExtAsyncTx async_tx;
|
||||
SubGhzDeviceCC1101ExtAsyncRx async_rx;
|
||||
bool power_amp;
|
||||
bool amp_and_leds;
|
||||
bool extended_range;
|
||||
} SubGhzDeviceCC1101Ext;
|
||||
|
||||
|
@ -219,11 +219,11 @@ bool subghz_device_cc1101_ext_alloc(SubGhzDeviceConf* conf) {
|
|||
subghz_device_cc1101_ext->async_mirror_pin = NULL;
|
||||
subghz_device_cc1101_ext->spi_bus_handle = &furi_hal_spi_bus_handle_external;
|
||||
subghz_device_cc1101_ext->g0_pin = SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO;
|
||||
subghz_device_cc1101_ext->power_amp = false;
|
||||
subghz_device_cc1101_ext->amp_and_leds = false;
|
||||
subghz_device_cc1101_ext->extended_range = false;
|
||||
if(conf) {
|
||||
if(conf->ver == SUBGHZ_DEVICE_CC1101_CONFIG_VER) {
|
||||
subghz_device_cc1101_ext->power_amp = conf->power_amp;
|
||||
subghz_device_cc1101_ext->amp_and_leds = conf->amp_and_leds;
|
||||
subghz_device_cc1101_ext->extended_range = conf->extended_range;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Config version mismatch");
|
||||
|
@ -233,7 +233,7 @@ bool subghz_device_cc1101_ext_alloc(SubGhzDeviceConf* conf) {
|
|||
subghz_device_cc1101_ext->async_rx.capture_delta_duration = 0;
|
||||
|
||||
furi_hal_spi_bus_handle_init(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
if(subghz_device_cc1101_ext->power_amp) {
|
||||
if(subghz_device_cc1101_ext->amp_and_leds) {
|
||||
furi_hal_gpio_init_simple(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, GpioModeOutputPushPull);
|
||||
}
|
||||
|
||||
|
@ -244,7 +244,7 @@ void subghz_device_cc1101_ext_free(void) {
|
|||
furi_assert(subghz_device_cc1101_ext != NULL);
|
||||
|
||||
furi_hal_spi_bus_handle_deinit(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
if(subghz_device_cc1101_ext->power_amp) {
|
||||
if(subghz_device_cc1101_ext->amp_and_leds) {
|
||||
furi_hal_gpio_init_simple(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, GpioModeAnalog);
|
||||
}
|
||||
|
||||
|
@ -421,6 +421,7 @@ void subghz_device_cc1101_ext_reset(void) {
|
|||
// Reset GDO2 (!TX/RX) to floating state
|
||||
cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHighImpedance);
|
||||
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
}
|
||||
|
||||
|
@ -430,13 +431,13 @@ void subghz_device_cc1101_ext_idle(void) {
|
|||
//waiting for the chip to switch to IDLE mode
|
||||
furi_check(cc1101_wait_status_state(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101StateIDLE, 10000));
|
||||
|
||||
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 0);
|
||||
// Reset GDO2 (!TX/RX) to floating state
|
||||
cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHighImpedance);
|
||||
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
if(subghz_device_cc1101_ext->power_amp) {
|
||||
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_rx(void) {
|
||||
|
@ -445,14 +446,17 @@ void subghz_device_cc1101_ext_rx(void) {
|
|||
//waiting for the chip to switch to Rx mode
|
||||
furi_check(
|
||||
cc1101_wait_status_state(subghz_device_cc1101_ext->spi_bus_handle, CC1101StateRX, 10000));
|
||||
// Go GDO2 (!TX/RX) to high (RX state)
|
||||
cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
|
||||
|
||||
if(subghz_device_cc1101_ext->amp_and_leds) {
|
||||
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 0);
|
||||
// Go GDO2 (!TX/RX) to high (RX state)
|
||||
cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle,
|
||||
CC1101_IOCFG2,
|
||||
CC1101IocfgHW | CC1101_IOCFG_INV);
|
||||
}
|
||||
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
if(subghz_device_cc1101_ext->power_amp) {
|
||||
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool subghz_device_cc1101_ext_tx(void) {
|
||||
|
@ -462,12 +466,14 @@ bool subghz_device_cc1101_ext_tx(void) {
|
|||
//waiting for the chip to switch to Tx mode
|
||||
furi_check(
|
||||
cc1101_wait_status_state(subghz_device_cc1101_ext->spi_bus_handle, CC1101StateTX, 10000));
|
||||
// Go GDO2 (!TX/RX) to low (TX state)
|
||||
cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
if(subghz_device_cc1101_ext->power_amp) {
|
||||
|
||||
if(subghz_device_cc1101_ext->amp_and_leds) {
|
||||
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 1);
|
||||
// Go GDO2 (!TX/RX) to low (TX state)
|
||||
cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW);
|
||||
}
|
||||
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
App(
|
||||
appid="example_event_loop_event_flags",
|
||||
name="Example: Event Loop Event Flags",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
sources=["example_event_loop_event_flags.c"],
|
||||
entry_point="example_event_loop_event_flags_app",
|
||||
fap_category="Examples",
|
||||
)
|
||||
|
||||
App(
|
||||
appid="example_event_loop_timer",
|
||||
name="Example: Event Loop Timer",
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
/**
|
||||
* @file example_event_loop_event_flags.c
|
||||
* @brief Example application demonstrating the use of the FuriEventFlag primitive in FuriEventLoop instances.
|
||||
*
|
||||
* This application receives keystrokes from the input service and sets the appropriate flags,
|
||||
* which are subsequently processed in the event loop
|
||||
*/
|
||||
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_port.h>
|
||||
|
||||
#include <furi_hal_random.h>
|
||||
|
||||
#define TAG "ExampleEventLoopEventFlags"
|
||||
|
||||
typedef struct {
|
||||
Gui* gui;
|
||||
ViewPort* view_port;
|
||||
FuriEventLoop* event_loop;
|
||||
FuriEventFlag* event_flag;
|
||||
} EventLoopEventFlagsApp;
|
||||
|
||||
typedef enum {
|
||||
EventLoopEventFlagsOk = (1 << 0),
|
||||
EventLoopEventFlagsUp = (1 << 1),
|
||||
EventLoopEventFlagsDown = (1 << 2),
|
||||
EventLoopEventFlagsLeft = (1 << 3),
|
||||
EventLoopEventFlagsRight = (1 << 4),
|
||||
EventLoopEventFlagsBack = (1 << 5),
|
||||
EventLoopEventFlagsExit = (1 << 6),
|
||||
} EventLoopEventFlags;
|
||||
|
||||
#define EVENT_LOOP_EVENT_FLAGS_MASK \
|
||||
(EventLoopEventFlagsOk | EventLoopEventFlagsUp | EventLoopEventFlagsDown | \
|
||||
EventLoopEventFlagsLeft | EventLoopEventFlagsRight | EventLoopEventFlagsBack | \
|
||||
EventLoopEventFlagsExit)
|
||||
|
||||
// This function is executed in the GUI context each time an input event occurs (e.g. the user pressed a key)
|
||||
static void event_loop_event_flags_app_input_callback(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
EventLoopEventFlagsApp* app = context;
|
||||
UNUSED(app);
|
||||
|
||||
if(event->type == InputTypePress) {
|
||||
if(event->key == InputKeyOk) {
|
||||
furi_event_flag_set(app->event_flag, EventLoopEventFlagsOk);
|
||||
} else if(event->key == InputKeyUp) {
|
||||
furi_event_flag_set(app->event_flag, EventLoopEventFlagsUp);
|
||||
} else if(event->key == InputKeyDown) {
|
||||
furi_event_flag_set(app->event_flag, EventLoopEventFlagsDown);
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
furi_event_flag_set(app->event_flag, EventLoopEventFlagsLeft);
|
||||
} else if(event->key == InputKeyRight) {
|
||||
furi_event_flag_set(app->event_flag, EventLoopEventFlagsRight);
|
||||
} else if(event->key == InputKeyBack) {
|
||||
furi_event_flag_set(app->event_flag, EventLoopEventFlagsBack);
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
if(event->key == InputKeyBack) {
|
||||
furi_event_flag_set(app->event_flag, EventLoopEventFlagsExit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function is executed each time a new event flag is inserted in the input event flag.
|
||||
static void
|
||||
event_loop_event_flags_app_event_flags_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_assert(context);
|
||||
EventLoopEventFlagsApp* app = context;
|
||||
|
||||
furi_assert(object == app->event_flag);
|
||||
|
||||
EventLoopEventFlags events =
|
||||
furi_event_flag_wait(app->event_flag, EVENT_LOOP_EVENT_FLAGS_MASK, FuriFlagWaitAny, 0);
|
||||
furi_check((events) != 0);
|
||||
|
||||
if(events & EventLoopEventFlagsOk) {
|
||||
FURI_LOG_I(TAG, "Press \"Ok\"");
|
||||
}
|
||||
if(events & EventLoopEventFlagsUp) {
|
||||
FURI_LOG_I(TAG, "Press \"Up\"");
|
||||
}
|
||||
if(events & EventLoopEventFlagsDown) {
|
||||
FURI_LOG_I(TAG, "Press \"Down\"");
|
||||
}
|
||||
if(events & EventLoopEventFlagsLeft) {
|
||||
FURI_LOG_I(TAG, "Press \"Left\"");
|
||||
}
|
||||
if(events & EventLoopEventFlagsRight) {
|
||||
FURI_LOG_I(TAG, "Press \"Right\"");
|
||||
}
|
||||
if(events & EventLoopEventFlagsBack) {
|
||||
FURI_LOG_I(TAG, "Press \"Back\"");
|
||||
}
|
||||
if(events & EventLoopEventFlagsExit) {
|
||||
FURI_LOG_I(TAG, "Exit App");
|
||||
furi_event_loop_stop(app->event_loop);
|
||||
}
|
||||
}
|
||||
|
||||
static EventLoopEventFlagsApp* event_loop_event_flags_app_alloc(void) {
|
||||
EventLoopEventFlagsApp* app = malloc(sizeof(EventLoopEventFlagsApp));
|
||||
|
||||
// Create event loop instances.
|
||||
app->event_loop = furi_event_loop_alloc();
|
||||
// Create event flag instances.
|
||||
app->event_flag = furi_event_flag_alloc();
|
||||
|
||||
// Create GUI instance.
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->view_port = view_port_alloc();
|
||||
// Gain exclusive access to the input events
|
||||
view_port_input_callback_set(app->view_port, event_loop_event_flags_app_input_callback, app);
|
||||
gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen);
|
||||
|
||||
// Notify the event loop about incoming messages in the event flag
|
||||
furi_event_loop_subscribe_event_flag(
|
||||
app->event_loop,
|
||||
app->event_flag,
|
||||
FuriEventLoopEventIn | FuriEventLoopEventFlagEdge,
|
||||
event_loop_event_flags_app_event_flags_callback,
|
||||
app);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
static void event_loop_event_flags_app_free(EventLoopEventFlagsApp* app) {
|
||||
gui_remove_view_port(app->gui, app->view_port);
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
app->gui = NULL;
|
||||
|
||||
// Delete all instances
|
||||
view_port_free(app->view_port);
|
||||
app->view_port = NULL;
|
||||
|
||||
// IMPORTANT: The user code MUST unsubscribe from all events before deleting the event loop.
|
||||
// Failure to do so will result in a crash.
|
||||
furi_event_loop_unsubscribe(app->event_loop, app->event_flag);
|
||||
|
||||
furi_event_flag_free(app->event_flag);
|
||||
app->event_flag = NULL;
|
||||
|
||||
furi_event_loop_free(app->event_loop);
|
||||
app->event_loop = NULL;
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
static void event_loop_event_flags_app_run(EventLoopEventFlagsApp* app) {
|
||||
FURI_LOG_I(TAG, "Press keys to see them printed here.");
|
||||
FURI_LOG_I(TAG, "Quickly press different keys to generate events.");
|
||||
FURI_LOG_I(TAG, "Long press \"Back\" to exit app.");
|
||||
|
||||
// Run the application event loop. This call will block until the application is about to exit.
|
||||
furi_event_loop_run(app->event_loop);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* vvv START HERE vvv
|
||||
*
|
||||
* The application's entry point - referenced in application.fam
|
||||
*******************************************************************/
|
||||
int32_t example_event_loop_event_flags_app(void* arg) {
|
||||
UNUSED(arg);
|
||||
|
||||
EventLoopEventFlagsApp* app = event_loop_event_flags_app_alloc();
|
||||
event_loop_event_flags_app_run(app);
|
||||
event_loop_event_flags_app_free(app);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -52,7 +52,7 @@ typedef struct {
|
|||
*/
|
||||
|
||||
// This function is executed each time the data is taken out of the stream buffer. It is used to restart the worker timer.
|
||||
static bool
|
||||
static void
|
||||
event_loop_multi_app_stream_buffer_worker_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_assert(context);
|
||||
EventLoopMultiAppWorker* worker = context;
|
||||
|
@ -62,8 +62,6 @@ static bool
|
|||
FURI_LOG_I(TAG, "Data was removed from buffer");
|
||||
// Restart the timer to generate another block of random data.
|
||||
furi_event_loop_timer_start(worker->timer, WORKER_DATA_INTERVAL_MS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This function is executed when the worker timer expires. The timer will NOT restart automatically
|
||||
|
@ -152,7 +150,7 @@ static void event_loop_multi_app_input_callback(InputEvent* event, void* context
|
|||
}
|
||||
|
||||
// This function is executed each time new data is available in the stream buffer.
|
||||
static bool
|
||||
static void
|
||||
event_loop_multi_app_stream_buffer_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_assert(context);
|
||||
EventLoopMultiApp* app = context;
|
||||
|
@ -172,12 +170,10 @@ static bool
|
|||
|
||||
FURI_LOG_I(TAG, "Received data: %s", furi_string_get_cstr(tmp_str));
|
||||
furi_string_free(tmp_str);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This function is executed each time a new message is inserted in the input queue.
|
||||
static bool event_loop_multi_app_input_queue_callback(FuriEventLoopObject* object, void* context) {
|
||||
static void event_loop_multi_app_input_queue_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_assert(context);
|
||||
EventLoopMultiApp* app = context;
|
||||
|
||||
|
@ -222,8 +218,6 @@ static bool event_loop_multi_app_input_queue_callback(FuriEventLoopObject* objec
|
|||
// Not a long press, just print the key's name.
|
||||
FURI_LOG_I(TAG, "Short press: %s", input_get_key_name(event.key));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This function is executed each time the countdown timer expires.
|
||||
|
|
|
@ -59,7 +59,7 @@ static int32_t event_loop_mutex_app_worker_thread(void* context) {
|
|||
}
|
||||
|
||||
// This function is being run each time when the mutex gets released
|
||||
static bool event_loop_mutex_app_event_callback(FuriEventLoopObject* object, void* context) {
|
||||
static void event_loop_mutex_app_event_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
EventLoopMutexApp* app = context;
|
||||
|
@ -82,8 +82,6 @@ static bool event_loop_mutex_app_event_callback(FuriEventLoopObject* object, voi
|
|||
MUTEX_EVENT_AND_FLAGS,
|
||||
event_loop_mutex_app_event_callback,
|
||||
app);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static EventLoopMutexApp* event_loop_mutex_app_alloc(void) {
|
||||
|
|
|
@ -54,7 +54,7 @@ static int32_t event_loop_stream_buffer_app_worker_thread(void* context) {
|
|||
}
|
||||
|
||||
// This function is being run each time when the number of bytes in the buffer is above its trigger level.
|
||||
static bool
|
||||
static void
|
||||
event_loop_stream_buffer_app_event_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_assert(context);
|
||||
EventLoopStreamBufferApp* app = context;
|
||||
|
@ -76,8 +76,6 @@ static bool
|
|||
|
||||
FURI_LOG_I(TAG, "Received data: %s", furi_string_get_cstr(tmp_str));
|
||||
furi_string_free(tmp_str);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static EventLoopStreamBufferApp* event_loop_stream_buffer_app_alloc(void) {
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
# Number Input
|
||||
# Number Input {#example_number_input}
|
||||
|
||||
Simple keyboard that limits user inputs to a full number (integer). Useful to enforce correct entries without the need of intense validations after a user input.
|
||||
Simple keyboard that limits user inputs to a full number (integer). Useful to enforce correct entries without the need for intense validations after a user input.
|
||||
|
||||
Definition of min/max values is required. Numbers are of type int32_t. If negative numbers are allowed withing min - max, an additional button is displayed to switch the sign between + and -.
|
||||
## Source code
|
||||
|
||||
It is also possible to define a header text, shown in this example app with the 3 different input options.
|
||||
Source code for this example can be found [here](https://github.com/flipperdevices/flipperzero-firmware/tree/dev/applications/examples/example_number_input).
|
||||
|
||||
## General principle
|
||||
|
||||
Definition of min/max values is required. Numbers are of type int32_t. If negative numbers are allowed within min - max, an additional button is displayed to switch the sign between + and -.
|
||||
|
||||
It is also possible to define a header text, as shown in this example app with the 3 different input options.
|
|
@ -94,6 +94,11 @@ static void bad_usb_save_settings(BadUsbApp* app) {
|
|||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
void bad_usb_set_interface(BadUsbApp* app, BadUsbHidInterface interface) {
|
||||
app->interface = interface;
|
||||
bad_usb_view_set_interface(app->bad_usb_view, interface);
|
||||
}
|
||||
|
||||
BadUsbApp* bad_usb_app_alloc(char* arg) {
|
||||
BadUsbApp* app = malloc(sizeof(BadUsbApp));
|
||||
|
||||
|
@ -125,7 +130,11 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
|
|||
// Custom Widget
|
||||
app->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget));
|
||||
app->view_dispatcher, BadUsbAppViewWidget, widget_get_view(app->widget));
|
||||
|
||||
// Popup
|
||||
app->popup = popup_alloc();
|
||||
view_dispatcher_add_view(app->view_dispatcher, BadUsbAppViewPopup, popup_get_view(app->popup));
|
||||
|
||||
app->var_item_list = variable_item_list_alloc();
|
||||
view_dispatcher_add_view(
|
||||
|
@ -171,9 +180,13 @@ void bad_usb_app_free(BadUsbApp* app) {
|
|||
bad_usb_view_free(app->bad_usb_view);
|
||||
|
||||
// Custom Widget
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWidget);
|
||||
widget_free(app->widget);
|
||||
|
||||
// Popup
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewPopup);
|
||||
popup_free(app->popup);
|
||||
|
||||
// Config menu
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig);
|
||||
variable_item_list_free(app->var_item_list);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <notification/notification_messages.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include "views/bad_usb_view.h"
|
||||
#include <furi_hal_usb.h>
|
||||
|
||||
|
@ -33,6 +34,7 @@ struct BadUsbApp {
|
|||
NotificationApp* notifications;
|
||||
DialogsApp* dialogs;
|
||||
Widget* widget;
|
||||
Popup* popup;
|
||||
VariableItemList* var_item_list;
|
||||
|
||||
BadUsbAppError error;
|
||||
|
@ -46,7 +48,10 @@ struct BadUsbApp {
|
|||
};
|
||||
|
||||
typedef enum {
|
||||
BadUsbAppViewError,
|
||||
BadUsbAppViewWidget,
|
||||
BadUsbAppViewPopup,
|
||||
BadUsbAppViewWork,
|
||||
BadUsbAppViewConfig,
|
||||
} BadUsbAppView;
|
||||
|
||||
void bad_usb_set_interface(BadUsbApp* app, BadUsbHidInterface interface);
|
||||
|
|
Binary file not shown.
|
@ -1,12 +1,17 @@
|
|||
REM This is BadUSB demo script for ChromeOS by kowalski7cc
|
||||
REM This is BadUSB demo script for Chrome and ChromeOS by kowalski7cc
|
||||
|
||||
REM Exit from Overview
|
||||
ESC
|
||||
REM Open a new tab
|
||||
CTRL t
|
||||
REM wait for some slower chromebooks
|
||||
DELAY 1000
|
||||
REM Make sure we have omnibox focus
|
||||
CTRL l
|
||||
DELAY 200
|
||||
REM Open an empty editable page
|
||||
DEFAULT_DELAY 50
|
||||
STRING data:text/html, <html contenteditable autofocus><style>body{font-family:monospace;}
|
||||
STRING data:text/html, <html contenteditable autofocus><title>Flipper Zero BadUSB Demo</title><style>body{font-family:monospace;}
|
||||
ENTER
|
||||
DELAY 500
|
||||
|
||||
|
|
|
@ -5,14 +5,22 @@ REM Check the `lsusb` command to know your own devices IDs
|
|||
|
||||
REM This is BadUSB demo script for Linux/Gnome
|
||||
|
||||
REM Exit from Overview
|
||||
ESC
|
||||
DELAY 200
|
||||
REM Open terminal window
|
||||
DELAY 1000
|
||||
ALT F2
|
||||
DELAY 500
|
||||
STRING gnome-terminal --maximize
|
||||
DELAY 500
|
||||
DELAY 1000
|
||||
REM Let's guess user terminal, based on (almost) glib order with ptyxis now default in Fedora 41
|
||||
STRING sh -c "xdg-terminal-exec||kgx||ptyxis||gnome-terminal||mate-terminal||xfce4-terminal||tilix||konsole||xterm"
|
||||
DELAY 300
|
||||
ENTER
|
||||
REM It can take a bit to open the correct terminal
|
||||
DELAY 1500
|
||||
|
||||
REM Make sure we are running in a POSIX-compliant shell
|
||||
STRING env sh
|
||||
ENTER
|
||||
DELAY 750
|
||||
|
||||
REM Clear the screen in case some banner was displayed
|
||||
STRING clear
|
||||
|
|
|
@ -2,31 +2,13 @@
|
|||
|
||||
enum SubmenuIndex {
|
||||
ConfigIndexKeyboardLayout,
|
||||
ConfigIndexInterface,
|
||||
ConfigIndexBleUnpair,
|
||||
};
|
||||
|
||||
const char* const interface_mode_text[2] = {
|
||||
"USB",
|
||||
"BLE",
|
||||
};
|
||||
|
||||
void bad_usb_scene_config_select_callback(void* context, uint32_t index) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
if(index != ConfigIndexInterface) {
|
||||
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, index);
|
||||
}
|
||||
}
|
||||
|
||||
void bad_usb_scene_config_interface_callback(VariableItem* item) {
|
||||
BadUsbApp* bad_usb = variable_item_get_context(item);
|
||||
furi_assert(bad_usb);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, interface_mode_text[index]);
|
||||
bad_usb->interface = index;
|
||||
|
||||
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, ConfigIndexInterface);
|
||||
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, index);
|
||||
}
|
||||
|
||||
static void draw_menu(BadUsbApp* bad_usb) {
|
||||
|
@ -36,16 +18,7 @@ static void draw_menu(BadUsbApp* bad_usb) {
|
|||
|
||||
variable_item_list_add(var_item_list, "Keyboard Layout (global)", 0, NULL, NULL);
|
||||
|
||||
VariableItem* item = variable_item_list_add(
|
||||
var_item_list, "Interface", 2, bad_usb_scene_config_interface_callback, bad_usb);
|
||||
if(bad_usb->interface == BadUsbHidInterfaceUsb) {
|
||||
variable_item_set_current_value_index(item, 0);
|
||||
variable_item_set_current_value_text(item, interface_mode_text[0]);
|
||||
} else {
|
||||
variable_item_set_current_value_index(item, 1);
|
||||
variable_item_set_current_value_text(item, interface_mode_text[1]);
|
||||
variable_item_list_add(var_item_list, "Remove Pairing", 0, NULL, NULL);
|
||||
}
|
||||
variable_item_list_add(var_item_list, "Remove Pairing", 0, NULL, NULL);
|
||||
}
|
||||
|
||||
void bad_usb_scene_config_on_enter(void* context) {
|
||||
|
@ -68,10 +41,8 @@ bool bad_usb_scene_config_on_event(void* context, SceneManagerEvent event) {
|
|||
consumed = true;
|
||||
if(event.event == ConfigIndexKeyboardLayout) {
|
||||
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigLayout);
|
||||
} else if(event.event == ConfigIndexInterface) {
|
||||
draw_menu(bad_usb);
|
||||
} else if(event.event == ConfigIndexBleUnpair) {
|
||||
bad_usb_hid_ble_remove_pairing();
|
||||
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfirmUnpair);
|
||||
} else {
|
||||
furi_crash("Unknown key type");
|
||||
}
|
||||
|
|
|
@ -3,3 +3,5 @@ ADD_SCENE(bad_usb, work, Work)
|
|||
ADD_SCENE(bad_usb, error, Error)
|
||||
ADD_SCENE(bad_usb, config, Config)
|
||||
ADD_SCENE(bad_usb, config_layout, ConfigLayout)
|
||||
ADD_SCENE(bad_usb, confirm_unpair, ConfirmUnpair)
|
||||
ADD_SCENE(bad_usb, unpair_done, UnpairDone)
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
#include "../bad_usb_app_i.h"
|
||||
|
||||
void bad_usb_scene_confirm_unpair_widget_callback(
|
||||
GuiButtonType type,
|
||||
InputType input_type,
|
||||
void* context) {
|
||||
UNUSED(input_type);
|
||||
SceneManagerEvent event = {.type = SceneManagerEventTypeCustom, .event = type};
|
||||
bad_usb_scene_confirm_unpair_on_event(context, event);
|
||||
}
|
||||
|
||||
void bad_usb_scene_confirm_unpair_on_enter(void* context) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
Widget* widget = bad_usb->widget;
|
||||
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeLeft, "Cancel", bad_usb_scene_confirm_unpair_widget_callback, context);
|
||||
widget_add_button_element(
|
||||
widget,
|
||||
GuiButtonTypeRight,
|
||||
"Unpair",
|
||||
bad_usb_scene_confirm_unpair_widget_callback,
|
||||
context);
|
||||
|
||||
widget_add_text_box_element(
|
||||
widget, 0, 0, 128, 64, AlignCenter, AlignTop, "\e#Unpair the Device?\e#\n", false);
|
||||
|
||||
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewWidget);
|
||||
}
|
||||
|
||||
bool bad_usb_scene_confirm_unpair_on_event(void* context, SceneManagerEvent event) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
SceneManager* scene_manager = bad_usb->scene_manager;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
consumed = true;
|
||||
if(event.event == GuiButtonTypeRight) {
|
||||
scene_manager_next_scene(scene_manager, BadUsbSceneUnpairDone);
|
||||
} else if(event.event == GuiButtonTypeLeft) {
|
||||
scene_manager_previous_scene(scene_manager);
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void bad_usb_scene_confirm_unpair_on_exit(void* context) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
Widget* widget = bad_usb->widget;
|
||||
|
||||
widget_reset(widget);
|
||||
}
|
|
@ -43,7 +43,7 @@ void bad_usb_scene_error_on_enter(void* context) {
|
|||
"Disconnect from\nPC or phone to\nuse this function.");
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewError);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewWidget);
|
||||
}
|
||||
|
||||
bool bad_usb_scene_error_on_event(void* context, SceneManagerEvent event) {
|
||||
|
|
39
applications/main/bad_usb/scenes/bad_usb_scene_unpair_done.c
Normal file
39
applications/main/bad_usb/scenes/bad_usb_scene_unpair_done.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include "../bad_usb_app_i.h"
|
||||
|
||||
static void bad_usb_scene_unpair_done_popup_callback(void* context) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
scene_manager_search_and_switch_to_previous_scene(bad_usb->scene_manager, BadUsbSceneConfig);
|
||||
}
|
||||
|
||||
void bad_usb_scene_unpair_done_on_enter(void* context) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
Popup* popup = bad_usb->popup;
|
||||
|
||||
bad_usb_hid_ble_remove_pairing();
|
||||
|
||||
popup_set_icon(popup, 48, 4, &I_DolphinDone_80x58);
|
||||
popup_set_header(popup, "Done", 20, 19, AlignLeft, AlignBottom);
|
||||
popup_set_callback(popup, bad_usb_scene_unpair_done_popup_callback);
|
||||
popup_set_context(popup, bad_usb);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_enable_timeout(popup);
|
||||
|
||||
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewPopup);
|
||||
}
|
||||
|
||||
bool bad_usb_scene_unpair_done_on_event(void* context, SceneManagerEvent event) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
UNUSED(bad_usb);
|
||||
UNUSED(event);
|
||||
bool consumed = false;
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void bad_usb_scene_unpair_done_on_exit(void* context) {
|
||||
BadUsbApp* bad_usb = context;
|
||||
Popup* popup = bad_usb->popup;
|
||||
UNUSED(popup);
|
||||
|
||||
popup_reset(popup);
|
||||
}
|
|
@ -20,14 +20,27 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
|
|||
bad_usb_script_close(app->bad_usb_script);
|
||||
app->bad_usb_script = NULL;
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig);
|
||||
if(app->interface == BadUsbHidInterfaceBle) {
|
||||
scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig);
|
||||
} else {
|
||||
scene_manager_next_scene(app->scene_manager, BadUsbSceneConfigLayout);
|
||||
}
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event.event == InputKeyOk) {
|
||||
bad_usb_script_start_stop(app->bad_usb_script);
|
||||
consumed = true;
|
||||
} else if(event.event == InputKeyRight) {
|
||||
bad_usb_script_pause_resume(app->bad_usb_script);
|
||||
if(bad_usb_view_is_idle_state(app->bad_usb_view)) {
|
||||
bad_usb_set_interface(
|
||||
app,
|
||||
app->interface == BadUsbHidInterfaceBle ? BadUsbHidInterfaceUsb :
|
||||
BadUsbHidInterfaceBle);
|
||||
bad_usb_script_close(app->bad_usb_script);
|
||||
app->bad_usb_script = bad_usb_script_open(app->file_path, app->interface);
|
||||
} else {
|
||||
bad_usb_script_pause_resume(app->bad_usb_script);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
|
@ -39,6 +52,8 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
|
|||
void bad_usb_scene_work_on_enter(void* context) {
|
||||
BadUsbApp* app = context;
|
||||
|
||||
bad_usb_view_set_interface(app->bad_usb_view, app->interface);
|
||||
|
||||
app->bad_usb_script = bad_usb_script_open(app->file_path, app->interface);
|
||||
bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ typedef struct {
|
|||
BadUsbState state;
|
||||
bool pause_wait;
|
||||
uint8_t anim_frame;
|
||||
BadUsbHidInterface interface;
|
||||
} BadUsbModel;
|
||||
|
||||
static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
|
||||
|
@ -40,14 +41,24 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
|
|||
|
||||
furi_string_reset(disp_str);
|
||||
|
||||
canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22);
|
||||
if(model->interface == BadUsbHidInterfaceBle) {
|
||||
canvas_draw_icon(canvas, 22, 24, &I_Bad_BLE_48x22);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22);
|
||||
}
|
||||
|
||||
BadUsbWorkerState state = model->state.state;
|
||||
|
||||
if((state == BadUsbStateIdle) || (state == BadUsbStateDone) ||
|
||||
(state == BadUsbStateNotConnected)) {
|
||||
elements_button_center(canvas, "Run");
|
||||
elements_button_left(canvas, "Config");
|
||||
if(model->interface == BadUsbHidInterfaceBle) {
|
||||
elements_button_right(canvas, "USB");
|
||||
elements_button_left(canvas, "Config");
|
||||
} else {
|
||||
elements_button_right(canvas, "BLE");
|
||||
elements_button_left(canvas, "Layout");
|
||||
}
|
||||
} else if((state == BadUsbStateRunning) || (state == BadUsbStateDelay)) {
|
||||
elements_button_center(canvas, "Stop");
|
||||
if(!model->pause_wait) {
|
||||
|
@ -266,6 +277,10 @@ void bad_usb_view_set_state(BadUsb* bad_usb, BadUsbState* st) {
|
|||
true);
|
||||
}
|
||||
|
||||
void bad_usb_view_set_interface(BadUsb* bad_usb, BadUsbHidInterface interface) {
|
||||
with_view_model(bad_usb->view, BadUsbModel * model, { model->interface = interface; }, true);
|
||||
}
|
||||
|
||||
bool bad_usb_view_is_idle_state(BadUsb* bad_usb) {
|
||||
bool is_idle = false;
|
||||
with_view_model(
|
||||
|
|
|
@ -23,4 +23,6 @@ void bad_usb_view_set_layout(BadUsb* bad_usb, const char* layout);
|
|||
|
||||
void bad_usb_view_set_state(BadUsb* bad_usb, BadUsbState* st);
|
||||
|
||||
void bad_usb_view_set_interface(BadUsb* bad_usb, BadUsbHidInterface interface);
|
||||
|
||||
bool bad_usb_view_is_idle_state(BadUsb* bad_usb);
|
||||
|
|
|
@ -10,5 +10,4 @@ typedef enum {
|
|||
|
||||
GpioUsbUartEventConfig,
|
||||
GpioUsbUartEventConfigSet,
|
||||
GpioUsbUartEventStop,
|
||||
} GpioCustomEvent;
|
||||
|
|
|
@ -3,4 +3,3 @@ ADD_SCENE(gpio, test, Test)
|
|||
ADD_SCENE(gpio, usb_uart, UsbUart)
|
||||
ADD_SCENE(gpio, usb_uart_cfg, UsbUartCfg)
|
||||
ADD_SCENE(gpio, usb_uart_close_rpc, UsbUartCloseRpc)
|
||||
ADD_SCENE(gpio, exit_confirm, ExitConfirm)
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
#include "gpio_app_i.h"
|
||||
|
||||
void gpio_scene_exit_confirm_dialog_callback(DialogExResult result, void* context) {
|
||||
GpioApp* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void gpio_scene_exit_confirm_on_enter(void* context) {
|
||||
GpioApp* app = context;
|
||||
DialogEx* dialog = app->dialog;
|
||||
|
||||
dialog_ex_set_context(dialog, app);
|
||||
dialog_ex_set_left_button_text(dialog, "Exit");
|
||||
dialog_ex_set_right_button_text(dialog, "Stay");
|
||||
dialog_ex_set_header(dialog, "Exit USB-UART?", 22, 12, AlignLeft, AlignTop);
|
||||
dialog_ex_set_result_callback(dialog, gpio_scene_exit_confirm_dialog_callback);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewExitConfirm);
|
||||
}
|
||||
|
||||
bool gpio_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||
GpioApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
if(consumed && event.event == DialogExResultLeft) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventStop);
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void gpio_scene_exit_confirm_on_exit(void* context) {
|
||||
GpioApp* app = context;
|
||||
|
||||
// Clean view
|
||||
dialog_ex_reset(app->dialog);
|
||||
}
|
|
@ -6,12 +6,7 @@ typedef struct {
|
|||
UsbUartState state;
|
||||
} SceneUsbUartBridge;
|
||||
|
||||
static SceneUsbUartBridge* scene_usb_uart;
|
||||
|
||||
typedef enum {
|
||||
UsbUartSceneStateInitialize,
|
||||
UsbUartSceneStateKeep,
|
||||
} UsbUartSceneState;
|
||||
static SceneUsbUartBridge* scene_usb_uart = NULL;
|
||||
|
||||
void gpio_scene_usb_uart_callback(GpioCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
|
@ -19,11 +14,21 @@ void gpio_scene_usb_uart_callback(GpioCustomEvent event, void* context) {
|
|||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void gpio_scene_usb_uart_dialog_callback(DialogExResult result, void* context) {
|
||||
GpioApp* app = context;
|
||||
if(result == DialogExResultLeft) {
|
||||
usb_uart_disable(app->usb_uart_bridge);
|
||||
free(scene_usb_uart);
|
||||
scene_usb_uart = NULL;
|
||||
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, GpioSceneStart);
|
||||
} else {
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewUsbUart);
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_scene_usb_uart_on_enter(void* context) {
|
||||
GpioApp* app = context;
|
||||
UsbUartSceneState state =
|
||||
scene_manager_get_scene_state(app->scene_manager, GpioAppViewUsbUart);
|
||||
if(state == UsbUartSceneStateInitialize) {
|
||||
if(!scene_usb_uart) {
|
||||
scene_usb_uart = malloc(sizeof(SceneUsbUartBridge));
|
||||
scene_usb_uart->cfg.vcp_ch = 0;
|
||||
scene_usb_uart->cfg.uart_ch = 0;
|
||||
|
@ -37,7 +42,6 @@ void gpio_scene_usb_uart_on_enter(void* context) {
|
|||
usb_uart_get_state(app->usb_uart_bridge, &scene_usb_uart->state);
|
||||
|
||||
gpio_usb_uart_set_callback(app->gpio_usb_uart, gpio_scene_usb_uart_callback, app);
|
||||
scene_manager_set_scene_state(app->scene_manager, GpioSceneUsbUart, 0);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewUsbUart);
|
||||
notification_message(app->notifications, &sequence_display_backlight_enforce_on);
|
||||
}
|
||||
|
@ -45,19 +49,16 @@ void gpio_scene_usb_uart_on_enter(void* context) {
|
|||
bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) {
|
||||
GpioApp* app = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GpioUsbUartEventConfig) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, GpioSceneUsbUart, UsbUartSceneStateKeep);
|
||||
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCfg);
|
||||
} else if(event.event == GpioUsbUartEventStop) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, GpioSceneUsbUart, UsbUartSceneStateInitialize);
|
||||
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, GpioSceneStart);
|
||||
}
|
||||
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCfg);
|
||||
return true;
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
scene_manager_set_scene_state(app->scene_manager, GpioSceneUsbUart, UsbUartSceneStateKeep);
|
||||
scene_manager_next_scene(app->scene_manager, GpioSceneExitConfirm);
|
||||
DialogEx* dialog = app->dialog;
|
||||
dialog_ex_set_context(dialog, app);
|
||||
dialog_ex_set_left_button_text(dialog, "Exit");
|
||||
dialog_ex_set_right_button_text(dialog, "Stay");
|
||||
dialog_ex_set_header(dialog, "Exit USB-UART?", 22, 12, AlignLeft, AlignTop);
|
||||
dialog_ex_set_result_callback(dialog, gpio_scene_usb_uart_dialog_callback);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewExitConfirm);
|
||||
return true;
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
uint32_t tx_cnt_last = scene_usb_uart->state.tx_cnt;
|
||||
|
@ -75,10 +76,5 @@ bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) {
|
|||
|
||||
void gpio_scene_usb_uart_on_exit(void* context) {
|
||||
GpioApp* app = context;
|
||||
uint32_t state = scene_manager_get_scene_state(app->scene_manager, GpioSceneUsbUart);
|
||||
if(state == UsbUartSceneStateInitialize) {
|
||||
usb_uart_disable(app->usb_uart_bridge);
|
||||
free(scene_usb_uart);
|
||||
}
|
||||
notification_message(app->notifications, &sequence_display_backlight_enforce_auto);
|
||||
}
|
||||
|
|
|
@ -991,31 +991,31 @@ type: raw
|
|||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3302 1639 405 423 407 420 410 1234 405 421 409 1210 440 387 432 420 410 417 413 1231 408 1238 412 388 431 422 408 392 438 1233 406 1238 412 389 430 396 434 419 411 390 440 413 406 394 436 391 439 388 431 421 409 417 413 414 405 421 409 392 438 1233 406 421 409 417 413 414 405 395 435 418 412 388 432 421 409 1236 414 387 432 420 410 390 440 388 431 1213 437 1208 431 1239 411 1234 405 1213 437 1208 431 1214 436 1235 415 386 433 420 410 1234 405 422 408 418 412 389 431 396 434 1211 439 388 432 422 408 418 412 1233 406 1238 412 415 404 422 408 1237 413 388 432 422 408 1236 414 1205 434 1210 440 1205 434 392 438 390 440 1231 408 392 438 415 404 396 434 392 438 415 404 422 408 419 411 416 414 412 407 394 436 417 413 414 405 421 409 417 413 1232 407 419 411 390 440 1204 435 418 412 415 415 412 407 419 411 1208 431 421 409 418 412 388 432 421 409 392 438 415 404 395 435 1211 439 388 432 1213 437 416 414 386 433 1212 438 415 404 396 434 392 438 416 414 413 406 420 410 417 413 1231 409 418 412 389 430 1240 410 391 439 1205 434 420 410 390 440 387 432 420 410 417 413
|
||||
#
|
||||
#
|
||||
name: Cool_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3293 1649 405 396 434 419 411 1207 432 395 435 1236 414 413 406 394 436 417 413 1232 407 1212 438 415 404 396 434 419 411 1234 405 1239 411 417 413 414 405 421 409 419 411 389 430 423 407 393 437 416 414 387 432 394 436 417 413 388 431 421 409 1236 414 387 432 421 409 418 412 414 405 422 408 418 412 415 404 1240 410 391 439 414 405 421 409 419 411 1234 405 1239 411 1208 431 1239 411 1235 404 1214 436 1210 440 1205 434 419 411 416 414 1204 435 418 412 415 404 396 434 393 437 1235 404 396 434 420 410 416 414 1231 408 1210 440 387 432 421 409 1235 415 414 405 395 435 418 412 1232 407 420 410 1208 431 422 408 1237 413 415 404 396 434 419 411 416 414 413 406 420 410 417 413 414 405 421 409 418 412 415 404 422 408 419 411 416 414 413 406 1238 412 415 404 422 408 1237 413 414 405 421 409 418 412 416 414 1231 408 418 412 415 404 422 408 419 411 416 414 413 406 420 410 1235 404 423 407 420 410 1234 405 422 408 1210 440 414 405 421 409 392 438 415 404 422 408 420 410 417 413 1231 408 419 411 416 414 413 406 1237 413 415 404 1239 411 417 413 1232 407 420 410 417 413
|
||||
#
|
||||
#
|
||||
name: Cool_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3302 1614 440 414 405 421 409 1235 414 413 406 1238 411 415 404 422 408 419 411 1234 405 1240 409 418 412 415 404 422 408 1237 412 1232 407 420 410 417 413 414 405 422 408 419 411 416 414 413 406 420 410 417 413 414 405 421 409 418 412 415 404 1239 410 418 412 415 404 422 408 419 411 416 414 413 406 420 410 1234 405 422 408 419 411 416 414 414 405 1239 411 1207 432 1239 410 1235 414 1230 409 1236 413 1232 407 1237 412 415 415 412 407 1237 412 414 405 422 408 419 411 416 414 1231 408 419 411 416 414 413 406 1238 411 1206 433 421 409 418 412 1206 433 421 409 418 412 1206 433 1238 412 1207 432 1213 436 390 440 1232 407 420 410 417 413 414 405 421 409 418 412 415 404 422 408 419 411 416 414 413 406 421 409 418 412 415 404 422 408 419 411 1233 406 421 409 418 412 1232 407 420 410 418 412 389 430 422 408 1210 440 414 405 395 435 418 412 415 404 423 407 420 410 416 414 414 405 422 408 418 412 415 404 1240 409 1235 414 413 406 420 410 417 413 414 405 422 408 419 411 416 414 1231 408 418 412 415 404 1240 409 1209 440 387 432 1212 437 1234 405 1214 435 1209 440 1204 435
|
||||
#
|
||||
#
|
||||
name: Heat_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3301 1615 439 415 404 422 408 1210 439 414 405 1239 410 416 414 414 405 395 435 1209 440 1205 434 419 411 417 413 414 405 1212 437 1207 432 422 408 419 411 416 414 414 405 421 409 418 412 415 404 422 408 393 437 416 414 413 406 420 410 417 413 1205 434 420 410 417 413 414 405 421 409 418 412 415 404 422 408 1210 439 414 405 422 408 419 411 417 413 1205 434 1236 413 1206 433 1211 438 1207 432 1212 437 1209 440 1204 435 418 412 415 415 1204 435 418 412 415 404 422 408 419 411 1208 441 412 407 420 410 417 413 1205 434 1237 412 414 405 422 408 1210 439 415 404 396 434 419 411 1207 432 1213 436 417 413 1205 434 420 410 417 413 1231 408 419 411 416 414 413 406 421 409 418 412 414 405 422 408 419 411 415 404 424 406 421 409 418 412 415 404 1239 410 417 413 414 405 1239 410 416 414 413 406 422 408 419 411 1233 406 421 409 418 412 415 404 423 407 419 411 416 414 413 406 1238 411 416 414 413 406 421 409 1235 414 1230 409 418 412 415 415 412 407 420 410 417 413 414 405 422 408 1236 413 413 406 421 409 1235 414 1204 435 1210 439 1206 433 1212 437 1207 432 395 435 1236 413
|
||||
#
|
||||
#
|
||||
name: Heat_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3295 1646 408 420 410 390 440 1205 434 393 437 1234 405 421 409 419 411 415 415 1230 409 1210 440 414 405 421 409 418 412 1233 406 1212 437 416 414 413 406 394 436 418 412 415 404 422 408 393 437 416 414 413 406 420 410 417 413 414 405 421 409 1236 413 414 405 421 409 418 412 415 404 423 407 419 411 416 414 1231 408 418 412 415 415 412 407 421 409 1235 414 1204 435 1209 441 1205 434 1210 440 1205 434 1212 437 1207 432 395 435 419 411 1233 406 421 409 418 412 415 404 422 408 1238 411 415 404 396 434 419 411 1234 405 1239 410 417 413 414 405 1213 436 417 413 414 405 1213 436 1235 404 1214 435 1209 441 413 406 421 409 418 412 1206 433 394 436 418 412 388 431 422 408 419 411 415 415 386 433 420 410 418 412 414 405 422 408 419 411 389 430 1241 408 418 412 415 404 1240 409 417 413 414 405 395 435 419 411 1233 406 395 435 418 412 415 404 422 408 419 411 416 414 413 406 421 409 1236 413 413 406 394 436 1235 414 1230 409 418 412 415 404 422 408 420 410 417 413 414 405 421 409 1236 413 413 406 420 410 417 413 1232 407 1237 412 416 414 1230 409 1236 413 1205 434 1210 439
|
||||
#
|
||||
#
|
||||
name: Off
|
||||
type: raw
|
||||
frequency: 38000
|
||||
|
@ -1029,25 +1029,25 @@ type: raw
|
|||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4349 4437 549 1615 551 1614 551 1614 551 1617 549 531 550 530 551 1615 550 531 550 532 549 530 551 531 550 530 551 1615 550 1614 551 531 550 1615 551 529 552 531 550 530 551 533 548 530 551 530 551 1616 549 1615 550 1616 550 1615 550 1614 551 1616 550 1615 551 1615 550 531 550 531 550 530 551 529 552 530 551 530 551 529 552 530 551 531 550 1615 550 532 549 1615 550 1616 550 531 550 531 550 530 551 530 551 529 552 532 549 530 551 530 551 531 550 529 552 531 550 1615 551 530 551 530 551 530 551 531 550 530 551 531 550 530 551 531 550 531 550 531 550 1616 550 1618 547 532 549 529 552 530 551 1615 551 1615 550 5379 4350 4436 550 1616 549 1615 551 1614 552 1615 550 529 552 530 551 1614 552 530 551 529 552 531 550 531 550 531 550 1614 552 1614 551 530 551 1615 550 530 551 530 551 530 551 530 551 531 550 532 549 1616 549 1615 551 1614 552 1615 550 1614 551 1616 550 1614 552 1615 550 529 552 530 551 530 551 530 551 531 550 531 550 530 551 530 551 531 550 1615 550 530 551 1615 550 1615 551 530 551 530 551 530 551 530 551 530 551 530 551 529 552 530 551 531 550 532 549 530 551 1615 551 531 550 530 551 530 551 530 551 530 551 531 550 531 550 531 550 530 551 531 550 1615 551 1615 551 532 549 531 550 531 550 1616 549 1614 552
|
||||
#
|
||||
#
|
||||
name: Cool_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4350 4438 549 1615 551 1614 552 1616 549 1616 550 530 551 531 550 1615 551 530 551 529 552 531 550 530 551 531 550 1614 551 1616 550 531 550 1616 549 530 551 531 550 530 551 529 552 530 551 531 550 1616 549 1616 550 1616 549 1616 550 1615 551 1614 551 1614 552 1615 551 530 551 531 550 530 551 531 550 531 550 529 552 532 549 531 550 530 551 1613 552 530 551 531 550 529 552 532 549 530 551 530 551 531 550 531 550 530 551 530 551 530 551 531 550 530 551 531 550 531 550 1615 551 529 552 530 551 530 551 530 551 530 551 530 551 530 551 530 551 532 549 531 550 531 550 532 549 531 550 531 550 530 551 530 551 5132 4351 4435 552 1616 550 1615 550 1615 551 1613 553 531 550 530 551 1615 550 530 551 531 550 531 550 530 551 532 549 1616 550 1616 549 530 551 1615 551 530 551 531 550 530 551 530 551 530 551 531 550 1615 551 1615 551 1614 551 1615 550 1615 551 1615 550 1615 550 1616 550 530 551 530 551 531 550 532 549 530 551 530 551 531 550 531 550 531 550 1615 550 530 551 530 551 530 551 529 552 531 550 530 551 531 550 531 550 530 551 530 551 531 550 530 551 530 551 530 551 531 550 1616 550 530 551 529 552 530 551 531 550 532 549 530 551 530 551 529 552 531 550 529 552 530 551 530 551 531 550 531 550 529 552 531 550
|
||||
#
|
||||
#
|
||||
name: Cool_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4350 4436 550 1617 549 1615 550 1615 550 1617 548 530 551 531 550 1615 551 531 550 531 550 530 551 530 551 531 550 1614 552 1615 550 530 551 1614 551 531 550 531 550 531 550 529 552 532 549 530 551 1617 549 1616 549 1615 551 1619 547 1615 550 1615 550 1616 549 1616 550 530 551 531 550 530 551 530 551 531 550 530 551 529 552 529 552 530 551 1617 548 533 548 1615 551 1613 552 530 551 531 550 531 550 530 551 530 551 532 549 531 550 531 550 530 551 531 550 531 550 531 550 1615 551 531 550 531 550 532 549 531 550 530 551 531 550 533 548 531 550 530 551 1617 548 1616 549 530 551 531 550 532 549 532 549 532 549 5200 4349 4436 550 1615 551 1615 551 1615 550 1616 550 531 550 530 551 1615 551 531 550 530 551 530 551 530 551 530 551 1616 549 1615 551 530 551 1615 551 531 550 531 550 530 551 531 550 531 550 531 550 1615 551 1616 550 1616 550 1615 550 1617 548 1616 549 1616 550 1615 550 531 550 530 551 531 550 531 550 532 549 530 551 531 550 531 550 532 549 1616 550 531 550 1616 550 1615 550 531 550 530 551 531 550 531 550 531 550 531 550 531 550 532 549 532 549 531 550 532 549 531 550 1616 550 531 550 530 551 532 549 532 549 530 551 532 549 531 550 532 549 531 550 1616 549 1617 549 531 550 530 551 531 550 532 549 532 549
|
||||
#
|
||||
#
|
||||
name: Heat_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4350 4437 547 1618 548 1620 546 1620 546 1619 547 534 547 535 546 1619 547 534 547 536 545 536 545 535 546 535 546 1619 547 1620 545 534 523 1644 546 535 522 559 546 535 546 534 547 535 546 535 545 1620 546 1620 546 1620 546 1619 547 1619 546 1619 547 1620 545 1620 546 535 546 534 547 537 520 558 523 558 547 534 547 536 521 559 522 559 522 1644 546 535 546 535 522 560 545 536 521 559 522 559 522 558 523 559 522 560 521 559 522 559 522 560 521 559 522 561 520 1644 521 1645 520 559 522 559 522 559 522 559 522 559 522 560 521 560 521 560 521 561 520 559 522 560 521 559 522 559 522 559 522 1644 522 559 522 5341 4349 4439 520 1645 521 1645 521 1646 519 1645 521 560 521 561 520 1645 521 560 521 560 521 559 522 560 521 561 520 1646 520 1645 521 561 520 1645 521 561 520 560 521 560 521 560 521 560 521 561 520 1644 522 1644 522 1645 520 1645 521 1645 521 1645 520 1646 520 1644 522 561 520 560 521 560 521 561 520 560 521 561 520 561 520 561 520 560 521 1646 520 562 519 561 520 561 520 562 519 560 521 560 521 561 520 561 520 560 521 560 521 561 520 560 521 560 521 562 519 1646 520 1645 521 561 520 561 520 561 520 560 521 560 521 561 520 560 521 559 522 560 521 561 520 561 520 560 521 562 519 559 522 1645 521 561 520
|
||||
#
|
||||
#
|
||||
name: Heat_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
|
@ -1061,33 +1061,79 @@ type: raw
|
|||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4387 4398 547 1609 547 530 547 1610 547 1611 545 530 547 530 547 1608 547 530 548 530 547 1611 545 532 546 532 547 1609 547 1610 547 531 547 1608 548 530 547 530 548 530 547 1610 546 1609 547 1610 547 1609 547 1609 547 1611 545 1609 548 1610 546 530 547 530 548 529 549 531 547 531 546 531 547 1608 548 1610 547 1608 548 533 545 1608 548 532 546 532 546 1611 545 532 547 532 545 530 548 1608 547 530 549 1608 547 1609 548 5203 4386 4398 547 1609 546 530 547 1609 546 1607 548 531 547 531 547 1609 547 530 548 531 547 1609 547 531 547 531 547 1608 547 1613 544 531 546 1609 547 531 547 531 547 532 546 1609 547 1609 546 1609 547 1609 547 1608 547 1608 548 1608 548 1609 547 530 547 530 547 530 547 532 546 530 547 530 548 1610 546 1608 547 1609 547 530 547 1609 547 530 547 530 548 1609 546 530 548 530 547 532 546 1610 546 531 546 1608 548 1608 548
|
||||
#
|
||||
#
|
||||
name: Cool_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4388 4398 547 1608 548 531 546 1610 546 1609 547 530 547 529 548 1608 548 532 547 530 548 1612 544 529 549 530 548 1608 547 1609 547 531 546 1608 548 1607 549 529 549 1608 549 1609 548 1608 548 1608 548 1611 545 1608 548 530 548 1609 547 531 547 530 548 530 548 531 547 529 549 530 548 530 547 531 547 530 548 530 547 529 549 530 548 532 547 530 548 1609 547 1610 547 1608 548 1609 547 1608 548 1608 548 1608 548 1608 548 5203 4388 4396 549 1609 547 529 549 1610 546 1608 548 529 549 530 547 1609 547 530 548 529 549 1608 548 531 547 532 546 1609 547 1609 547 530 548 1609 548 1609 548 529 548 1608 548 1609 548 1609 547 1609 547 1608 548 1609 547 532 546 1608 548 531 548 531 548 530 548 530 548 531 547 530 548 531 548 531 547 530 548 530 548 530 548 531 547 529 549 529 549 1609 548 1608 548 1609 547 1608 548 1608 548 1608 548 1607 549 1607 549
|
||||
#
|
||||
#
|
||||
name: Cool_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4384 4400 572 1585 571 505 572 1583 573 1584 572 508 570 503 575 1584 572 505 572 506 572 1583 573 504 573 506 571 1586 570 1585 572 532 546 1586 570 1585 571 506 571 1585 571 1583 573 1586 570 1583 573 1584 572 1589 569 505 572 1585 571 506 571 506 573 506 572 505 573 532 545 504 574 509 570 1611 545 506 572 1582 574 506 572 507 571 507 571 507 570 1584 572 507 571 1587 569 506 572 1584 572 1585 571 1583 573 1612 544 5179 4386 4400 570 1584 572 507 571 1583 572 1585 571 506 572 506 572 1584 572 505 572 504 574 1584 572 507 571 504 574 1583 573 1585 572 507 571 1584 572 1610 545 508 571 1587 569 1583 573 1583 573 1585 571 1585 572 1585 572 505 572 1584 572 505 573 507 572 506 571 504 574 505 573 505 574 508 571 1585 571 507 571 1585 571 506 571 506 572 504 574 505 572 1586 570 507 571 1586 570 505 573 1584 572 1585 571 1587 569 1584 573
|
||||
#
|
||||
#
|
||||
name: Heat_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4386 4398 575 1582 574 503 575 1583 573 1582 574 505 573 504 574 1582 574 506 572 508 570 1583 573 504 574 505 573 1583 573 1584 573 505 573 1582 575 1583 574 504 574 1582 574 1583 573 1583 573 1583 573 1585 571 1586 572 504 573 1584 572 504 573 505 573 505 573 505 573 504 573 506 571 1583 574 505 573 1583 573 1583 573 1584 572 1583 573 505 572 505 573 504 574 1583 574 505 573 505 573 504 574 505 572 1584 572 1584 573 5178 4387 4400 571 1583 573 504 574 1584 572 1584 572 507 572 504 574 1582 574 505 572 505 573 1583 573 504 574 504 574 1582 574 1584 573 503 574 1583 573 1582 574 505 573 1583 573 1582 575 1583 573 1610 546 1584 572 1583 573 505 573 1610 546 506 572 505 573 504 574 504 574 505 573 505 573 1584 573 505 573 1582 574 1584 572 1583 573 1583 573 504 574 503 575 504 574 1585 571 507 571 504 573 506 572 505 572 1584 572 1585 571
|
||||
#
|
||||
#
|
||||
name: Heat_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4388 4399 547 1608 548 530 548 1610 547 1610 547 529 549 529 548 1608 548 530 548 530 548 1607 549 533 545 531 548 1608 548 1610 546 531 547 1609 547 1608 548 529 549 1609 547 1609 547 1609 547 1609 547 1609 547 1608 548 529 548 1638 519 530 548 530 548 530 548 529 550 528 549 530 548 530 548 1608 548 530 548 1609 548 1610 547 1609 547 531 546 529 549 1608 548 530 548 1609 548 530 548 529 548 530 548 1609 548 1609 548 5205 4387 4398 547 1609 548 531 546 1609 547 1609 547 530 548 531 546 1609 547 531 548 530 573 1583 573 507 571 506 572 1583 573 1582 574 504 574 1581 575 1582 574 506 572 1583 574 1583 573 1583 573 1585 571 1584 572 1585 570 507 571 1582 574 505 574 532 545 505 573 505 572 506 571 505 573 505 573 1584 572 506 572 1583 573 1584 572 1583 573 505 572 504 573 1583 573 505 573 1586 571 506 572 505 573 507 572 1583 573 1584 572
|
||||
#
|
||||
#
|
||||
name: Off
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4388 4399 572 1583 573 532 546 1585 571 1583 574 503 575 505 573 1584 572 504 574 505 573 1584 573 506 572 504 573 1584 573 1584 572 505 574 1611 545 506 573 1583 573 1585 571 1586 545 1609 547 531 547 1611 545 1608 548 1607 549 530 548 529 548 531 548 532 546 1610 546 533 545 530 547 1609 547 1610 547 1609 547 533 545 529 548 530 548 530 547 531 546 530 547 530 548 533 544 1608 548 1608 548 1610 546 1606 550 1609 547 5203 4388 4397 548 1609 547 531 547 1608 548 1608 548 530 548 530 548 1608 548 531 547 531 547 1610 546 531 547 530 548 1609 547 1611 546 532 547 1609 547 531 547 1608 548 1610 546 1609 547 1608 548 530 547 1609 547 1608 548 1609 547 531 546 530 548 530 547 530 547 1608 548 532 547 534 545 1608 548 1608 548 1609 547 530 548 531 547 531 547 532 546 531 546 531 547 532 546 530 548 1608 547 1608 548 1610 546 1608 548 1608 548
|
||||
data: 4388 4399 572 1583 573 532 546 1585 571 1583 574 503 575 505 573 1584 572 504 574 505 573 1584 573 506 572 504 573 1584 573 1584 572 505 574 1611 545 506 573 1583 573 1585 571 1586 545 1609 547 531 547 1611 545 1608 548 1607 549 530 548 529 548 531 548 532 546 1610 546 533 545 530 547 1609 547 1610 547 1609 547 533 545 529 548 530 548 530 547 531 546 530 547 530 548 533 544 1608 548 1608 548 1610 546 1606 550 1609 547 5203 4388 4397 548 1609 547 531 547 1608 548 1608 548 530 548 530 548 1608 548 531 547 531 547 1610 546 531 547 530 548 1609 547 1611 546 532 547 1609 547 531 547 1608 548 1610 546 1609 547 1608 548 530 547 1609 547 1608 548 1609 547 531 546 530 548 530 547 530 547 1608 548 532 547 534 545 1608 548 1608 548 1609 547 530 548 531 547 531 547 532 546 531 546 531 547 532 546 530 548 1608 547 1608 548 1610 546 1608 548 1608 548
|
||||
#
|
||||
# Model: Panasonic CS-E9HKR
|
||||
#
|
||||
name: Dh
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3466 1748 445 367 502 1292 444 422 444 420 445 422 443 420 445 421 445 420 445 363 503 420 445 422 444 420 445 424 445 1292 445 421 445 451 414 421 444 421 444 421 445 422 443 423 446 1292 443 1292 445 1292 445 421 497 372 444 1293 445 420 445 421 444 421 444 421 445 421 444 421 444 420 445 422 444 420 445 421 444 421 444 421 445 422 443 356 509 420 445 421 445 429 436 421 444 421 444 414 452 420 445 421 444 421 444 423 443 421 444 421 444 421 444 423 443 420 445 424 445 1291 444 1294 444 421 444 421 444 421 444 422 444 423 445 9989 3463 1752 444 424 445 1293 443 422 444 392 473 421 444 416 449 423 443 421 444 421 444 421 444 423 443 422 443 425 444 1292 444 423 443 422 443 419 446 421 444 423 443 421 444 426 443 1292 444 1294 443 1294 443 421 444 425 444 1294 444 422 443 421 444 422 443 424 442 421 444 421 444 421 444 423 444 421 444 422 443 421 444 423 443 425 444 1293 444 421 444 421 444 1293 444 423 446 1292 445 321 546 421 444 421 444 385 480 423 443 425 444 1291 445 1293 443 422 445 422 443 421 444 421 496 370 444 422 443 421 496 370 443 421 444 1291 497 1239 444 1284 504 1237 447 1293 444 425 444 1293 496 371 494 1241 495 370 496 369 497 297 517 421 496 370 495 369 496 370 496 370 495 370 495 369 496 372 494 370 495 369 496 370 495 370 496 370 495 373 495 1240 495 1241 495 1240 497 369 496 371 494 371 443 422 496 369 496 368 497 370 496 369 496 372 497 1239 496 1241 496 1241 496 370 495 310 555 371 495 371 494 368 497 370 495 370 496 361 504 370 495 369 496 372 494 372 494 369 496 371 494 371 495 373 495 1240 497 370 495 371 495 370 495 369 496 370 495 370 495 1242 495 373 492 370 495 366 500 369 496 371 495 370 495 371 495 369 496 371 494 370 495 371 495 371 494 371 494 370 495 372 494 380 488 1241 496 374 495 1241 495 1240 495 1240 495 1241 495 1242 494 1244 494
|
||||
#
|
||||
name: Cool_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3467 1751 442 425 444 1294 443 424 442 422 443 423 442 422 443 422 444 421 444 421 444 424 441 423 443 421 444 425 444 1294 443 424 442 423 442 422 443 425 440 423 443 423 442 427 442 1292 443 1322 415 1293 444 422 443 425 443 1295 443 424 441 421 444 423 442 424 442 425 440 423 442 423 442 424 442 292 573 421 444 423 442 422 444 422 443 422 443 423 442 425 441 423 442 425 440 421 444 424 442 422 443 422 443 422 443 424 442 422 443 422 443 422 443 424 442 421 444 426 443 1292 443 1294 444 423 442 422 443 423 442 424 442 426 442 9989 3465 1753 442 425 444 1292 445 424 442 424 441 421 444 422 443 422 444 423 442 423 442 352 513 423 443 423 442 425 443 1296 441 423 443 422 443 422 443 424 441 423 443 422 443 427 442 1293 442 1322 415 1293 444 421 444 425 443 1294 444 422 443 422 443 421 444 425 441 423 442 422 443 421 444 423 443 421 444 422 443 422 443 424 442 425 444 1261 475 422 443 422 443 1292 444 1293 442 1295 441 424 442 422 443 422 443 427 442 1322 415 1292 444 1292 444 1294 442 423 443 422 443 421 444 422 443 423 443 421 444 421 444 423 442 421 444 1291 444 1293 443 1294 442 1195 541 1293 444 425 443 1293 443 422 444 1322 414 421 444 422 443 423 443 422 443 423 442 422 443 425 441 422 443 422 443 423 442 423 443 422 443 422 443 421 444 423 444 421 444 424 444 1292 444 1293 444 1294 442 422 443 421 444 423 443 422 443 421 444 422 443 424 442 421 444 426 443 1291 444 1293 443 1293 444 422 443 421 444 422 444 421 444 422 443 421 444 423 443 423 442 421 444 422 443 423 444 421 444 421 444 421 444 422 444 425 444 1294 443 422 443 423 444 424 441 422 443 422 443 422 443 1294 443 422 443 421 444 424 442 421 444 413 452 421 444 423 443 421 444 422 443 422 443 422 444 421 444 422 443 422 443 423 443 426 443 1294 442 421 444 423 442 1293 443 1293 443 421 444 422 444 362 505
|
||||
#
|
||||
name: Cool_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3467 1751 444 424 444 1291 446 422 444 420 445 420 445 419 446 421 445 378 487 421 444 420 445 420 446 421 444 423 446 1321 415 451 415 420 445 420 445 419 446 421 445 419 446 422 447 1290 445 1291 445 1291 446 420 445 424 445 1293 445 420 445 420 445 420 445 421 445 420 445 420 445 419 446 421 445 420 445 421 444 420 445 421 445 420 445 420 445 420 445 421 445 419 446 420 445 420 445 420 446 420 445 421 444 419 446 422 444 420 445 420 445 421 444 421 445 421 444 424 445 1290 445 1292 446 420 445 421 444 420 445 423 443 424 444 9988 3465 1751 446 423 445 1291 446 421 445 420 445 420 445 420 445 422 444 420 445 420 445 421 444 421 446 421 444 424 445 1291 446 421 445 421 444 420 445 420 445 420 446 421 444 423 446 1291 444 1293 444 1292 445 420 445 423 446 1294 444 419 446 420 445 421 444 422 444 420 445 421 444 420 445 421 445 421 444 420 445 420 445 422 444 421 444 420 445 420 445 421 444 1320 415 1291 445 1292 444 422 444 420 445 419 446 420 445 421 445 421 444 424 445 1291 446 421 445 420 445 420 445 421 444 421 445 421 444 421 444 420 445 420 445 1291 445 1292 443 1290 445 1291 446 1292 445 424 444 1293 444 421 444 1292 445 422 443 421 444 381 485 420 445 420 445 420 445 422 444 421 444 420 445 421 444 421 445 421 444 421 444 420 445 421 445 421 444 424 445 1291 444 1292 445 1291 446 420 445 419 446 422 444 421 444 420 445 420 445 421 445 420 445 423 446 1291 444 1291 446 1292 445 420 445 420 445 422 444 420 445 420 445 420 445 422 444 421 444 420 445 419 446 420 446 420 445 419 446 419 446 421 445 423 445 1293 444 419 446 421 445 420 445 419 446 420 445 420 445 1292 445 420 445 420 445 421 445 420 445 419 446 419 446 420 446 419 446 420 445 420 445 420 446 420 445 420 445 420 445 421 445 419 446 420 445 423 446 1292 445 1290 445 1290 445 1292 444 1291 445 1293 445
|
||||
#
|
||||
name: Heat_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3463 1751 443 424 445 1293 443 422 444 420 445 421 444 421 444 422 444 421 444 421 444 421 444 353 513 422 443 425 444 1293 444 422 444 421 444 420 445 421 444 422 444 421 444 425 444 1291 444 1294 443 1293 444 421 444 424 445 1294 444 420 445 421 444 416 449 422 444 421 444 421 444 421 444 422 444 420 445 421 444 422 443 422 444 421 444 421 444 420 445 373 493 420 445 421 444 420 445 422 444 420 445 422 443 421 444 422 444 421 444 421 444 422 443 421 445 421 444 424 445 1291 444 1294 444 421 444 420 445 420 445 422 444 424 444 9991 3463 1751 445 425 444 1293 444 422 444 421 444 420 445 421 444 423 443 421 444 421 444 421 444 422 444 421 444 424 445 1293 444 422 444 420 445 422 443 421 444 424 442 421 444 425 444 1292 443 1292 445 1292 445 421 444 424 445 1293 445 421 444 421 444 421 444 422 444 421 444 421 444 422 443 422 444 423 442 421 444 423 442 423 443 425 443 1293 444 423 442 421 444 1292 444 422 443 425 443 1295 443 421 444 368 549 373 443 1293 496 1240 495 1240 495 1241 496 371 495 370 495 370 495 370 495 371 495 370 495 369 496 371 494 371 494 1240 442 1293 495 1240 496 1241 496 1240 497 373 496 1241 496 371 494 1184 553 370 495 370 495 370 496 370 443 423 494 370 443 424 495 370 442 423 442 422 443 424 442 423 442 423 442 425 440 424 442 424 441 427 442 1294 441 1294 443 1294 443 424 441 423 442 425 442 421 444 423 442 424 441 425 441 424 441 426 443 1293 442 1295 442 1295 441 424 441 394 471 425 441 423 442 423 442 424 441 424 442 424 441 423 442 423 442 424 442 423 442 424 441 423 442 424 442 428 440 1295 442 424 441 425 441 424 441 424 441 423 442 424 441 1294 443 424 441 424 441 424 442 423 442 423 442 423 442 425 441 424 441 424 441 424 441 424 442 424 441 449 416 423 442 424 442 427 442 1295 442 424 441 424 441 1295 442 427 442 1295 441 425 441 426 441
|
||||
#
|
||||
name: Heat_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3461 1753 439 429 440 1298 439 427 439 426 439 426 439 426 439 427 439 426 439 426 439 426 439 427 439 426 439 430 438 1298 438 428 438 426 439 427 438 427 438 427 439 427 438 430 414 1321 439 1299 413 1323 414 451 414 455 414 1324 414 452 413 451 414 453 413 436 430 452 413 452 413 451 414 453 413 452 413 451 414 452 413 454 412 452 413 452 413 452 413 453 413 452 413 452 413 452 413 454 413 453 412 452 413 452 413 453 413 452 413 452 413 452 413 453 413 452 413 456 412 1323 412 1325 413 452 413 453 412 453 412 454 412 455 390 10044 3438 1779 412 457 412 1324 413 454 412 453 412 453 412 453 412 454 412 453 412 453 412 454 411 455 411 453 412 457 389 1347 390 477 389 476 389 476 389 476 389 402 465 475 390 479 390 1346 389 1348 389 1347 390 476 389 479 390 1348 390 476 389 476 389 476 389 477 389 475 390 476 389 476 389 477 389 476 389 476 389 476 389 478 388 480 389 1347 390 475 390 476 389 1347 390 476 389 479 389 1349 389 476 389 476 389 476 389 477 389 476 389 479 390 1348 389 477 389 476 389 476 389 476 389 476 390 476 389 476 389 476 389 476 389 1346 389 1347 389 1346 389 1347 390 1346 390 479 390 1347 390 476 389 1374 363 474 415 454 388 480 386 475 414 454 387 474 391 476 414 455 387 473 392 476 414 453 389 476 389 475 390 475 390 476 390 476 390 479 389 1346 389 1347 390 1348 389 476 389 476 389 477 389 476 389 476 389 475 390 477 389 440 425 479 389 1345 390 1347 390 1347 390 476 389 475 390 477 389 476 389 476 389 476 389 477 389 476 389 476 389 475 390 477 389 476 389 476 389 476 389 477 389 479 390 1347 390 476 389 477 389 476 389 476 389 476 389 476 389 1347 390 476 389 476 389 477 389 503 362 476 389 476 389 477 389 475 390 476 389 476 389 477 389 476 389 476 389 476 389 477 389 479 389 1347 390 479 390 1347 390 1348 389 476 389 476 389 477 389 477 390
|
||||
#
|
||||
name: Off
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3489 1725 493 375 493 1167 569 375 491 373 492 372 493 374 492 373 493 372 493 373 442 423 492 375 493 372 492 378 490 1245 443 423 493 374 491 375 490 374 442 424 492 374 491 379 440 1293 492 1245 443 1294 442 423 491 379 441 1296 491 375 441 423 442 423 442 425 441 423 442 425 440 424 441 425 441 424 441 421 444 424 441 425 441 423 442 423 442 423 442 453 413 424 442 451 414 424 441 426 440 424 441 424 441 424 441 425 441 424 441 424 441 424 441 426 440 425 440 427 442 1322 413 1296 442 424 441 423 442 424 441 424 442 427 441 9994 3463 1755 440 428 441 1296 441 426 440 425 440 426 439 425 440 426 440 423 442 425 440 425 440 372 494 425 440 428 440 1297 440 426 440 425 440 426 439 426 439 427 439 425 440 429 439 1297 439 1297 439 1297 440 426 439 429 440 1299 439 426 439 426 439 428 437 427 439 426 439 426 439 427 438 427 439 427 438 427 438 427 438 429 437 427 414 451 414 451 414 418 447 1323 414 452 413 455 414 1325 413 452 413 452 413 452 413 453 413 452 413 456 413 1324 413 453 413 452 413 453 412 452 413 454 412 453 412 453 412 453 412 452 413 1324 412 1323 412 1324 412 1324 412 1325 412 456 413 1324 412 404 461 1325 412 453 412 453 412 454 412 453 412 453 412 454 411 455 411 453 412 453 412 453 412 454 412 453 412 453 412 453 412 454 413 453 412 457 412 1323 413 1324 413 1324 412 453 412 453 412 454 413 453 412 453 412 453 412 454 412 452 413 456 412 1323 413 1324 413 1323 414 453 412 452 413 453 413 452 413 452 413 452 413 453 413 450 415 452 413 452 413 453 413 452 413 451 439 427 438 428 439 430 439 1298 439 426 439 428 438 426 439 428 437 426 439 427 438 1298 439 427 438 426 439 427 439 426 439 426 439 425 440 427 440 426 439 426 439 426 439 425 441 426 439 425 440 425 440 427 439 426 439 425 440 429 439 1297 440 1297 440 425 440 425 440 426 441 427 440
|
||||
#
|
||||
# Model: Maytag M6X06F2A
|
||||
#
|
||||
name: Off
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 20 00 00 00
|
||||
command: 02 00 00 00
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
|||
Filetype: IR library file
|
||||
Version: 1
|
||||
#Last Updated 18th Feb, 2024
|
||||
#Last Checked 18th Feb, 2024
|
||||
# Last Updated 5th Oct, 2024
|
||||
# Last Checked 5th Oct, 2024
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
|
@ -1743,7 +1743,7 @@ type: parsed
|
|||
protocol: NEC
|
||||
address: 30 00 00 00
|
||||
command: 86 00 00 00
|
||||
#
|
||||
#
|
||||
name: Mode
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
|
@ -1989,115 +1989,115 @@ type: raw
|
|||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8993 4485 589 1651 589 529 590 529 591 530 590 530 589 530 590 531 589 530 589 531 589 1649 590 1650 589 1649 590 1650 589 1651 588 1649 590 1650 589 1654 585 1650 589 1651 588 1650 590 533 586 531 588 532 588 530 590 530 590 532 587 531 588 530 589 1650 589 1650 589 1652 587 1651 588 1651 588 1650 589 1650 589 1652 587 530 590 530 589 530 589 531 588 531 588 531 588 530 589 531 588 1651 588 1650 590 1651 589 1651 589
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2280 776 785 1565 783 796 782 790 783 1549 783 810 752 805 752 800 752 858 752 830 752 826 776 797 775 793 774 789 773 810 747 805 747 102605 2223 832 752 1595 753 825 752 820 752 1581 752 811 751 806 751 802 750 860 750 833 775 804 773 799 773 795 773 790 773 785 772 780 773
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4612 4435 543 1461 544 1460 545 1461 544 1460 543 1462 518 1487 518 2441 516 1513 491 1513 492 2465 492 1513 516 2441 516 1488 516 1489 515 2443 514 1492 514 1485 4580 4467 513 1492 513 1492 513 1492 513 1491 514 1492 513 1492 513 2445 513 1492 513 1492 513 2445 513 1492 513 2445 513 1492 513 1492 513 2445 513 1493 513 14064 9205 2275 513
|
||||
#
|
||||
#
|
||||
name: Speed_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4611 4435 544 1460 545 1460 546 1459 546 1460 519 1487 517 1487 518 2440 518 1488 517 1488 516 1512 517 2440 517 1488 516 1488 516 1489 515 2444 513 2445 514 1485 4581 4467 513 1492 513 1492 513 1492 513 1492 513 1492 513 1492 513 2444 514 1492 513 1491 514 1492 513 2445 513 1492 513 1492 513 1492 513 2444 513 2446 513 14066 9203 2275 513
|
||||
#
|
||||
#
|
||||
name: Speed_dn
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4611 4434 545 1460 545 1459 546 1457 548 1458 521 1485 520 1485 545 2413 544 1462 542 2439 518 1487 517 1489 515 2444 512 1493 512 1493 512 1493 512 2446 512 1486 4581 4470 512 1493 511 1493 512 1493 512 1493 512 1493 512 1493 512 2446 511 1493 511 2446 512 1493 512 1493 512 2446 512 1493 512 1494 511 1493 512 2447 512 14071 9203 2279 511
|
||||
#
|
||||
#
|
||||
name: Timer
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4608 4436 545 1458 547 1458 547 1458 547 1458 521 1484 521 1485 520 2439 544 1461 544 2440 518 1487 517 2441 516 1489 515 2444 513 1493 512 1492 513 1494 512 1486 4577 4471 512 1493 512 1493 512 1493 512 1492 513 1493 512 1493 512 2446 512 1493 512 2446 512 1493 512 2446 512 1493 512 2446 512 1493 512 1493 512 1494 512 14051 9198 2279 512
|
||||
#
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4605 4437 544 1460 545 1459 546 1458 546 1459 520 1485 520 1486 545 2414 543 1487 517 1488 515 1489 515 1491 513 2446 512 2446 511 2446 512 1493 512 1494 511 1487 4573 4472 511 1493 511 1493 511 1493 511 1493 512 1494 510 1494 511 2446 511 1493 511 1494 511 1494 510 1493 511 2447 511 2446 511 2446 511 1494 511 1495 511 14064 9191 2281 510
|
||||
#
|
||||
#
|
||||
name: Mode
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4617 4436 544 1459 545 1458 545 1458 546 1458 520 1485 519 1485 545 2413 544 1462 542 1486 517 2440 515 2442 513 1492 512 1492 513 2444 512 1492 512 1493 513 1485 4582 4469 512 1493 512 1492 512 1492 512 1493 511 1493 512 1492 512 2445 511 1493 511 1493 511 2445 512 2446 511 1493 511 1493 511 2445 511 1493 511 1494 511 14048 9216 2280 512
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9220 4459 632 565 628 539 628 539 627 540 626 542 624 545 622 548 619 571 596 1652 596 1652 596 1652 596 1652 596 1652 596 1652 596 1652 596 1652 596 1652 596 1652 596 1652 596 571 596 571 596 572 595 1652 596 571 596 571 596 571 596 572 595 1652 596 1652 596 1653 595 571 596 1652 596 39508 9197 2229 595 96159 9231 2229 596
|
||||
#
|
||||
#
|
||||
name: Speed_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9244 4432 633 564 629 538 630 538 629 539 627 540 626 542 624 570 598 547 620 1651 597 1651 597 1651 597 1651 597 1651 597 1651 597 1651 598 1651 597 1651 597 1651 597 1651 597 570 597 570 597 570 597 570 597 570 597 570 597 570 597 570 598 1651 597 1651 597 1651 597 1651 597 1652 596 39509 9207 2227 597
|
||||
#
|
||||
#
|
||||
name: Speed_dn
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9223 4461 632 565 628 540 627 540 626 541 625 542 624 545 622 547 621 571 597 1629 620 1652 597 1653 595 1653 596 1653 596 1653 596 1653 596 1653 596 572 596 572 595 1653 596 1653 595 572 595 572 596 572 595 572 595 1653 596 1653 596 572 595 572 595 1653 596 1653 595 1653 596 1653 595 39519 9204 2229 596
|
||||
#
|
||||
#
|
||||
name: Timer
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9227 4459 634 564 629 539 629 538 629 539 627 541 625 543 624 570 598 571 597 1652 597 1652 597 1652 597 1652 597 1652 597 1652 597 1652 597 1652 597 1652 597 571 597 571 596 1652 597 571 596 571 597 571 596 571 597 571 596 1652 597 1652 597 571 597 1652 597 1652 597 1653 596 1653 596 39523 9207 2229 596
|
||||
#
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9223 4459 633 564 629 538 629 538 628 539 627 541 624 544 622 570 597 570 597 1651 597 1651 597 1651 597 1651 598 1651 597 1651 597 1651 597 1651 597 570 597 1651 597 1651 597 1651 597 1651 597 570 598 1651 597 570 597 1651 597 570 597 570 597 570 597 570 597 1652 596 570 597 1652 596 39519 9202 2226 597
|
||||
#
|
||||
#
|
||||
name: Mode
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9241 4434 633 565 602 565 628 539 628 539 627 540 626 542 624 545 622 547 620 1628 620 1629 619 1629 619 1652 596 1653 595 1629 619 1652 596 1653 595 571 596 1653 595 571 596 571 596 572 595 571 596 1653 595 572 595 1653 595 571 596 1653 595 1653 595 1653 595 1653 596 572 595 1653 595 39519 9226 2229 597
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 40000
|
||||
frequency: 38000
|
||||
duty_cycle: 0.4
|
||||
data: 20592 6864 2288 9152 11440 2288 2288 6864 2288 2288 2288 13728
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1328 375 1304 375 460 1196 1327 379 1299 379 430 1221 459 1221 458 1222 483 1197 483 1198 481 1222 1299 7068 1297 382 1297 382 453 1227 1296 382 1297 382 453 1227 453 1228 452 1228 452 1227 453 1228 452 1228 1296 7322 1295 383 1296 383 452 1228 1296 383 1296 383 452 1228 452 1228 452 1228 452 1228 452 1228 452 1228 1296 7070 1295 383 1296 384 451 1228 1296 383 1296 383 452 1228 452 1229 451 1228 451 1229 451 1228 451 1229 1295
|
||||
#
|
||||
#
|
||||
name: Speed_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1327 373 1306 377 459 1194 1329 373 1305 377 1276 402 433 1219 486 1194 486 1195 484 1219 1302 379 1299 7067 1299 380 1299 381 455 1224 1299 381 1298 381 1298 381 455 1225 455 1225 455 1225 455 1225 1298 381 1298 7344 1298 381 1299 381 455 1225 1298 381 1298 381 1298 381 455 1225 455 1225 455 1225 455 1226 1298 381 1298 7069 1298 382 1298 382 454 1225 1298 382 1298 382 1298 382 454 1226 454 1226 454 1226 454 1226 1297 382 1297
|
||||
#
|
||||
#
|
||||
name: Speed_dn
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1330 377 1302 377 459 1193 1330 376 1303 376 1277 401 435 1218 487 1194 486 1194 1329 377 1299 380 456 7911 1299 380 1299 380 456 1225 1299 380 1299 380 1299 380 456 1224 456 1225 455 1225 1298 381 1299 380 456 8149 1299 381 1298 381 455 1225 1299 380 1299 381 1299 381 455 1225 455 1225 455 1226 1298 381 1299 381 455 7913 1298 381 1299 381 455 1226 1298 381 1299 381 1298 382 454 1225 455 1226 454 1226 1298 382 1298 381 455
|
||||
#
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1329 373 1306 377 459 1193 1330 377 1302 377 1277 402 434 1219 485 1195 1329 377 1300 379 456 1224 455 7911 1299 381 1298 381 455 1224 1299 380 1299 381 1298 381 455 1225 455 1225 1299 380 1299 381 455 1225 455 8165 1298 381 1299 381 455 1225 1299 381 1299 381 1298 381 455 1225 455 1226 1298 381 1299 381 455 1225 455 7913 1298 381 1298 381 455 1226 1297 381 1298 382 1297 382 454 1226 454 1226 1297 382 1298 382 454 1226 454
|
||||
#
|
||||
#
|
||||
name: Timer
|
||||
type: raw
|
||||
frequency: 38000
|
||||
|
@ -2139,69 +2139,393 @@ type: raw
|
|||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2221 844 752 1600 758 1591 757 820 756 816 749 817 748 813 752 804 751 1632 758 1596 752 1597 751 1594 754 1585 752 1582 756 806 749 808 757 102464 2224 841 756 1597 751 1599 749 828 748 824 752 815 750 811 754 802 753 1629 750 1604 754 1595 753 1591 757 1583 755 1579 759 804 751 806 749
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1261 425 1261 425 444 1241 1261 425 1261 454 414 1241 445 1240 445 1241 444 1241 444 1242 443 1239 1263 7168 1261 424 1262 425 444 1241 1261 424 1261 425 444 1242 444 1240 445 1241 444 1240 445 1240 445 1241 1261
|
||||
#
|
||||
#
|
||||
name: Speed_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1261 424 1261 424 445 1241 1261 425 1260 424 445 1242 444 1240 445 1240 445 1239 446 1241 1261 424 445 7984 1261 424 1261 424 445 1241 1261 424 1261 424 445 1240 446 1240 445 1240 445 1241 444 1240 1262 425 444 7983 1262 424 1261 424 445 1239 1263 424 1261 424 445 1241 445 1240 445 1240 445 1239 446 1240 1262 425 444 7983 1262 424 1261 425 444 1239 1263 425 1260 425 443 1241 445 1241 444 1241 444 1241 445 1240 1262 424 445 7982 1263 425 1260 424 445 1240 1262 424 1261 424 445 1240 446 1241 444 1241 444 1239 446 1239 1263 425 444 7984 1261 424 1261 424 444 1240 1262 425 1260 424 445 1240 445 1241 444 1240 445 1240 445 1241 1261 424 444 7984 1261 425 1261 424 444 1241 1261 424 1261 425 444 1240 445 1240 445 1240 445 1240 445 1240 1262 424 445 7984 1261 425 1260 425 444 1240 1262 425 1260 425 444 1241 445 1240 445 1240 445 1240 445 1240 1262 425 444 7984 1261 425 1260 426 443 1241 1261 425 1260 426 442 1240 446 1241 444 1241 444 1242 443 1240 1262 426 443 7985 1260 426 1259 426 442 1243 1259 426 1259 426 442 1241 445 1241 444 1240 445 1241 444 1241 1261 425 443 7984 1261 425 1260 425 443 1242 1261 426 1259 426 442 1242 444 1241 444 1241 444 1241 444 1241 1261 425 443 7986 1260 425 1260 425 444 1241 1261 426 1259 427 442 1242 444 1240 445 1241 444 1240 445 1240 1262 425 444
|
||||
#
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1261 425 1260 424 445 1241 1261 426 1260 424 445 1241 445 1240 1262 426 443 1240 446 1240 445 1241 444 7985 1260 424 1261 426 443 1241 1261 425 1260 426 443 1240 446 1240 1261 425 444 1241 445 1241 444 1241 444
|
||||
#
|
||||
#
|
||||
name: Timer
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1261 425 1260 426 442 1241 1262 426 1259 425 444 1241 445 1241 444 1240 1262 425 443 1241 445 1241 444 7983 1262 425 1260 425 444 1241 1261 425 1260 425 444 1241 445 1240 445 1240 1262 425 444 1240 446 1240 445 7985 1260 424 1261 425 444 1241 1261 425 1260 425 444 1239 447 1240 445 1240 1262 425 444 1241 444 1241 444 7983 1262 425 1260 424 445 1241 1261 424 1261 424 445 1241 445 1240 445 1240 1262 424 445 1240 446 1241 444 7983 1262 425 1260 425 444 1240 1262 425 1260 424 445 1240 446 1240 445 1241 1261 425 444 1240 446 1240 445 7985 1260 424 1261 425 444 1241 1261 424 1261 425 444 1240 446 1239 446 1240 1262 426 443 1240 446 1241 444 7984 1261 424 1261 424 445 1241 1261 425 1260 425 444 1241 445 1240 445 1239 1263 424 445 1240 446 1240 445 7984 1261 424 1261 425 444 1240 1262 424 1261 425 444 1241 444 1241 444 1240 1262 425 444 1242 444 1239 446 7983 1262 424 1261 426 443 1240 1262 426 1259 425 444 1242 444 1241 444 1239 1263 425 444 1241 444 1241 445 7983 1262 424 1261 424 445 1240 1262 425 1260 425 444 1241 445 1240 445 1241 1261 425 444 1241 445 1239 446 7983 1262 425 1260 425 444 1240 1262 425 1260 425 444 1242 443 1239 446 1241 1261 425 444 1241 444 1241 444 7983 1262 425 1260 426 443 1241 1261 426 1259 425 443 1241 445 1241 444 1242 1260 426 442 1241 445 1241 444 7984 1261 425 1260 426 494 1190 1260 426 1259 425 496 1189 497 1188 497 1188 1262 427 494 1190 496 1189 496 7932 1261 426 1259 426 494 1190 1260 426 1259 425 495 1190 496 1189 496 1190 1260 428 492 1190 496 1189 496
|
||||
#
|
||||
#
|
||||
name: Mode
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1259 425 1260 454 415 1244 1259 426 1259 425 444 1245 441 1241 444 1241 444 1241 1261 454 415 1242 444 7984 1261 425 1261 426 443 1243 1259 426 1260 427 442 1241 445 1240 445 1242 443 1242 1260 427 442 1242 443
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1292 432 1293 433 444 1244 1296 458 1266 459 418 1245 449 1244 449 1245 448 1244 448 1243 449 1245 1293 7239 1292 458 1263 458 418 1245 1292 432 1289 433 443 1244 448 1245 447 1244 448 1245 446 1244 447 1245 1290 8319 1290 432 1287 432 443 1244 1291 458 1261 458 417 1244 448 1245 446 1244 447 1244 447 1244 447 1245 1289 7239 1289 458 1260 458 417 1245 1289 458 1260 458 417 1245 447 1244 447 1244 446 1244 446 1244 446 1245 1287 8320 1287 458 1259 432 443 1245 1288 431 1286 432 443 1246 445 1244 446 1244 446 1243 447 1245 445 1244 1287 7237 1287 458 1258 458 416 1245 1287 431 1285 458 416 1244 447 1244 446 1244 446 1244 446 1244 446 1244 1287 8318 1286 458 1258 433 441 1245 1287 431 1285 458 416 1244 446 1243 447 1245 445 1243 446 1244 445 1244 1286 7237 1286 432 1284 458 416 1244 1287 432 1284 431 443 1245 445 1243 446 1244 445 1243 446 1244 445 1244 1286 8317 1285 431 1284 432 441 1244 1287 431 1285 431 443 1245 445 1244 445 1243 446 1243 446 1244 445 1244 1286 7236 1286 458 1257 431 443 1244 1287 431 1285 432 442 1245 445 1244 445 1244 446 1244 445 1244 446 1244 1287 8316 1287 458 1259 432 442 1245 1288 432 1285 432 442 1245 446 1245 445 1244 446 1244 446 1244 446 1243 1289 7236 1287 431 1286 432 442 1244 1289 431 1286 433 441 1245 446 1244 446 1244 446 1244 446 1244 446 1245 1286 8317 1286 432 1284 432 442 1245 1287 458 1259 432 442 1245 446 1244 446 1244 446 1244 446 1244 446 1244 1287 7237 1286 431 1285 431 443 1245 1287 433 1284 458 416 1245 445 1245 445 1243 446 1244 446 1244 445 1244 1287 8317 1286 432 1284 458 416 1245 1287 431 1285 432 442 1245 445 1244 445 1244 445 1243 446 1244 445 1244 1286 7235 1286 433 1282 431 442 1244 1287 431 1284 432 441 1245 445 1244 445 1244 445 1244 445 1244 445 1244 1286 8316 1285 431 1284 431 442 1244 1287 431 1284 433 440 1244 446 1244 445 1243 446 1244 445 1244 445 1243 1286 7236 1284 431 1283 431 442 1244 1286 431 1284 431 442 1245 445 1244 445 1244 445 1244 445 1244 445 1244 1286 8315 1285 431 1283 431 442 1245 1285 431 1284 432 441 1244 446 1244 445 1244 445 1244 445 1244 445 1244 1285 7235 1285 431 1283 430 443 1244 1286 431 1284 430 443 1245 445 1244 445 1244 445 1244 445 1244 445 1243 1286 8316 1284 457 1257 430 443 1244 1286 432 1283 431 442 1245 445 1244 445 1243 446 1243 446 1244 445 1243 1286 7235 1285 431 1283 432 441 1244 1286 431 1284 431 442 1245 445 1244 445 1244 445 1244 445 1244 445 1244 1285 8316 1284 431 1283 431 442 1245 1285 430 1285 430 443 1245 445 1243 446 1244 445 1244 445 1244 445 1244 1285 7235 1285 432 1282 431 442 1245 1285 432 1282 431 442 1245 445 1244 445 1243 446 1244 445 1244 445 1244 1285 8314 1285 431 1283 431 442 1245 1285 430 1284 431 442 1244 446 1244 445 1244 445 1244 445 1244 445 1244 1285 7235 1284 431 1283 431 442 1245 1285 431 1283 431 442 1244 446 1244 445 1244 445 1244 445 1244 445 1244 1285 8316 1284 431 1283 431 442 1245 1285 431 1283 430 443 1245 445 1244 445 1244 445 1244 445 1244 445 1243 1286 7236 1285 430 1285 431 442 1245 1287 431 1285 431 443 1245 446 1244 446 1244 446 1244 445 1244 446 1244 1285 8319 1292 432 1291 432 444 1246 1291 432 1292 432 444 1246 447 1245 447 1245 447 1245 447 1245 447 1245 1296 7239 1288 430 1287 431 443 1246 1288 431 1287 431 443 1246 446 1244 447 1245 446 1244 447 1245 445 1245 1288 8319 1287 431 1285 431 443 1245 1288 431 1285 431 442 1245 446 1244 446 1245 445 1245 445 1245 445 1245 1287 7237 1288 431 1286 431 443 1245 1291 431 1290 431 444 1246 446 1244 447 1245 446 1244 447 1244 446 1244 1288
|
||||
#
|
||||
#
|
||||
name: Speed_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1290 458 1263 432 444 1245 1292 458 1263 433 443 1245 472 1221 448 1244 448 1245 447 1244 1292 433 443 8060 1289 458 1261 458 417 1245 1291 458 1261 458 418 1245 448 1244 472 1220 471 1220 448 1244 1290 431 444 9141 1290 458 1261 458 417 1245 1290 458 1261 432 444 1245 470 1220 472 1220 447 1244 447 1243 1290 457 418 8059 1288 457 1260 458 417 1245 1289 458 1260 431 444 1245 471 1220 471 1219 471 1220 448 1244 1288 457 417 9140 1287 432 1285 458 416 1244 1289 457 1260 431 444 1243 448 1244 471 1220 446 1244 471 1220 1288 430 445 8057 1289 431 1285 457 417 1244 1289 457 1259 458 416 1245 470 1220 471 1220 446 1244 447 1243 1288 432 442 9139 1287 457 1259 431 443 1244 1288 457 1259 432 443 1244 447 1243 447 1244 446 1243 472 1219 1288 457 417 8058 1287 457 1259 430 444 1245 1287 431 1285 457 417 1245 446 1244 447 1244 446 1244 446 1244 1287 457 417 9139 1287 457 1258 457 417 1244 1287 457 1259 432 442 1245 446 1243 447 1244 447 1244 446 1243 1288 431 443 8057 1287 431 1284 431 443 1245 1287 431 1285 431 443 1244 447 1243 447 1243 447 1244 446 1243 1287 431 443 9139 1286 431 1284 457 417 1245 1287 430 1286 457 417 1245 446 1243 447 1243 447 1243 447 1244 1287 431 443 8057 1287 430 1285 457 417 1243 1289 431 1284 457 417 1244 447 1244 446 1243 447 1243 447 1243 1287 431 443 9136 1286 431 1284 457 417 1244 1287 430 1285 457 417 1244 447 1243 447 1244 446 1243 447 1243 1287 430 444 8054 1286 430 1284 431 443 1244 1286 430 1285 431 443 1244 447 1243 447 1243 447 1243 447 1243 1287 431 443
|
||||
#
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1304 432 1273 432 443 1214 1304 433 1273 432 443 1213 475 1214 1304 432 443 1212 476 1215 472 1212 475 8025 1304 432 1273 432 443 1212 1306 432 1274 432 443 1215 473 1213 1304 432 443 1213 474 1212 475 1212 475 9100 1305 432 1273 432 443 1213 1305 432 1274 433 442 1214 474 1212 1305 432 443 1212 476 1213 474 1214 473 8026 1302 432 1273 433 442 1213 1305 432 1274 432 443 1213 475 1213 1304 432 443 1213 474 1213 474 1212 475
|
||||
#
|
||||
#
|
||||
name: Timer
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1304 432 1276 404 472 1213 1307 404 1304 405 470 1214 473 1215 472 1212 1333 378 471 1214 526 1160 527 7968 1330 378 1329 378 523 1163 1329 379 1328 379 522 1163 524 1164 523 1163 1304 404 521 1165 522 1163 523 9058 1303 404 1302 405 519 1165 1304 405 1302 405 519 1166 521 1164 523 1165 1303 406 518 1166 521 1165 522 7973 1302 404 1302 405 519 1165 1304 404 1303 403 522 1165 522 1164 522 1164 1304 404 521 1164 523 1165 521 9062 1301 404 1302 405 468 1215 1304 404 1302 406 467 1216 471 1216 470 1216 1303 406 467 1218 469 1217 469 8025 1278 430 1276 430 440 1244 1278 429 1277 456 414 1245 442 1244 442 1244 1278 430 439 1244 443 1243 443
|
||||
#
|
||||
#
|
||||
name: Mode
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1307 432 1277 432 444 1213 1309 432 1278 433 443 1213 476 1213 475 1212 476 1213 1308 432 444 1213 476 8021 1309 432 1277 432 444 1213 1309 432 1278 433 443 1212 476 1212 476 1212 476 1212 1309 432 444 1213 475 9107 1307 432 1277 432 444 1213 1308 432 1277 433 443 1212 476 1211 477 1212 476 1211 1310 432 444 1213 476 8022 1308 432 1277 432 444 1212 1309 432 1278 432 444 1212 476 1211 477 1212 476 1212 1308 432 444 1212 476 9107 1307 431 1305 405 497 1162 1333 379 1331 405 497 1163 525 1162 525 1164 523 1163 1308 432 442 1217 471 8026 1283 430 1279 430 442 1244 1281 431 1279 431 440 1244 445 1244 444 1243 444 1243 1282 430 441 1245 444
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1793 719 954 1558 955 720 955 1558 954 720 955 720 1769 743 930 2420 6794 2446 926 5775 926 1586 5955 746 926 1587 925 4938 900 2450 5117 747 1764 1586 925 4100 926 3263 4252 773 2602 1586 2602 1586 1764 3262 7629 1585 4252 774 923 751 924 1589 923 751 899 3290 1762 1588 923 8291 923 1589 2601 750 1762 1588 923 752 2575 1613 898
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4482 4502 457 1536 457 1538 456 1538 456 1538 456 1536 458 1537 458 2486 457 1536 458 1537 457 2485 458 1537 457 2485 458 1536 458 1538 456 2486 457 1537 458 1536 4483 4502 457 1536 457 1538 457 1537 458 1538 457 1538 456 1537 457 2486 457 1537 457 1538 456 2486 457 1538 456 2486 457 1538 456 1537 457 2486 457 1537 457 13998 9008 2315 456 49985 9008 2315 506 49937 9031 2292 507 49938 9009 2316 506
|
||||
#
|
||||
name: Timer
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4504 4479 509 1483 510 1485 509 1484 510 1485 510 1485 509 1484 511 2433 510 1485 509 2435 509 1484 511 2433 510 1485 510 2434 509 1486 509 1484 511 1486 508 1483 4507 4480 508 1484 509 1484 510 1485 509 1485 509 1485 510 1485 509 2433 511 1486 508 2435 508 1485 509 2433 510 1485 509 2433 510 1486 508 1485 509 1485 509 13943 9034 2291 509 49934 9031 2292 509 49936 9030 2291 509
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4505 4479 509 1483 511 1484 511 1485 510 1485 509 1485 510 1485 509 2433 510 1484 510 1486 508 1485 509 1485 509 2434 509 2433 510 2433 510 1485 510 1486 508 1483 4507 4479 509 1483 510 1486 509 1485 509 1484 511 1484 511 1484 510 2435 509 1484 510 1485 510 1486 509 1484 511 2435 508 2434 510 2434 510 1485 510 1484 511 13947 9033 2291 510 49944 9033 2292 510
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1268 414 1273 415 430 1244 1271 416 1270 415 429 1248 425 1245 427 1242 430 1244 428 1244 428 1246 1268 7164 1270 414 1272 414 430 1244 1272 414 1272 415 429 1245 428 1247 425 1248 424 1243 429 1245 427 1246 1269 8269 1241 414 1271 414 429 1248 1267 415 1271 415 428 1244 429 1246 426 1245 427 1245 427 1245 427 1244 1270 7166 1267 414 1272 414 429 1245 1271 414 1272 416 427 1246 427 1244 428 1245 427 1246 426 1247 425 1246 1269 8242 1268 414 1271 416 427 1246 1270 415 1271 414 430 1246 427 1244 428 1247 425 1244 428 1245 427 1245 1269 7164 1269 414 1270 416 428 1246 1269 415 1271 416 427 1245 428 1246 426 1244 428 1246 426 1243 429 1246 1244 8266 1268 414 1272 414 430 1245 1271 416 1270 415 429 1246 427 1244 428 1244 428 1245 427 1244 428 1245 1245 7189 1268 415 1271 415 428 1247 1268 415 1247 441 426 1248 425 1245 427 1244 428 1243 429 1245 427 1244 1270
|
||||
#
|
||||
name: Mode
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1244 437 1274 415 430 1246 1247 439 1272 415 430 1245 429 1243 430 1243 429 1243 1247 439 429 1246 428 7992 1246 438 1248 438 430 1246 1269 415 1272 416 429 1246 428 1243 430 1245 427 1243 1270 416 429 1244 430 9049 1246 438 1271 416 429 1244 1271 414 1273 415 430 1245 429 1244 429 1243 429 1245 1268 416 429 1244 430 7993 1247 439 1271 415 430 1245 1247 438 1272 415 430 1246 428 1246 427 1243 429 1246 1244 438 430 1245 429
|
||||
#
|
||||
name: Timer
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1245 438 1248 438 430 1245 1247 439 1271 417 427 1246 428 1245 427 1245 1245 438 429 1248 425 1246 426 7994 1242 437 1249 438 429 1249 1242 439 1266 419 429 1246 427 1244 428 1245 1245 438 429 1245 428 1245 427 9305 1245 438 1247 439 429 1245 1246 438 1271 416 428 1246 427 1244 428 1243 1246 439 428 1245 428 1243 429 7989 1246 439 1246 439 429 1247 1243 439 1246 440 428 1246 427 1247 425 1248 1241 439 428 1246 427 1244 428 9305 1243 439 1246 439 429 1244 1247 440 1246 439 429 1245 428 1244 428 1243 1247 440 427 1246 427 1246 426 7990 1246 438 1270 416 429 1243 1248 438 1271 416 429 1244 429 1244 428 1243 1246 438 429 1245 428 1244 428
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1311 373 1313 373 468 1179 1340 372 1314 372 469 1180 495 1179 495 1179 495 1178 496 1177 497 1178 1341 7109 1340 372 1314 366 476 1206 1313 372 1314 373 468 1178 497 1181 493 1205 469 1178 496 1179 495 1181 1338 8215 1314 373 1313 372 469 1206 1313 373 1313 372 469 1206 469 1206 468 1204 470 1179 496 1180 494 1205 1313 7136 1314 373 1313 372 469 1181 1338 372 1314 372 469 1205 469 1206 468 1206 468 1206 468 1206 468 1205 1314 8215 1424 364 1322 363 479 1094 1424 364 1322 364 477 1095 580 1069 605 1095 524 1151 523 1150 524 1126 1393 7082 1419 364 1270 365 503 1124 1395 365 1320 365 397 1205 470 1205 469 1204 470 1204 470 1204 470 1204 1315 8215 1313 371 1315 371 495 1180 1315 371 1315 371 470 1204 495 1180 470 1205 494 1180 494 1180 494 1180 1338 7112 1338 366 1320 366 476 1181 1338 366 1320 366 476 1181 493 1181 494 1181 493 1181 494 1181 493 1181 1338 8194 1337 366 1320 366 476 1182 1337 366 1320 366 476 1182 493 1181 493 1181 494 1182 492 1182 493 1181 1337 7114 1337 366 1320 366 476 1182 1337 366 1320 366 476 1182 493 1182 492 1182 493 1182 492 1182 492 1182 1337 8194 1336 366 1320 366 476 1182 1337 366 1320 366 476 1182 493 1182 492 1182 492 1182 493 1182 492 1182 1336 7115 1336 366 1320 366 476 1183 1336 366 1320 366 476 1182 493 1182 493 1182 492 1182 492 1182 493 1182 1336
|
||||
#
|
||||
name: Mode
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1397 363 1322 364 476 1149 1369 364 1321 364 422 1204 470 1177 497 1177 497 1176 1342 371 469 1177 497 7967 1314 371 1314 371 469 1178 1341 373 1312 372 468 1205 468 1205 469 1206 468 1205 1314 372 468 1205 524 8943 1397 364 1321 363 478 1121 1397 364 1321 364 477 1122 552 1149 525 1123 551 1121 1397 364 476 1150 524 7913 1368 364 1266 373 523 1150 1313 372 1313 373 468 1177 497 1205 469 1205 469 1179 1340 372 468 1205 469 9029 1314 372 1314 372 468 1179 1340 372 1313 371 470 1205 469 1205 469 1205 469 1204 1315 371 469 1205 469 7969 1313 371 1314 370 470 1178 1396 364 1322 364 476 1125 550 1123 551 1149 525 1123 1395 363 478 1149 525
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1396 364 1322 364 477 1123 1396 364 1322 364 477 1125 549 1124 1395 364 477 1126 548 1125 549 1127 547 7892 1391 364 1322 364 477 1129 1390 364 1272 371 470 1179 546 1128 1342 370 471 1205 470 1179 496 1204 470 9004 1391 365 1321 364 477 1127 1392 364 1272 371 520 1128 547 1128 1341 370 471 1204 521 1130 544 1154 520 7894 1391 364 1272 371 470 1205 1315 370 1316 370 471 1179 496 1204 1316 370 471 1179 496 1204 470 1204 470 9029 1315 370 1316 370 471 1181 1339 370 1315 370 471 1204 470 1204 1315 370 471 1204 470 1204 470 1204 470 7968 1315 370 1316 370 470 1204 1315 370 1316 370 470 1203 471 1203 1316 369 472 1203 471 1203 471 1203 471 9026 1316 369 1316 368 472 1202 1317 369 1316 369 471 1203 471 1202 1316 369 471 1202 471 1203 471 1203 496 7942 1341 364 1321 364 476 1178 1341 364 1322 364 476 1177 497 1178 1341 364 476 1178 496 1178 496 1177 497
|
||||
#
|
||||
name: Timer
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1338 372 1314 372 469 1179 1339 371 1314 372 469 1178 496 1178 496 1179 1339 371 470 1204 470 1178 496 7942 1339 372 1367 364 479 1124 1451 362 1323 362 480 1092 582 1093 581 1093 1424 363 478 1094 524 1149 525 9208 1391 364 1321 364 478 1150 1368 364 1322 364 532 1095 576 1098 524 1150 1367 364 505 1123 550 1123 550 7888 1314 371 1315 371 470 1204 1315 371 1314 371 470 1204 470 1204 470 1204 1315 371 470 1204 470 1204 470
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2228 672 788 676 787 675 788 676 816 676 787 1409 759 1437 759 704 785 678 785 1412 784 680 783 681 782 683 781 683 780 684 779 684 780 684 779 1417 780 684 779 1417 780 1417 779 1417 779 49573 2249 689 780 1417 779 49573 2250 690 780 1417 780
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2278 652 808 655 784 679 785 681 782 704 759 1437 759 1437 759 705 784 679 785 1412 783 680 782 682 781 1415 781 1416 780 683 780 683 781 1416 780 683 780 1416 780 683 781 683 781 683 781 49575 2250 689 781 1416 780
|
||||
#
|
||||
name: Timer
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2259 672 788 674 789 674 789 704 787 677 787 1408 758 1437 759 705 758 705 758 1437 784 679 784 680 783 1414 782 1415 781 1416 780 684 779 684 779 1417 779 684 779 684 779 684 779 1417 779 49567 2253 687 782 1415 781
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1335 509 1337 510 448 1390 1336 509 1337 511 447 1391 448 1390 449 1391 1335 511 447 1394 445 1391 448 9180 1334 510 1335 511 447 1393 1333 510 1335 511 448 1392 447 1391 448 1390 1335 511 447 1392 447 1391 448 9180 1334 510 1335 511 447 1391 1335 510 1336 511 448 1391 449 1391 448 1391 1335 511 447 1392 447 1391 448 9180 1335 510 1335 511 447 1391 1335 509 1337 510 448 1392 448 1391 448 1391 1335 511 448 1391 448 1391 448 9181 1335 510 1335 511 447 1391 1336 509 1337 511 448 1392 448 1392 447 1391 1335 511 447 1392 448 1393 446 9182 1334 510 1335 511 447 1391 1335 510 1336 511 448 1392 448 1392 447 1391 1335 511 447 1392 448 1392 447 9182 1334 510 1335 511 447 1391 1335 510 1335 511 448 1393 447 1392 447 1390 1336 511 447 1393 446 1393 446 9182 1334 511 1356 490 473 1366 1357 487 1335 511 474 1366 474 1365 474 1364 1334 511 475 1366 473 1366 473 9155 1334 510 1345 501 474 1365 1358 487 1335 512 474 1366 473 1365 474 1364 1334 511 475 1367 472 1366 473
|
||||
#
|
||||
name: Mode
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 43 00 00 00
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1286 403 1287 401 447 1245 1289 405 1289 402 446 1244 447 1245 446 1246 445 1247 444 1248 443 1245 1288 7139 1286 403 1287 402 446 1246 1287 406 1288 402 446 1246 445 1244 447 1247 444 1244 446 1244 446 1246 1287 7138 1286 402 1288 402 446 1246 1288 405 1289 402 445 1245 446 1247 444 1245 446 1246 445 1273 418 1247 1287 7137 1288 402 1288 402 445 1247 1286 406 1288 402 445 1247 444 1245 446 1245 446 1244 447 1246 445 1245 1288 7137 1288 402 1288 402 446 1246 1287 405 1288 402 445 1247 444 1246 444 1247 444 1246 445 1246 445 1246 1287 7138 1287 403 1287 402 445 1246 1288 406 1288 402 446 1246 445 1246 445 1245 446 1245 446 1246 445 1246 1288 7139 1286 402 1288 401 446 1246 1287 406 1287 402 446 1247 444 1245 446 1247 444 1245 446 1247 444 1246 1287 7138 1288 401 1289 401 447 1248 1285 405 1289 402 446 1245 446 1246 445 1246 445 1245 446 1245 445 1247 1286 7138 1288 402 1288 401 447 1247 1286 406 1288 402 446 1246 445 1245 446 1246 445 1245 446 1245 446 1246 1287 7138 1287 402 1288 401 447 1245 1288 406 1288 401 447 1245 446 1245 446 1246 445 1244 447 1245 446 1247 1286
|
||||
#
|
||||
name: Speed_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1287 402 1289 402 446 1249 1285 406 1288 402 446 1245 446 1246 445 1246 445 1247 444 1247 1286 402 446 7981 1286 404 1287 402 445 1247 1287 406 1288 402 446 1245 446 1246 445 1246 445 1246 445 1247 1287 402 446 7978 1288 403 1288 402 446 1246 1288 406 1288 402 446 1248 443 1248 443 1274 417 1247 445 1248 1286 402 446 7980 1289 402 1289 402 446 1246 1288 406 1288 402 446 1247 444 1246 445 1247 445 1246 445 1249 1285 403 445 7986 1234 454 1288 403 445 1275 1208 458 1237 454 445 1247 444 1247 445 1247 444 1247 445 1247 1236 454 445 7988 1233 454 1237 454 445 1247 1287 408 1236 454 445 1247 445 1248 444 1247 445 1248 443 1248 1286 403 445 7986 1286 403 1288 403 445 1249 1285 406 1288 403 445 1249 442 1246 445 1249 442 1248 443 1248 1286 403 445 7985 1286 403 1288 403 445 1247 1287 406 1288 403 445 1249 442 1247 444 1247 444 1246 445 1247 1287 403 445 7984 1286 404 1286 402 446 1248 1285 407 1287 402 446 1247 444 1246 445 1246 445 1247 444 1247 1287 402 446 7985 1284 403 1287 403 445 1248 1285 407 1287 403 445 1247 444 1247 444 1247 444 1246 445 1247 1286 403 445 7982 1287 403 1287 402 446 1247 1287 407 1287 402 446 1246 445 1246 445 1246 445 1248 443 1247 1287 402 446
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1287 402 1289 401 447 1247 1287 405 1289 401 447 1247 444 1245 1289 401 447 1247 444 1245 447 1247 445 7983 1287 403 1288 402 446 1245 1290 406 1289 401 447 1245 447 1248 1286 402 446 1246 446 1246 446 1246 446 7981 1289 402 1289 402 446 1247 1287 406 1288 403 445 1246 445 1248 1286 401 447 1246 445 1245 446 1248 443 7984 1288 403 1288 402 446 1247 1287 406 1288 401 447 1245 446 1246 1288 401 447 1246 445 1245 446 1248 443 7984 1286 403 1288 401 447 1249 1285 405 1289 402 446 1246 445 1246 1288 402 446 1246 445 1247 444 1246 445 7982 1288 402 1289 401 447 1247 1287 405 1289 401 447 1245 446 1249 1285 401 447 1250 441 1245 446 1245 447 7984 1286 402 1288 401 447 1244 1290 405 1289 401 447 1245 446 1244 1290 401 447 1246 445 1246 445 1247 444 7981 1288 402 1288 402 446 1246 1287 405 1289 401 447 1244 447 1246 1288 401 447 1245 446 1246 445 1246 445 7983 1287 403 1288 402 446 1245 1289 406 1288 402 446 1246 445 1247 1287 402 446 1247 444 1246 445 1246 445 7985 1286 403 1288 402 446 1246 1288 406 1288 402 446 1245 446 1247 1287 402 446 1248 443 1246 445 1246 445
|
||||
#
|
||||
name: Timer
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1235 454 1236 454 444 1248 1235 459 1234 454 443 1249 441 1249 442 1249 1234 456 441 1248 443 1250 440 7985 1234 456 1234 454 497 1195 1234 458 1235 455 490 1200 496 1194 491 1199 1237 454 491 1200 497 1194 491 7937 1234 455 1235 455 490 1201 1234 459 1235 455 490 1200 497 1195 496 1196 1234 455 416 1274 497 1193 492 7937 1233 455 1235 454 417 1275 1234 459 1234 455 441 1250 441 1248 442 1249 1236 455 441 1249 442 1250 441 7985 1234 455 1235 454 443 1249 1235 458 1236 455 441 1249 442 1248 442 1250 1233 454 443 1247 443 1247 443 7983 1235 455 1235 454 443 1247 1236 458 1236 454 444 1250 441 1249 442 1248 1235 454 443 1248 443 1249 442 7984 1235 455 1235 455 442 1249 1235 459 1234 455 416 1275 415 1274 491 1201 1235 454 416 1276 415 1274 417 8011 1233 455 1235 456 414 1276 1234 457 1236 453 417 1275 416 1276 414 1274 1236 454 416 1276 415 1275 416 8011 1234 455 1235 453 394 1299 1235 458 1236 454 392 1300 391 1298 393 1298 1236 455 392 1298 393 1300 391
|
||||
#
|
||||
name: Mode
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1233 456 1234 454 416 1276 1235 458 1236 455 415 1275 416 1274 417 1274 417 1274 1237 454 416 1274 417 8009 1234 456 1234 456 414 1275 1236 458 1236 454 416 1276 415 1276 392 1298 393 1299 1235 453 394 1298 393 8030 1235 455 1235 453 393 1299 1235 459 1235 455 391 1299 392 1299 392 1298 392 1299 1235 454 392 1300 391 8032 1235 454 1236 456 390 1300 1235 458 1236 454 392 1298 393 1299 392 1300 391 1298 1237 453 393 1298 393 8035 1235 455 1235 453 393 1299 1236 458 1236 454 393 1297 394 1299 392 1297 394 1298 1236 456 391 1297 394 8035 1234 453 1237 453 393 1299 1235 461 1232 452 394 1299 392 1297 393 1300 391 1300 1234 453 393 1298 393 8034 1236 453 1237 453 393 1298 1236 457 1237 453 393 1298 393 1299 392 1299 392 1299 1235 454 393 1298 393
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 02 00 00 00
|
||||
command: 11 00 00 00
|
||||
#
|
||||
name: Speed_up
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 02 00 00 00
|
||||
command: 0D 00 00 00
|
||||
#
|
||||
name: Timer
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 02 00 00 00
|
||||
command: 09 00 00 00
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 654 1906 626 1880 1921 610 1922 637 626 1906 626 1880 652 1880 1920 612 652 1881 1920 637 1895 638 625 1881 651 1881 651 1906 1895 610 654 1906 626 1907 1894 638 1894 610 654 1906 626 1882 650 1878 1923 609 654 22169 625 1881 651 1880 1921 637 1895 610 653 1878 654 1906 626 1880 1921 637 626 1906 1895 612 1920 637 626 1906 626 1880 653 1906 1895 610 653 1879 653 1907 1894 609 1923 637 626 1906 626 1906 626 1879 1922 637 626 22140 654 1881 651 1906 1895 609 1923 637 626 1906 626 1877 655 1906 1895 612 651 1880 1921 612 1920 638 625 1906 626 1881 651 1906 1895 638 625 1880 652 1879 1922 638 1894 611 652 1879 653 1906 626 1906 1895 610 653 22169 625 1880 652 1879 1922 610 1922 613 650 1879 653 1880 652 1906 1895 612 651 1906 1895 610 1922 637 626 1882 650 1907 625 1878 1923 612 652 1906 626 1906 1895 638 1894 611 653 1879 653 1906 626 1880 1921 610 653 22141 653 1907 625 1880 1921 612 1920 637 626 1879 653 1906 626 1879 1922 637 626 1880 1921 609 1923 638 625 1907 625 1884 648 1879 1922 637 626 1906 626 1906 1895 612 1920 637 626 1879 653 1878 654 1906 1895 612 651 22169 625 1906 626 1907 1894 610 1922 637 626 1881 651 1906 626 1879 1922 638 626 1906 1895 613 1919 638 625 1907 625 1880 652 1906 1895 638 625 1907 625 1879 1922 611 1921 638 625 1906 626 1907 625 1907 1894 611 652 22143 651 1881 651 1906 1895 611 1921 637 626 1906 626 1880 652 1907 1894 611 652 1879 1922 612 1920 611 652 1907 625 1906 626 1881 1920 637 627 1907 625 1906 1895 638 1894 638 625 1880 652 1877 655 1906 1895 638 625 22143 651 1907 625 1906 1895 609 1923 608 655 1906 626 1878 654 1906 1894 637 627 1878 1923 637 1895 637 626 1879 653 1907 625 1907 1894 611 653 1906 626 1880 1921 637 1895 612 652 1907 625 1907 625 1881 1920 611 653 22168 626 1879 653 1906 1895 638 1894 609 654 1907 625 1906 626 1879 1922 638 625 1880 1921 638 1894 608 655 1878 654 1906 626 1907 1894 637 626 1906 626 1906 1895 638 1894 608 656 1906 626 1907 625 1880 1921 639 625 22168 626 1906 626 1880 1921 610 1922 638 625 1906 626 1906 626 1881 1920 638 626 1906 1895 637 1895 612 652 1906 626 1878 654 1906 1895 637 626 1877 655 1907 1894 638 1894 610 654 1906 626 1906 626 1907 1894 609 654 22145 649 1879 653 1880 1921 637 1895 611 653 1906 626 1907 625 1878 1923 638 625 1906 1895 610 1922 637 626 1878 654 1881 651 1881 1920 610 654 1907 625 1906 1895 637 1895 637 626 1906 626 1880 652 1906 1895 610 654 22140 654 1882 650 1881 1920 609 1923 611 653 1879 653 1879 653 1879 1922 637 626 1906 1895 613 1919 613 651 1906 626 1880 652 1881 1920 637 626 1883 649 1907 1894 638 1894 609 655 1907 625 1879 653 1906 1895 638 626 22146 649 1906 626 1906 1895 637 1895 638 625 1879 653 1906 626 1906 1895 610 653 1907 1893 638 1894 610 654 1906 626 1906 626 1882 1919 611 653 1907 625 1881 1920 611 1921 610 654 1880 652 1906 626 1907 1894 610 654 22169 625 1906 626 1906 1895 611 1921 610 654 1906 626 1906 626 1881 1920 610 653 1906 1895 637 1895 638 625 1906 626 1880 652 1906 1895 613 651 1907 625 1906 1895 611 1921 638 625 1906 626 1880 652 1881 1920 615 649 22169 625 1878 654 1881 1920 637 1895 612 651 1907 625 1907 625 1906 1895 612 651 1906 1895 612 1920 638 625 1879 653 1906 626 1906 1895 614 650 1907 625 1906 1895 611 1921 638 625 1882 650 1879 653 1878 1923 610 653 22142 653 1878 654 1880 1921 612 1920 613 650 1906 626 1906 626 1881 1920 611 653 1879 1922 612 1920 610 653 1880 652 1906 626 1906 1895 613 650 1907 625 1881 1920 638 1894 614 649 1881 651 1907 625 1881 1920 611 652 22169 625 1906 626 1880 1921 612 1920 608 656 1906 626 1881 651 1879 1922 609 654 1881 1920 612 1920 614 649 1880 652 1906 626 1907 1894 637 627 1906 626 1907 1894 613 1919 611 652 1881 651 1879 653 1906 1895 610 654 22169 625 1880 652 1906 1895 637 1895 609 654 1881 651 1879 653 1905 1896 609 654 1907 1894 614 1918 637 626 1906 626 1880 652 1906 1895 614 649 1906 626 1879 1922 609 1923 638 626 1880 652 1906 626 1906 1895 637 626 22145 649 1879 653 1880 1921 612 1920 608 655 1882 650 1906 626 1906 1895 638 625 1879 1922 637 1895 638 626 1879 653 1880 652 1907 1894 615 649 1906 626 1882 1919 612 1920 612 651 1906 626 1879 653 1881 1920 638 625 22142 652 1879 653 1878 1923 610 1922 612 652 1879 653 1879 653 1879 1922 611 653 1878 1923 609 1923 610 654 1880 652 1906 626 1882 1919 609 655 1906 626 1906 1895 612 1920 611 652 1880 652 1906 626 1880 1921 609 655
|
||||
#
|
||||
name: Timer
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 627 1905 627 1906 1895 610 1923 611 653 1906 627 1878 655 1906 1895 609 1923 636 1896 636 628 1906 1895 611 653 1878 654 1879 1922 610 654 1877 1924 637 1895 637 627 1906 1895 637 627 1882 650 1906 1895 637 627 22143 654 1878 654 1906 1895 612 1921 611 653 1879 654 1880 653 1880 1921 637 1895 610 1923 637 627 1906 1895 609 655 1906 627 1877 1924 609 654 1906 1895 636 1896 611 653 1879 1922 637 626 1906 626 1906 1895 609 655 22170 627 1905 627 1906 1895 636 1896 611 653 1879 654 1880 652 1878 1923 637 1895 611 1922 608 655 1879 1922 637 627 1880 653 1879 1922 610 654 1879 1922 611 1921 607 657 1878 1923 610 653 1905 627 1906 1895 609 655
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 654 1906 599 1906 1895 665 1867 638 626 1908 625 1909 651 1906 1867 638 1895 638 1894 639 653 1881 652 1879 653 1906 1895 610 654 1906 1868 637 1895 664 1896 609 655 1878 655 1905 627 1878 1923 637 627 1879 1922 20875 653 1878 655 1880 1921 612 1921 612 652 1880 652 1880 653 1905 1896 611 1921 613 1920 609 655 1878 655 1905 627 1880 1921 637 627 1880 1921 610 1923 610 1922 611 653 1905 627 1878 655 1882 1919 637 627 1879 1922 20875 653 1906 627 1883 1918 636 1896 610 654 1881 652 1879 653 1906 1895 637 1895 611 1921 610 654 1879 654 1879 654 1881 1920 609 655 1878 1923 612 1920 608 1925 610 654 1882 651 1906 626 1880 1921 610 654 1879 1922
|
||||
#
|
||||
name: Speed_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 574 1958 574 1934 1868 689 1843 663 601 1957 575 1931 602 1931 1871 689 574 1932 1870 661 602 1932 1870 662 1871 661 602 1930 603 1931 601 1930 603 1929 1873 689 574 1931 1871 689 1843 689 574 1958 574 1930 603 22195 602 1958 574 1932 1870 660 1873 661 602 1932 601 1957 575 1958 1844 689 574 1932 1870 661 602 1931 1871 689 1844 661 602 1932 601 1929 603 1958 574 1958 1844 662 601 1930 1872 688 1844 663 600 1933 599 1933 600 22222 575 1932 600 1932 1870 661 1871 662 601 1958 574 1931 602 1930 1871 660 603 1958 1844 688 575 1931 1871 661 1871 688 575 1931 602 1958 574 1931 602 1931 1871 661 602 1932 1870 661 1872 689 574 1930 602 1932 601 22198 599 1932 601 1958 1843 663 1870 661 602 1931 601 1931 602 1958 1844 660 603 1931 1871 662 601 1930 1871 663 1870 661 602 1931 602 1957 575 1930 603 1931 1871 662 601 1929 1873 664 1868 661 603 1931 602 1932 601
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1269 409 1272 433 402 1253 1264 417 1264 451 405 1259 432 1256 1271 418 438 1253 428 1263 428 1262 429 8016 1267 411 1270 409 436 1245 1272 409 1272 443 402 1261 430 1258 1269 420 436 1255 436 1254 437 1253 438 8046 1268 410 1271 407 428 1253 1264 417 1264 425 431 1259 432 1256 1271 417 428 1263 428 1262 429 1261 430 8026 1267 410 1271 409 436 1244 1262 418 1263 425 431 1259 432 1256 1271 418 438 1252 429 1261 430 1260 431 8027 1267 411 1270 435 410 1244 1262 418 1263 452 404 1259 432 1256 1271 418 438 1252 429 1261 430 1260 431 8014 1269 408 1273 432 403 1251 1266 414 1267 449 407 1255 436 1252 1265 425 431 1259 432 1258 433 1257 434 8050 1264 413 1268 437 408 1246 1271 409 1272 443 402 1260 431 1257 1270 418 438 1253 428 1262 429 1260 431 8025 1268 408 1273 406 429 1251 1266 415 1266 448 408 1256 435 1252 1265 424 432 1258 433 1256 435 1255 436 8017 1266 410 1271 435 410 1243 1263 416 1265 451 405 1257 434 1254 1273 443 402 1260 431 1259 432 1258 433
|
||||
#
|
||||
name: Mode
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1270 407 1264 441 404 1248 1269 413 1268 445 411 1251 430 1260 431 1259 432 1255 1272 444 401 1260 431 7984 1268 408 1263 441 404 1248 1269 439 1242 418 427 1260 431 1259 432 1257 434 1254 1263 426 430 1257 434 8018 1266 411 1270 434 401 1251 1266 442 1239 420 436 1252 429 1261 430 1259 432 1255 1272 417 428 1259 432 7992 1271 405 1266 438 407 1244 1262 444 1237 423 433 1255 436 1253 428 1261 430 1257 1270 446 410 1251 430 7998 1265 411 1270 434 401 1251 1266 442 1239 420 436 1252 429 1261 430 1259 432 1255 1272 444 401 1259 432 7982 1270 405 1266 439 406 1245 1272 435 1236 424 432 1256 435 1254 437 1252 429 1259 1268 447 409 1252 429 8022 1272 404 1267 438 407 1244 1262 444 1237 422 434 1254 437 1252 429 1260 431 1256 1271 444 401 1259 432
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 80 00 00 00
|
||||
command: 12 00 00 00
|
||||
#
|
||||
name: Timer
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 80 00 00 00
|
||||
command: 1F 00 00 00
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8997 4462 577 1659 577 541 576 540 578 540 577 541 577 540 578 539 578 540 578 540 578 1658 578 1658 578 1657 578 1658 578 1657 579 1658 578 1658 578 1659 577 1658 578 540 578 539 579 540 578 540 578 540 578 540 578 540 578 539 578 1658 578 1659 577 1658 578 1658 578 1658 578 1658 578 1659 577 1658 578 541 577 540 577 540 578 540 578 539 579 540 578 540 578 539 579 1658 578 1658 578 1658 578 1658 578 1658 578 1658 578
|
||||
#
|
||||
name: Speed_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8998 4462 575 1659 576 540 577 540 578 540 578 540 577 540 577 541 576 540 577 540 577 1658 577 1656 579 1658 577 1657 578 1658 577 1657 578 1657 578 1657 578 1658 577 1658 578 540 578 539 579 539 579 541 577 540 578 539 578 540 578 539 578 1657 578 1657 579 1658 578 1657 579 1658 578 1657 578 1657 579 1657 578 539 579 539 578 540 577 540 577 540 577 539 578 540 577 539 578 1659 576 1658 578 1658 577 1657 578 1657 604
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8998 4462 577 1660 577 538 580 541 577 541 577 540 578 541 577 540 578 540 578 540 578 1659 578 1658 579 1659 578 1658 578 1660 577 1659 578 1659 578 1658 579 1659 578 541 577 540 578 1658 579 539 579 540 578 541 577 541 577 541 577 1659 577 1660 577 540 578 1658 579 1659 578 1660 577 1659 577 1658 578 540 578 541 577 1659 577 540 578 541 577 540 578 541 577 540 578 1659 577 1659 577 540 578 1658 578 1660 576 1658 578
|
||||
#
|
||||
name: Timer
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9001 4465 577 1659 579 540 578 539 579 540 578 541 577 540 578 540 578 541 577 540 578 1658 579 1659 578 1659 578 1660 577 1659 578 1659 578 1658 579 1658 579 1658 579 540 578 1658 579 540 578 540 578 540 578 540 578 541 577 539 579 1660 577 539 579 1658 578 1659 578 1659 578 1658 578 1658 578 1658 578 540 578 1659 577 539 579 540 578 540 578 540 578 540 578 540 578 1659 577 540 578 1658 578 1659 577 1658 578 1658 578
|
||||
#
|
||||
name: Mode
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8997 4461 578 1658 579 539 579 541 577 539 579 540 578 540 578 539 579 540 578 540 578 1658 578 1658 578 1658 578 1657 579 1658 578 1658 578 1658 578 1658 578 1658 578 1659 578 1659 578 539 579 541 577 540 578 540 578 540 578 541 577 540 578 540 578 1658 579 1659 578 1658 579 1659 578 1659 578 1658 578 1657 579 1657 579 539 579 540 578 541 576 539 579 540 578 540 578 540 578 540 577 1658 578 1658 578 1658 578 1658 578
|
||||
#
|
||||
name: Rotate
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 30 00 00 00
|
||||
command: 83 00 00 00
|
||||
#
|
||||
name: Rotate
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 30 00 00 00
|
||||
command: 9C 00 00 00
|
||||
#
|
||||
name: Timer
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 30 00 00 00
|
||||
command: 87 00 00 00
|
||||
#
|
||||
name: Mode
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 30 00 00 00
|
||||
command: 86 00 00 00
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1239 476 1211 476 390 1268 420 1268 418 1267 420 1267 1240 476 389 1268 419 1267 420 1266 421 1266 421 8016 1240 476 1211 476 390 1267 421 1267 419 1267 420 1266 1241 476 390 1268 419 1267 420 1266 448 1240 446 1238 102 6648 1241 476 1211 476 390 1268 420 1266 420 1268 419 1266 1241 476 390 1268 420 1267 420 1267 447 1240 446 7990 1239 476 1211 476 390 1269 419 1266 420 1267 420 1266 1241 476 390 1268 420 1266 421 1266 448 1240 447 7990 1238 476 1211 476 390 1267 421 1267 419 1268 419 1267 1240 476 390 1269 419 1267 420 1266 448 1240 446 1236 104 6649 1239 476 1211 476 390 1268 420 1267 419 1267 420 1265 1242 476 390 1268 420 1267 420 1266 447 1239 422
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1202 481 1202 481 437 1248 1200 483 1201 481 437 1247 436 1247 436 1247 436 1247 436 1248 435 1247 1201 7032 1202 482 1201 481 437 1247 1178 506 1177 505 436 1248 435 1248 435 1248 435 1246 437 1248 435 1247 1179 7056 1178 504 1179 506 434 1248 1178 505 1178 505 436 1247 436 1247 436 1247 436 1248 435 1247 436 1247 1179 7056 1178 505 1178 505 435 1247 1179 505 1178 504 436 1247 436 1248 434 1249 435 1247 436 1246 437 1248 1178
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1309 373 1310 373 493 1192 1308 374 1309 372 495 1191 492 1189 1311 375 491 1190 494 1189 494 1191 492 7740 1310 373 1310 373 494 1192 1308 376 1307 374 493 1191 492 1190 1310 376 491 1190 493 1219 464 1190 493 7743 1308 374 1309 376 491 1190 1309 375 1308 377 491 1190 493 1192 1257 426 491 1219 464 1192 491 1190 493 7742 1258 427 1256 426 491 1219 1230 425 1258 424 493 1190 493 1192 1258 453 464 1192 491 1193 490 1220 463
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 55 00 00 00
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1226 441 1228 442 441 1228 1227 472 1198 441 443 1231 439 1228 442 1227 443 1227 442 1226 443 1227 1228 7154
|
||||
#
|
||||
name: Speed_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1197 472 1198 442 414 1260 1223 472 1198 444 413 1285 385 1256 1227 472 385 1285 385 1285 385 1256 414 7968
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9358 4535 573 574 575 572 577 570 579 568 571 576 573 574 575 572 577 571 578 596 553 565 574 1695 574 1696 573 1697 572 1697 572 1698 571 1700 579 567 572 1697 572 1699 580 568 571 576 573 574 575 571 578 1718 551 1694 575 572 577 569 580 1689 580 1690 579 1690 579 1693 576 558 581 41436 9369 2240 578 95786 9363 2236 572
|
||||
#
|
||||
name: Mode
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9302 4546 571 576 573 571 578 567 572 573 576 569 570 575 574 571 578 567 572 574 575 568 571 1699 569 1700 568 1702 576 1693 575 1694 574 1698 570 573 576 1693 575 1695 573 1699 569 576 573 572 577 566 573 1697 571 1701 577 567 572 573 576 567 572 1699 569 1700 578 1694 574 557 572 41653 9292 2245 573 96004 9293 2241 577
|
||||
#
|
||||
name: Speed_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9413 4549 577 572 577 573 576 574 575 575 574 576 573 577 572 577 582 568 581 569 580 567 582 1693 575 1699 579 1695 573 1701 577 1697 581 1693 575 1701 577 573 576 571 578 1699 579 570 579 571 578 570 579 1724 554 566 573 1702 576 1700 578 569 580 1695 573 1701 577 1699 579 583 546 41516 9407 2244 573 95961 9506 2241 586
|
||||
#
|
||||
name: Speed_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1329 376 1303 374 462 1193 1331 377 1302 376 460 1192 462 1218 462 1218 462 1218 487 1193 1330 376 459 7907 1300 380 1299 380 456 1224 1299 380 1299 380 456 1224 456 1224 456 1224 456 1224 456 1225 1298 381 455 8172 1298 380 1299 380 456 1224 1299 380 1299 381 455 1225 455 1225 455 1225 455 1225 455 1225 1298 381 455 7912 1298 381 1298 381 455 1225 1298 381 1298 381 455 1225 454 1225 455 1225 455 1225 455 1225 1298 381 455
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1329 378 1301 378 458 1195 1329 375 1304 378 456 1196 460 1220 1329 379 457 1196 484 1221 458 1222 457 7910 1298 382 1297 382 454 1226 1297 382 1297 382 454 1226 454 1226 1297 382 454 1226 454 1226 454 1226 454 8158 1297 382 1297 382 454 1226 1297 382 1297 382 454 1226 454 1226 1297 382 453 1227 453 1227 453 1227 453 7913 1296 382 1297 383 453 1227 1296 383 1296 383 453 1227 453 1227 1296 383 453 1227 453 1227 453 1228 452
|
||||
#
|
||||
name: Mode
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1245 415 1250 436 386 1274 1224 410 1245 441 381 1278 387 1272 383 1250 405 1255 1254 407 405 1281 384 8184 1248 413 1252 434 388 1272 1216 418 1247 439 383 1250 405 1280 385 1248 407 1279 1219 415 407 1278 387 8179 1253 408 1247 439 383 1250 1248 412 1243 444 378 1255 410 1275 380 1280 385 1275 1223 411 411 1249 406
|
||||
#
|
||||
name: Speed_up
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 80 00 00 00
|
||||
command: 11 00 00 00
|
||||
#
|
||||
name: Rotate
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 4608 4604 546 1509 540 1516 544 1512 548 1509 540 1517 543 1513 547 2555 545 1511 539 2564 546 1510 540 2562 538 1518 542 2559 541 1516 544 1512 548 1509 541 1514 4605 4605 545 1510 540 1517 543 1514 546 1510 540 1517 543 1514 546 2556 544 1512 548 2555 545 1510 540 2563 547 1508 542 2587 513 1517 543 1513 547 1510 540 13755 9237 2298 545
|
||||
|
|
2938
applications/main/infrared/resources/infrared/assets/leds.ir
Normal file
2938
applications/main/infrared/resources/infrared/assets/leds.ir
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,8 @@
|
|||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 18th Feb, 2024
|
||||
# Last Checked 18th Feb, 2024
|
||||
#
|
||||
# Last Updated 5th Oct, 2024
|
||||
# Last Checked 5th Oct, 2024
|
||||
#
|
||||
# TEMP FIX FOR POWER
|
||||
#
|
||||
# ON
|
||||
|
@ -71,7 +71,7 @@ type: parsed
|
|||
protocol: NECext
|
||||
address: 00 30 00 00
|
||||
command: 83 7C 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
|
@ -107,13 +107,13 @@ type: parsed
|
|||
protocol: NECext
|
||||
address: 87 4E 00 00
|
||||
command: 29 D6 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 87 4E 00 00
|
||||
command: 08 F7 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
|
@ -149,7 +149,6 @@ type: parsed
|
|||
protocol: NEC
|
||||
address: 02 00 00 00
|
||||
command: 1D 00 00 00
|
||||
#
|
||||
# ON
|
||||
name: Power
|
||||
type: raw
|
||||
|
@ -162,7 +161,6 @@ type: parsed
|
|||
protocol: NEC
|
||||
address: 02 00 00 00
|
||||
command: 1D 00 00 00
|
||||
#
|
||||
# ON
|
||||
name: Power
|
||||
type: raw
|
||||
|
@ -835,25 +833,25 @@ type: raw
|
|||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 243 27700 170 27632 246 27694 282 27595 307 27497 241 27696 177 27710 164 27644 245 27629 246 27712 174 27638 211 27736 131 27741 306 27504 214 27727 135 27749 132 27761 126 27744 131 27753 127 27764 121 27767 132 27773 307 27577 131 27706 213 27761 129 27759 128 27770 125 27694 213 27751 307 27578 131 27737 131 27745 304 27575 335 27540 124 27752 132 27749 132 27747 134 27757 134 27758 127 27762 131 27748 131 27750 122 27749 130 27748 125 27772 131 27774 136 27762 135 27686 215 27742 131 27749 132 27756 133 27764 126 24073 9255 4460 672 488 618 541 619 541 619 1675 619 1676 618 542 618 542 618 542 618 1676 618 542 618 543 617 1678 616 568 592 1702 592 1702 592 1703 617 543 617 543 617 1677 617 543 617 1678 615 544 616 544 616 544 616 1678 616 1679 615 544 616 1679 615 545 615 1679 615 1679 615 1679 615 40240 9173 2273 591
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 219 27658 217 27663 216 27658 216 27634 216 27642 215 27646 217 27662 217 27637 216 27649 216 27649 218 27656 217 27658 215 27640 214 27636 217 27649 216 27644 218 27635 217 27630 215 27645 216 27631 215 27632 216 27650 216 27628 217 27630 214 27627 217 27623 215 27632 215 27641 216 27634 214 27633 215 27648 215 27648 217 27651 215 27635 216 27629 216 27630 216 2021 9254 4461 618 542 618 542 618 542 618 1675 619 1676 618 541 619 541 619 542 618 1677 617 543 617 543 617 1678 616 568 592 1702 592 1702 618 1676 618 542 618 542 618 543 617 1677 617 543 617 544 616 1678 616 544 616 1678 616 1678 616 1678 616 544 616 1678 616 1678 616 544 616 1678 616 40239 9200 2247 617 99930 110 27739 119 27738 123 27750 126 27738 175 27617 214 27716 203 27604 213 27639 217 27631 214 27722 136 27753 119 27736 175 27618 246 27683 177 27619 245 27685 171 55486 244 27693 158 27635 241 27695 170 27693 129 27717 340 27530 113 27757 106 27751 124 27728 172 27707 126 27666 215 27708 123 27733 123
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 18 E9 00 00
|
||||
command: 49 B6 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 02 00 00 00
|
||||
command: 14 00 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
|
@ -865,13 +863,13 @@ type: parsed
|
|||
protocol: NEC
|
||||
address: 02 00 00 00
|
||||
command: 48 00 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 02 00 00 00
|
||||
command: 40 00 00 00
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
|
@ -901,7 +899,7 @@ type: parsed
|
|||
protocol: NECext
|
||||
address: B8 57 00 00
|
||||
command: 1E E1 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
|
@ -925,13 +923,13 @@ type: parsed
|
|||
protocol: NEC
|
||||
address: 32 00 00 00
|
||||
command: 8F 00 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 32 00 00 00
|
||||
command: 8C 00 00 00
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: raw
|
||||
frequency: 38000
|
||||
|
@ -949,19 +947,19 @@ type: parsed
|
|||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: A8 00 00 00
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 88 00 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 9C 00 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
|
@ -979,19 +977,19 @@ type: parsed
|
|||
protocol: NECext
|
||||
address: 87 45 00 00
|
||||
command: 17 E8 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9064 4354 666 1559 666 1562 662 1586 638 475 636 477 635 477 635 478 635 1590 635 1591 634 478 635 1591 634 478 634 478 635 478 634 1591 635 478 634 1591 634 478 635 478 634 478 635 1591 634 478 634 1591 635 478 634 478 634 1591 634 1591 635 1591 634 478 635 1591 634 478 634 1591 635 40957 9035 2144 634 95483 9047 2155 632 95484 9048 2153 633
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 87 45 00 00
|
||||
command: 50 AF 00 00
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: raw
|
||||
frequency: 38000
|
||||
|
@ -1009,13 +1007,13 @@ type: parsed
|
|||
protocol: NECext
|
||||
address: FF FF 00 00
|
||||
command: E8 17 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: FF FF 00 00
|
||||
command: BD 42 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
|
@ -1033,13 +1031,13 @@ type: parsed
|
|||
protocol: Kaseikyo
|
||||
address: 41 54 32 00
|
||||
command: 05 00 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: Kaseikyo
|
||||
address: 41 54 32 00
|
||||
command: 70 01 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: Kaseikyo
|
||||
|
@ -1099,61 +1097,61 @@ type: parsed
|
|||
protocol: NECext
|
||||
address: 4F 50 00 00
|
||||
command: 02 FD 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 4F 50 00 00
|
||||
command: 08 F7 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 4F 50 00 00
|
||||
command: 0B F4 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 81 03 00 00
|
||||
command: F0 0F 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 87 45 00 00
|
||||
command: 51 AE 00 00
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 87 45 00 00
|
||||
command: 52 AD 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8811 4222 530 1580 531 1579 531 507 531 507 531 507 531 508 531 508 530 1582 528 1583 527 535 503 1608 502 536 501 1609 501 537 501 1610 500 538 500 1611 499 538 500 539 500 538 500 1611 500 539 499 538 500 1611 499 539 499 1611 499 1611 500 1611 499 539 499 1611 500 1611 500 539 499 35437 8784 4252 500 1611 500 1612 500 539 500 539 500 539 500 539 500 539 500 1611 500 1612 499 539 500 1612 500 539 500 1612 499 539 500 1612 500 539 500 1612 499 539 500 539 500 539 499 1612 499 540 499 539 500 1612 499 539 500 1612 499 1613 499 1612 499 539 500 1612 500 1612 500 539 500
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8811 4222 530 1580 531 1579 531 507 531 507 531 507 531 508 531 508 530 1582 528 1583 527 535 503 1608 502 536 501 1609 501 537 501 1610 500 538 500 1611 499 538 500 539 500 538 500 1611 500 539 499 538 500 1611 499 539 499 1611 499 1611 500 1611 499 539 499 1611 500 1611 500 539 499 35437 8784 4252 500 1611 500 1612 500 539 500 539 500 539 500 539 500 539 500 1611 500 1612 499 539 500 1612 500 539 500 1612 499 539 500 1612 500 539 500 1612 499 539 500 539 500 539 499 1612 499 540 499 539 500 1612 499 539 500 1612 499 1613 499 1612 499 539 500 1612 500 1612 500 539 500
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 06 00 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 09 00 00 00
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
|
@ -1171,253 +1169,253 @@ type: parsed
|
|||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 00 00 00 00
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9035 4437 563 548 563 548 563 522 594 1645 591 1639 592 518 593 548 563 552 563 1640 592 548 563 553 562 1668 564 524 592 1642 594 1674 562 1673 563 1639 593 548 563 552 564 1669 562 548 563 520 615 529 586 1645 587 529 587 1650 586 1646 586 529 586 1650 586 1649 587 1646 586 524 587 524 587 524 587 524 587 525 643 467 644 440 671 467 644 472 643 1592 644 1593 643 1593 642 1594 641 1594 587 1649 585 1651 563 1682 562 14430 9008 2205 562
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 84 F4 00 00
|
||||
command: 2C D3 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 84 F4 00 00
|
||||
command: 2F D0 00 00
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 4F 50 00 00
|
||||
command: 0F F0 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 02 00 00 00
|
||||
command: 12 00 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 02 00 00 00
|
||||
command: 12 00 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 02 00 00 00
|
||||
command: 06 00 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 02 00 00 00
|
||||
command: 00 00 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 04 B1 00 00
|
||||
command: 58 A7 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 04 B1 00 00
|
||||
command: 58 A7 00 00
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9107 4376 681 1573 681 472 655 472 654 474 652 475 652 476 651 476 652 476 651 476 651 1604 651 1604 651 1604 651 1603 652 1604 651 1604 651 1604 651 1604 650 476 651 477 650 477 650 476 651 477 651 1604 650 476 651 477 650 1604 651 1604 650 1604 651 1604 650 1604 651 477 650 1604 650 39498 9079 2178 651
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 8B CA 00 00
|
||||
command: 12 ED 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 8B CA 00 00
|
||||
command: 12 ED 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 8B CA 00 00
|
||||
command: 44 BB 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 8B CA 00 00
|
||||
command: 46 B9 00 00
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 8B CA 00 00
|
||||
command: 11 EE 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 81 03 00 00
|
||||
command: F0 0F 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 40 00 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 BD 00 00
|
||||
command: 01 FE 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 40 00 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 BD 00 00
|
||||
command: 01 FE 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 BD 00 00
|
||||
command: 10 EF 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 BD 00 00
|
||||
command: 0C F3 00 00
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 BD 00 00
|
||||
command: 6A 95 00 00
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 02 00 00 00
|
||||
command: 11 00 00 00
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 87 4E 00 00
|
||||
command: 51 AE 00 00
|
||||
#
|
||||
#
|
||||
name: Pause
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 30 00 00
|
||||
command: A8 57 00 00
|
||||
#
|
||||
#
|
||||
name: Play
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 30 00 00
|
||||
command: A9 56 00 00
|
||||
#
|
||||
#
|
||||
name: Pause
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 30 00 00
|
||||
command: A9 56 00 00
|
||||
#
|
||||
#
|
||||
name: Play
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 83 55 00 00
|
||||
command: 5E A1 00 00
|
||||
#
|
||||
#
|
||||
name: Pause
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 83 55 00 00
|
||||
command: 5B A4 00 00
|
||||
#
|
||||
#
|
||||
name: Play
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 93 00 00 00
|
||||
#
|
||||
#
|
||||
name: Pause
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 93 00 00 00
|
||||
#
|
||||
#
|
||||
name: Play
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 15 00 00 00
|
||||
#
|
||||
#
|
||||
name: Pause
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 15 00 00 00
|
||||
#
|
||||
#
|
||||
name: Play
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: B8 57 00 00
|
||||
command: 18 E7 00 00
|
||||
#
|
||||
#
|
||||
name: Play
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8981 4411 532 1616 557 1592 557 465 556 465 556 466 555 467 554 468 554 1595 554 467 554 468 554 1595 554 467 580 1569 581 1568 581 1568 581 1569 580 441 581 1569 580 442 580 1570 579 1594 555 467 555 443 579 442 580 1594 554 467 555 1594 555 467 555 468 554 1595 554 1595 528 1620 529 42169 9008 2106 531
|
||||
#
|
||||
#
|
||||
name: Pause
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8981 4411 532 1616 557 1592 557 465 556 465 556 466 555 467 554 468 554 1595 554 467 554 468 554 1595 554 467 580 1569 581 1568 581 1568 581 1569 580 441 581 1569 580 442 580 1570 579 1594 555 467 555 443 579 442 580 1594 554 467 555 1594 555 467 555 468 554 1595 554 1595 528 1620 529 42169 9008 2106 531
|
||||
#
|
||||
#
|
||||
name: Play
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 31 00 00 00
|
||||
command: 41 00 00 00
|
||||
#
|
||||
#
|
||||
name: Pause
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 31 00 00 00
|
||||
command: 41 00 00 00
|
||||
#
|
||||
#
|
||||
name: Play
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 03 00 00 00
|
||||
#
|
||||
#
|
||||
name: Pause
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
|
@ -1483,75 +1481,339 @@ type: raw
|
|||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 353 1742 355 693 355 1742 355 1742 355 693 355 1744 353 694 354 1743 354 693 355 1743 354 694 354 693 355 694 354 1742 355 695 353 43687 354 1743 354 696 352 1744 353 1744 353 694 354 695 353 1742 355 694 354 1743 354 694 354 1743 354 1742 355 1742 355 694 354 1744 353 41606 351 1745 352 696 352 1746 351 1746 351 697 351 1747 350 696 352 1745 352 698 350 1746 351 698 350 696 352 698 350 1746 351 699 349
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: Samsung32
|
||||
address: 07 00 00 00
|
||||
command: 02 00 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: Samsung32
|
||||
address: 07 00 00 00
|
||||
command: 02 00 00 00
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: Samsung32
|
||||
address: 07 00 00 00
|
||||
command: D1 00 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 8A 00 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 8A 00 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 81 03 00 00
|
||||
command: F0 0F 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 81 03 00 00
|
||||
command: F0 0F 00 00
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9033 4255 562 543 564 1701 562 1674 563 567 565 541 564 567 565 567 537 1700 564 1700 537 568 564 1699 564 541 565 1699 565 540 565 567 565 570 535 567 565 567 565 1673 564 567 565 1673 564 567 565 540 618 514 565 1700 563 1674 564 567 564 1674 563 569 563 1672 565 1700 589 1648 564
|
||||
#
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9033 4255 562 543 564 1701 562 1674 563 567 565 541 564 567 565 567 537 1700 564 1700 537 568 564 1699 564 541 565 1699 565 540 565 567 565 570 535 567 565 567 565 1673 564 567 565 1673 564 567 565 540 618 514 565 1700 563 1674 564 567 564 1674 563 569 563 1672 565 1700 589 1648 564
|
||||
#
|
||||
#
|
||||
name: Mute
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9034 4255 564 567 564 1671 566 1699 564 540 565 567 565 540 564 566 566 1699 563 1672 567 565 566 1673 565 567 565 1672 565 566 566 539 565 567 565 1698 539 566 566 1698 564 541 565 565 567 1672 565 566 566 1672 565 567 565 1699 538 566 566 1698 564 1673 566 566 565 1672 566 566 566
|
||||
#
|
||||
#
|
||||
name: Vol_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9035 4254 565 566 565 1672 566 1699 564 539 567 566 566 540 564 567 565 1698 539 1698 566 566 564 1673 565 566 565 1672 565 566 566 539 566 566 566 567 563 541 565 566 566 538 566 566 566 1671 566 566 566 1697 565 1675 563 1699 563 1674 565 1699 538 1700 564 565 565 1674 564 567 565
|
||||
#
|
||||
#
|
||||
name: Vol_dn
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9010 4253 564 566 566 1671 566 1699 565 565 539 568 564 566 565 539 566 1699 565 1672 565 566 566 1672 564 567 565 1672 565 567 565 567 564 541 564 1698 566 539 565 567 565 567 562 542 565 1699 564 539 567 1699 565 540 564 1698 566 1672 565 1698 566 1672 565 567 565 1671 565 566 566
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 30 00 00
|
||||
command: 97 68 00 00
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 30 00 00
|
||||
command: 98 67 00 00
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 48 50 00 00
|
||||
command: 02 FD 00 00
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 48 50 00 00
|
||||
command: 02 FD 00 00
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 48 50 00 00
|
||||
command: 27 D8 00 00
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2288 611 571 587 1153 587 572 587 572 1167 572 1168 571 587 573 587 572 587 572 589 570 587 572 587 572 587 572 588 571 77346 2287 611 571 588 1152 588 571 588 571 1168 571 1168 571 588 571 588 571 588 571 589 570 587 572 588 572 587 572 587 572
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2288 611 571 587 1153 587 572 587 572 1167 572 1168 571 587 573 587 572 587 572 589 570 587 572 587 572 587 572 588 571 77346 2287 611 571 588 1152 588 571 588 571 1168 571 1168 571 588 571 588 571 588 571 589 570 587 572 588 572 587 572 587 572
|
||||
#
|
||||
name: Vol_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2288 610 572 588 1151 587 573 588 571 1169 570 586 573 587 572 587 1152 587 573 586 1153 588 572 587 573 586 573 587 572 76771 2289 610 572 588 1151 587 573 587 572 1166 573 587 572 587 572 587 1152 588 571 588 1151 587 573 587 572 587 573 588 571
|
||||
#
|
||||
name: Vol_dn
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2310 588 571 589 1151 588 571 589 570 1168 572 1169 1150 588 1151 588 1151 590 570 588 1152 588 572 589 570 588 572 588 572 75033 2288 609 573 587 1152 587 572 586 574 1168 571 1167 1152 587 1152 586 1153 587 572 587 1152 587 572 588 571 587 572 587 572
|
||||
#
|
||||
name: Mute
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 2288 610 572 586 1153 587 573 587 572 1166 574 1168 571 1167 1152 588 572 587 1152 588 572 587 572 587 573 587 572 588 571 75611 2288 610 572 587 1152 588 572 588 572 1167 572 1166 573 1167 1152 587 573 587 1152 588 572 588 571 586 573 586 573 585 574
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 83 55 00 00
|
||||
command: AD 52 00 00
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 83 55 00 00
|
||||
command: B1 4E 00 00
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 83 55 00 00
|
||||
command: B3 4C 00 00
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 30 00 00 00
|
||||
command: 0B 00 00 00
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 30 00 00 00
|
||||
command: 0B 00 00 00
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 86 6B 00 00
|
||||
command: 0A F5 00 00
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 86 6B 00 00
|
||||
command: 0A F5 00 00
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 86 6B 00 00
|
||||
command: 4A B5 00 00
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 86 6B 00 00
|
||||
command: 48 B7 00 00
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 86 6B 00 00
|
||||
command: 0E F1 00 00
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 6A 00 00
|
||||
command: 40 BF 00 00
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 6A 00 00
|
||||
command: 40 BF 00 00
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 04 0F 00 00
|
||||
command: AD 52 00 00
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 04 0F 00 00
|
||||
command: AD 52 00 00
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 04 0F 00 00
|
||||
command: 02 FD 00 00
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 04 0F 00 00
|
||||
command: 03 FC 00 00
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 04 0F 00 00
|
||||
command: 09 F6 00 00
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 32 00 00 00
|
||||
command: 03 00 00 00
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 32 00 00 00
|
||||
command: 09 00 00 00
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 32 00 00 00
|
||||
command: 0C 00 00 00
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9024 4506 570 582 542 582 518 606 518 606 518 606 518 606 518 606 518 610 518 1698 548 1698 546 1700 546 1700 546 1698 546 1700 546 1696 548 1702 570 1674 546 610 516 1698 546 606 542 582 542 582 544 1674 546 610 520 606 542 1674 570 582 542 1676 546 1698 570 1674 572 582 520 1698 546
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9024 4506 570 582 542 582 518 606 518 606 518 606 518 606 518 606 518 610 518 1698 548 1698 546 1700 546 1700 546 1698 546 1700 546 1696 548 1702 570 1674 546 610 516 1698 546 606 542 582 542 582 544 1674 546 610 520 606 542 1674 570 582 542 1676 546 1698 570 1674 572 582 520 1698 546
|
||||
#
|
||||
name: Mute
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9044 4484 572 580 544 580 544 580 544 580 542 582 544 580 520 604 542 586 544 1674 570 1674 570 1676 570 1674 572 1672 570 1674 546 1700 568 1678 570 582 542 1672 572 580 542 580 542 1674 566 582 542 1672 570 584 538 1674 564 580 534 1674 556 1674 556 580 530 1672 558 582 524 1676 552
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1221 1171 433 566 433 881 433 2381 433 1486 434 565 434 1486 433 1776 433 2380 433 565 434 2381 433 1170 434 87358 1220 1171 433 566 433 883 431 2381 433 1486 433 567 432 1487 432 1775 434 2381 432 566 433 2380 434 1171 433 86252 1221 1172 432 565 434 880 435 2381 433 1486 433 565 434 1487 432 1776 433 2380 434 566 433 2379 434 1170 434
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1221 1171 433 566 433 881 433 2381 433 1486 434 565 434 1486 433 1776 433 2380 433 565 434 2381 433 1170 434 87358 1220 1171 433 566 433 883 431 2381 433 1486 433 567 432 1487 432 1775 434 2381 432 566 433 2380 434 1171 433 86252 1221 1172 432 565 434 880 435 2381 433 1486 433 565 434 1487 432 1776 433 2380 434 566 433 2379 434 1170 434
|
||||
#
|
||||
name: Vol_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1221 1173 431 566 433 882 432 2382 432 1487 432 566 433 565 434 566 433 2671 432 2670 433 2381 433 566 433 87411 324 937 325 358 325 647 326
|
||||
#
|
||||
name: Vol_dn
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1221 1172 432 566 433 882 433 2381 432 1486 434 566 433 565 434 882 433 1486 434 2669 434 2065 433 566 433 87779 324 936 326 358 325 647 326
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: SIRC15
|
||||
address: 54 00 00 00
|
||||
command: 12 00 00 00
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: SIRC15
|
||||
address: 54 00 00 00
|
||||
command: 13 00 00 00
|
||||
#
|
||||
name: Play
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 30 00 00
|
||||
command: 21 DE 00 00
|
||||
#
|
||||
name: Pause
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 30 00 00
|
||||
command: 21 DE 00 00
|
||||
#
|
||||
name: Play
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 86 6B 00 00
|
||||
command: 09 F6 00 00
|
||||
#
|
||||
name: Pause
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 86 6B 00 00
|
||||
command: 09 F6 00 00
|
||||
#
|
||||
name: Vol_down
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 4F 50 00 00
|
||||
command: 0B F4 00 00
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -20,6 +20,7 @@ ADD_SCENE(infrared, universal_ac, UniversalAC)
|
|||
ADD_SCENE(infrared, universal_fan, UniversalFan)
|
||||
ADD_SCENE(infrared, universal_audio, UniversalAudio)
|
||||
ADD_SCENE(infrared, universal_projector, UniversalProjector)
|
||||
ADD_SCENE(infrared, universal_leds, UniversalLEDs)
|
||||
ADD_SCENE(infrared, gpio_settings, GpioSettings)
|
||||
ADD_SCENE(infrared, debug, Debug)
|
||||
ADD_SCENE(infrared, error_databases, ErrorDatabases)
|
||||
|
|
|
@ -4,6 +4,7 @@ typedef enum {
|
|||
SubmenuIndexUniversalTV,
|
||||
SubmenuIndexUniversalAudio,
|
||||
SubmenuIndexUniversalProjector,
|
||||
SubmenuIndexUniversalLEDs,
|
||||
SubmenuIndexUniversalFan,
|
||||
SubmenuIndexUniversalAirConditioner,
|
||||
} SubmenuIndex;
|
||||
|
@ -38,6 +39,13 @@ void infrared_scene_universal_on_enter(void* context) {
|
|||
infrared_scene_universal_submenu_callback,
|
||||
context);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"LEDs",
|
||||
SubmenuIndexUniversalLEDs,
|
||||
infrared_scene_universal_submenu_callback,
|
||||
context);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Fans",
|
||||
|
@ -73,6 +81,9 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) {
|
|||
} else if(event.event == SubmenuIndexUniversalProjector) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneUniversalProjector);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexUniversalLEDs) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneUniversalLEDs);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexUniversalFan) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneUniversalFan);
|
||||
consumed = true;
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
#include "../infrared_app_i.h"
|
||||
|
||||
#include "common/infrared_scene_universal_common.h"
|
||||
|
||||
void infrared_scene_universal_leds_on_enter(void* context) {
|
||||
InfraredApp* infrared = context;
|
||||
ButtonPanel* button_panel = infrared->button_panel;
|
||||
InfraredBruteForce* brute_force = infrared->brute_force;
|
||||
|
||||
// Button codes
|
||||
// Power_off, Power_on, Brightness_up, Brightness_dn, Red, Blue, Green, White
|
||||
|
||||
infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/leds.ir"));
|
||||
|
||||
button_panel_reserve(button_panel, 2, 4);
|
||||
uint32_t i = 0;
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
0,
|
||||
10,
|
||||
12,
|
||||
&I_power_19x20,
|
||||
&I_power_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 15, 34, &I_on_text_9x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Power_on");
|
||||
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
0,
|
||||
35,
|
||||
12,
|
||||
&I_off_19x20,
|
||||
&I_off_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 38, 34, &I_off_text_12x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Power_off");
|
||||
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
1,
|
||||
10,
|
||||
42,
|
||||
&I_plus_19x20,
|
||||
&I_plus_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Brightness_up");
|
||||
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
1,
|
||||
35,
|
||||
42,
|
||||
&I_minus_19x20,
|
||||
&I_minus_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 12, 64, &I_brightness_text_40x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Brightness_dn");
|
||||
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
2,
|
||||
10,
|
||||
74,
|
||||
&I_red_19x20,
|
||||
&I_red_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Red");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
2,
|
||||
35,
|
||||
74,
|
||||
&I_green_19x20,
|
||||
&I_green_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Green");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
0,
|
||||
3,
|
||||
10,
|
||||
99,
|
||||
&I_blue_19x20,
|
||||
&I_blue_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
infrared_brute_force_add_record(brute_force, i++, "Blue");
|
||||
button_panel_add_item(
|
||||
button_panel,
|
||||
i,
|
||||
1,
|
||||
3,
|
||||
35,
|
||||
99,
|
||||
&I_white_19x20,
|
||||
&I_white_hover_19x20,
|
||||
infrared_scene_universal_common_item_callback,
|
||||
context);
|
||||
button_panel_add_icon(button_panel, 19, 121, &I_color_text_24x5);
|
||||
infrared_brute_force_add_record(brute_force, i++, "White");
|
||||
|
||||
button_panel_add_label(button_panel, 20, 9, FontPrimary, "LEDs");
|
||||
|
||||
infrared_scene_universal_common_on_enter(context);
|
||||
}
|
||||
|
||||
bool infrared_scene_universal_leds_on_event(void* context, SceneManagerEvent event) {
|
||||
return infrared_scene_universal_common_on_event(context, event);
|
||||
}
|
||||
|
||||
void infrared_scene_universal_leds_on_exit(void* context) {
|
||||
infrared_scene_universal_common_on_exit(context);
|
||||
}
|
|
@ -2,6 +2,20 @@
|
|||
|
||||
#define TAG "Mosgortrans"
|
||||
|
||||
void render_section_header(
|
||||
FuriString* str,
|
||||
const char* name,
|
||||
uint8_t prefix_separator_cnt,
|
||||
uint8_t suffix_separator_cnt) {
|
||||
for(uint8_t i = 0; i < prefix_separator_cnt; i++) {
|
||||
furi_string_cat_printf(str, ":");
|
||||
}
|
||||
furi_string_cat_printf(str, "[ %s ]", name);
|
||||
for(uint8_t i = 0; i < suffix_separator_cnt; i++) {
|
||||
furi_string_cat_printf(str, ":");
|
||||
}
|
||||
}
|
||||
|
||||
void from_days_to_datetime(uint32_t days, DateTime* datetime, uint16_t start_year) {
|
||||
uint32_t timestamp = days * 24 * 60 * 60;
|
||||
DateTime start_datetime = {0};
|
||||
|
|
|
@ -10,6 +10,11 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
void render_section_header(
|
||||
FuriString* str,
|
||||
const char* name,
|
||||
uint8_t prefix_separator_cnt,
|
||||
uint8_t suffix_separator_cnt);
|
||||
bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* result);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -15,4 +15,11 @@ static constexpr auto nfc_app_api_table = sort(create_array_t<sym_entry>(
|
|||
API_METHOD(
|
||||
mosgortrans_parse_transport_block,
|
||||
bool,
|
||||
(const MfClassicBlock* block, FuriString* result))));
|
||||
(const MfClassicBlock* block, FuriString* result)),
|
||||
API_METHOD(
|
||||
render_section_header,
|
||||
void,
|
||||
(FuriString * str,
|
||||
const char* name,
|
||||
uint8_t prefix_separator_cnt,
|
||||
uint8_t suffix_separator_cnt))));
|
||||
|
|
|
@ -246,8 +246,28 @@ App(
|
|||
)
|
||||
|
||||
App(
|
||||
appid="ndef_parser",
|
||||
appid="ndef_ul_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
cdefines=[("NDEF_PROTO", "NDEF_PROTO_UL")],
|
||||
entry_point="ndef_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/ndef.c"],
|
||||
)
|
||||
App(
|
||||
appid="ndef_mfc_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
cdefines=[("NDEF_PROTO", "NDEF_PROTO_MFC")],
|
||||
entry_point="ndef_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/ndef.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="ndef_slix_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
cdefines=[("NDEF_PROTO", "NDEF_PROTO_SLIX")],
|
||||
entry_point="ndef_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
|
@ -272,6 +292,24 @@ App(
|
|||
sources=["plugins/supported_cards/skylanders.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="hworld_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="hworld_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/hworld.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="trt_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="trt_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/trt.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="nfc_cli",
|
||||
targets=["f7"],
|
||||
|
|
|
@ -117,7 +117,7 @@ static void nfc_scene_read_menu_on_enter_mf_classic(NfcApp* instance) {
|
|||
if(!mf_classic_is_card_read(data)) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Extract MF Keys",
|
||||
"Extract MFC Keys",
|
||||
SubmenuIndexDetectReader,
|
||||
nfc_protocol_support_common_submenu_callback,
|
||||
instance);
|
||||
|
@ -155,7 +155,7 @@ static void nfc_scene_saved_menu_on_enter_mf_classic(NfcApp* instance) {
|
|||
if(!mf_classic_is_card_read(data)) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Extract MF Keys",
|
||||
"Extract MFC Keys",
|
||||
SubmenuIndexDetectReader,
|
||||
nfc_protocol_support_common_submenu_callback,
|
||||
instance);
|
||||
|
|
|
@ -559,6 +559,7 @@ static void nfc_protocol_support_scene_save_name_on_exit(NfcApp* instance) {
|
|||
*/
|
||||
enum {
|
||||
NfcSceneEmulateStateWidget, /**< Widget view is displayed. */
|
||||
NfcSceneEmulateStateWidgetLog, /**< Widget view with Log button is displayed */
|
||||
NfcSceneEmulateStateTextBox, /**< TextBox view is displayed. */
|
||||
};
|
||||
|
||||
|
@ -637,12 +638,14 @@ static bool
|
|||
"Log",
|
||||
nfc_protocol_support_common_widget_callback,
|
||||
instance);
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager, NfcSceneEmulate, NfcSceneEmulateStateWidgetLog);
|
||||
}
|
||||
// Update TextBox data
|
||||
text_box_set_text(instance->text_box, furi_string_get_cstr(instance->text_box_store));
|
||||
consumed = true;
|
||||
} else if(event.event == GuiButtonTypeCenter) {
|
||||
if(state == NfcSceneEmulateStateWidget) {
|
||||
if(state == NfcSceneEmulateStateWidgetLog) {
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewTextBox);
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager, NfcSceneEmulate, NfcSceneEmulateStateTextBox);
|
||||
|
@ -653,7 +656,7 @@ static bool
|
|||
if(state == NfcSceneEmulateStateTextBox) {
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget);
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager, NfcSceneEmulate, NfcSceneEmulateStateWidget);
|
||||
instance->scene_manager, NfcSceneEmulate, NfcSceneEmulateStateWidgetLog);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,8 +75,12 @@
|
|||
#define NFC_APP_MFKEY32_LOGS_FILE_NAME ".mfkey32.log"
|
||||
#define NFC_APP_MFKEY32_LOGS_FILE_PATH (NFC_APP_FOLDER "/" NFC_APP_MFKEY32_LOGS_FILE_NAME)
|
||||
|
||||
#define NFC_APP_MF_CLASSIC_DICT_USER_PATH (NFC_APP_FOLDER "/assets/mf_classic_dict_user.nfc")
|
||||
#define NFC_APP_MF_CLASSIC_DICT_USER_PATH (NFC_APP_FOLDER "/assets/mf_classic_dict_user.nfc")
|
||||
#define NFC_APP_MF_CLASSIC_DICT_USER_NESTED_PATH \
|
||||
(NFC_APP_FOLDER "/assets/mf_classic_dict_user_nested.nfc")
|
||||
#define NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH (NFC_APP_FOLDER "/assets/mf_classic_dict.nfc")
|
||||
#define NFC_APP_MF_CLASSIC_DICT_SYSTEM_NESTED_PATH \
|
||||
(NFC_APP_FOLDER "/assets/mf_classic_dict_nested.nfc")
|
||||
|
||||
typedef enum {
|
||||
NfcRpcStateIdle,
|
||||
|
@ -94,6 +98,12 @@ typedef struct {
|
|||
bool is_key_attack;
|
||||
uint8_t key_attack_current_sector;
|
||||
bool is_card_present;
|
||||
MfClassicNestedPhase nested_phase;
|
||||
MfClassicPrngType prng_type;
|
||||
MfClassicBackdoor backdoor;
|
||||
uint16_t nested_target_key;
|
||||
uint16_t msb_count;
|
||||
bool enhanced_dict;
|
||||
} NfcMfClassicDictAttackContext;
|
||||
|
||||
struct NfcApp {
|
||||
|
|
|
@ -107,7 +107,7 @@ static const IdMapping bart_zones[] = {
|
|||
{.id = 0x0023, .name = "South Hayward"},
|
||||
{.id = 0x0024, .name = "Union City"},
|
||||
{.id = 0x0025, .name = "Fremont"},
|
||||
{.id = 0x0026, .name = "Daly City(2)?"},
|
||||
{.id = 0x0026, .name = "Castro Valley"},
|
||||
{.id = 0x0027, .name = "Dublin/Pleasanton"},
|
||||
{.id = 0x0028, .name = "South San Francisco"},
|
||||
{.id = 0x0029, .name = "San Bruno"},
|
||||
|
@ -116,6 +116,8 @@ static const IdMapping bart_zones[] = {
|
|||
{.id = 0x002c, .name = "West Dublin/Pleasanton"},
|
||||
{.id = 0x002d, .name = "OAK Airport"},
|
||||
{.id = 0x002e, .name = "Warm Springs/South Fremont"},
|
||||
{.id = 0x002f, .name = "Milpitas"},
|
||||
{.id = 0x0030, .name = "Berryessa/North San Jose"},
|
||||
};
|
||||
static const size_t kNumBARTZones = COUNT(bart_zones);
|
||||
|
||||
|
@ -138,6 +140,19 @@ static const IdMapping actransit_zones[] = {
|
|||
};
|
||||
static const size_t kNumACTransitZones = COUNT(actransit_zones);
|
||||
|
||||
// Instead of persisting individual Station IDs, Caltrain saves Zone numbers.
|
||||
// https://www.caltrain.com/stations-zones
|
||||
static const IdMapping caltrain_zones[] = {
|
||||
{.id = 0x0001, .name = "Zone 1"},
|
||||
{.id = 0x0002, .name = "Zone 2"},
|
||||
{.id = 0x0003, .name = "Zone 3"},
|
||||
{.id = 0x0004, .name = "Zone 4"},
|
||||
{.id = 0x0005, .name = "Zone 5"},
|
||||
{.id = 0x0006, .name = "Zone 6"},
|
||||
};
|
||||
|
||||
static const size_t kNumCaltrainZones = COUNT(caltrain_zones);
|
||||
|
||||
//
|
||||
// Full agency+zone mapping.
|
||||
//
|
||||
|
@ -148,6 +163,7 @@ static const struct {
|
|||
} agency_zone_map[] = {
|
||||
{.agency_id = 0x0001, .zone_map = actransit_zones, .zone_count = kNumACTransitZones},
|
||||
{.agency_id = 0x0004, .zone_map = bart_zones, .zone_count = kNumBARTZones},
|
||||
{.agency_id = 0x0006, .zone_map = caltrain_zones, .zone_count = kNumCaltrainZones},
|
||||
{.agency_id = 0x0012, .zone_map = muni_zones, .zone_count = kNumMUNIZones}};
|
||||
static const size_t kNumAgencyZoneMaps = COUNT(agency_zone_map);
|
||||
|
||||
|
|
243
applications/main/nfc/plugins/supported_cards/hworld.c
Normal file
243
applications/main/nfc/plugins/supported_cards/hworld.c
Normal file
|
@ -0,0 +1,243 @@
|
|||
// Flipper Zero parser for H World Hotel Key Cards
|
||||
// H World operates around 10,000 hotels, most of which in mainland China
|
||||
// Reverse engineering and parser written by @Torron (Github: @zinongli)
|
||||
#include "nfc_supported_card_plugin.h"
|
||||
#include <flipper_application.h>
|
||||
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
|
||||
#include <bit_lib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TAG "H World"
|
||||
#define ROOM_SECTOR 1
|
||||
#define VIP_SECTOR 5
|
||||
#define ROOM_SECTOR_KEY_BLOCK 7
|
||||
#define VIP_SECTOR_KEY_BLOCK 23
|
||||
#define ACCESS_INFO_BLOCK 5
|
||||
#define ROOM_NUM_DECIMAL_BLOCK 6
|
||||
#define H_WORLD_YEAR_OFFSET 2000
|
||||
|
||||
typedef struct {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
} MfClassicKeyPair;
|
||||
|
||||
static MfClassicKeyPair hworld_standard_keys[] = {
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 000
|
||||
{.a = 0x543071543071, .b = 0x5F01015F0101}, // 001
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 002
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 003
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 004
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 005
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 006
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 007
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 008
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 009
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 010
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 011
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 012
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 013
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 014
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 015
|
||||
};
|
||||
|
||||
static MfClassicKeyPair hworld_vip_keys[] = {
|
||||
{.a = 0x000000000000, .b = 0xFFFFFFFFFFFF}, // 000
|
||||
{.a = 0x543071543071, .b = 0x5F01015F0101}, // 001
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 002
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 003
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 004
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0x200510241234}, // 005
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0x200510241234}, // 006
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0x200510241234}, // 007
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0x200510241234}, // 008
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0x200510241234}, // 009
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0x200510241234}, // 010
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0x200510241234}, // 011
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0x200510241234}, // 012
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 013
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 014
|
||||
{.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, // 015
|
||||
};
|
||||
|
||||
static bool hworld_verify(Nfc* nfc) {
|
||||
bool verified = false;
|
||||
|
||||
do {
|
||||
const uint8_t block_num = mf_classic_get_first_block_num_of_sector(ROOM_SECTOR);
|
||||
|
||||
MfClassicKey standard_key = {0};
|
||||
bit_lib_num_to_bytes_be(
|
||||
hworld_standard_keys[ROOM_SECTOR].a, COUNT_OF(standard_key.data), standard_key.data);
|
||||
|
||||
MfClassicAuthContext auth_context;
|
||||
MfClassicError standard_error = mf_classic_poller_sync_auth(
|
||||
nfc, block_num, &standard_key, MfClassicKeyTypeA, &auth_context);
|
||||
|
||||
if(standard_error != MfClassicErrorNone) {
|
||||
FURI_LOG_D(TAG, "Failed static key check for block %u", block_num);
|
||||
break;
|
||||
}
|
||||
|
||||
MfClassicKey vip_key = {0};
|
||||
bit_lib_num_to_bytes_be(
|
||||
hworld_vip_keys[VIP_SECTOR].b, COUNT_OF(vip_key.data), vip_key.data);
|
||||
|
||||
MfClassicError vip_error = mf_classic_poller_sync_auth(
|
||||
nfc, block_num, &vip_key, MfClassicKeyTypeB, &auth_context);
|
||||
|
||||
if(vip_error == MfClassicErrorNone) {
|
||||
FURI_LOG_D(TAG, "VIP card detected");
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Standard card detected");
|
||||
}
|
||||
|
||||
verified = true;
|
||||
} while(false);
|
||||
|
||||
return verified;
|
||||
}
|
||||
|
||||
static bool hworld_read(Nfc* nfc, NfcDevice* device) {
|
||||
furi_assert(nfc);
|
||||
furi_assert(device);
|
||||
|
||||
bool is_read = false;
|
||||
|
||||
MfClassicData* data = mf_classic_alloc();
|
||||
nfc_device_copy_data(device, NfcProtocolMfClassic, data);
|
||||
|
||||
do {
|
||||
MfClassicType type = MfClassicType1k;
|
||||
MfClassicError standard_error = mf_classic_poller_sync_detect_type(nfc, &type);
|
||||
MfClassicError vip_error = MfClassicErrorNotPresent;
|
||||
if(standard_error != MfClassicErrorNone) break;
|
||||
data->type = type;
|
||||
|
||||
MfClassicDeviceKeys standard_keys = {};
|
||||
for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) {
|
||||
bit_lib_num_to_bytes_be(
|
||||
hworld_standard_keys[i].a, sizeof(MfClassicKey), standard_keys.key_a[i].data);
|
||||
FURI_BIT_SET(standard_keys.key_a_mask, i);
|
||||
bit_lib_num_to_bytes_be(
|
||||
hworld_standard_keys[i].b, sizeof(MfClassicKey), standard_keys.key_b[i].data);
|
||||
FURI_BIT_SET(standard_keys.key_b_mask, i);
|
||||
}
|
||||
|
||||
standard_error = mf_classic_poller_sync_read(nfc, &standard_keys, data);
|
||||
if(standard_error == MfClassicErrorNone) {
|
||||
FURI_LOG_I(TAG, "Standard card successfully read");
|
||||
} else {
|
||||
MfClassicDeviceKeys vip_keys = {};
|
||||
for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) {
|
||||
bit_lib_num_to_bytes_be(
|
||||
hworld_vip_keys[i].a, sizeof(MfClassicKey), vip_keys.key_a[i].data);
|
||||
FURI_BIT_SET(vip_keys.key_a_mask, i);
|
||||
bit_lib_num_to_bytes_be(
|
||||
hworld_vip_keys[i].b, sizeof(MfClassicKey), vip_keys.key_b[i].data);
|
||||
FURI_BIT_SET(vip_keys.key_b_mask, i);
|
||||
}
|
||||
|
||||
vip_error = mf_classic_poller_sync_read(nfc, &vip_keys, data);
|
||||
|
||||
if(vip_error == MfClassicErrorNone) {
|
||||
FURI_LOG_I(TAG, "VIP card successfully read");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nfc_device_set_data(device, NfcProtocolMfClassic, data);
|
||||
|
||||
is_read = (standard_error == MfClassicErrorNone) | (vip_error == MfClassicErrorNone);
|
||||
} while(false);
|
||||
|
||||
mf_classic_free(data);
|
||||
|
||||
return is_read;
|
||||
}
|
||||
|
||||
bool hworld_parse(const NfcDevice* device, FuriString* parsed_data) {
|
||||
furi_assert(device);
|
||||
const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic);
|
||||
bool parsed = false;
|
||||
|
||||
do {
|
||||
// Check card type
|
||||
if(data->type != MfClassicType1k) break;
|
||||
|
||||
// Check static key for verificaiton
|
||||
const uint8_t* data_room_sec_key_a_ptr = &data->block[ROOM_SECTOR_KEY_BLOCK].data[0];
|
||||
const uint8_t* data_room_sec_key_b_ptr = &data->block[ROOM_SECTOR_KEY_BLOCK].data[10];
|
||||
uint64_t data_room_sec_key_a = bit_lib_get_bits_64(data_room_sec_key_a_ptr, 0, 48);
|
||||
uint64_t data_room_sec_key_b = bit_lib_get_bits_64(data_room_sec_key_b_ptr, 0, 48);
|
||||
if((data_room_sec_key_a != hworld_standard_keys[ROOM_SECTOR].a) |
|
||||
(data_room_sec_key_b != hworld_standard_keys[ROOM_SECTOR].b))
|
||||
break;
|
||||
|
||||
// Check whether this card is VIP
|
||||
const uint8_t* data_vip_sec_key_b_ptr = &data->block[VIP_SECTOR_KEY_BLOCK].data[10];
|
||||
uint64_t data_vip_sec_key_b = bit_lib_get_bits_64(data_vip_sec_key_b_ptr, 0, 48);
|
||||
bool is_hworld_vip = (data_vip_sec_key_b == hworld_vip_keys[VIP_SECTOR].b);
|
||||
uint8_t room_floor = data->block[ACCESS_INFO_BLOCK].data[13];
|
||||
uint8_t room_num = data->block[ACCESS_INFO_BLOCK].data[14];
|
||||
|
||||
// Check in date & time
|
||||
uint16_t check_in_year = data->block[ACCESS_INFO_BLOCK].data[2] + H_WORLD_YEAR_OFFSET;
|
||||
uint8_t check_in_month = data->block[ACCESS_INFO_BLOCK].data[3];
|
||||
uint8_t check_in_day = data->block[ACCESS_INFO_BLOCK].data[4];
|
||||
uint8_t check_in_hour = data->block[ACCESS_INFO_BLOCK].data[5];
|
||||
uint8_t check_in_minute = data->block[ACCESS_INFO_BLOCK].data[6];
|
||||
|
||||
// Expire date & time
|
||||
uint16_t expire_year = data->block[ACCESS_INFO_BLOCK].data[7] + H_WORLD_YEAR_OFFSET;
|
||||
uint8_t expire_month = data->block[ACCESS_INFO_BLOCK].data[8];
|
||||
uint8_t expire_day = data->block[ACCESS_INFO_BLOCK].data[9];
|
||||
uint8_t expire_hour = data->block[ACCESS_INFO_BLOCK].data[10];
|
||||
uint8_t expire_minute = data->block[ACCESS_INFO_BLOCK].data[11];
|
||||
|
||||
furi_string_cat_printf(parsed_data, "\e#H World Card\n");
|
||||
furi_string_cat_printf(
|
||||
parsed_data, "%s\n", is_hworld_vip ? "VIP card" : "Standard room key");
|
||||
furi_string_cat_printf(parsed_data, "Room Num: %u%02u\n", room_floor, room_num);
|
||||
furi_string_cat_printf(
|
||||
parsed_data,
|
||||
"Check-in Date: \n%04u-%02d-%02d\n%02d:%02d:00\n",
|
||||
check_in_year,
|
||||
check_in_month,
|
||||
check_in_day,
|
||||
check_in_hour,
|
||||
check_in_minute);
|
||||
furi_string_cat_printf(
|
||||
parsed_data,
|
||||
"Expiration Date: \n%04u-%02d-%02d\n%02d:%02d:00",
|
||||
expire_year,
|
||||
expire_month,
|
||||
expire_day,
|
||||
expire_hour,
|
||||
expire_minute);
|
||||
parsed = true;
|
||||
} while(false);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/* Actual implementation of app<>plugin interface */
|
||||
static const NfcSupportedCardsPlugin hworld_plugin = {
|
||||
.protocol = NfcProtocolMfClassic,
|
||||
.verify = hworld_verify,
|
||||
.read = hworld_read,
|
||||
.parse = hworld_parse,
|
||||
};
|
||||
|
||||
/* Plugin descriptor to comply with basic plugin specification */
|
||||
static const FlipperAppPluginDescriptor hworld_plugin_descriptor = {
|
||||
.appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID,
|
||||
.ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION,
|
||||
.entry_point = &hworld_plugin,
|
||||
};
|
||||
|
||||
/* Plugin entry point - must return a pointer to const descriptor */
|
||||
const FlipperAppPluginDescriptor* hworld_plugin_ep(void) {
|
||||
return &hworld_plugin_descriptor;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,12 +1,24 @@
|
|||
#include "nfc_supported_card_plugin.h"
|
||||
#include <flipper_application.h>
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
|
||||
#include <nfc/nfc_device.h>
|
||||
#include <bit_lib/bit_lib.h>
|
||||
#include <datetime.h>
|
||||
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
|
||||
|
||||
#include <bit_lib.h>
|
||||
|
||||
#define TAG "Plantain"
|
||||
|
||||
void from_minutes_to_datetime(uint32_t minutes, DateTime* datetime, uint16_t start_year) {
|
||||
uint32_t timestamp = minutes * 60;
|
||||
DateTime start_datetime = {0};
|
||||
start_datetime.year = start_year - 1;
|
||||
start_datetime.month = 12;
|
||||
start_datetime.day = 31;
|
||||
timestamp += datetime_datetime_to_timestamp(&start_datetime);
|
||||
datetime_timestamp_to_datetime(timestamp, datetime);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
|
@ -189,8 +201,9 @@ static bool plantain_read(Nfc* nfc, NfcDevice* device) {
|
|||
|
||||
static bool plantain_parse(const NfcDevice* device, FuriString* parsed_data) {
|
||||
furi_assert(device);
|
||||
|
||||
size_t uid_len = 0;
|
||||
const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic);
|
||||
const uint8_t* uid = mf_classic_get_uid(data, &uid_len);
|
||||
|
||||
bool parsed = false;
|
||||
|
||||
|
@ -207,29 +220,161 @@ static bool plantain_parse(const NfcDevice* device, FuriString* parsed_data) {
|
|||
bit_lib_bytes_to_num_be(sec_tr->key_a.data, COUNT_OF(sec_tr->key_a.data));
|
||||
if(key != cfg.keys[cfg.data_sector].a) break;
|
||||
|
||||
// Point to block 0 of sector 4, value 0
|
||||
const uint8_t* temp_ptr = data->block[16].data;
|
||||
// Read first 4 bytes of block 0 of sector 4 from last to first and convert them to uint32_t
|
||||
// 38 18 00 00 becomes 00 00 18 38, and equals to 6200 decimal
|
||||
uint32_t balance =
|
||||
((temp_ptr[3] << 24) | (temp_ptr[2] << 16) | (temp_ptr[1] << 8) | temp_ptr[0]) / 100;
|
||||
// Read card number
|
||||
// Point to block 0 of sector 0, value 0
|
||||
temp_ptr = data->block[0].data;
|
||||
// Read first 7 bytes of block 0 of sector 0 from last to first and convert them to uint64_t
|
||||
// 04 31 16 8A 23 5C 80 becomes 80 5C 23 8A 16 31 04, and equals to 36130104729284868 decimal
|
||||
uint8_t card_number_arr[7];
|
||||
for(size_t i = 0; i < 7; i++) {
|
||||
card_number_arr[i] = temp_ptr[6 - i];
|
||||
furi_string_printf(parsed_data, "\e#Plantain card\n");
|
||||
|
||||
const uint8_t* temp_ptr = &uid[0];
|
||||
|
||||
// UID is read from last to first byte
|
||||
uint8_t card_number_tmp[uid_len];
|
||||
|
||||
if(uid_len == 4) {
|
||||
for(size_t i = 0; i < 4; i++) {
|
||||
card_number_tmp[i] = temp_ptr[3 - i];
|
||||
}
|
||||
} else if(uid_len == 7) {
|
||||
for(size_t i = 0; i < 7; i++) {
|
||||
card_number_tmp[i] = temp_ptr[6 - i];
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
// Copy card number to uint64_t
|
||||
//UID is converted to a card number
|
||||
uint64_t card_number = 0;
|
||||
for(size_t i = 0; i < 7; i++) {
|
||||
card_number = (card_number << 8) | card_number_arr[i];
|
||||
for(size_t i = 0; i < uid_len; i++) {
|
||||
card_number = (card_number << 8) | card_number_tmp[i];
|
||||
}
|
||||
|
||||
furi_string_printf(
|
||||
parsed_data, "\e#Plantain\nNo.: %lluX\nBalance: %lu\n", card_number, balance);
|
||||
// Print card number with 4-digit groups. "3" in "3078" denotes a ticket type "3 - full ticket", will differ on discounted cards.
|
||||
furi_string_cat_printf(parsed_data, "Number: ");
|
||||
FuriString* card_number_s = furi_string_alloc();
|
||||
furi_string_cat_printf(card_number_s, "%llu", card_number);
|
||||
FuriString* tmp_s = furi_string_alloc_set_str("9643 3078 ");
|
||||
for(uint8_t i = 0; i < 24; i += 4) {
|
||||
for(uint8_t j = 0; j < 4; j++) {
|
||||
furi_string_push_back(tmp_s, furi_string_get_char(card_number_s, i + j));
|
||||
}
|
||||
furi_string_push_back(tmp_s, ' ');
|
||||
}
|
||||
furi_string_cat_printf(parsed_data, "%s\n", furi_string_get_cstr(tmp_s));
|
||||
// this works for 2K Plantain
|
||||
if(data->type == MfClassicType1k) {
|
||||
//balance
|
||||
uint32_t balance = 0;
|
||||
for(uint8_t i = 0; i < 4; i++) {
|
||||
balance = (balance << 8) | data->block[16].data[3 - i];
|
||||
}
|
||||
furi_string_cat_printf(parsed_data, "Balance: %ld rub\n", balance / 100);
|
||||
|
||||
//trips
|
||||
uint8_t trips_metro = data->block[21].data[0];
|
||||
uint8_t trips_ground = data->block[21].data[1];
|
||||
furi_string_cat_printf(parsed_data, "Trips: %d\n", trips_metro + trips_ground);
|
||||
//trip time
|
||||
uint32_t last_trip_timestamp = 0;
|
||||
for(uint8_t i = 0; i < 3; i++) {
|
||||
last_trip_timestamp = (last_trip_timestamp << 8) | data->block[21].data[4 - i];
|
||||
}
|
||||
DateTime last_trip = {0};
|
||||
from_minutes_to_datetime(last_trip_timestamp + 24 * 60, &last_trip, 2010);
|
||||
furi_string_cat_printf(
|
||||
parsed_data,
|
||||
"Trip start: %02d.%02d.%04d %02d:%02d\n",
|
||||
last_trip.day,
|
||||
last_trip.month,
|
||||
last_trip.year,
|
||||
last_trip.hour,
|
||||
last_trip.minute);
|
||||
//validator
|
||||
uint16_t validator = (data->block[20].data[5] << 8) | data->block[20].data[4];
|
||||
furi_string_cat_printf(parsed_data, "Validator: %d\n", validator);
|
||||
//tariff
|
||||
uint16_t fare = (data->block[20].data[7] << 8) | data->block[20].data[6];
|
||||
furi_string_cat_printf(parsed_data, "Tariff: %d rub\n", fare / 100);
|
||||
//trips in metro
|
||||
furi_string_cat_printf(parsed_data, "Trips (Metro): %d\n", trips_metro);
|
||||
//trips on ground
|
||||
furi_string_cat_printf(parsed_data, "Trips (Ground): %d\n", trips_ground);
|
||||
//last payment
|
||||
uint32_t last_payment_timestamp = 0;
|
||||
for(uint8_t i = 0; i < 3; i++) {
|
||||
last_payment_timestamp = (last_payment_timestamp << 8) |
|
||||
data->block[18].data[4 - i];
|
||||
}
|
||||
DateTime last_payment_date = {0};
|
||||
from_minutes_to_datetime(last_payment_timestamp + 24 * 60, &last_payment_date, 2010);
|
||||
furi_string_cat_printf(
|
||||
parsed_data,
|
||||
"Last pay: %02d.%02d.%04d %02d:%02d\n",
|
||||
last_payment_date.day,
|
||||
last_payment_date.month,
|
||||
last_payment_date.year,
|
||||
last_payment_date.hour,
|
||||
last_payment_date.minute);
|
||||
//payment amount. This needs to be investigated more, currently it shows incorrect amount on some cards.
|
||||
uint16_t last_payment = (data->block[18].data[9] << 8) | data->block[18].data[8];
|
||||
furi_string_cat_printf(parsed_data, "Amount: %d rub", last_payment / 100);
|
||||
furi_string_free(card_number_s);
|
||||
furi_string_free(tmp_s);
|
||||
//This is for 4K Plantains.
|
||||
} else if(data->type == MfClassicType4k) {
|
||||
//balance
|
||||
uint32_t balance = 0;
|
||||
for(uint8_t i = 0; i < 4; i++) {
|
||||
balance = (balance << 8) | data->block[16].data[3 - i];
|
||||
}
|
||||
furi_string_cat_printf(parsed_data, "Balance: %ld rub\n", balance / 100);
|
||||
|
||||
//trips
|
||||
uint8_t trips_metro = data->block[21].data[0];
|
||||
uint8_t trips_ground = data->block[21].data[1];
|
||||
furi_string_cat_printf(parsed_data, "Trips: %d\n", trips_metro + trips_ground);
|
||||
//trip time
|
||||
uint32_t last_trip_timestamp = 0;
|
||||
for(uint8_t i = 0; i < 3; i++) {
|
||||
last_trip_timestamp = (last_trip_timestamp << 8) | data->block[21].data[4 - i];
|
||||
}
|
||||
DateTime last_trip = {0};
|
||||
from_minutes_to_datetime(last_trip_timestamp + 24 * 60, &last_trip, 2010);
|
||||
furi_string_cat_printf(
|
||||
parsed_data,
|
||||
"Trip start: %02d.%02d.%04d %02d:%02d\n",
|
||||
last_trip.day,
|
||||
last_trip.month,
|
||||
last_trip.year,
|
||||
last_trip.hour,
|
||||
last_trip.minute);
|
||||
//validator
|
||||
uint16_t validator = (data->block[20].data[5] << 8) | data->block[20].data[4];
|
||||
furi_string_cat_printf(parsed_data, "Validator: %d\n", validator);
|
||||
//tariff
|
||||
uint16_t fare = (data->block[20].data[7] << 8) | data->block[20].data[6];
|
||||
furi_string_cat_printf(parsed_data, "Tariff: %d rub\n", fare / 100);
|
||||
//trips in metro
|
||||
furi_string_cat_printf(parsed_data, "Trips (Metro): %d\n", trips_metro);
|
||||
//trips on ground
|
||||
furi_string_cat_printf(parsed_data, "Trips (Ground): %d\n", trips_ground);
|
||||
//last payment
|
||||
uint32_t last_payment_timestamp = 0;
|
||||
for(uint8_t i = 0; i < 3; i++) {
|
||||
last_payment_timestamp = (last_payment_timestamp << 8) |
|
||||
data->block[18].data[4 - i];
|
||||
}
|
||||
DateTime last_payment_date = {0};
|
||||
from_minutes_to_datetime(last_payment_timestamp + 24 * 60, &last_payment_date, 2010);
|
||||
furi_string_cat_printf(
|
||||
parsed_data,
|
||||
"Last pay: %02d.%02d.%04d %02d:%02d\n",
|
||||
last_payment_date.day,
|
||||
last_payment_date.month,
|
||||
last_payment_date.year,
|
||||
last_payment_date.hour,
|
||||
last_payment_date.minute);
|
||||
//payment amount
|
||||
uint16_t last_payment = (data->block[18].data[9] << 8) | data->block[18].data[8];
|
||||
furi_string_cat_printf(parsed_data, "Amount: %d rub", last_payment / 100);
|
||||
furi_string_free(card_number_s);
|
||||
furi_string_free(tmp_s);
|
||||
}
|
||||
parsed = true;
|
||||
} while(false);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -82,20 +82,6 @@ static const MfClassicKeyPair troika_4k_keys[] = {
|
|||
{.a = 0xBB52F8CCE07F, .b = 0x6B6119752C70}, //40
|
||||
};
|
||||
|
||||
static void troika_render_section_header(
|
||||
FuriString* str,
|
||||
const char* name,
|
||||
uint8_t prefix_separator_cnt,
|
||||
uint8_t suffix_separator_cnt) {
|
||||
for(uint8_t i = 0; i < prefix_separator_cnt; i++) {
|
||||
furi_string_cat_printf(str, ":");
|
||||
}
|
||||
furi_string_cat_printf(str, "[ %s ]", name);
|
||||
for(uint8_t i = 0; i < suffix_separator_cnt; i++) {
|
||||
furi_string_cat_printf(str, ":");
|
||||
}
|
||||
}
|
||||
|
||||
static bool troika_get_card_config(TroikaCardConfig* config, MfClassicType type) {
|
||||
bool success = true;
|
||||
|
||||
|
@ -212,23 +198,25 @@ static bool troika_parse(const NfcDevice* device, FuriString* parsed_data) {
|
|||
FuriString* ground_result = furi_string_alloc();
|
||||
FuriString* tat_result = furi_string_alloc();
|
||||
|
||||
bool result1 = mosgortrans_parse_transport_block(&data->block[32], metro_result);
|
||||
bool result2 = mosgortrans_parse_transport_block(&data->block[28], ground_result);
|
||||
bool result3 = mosgortrans_parse_transport_block(&data->block[16], tat_result);
|
||||
bool is_metro_data_present =
|
||||
mosgortrans_parse_transport_block(&data->block[32], metro_result);
|
||||
bool is_ground_data_present =
|
||||
mosgortrans_parse_transport_block(&data->block[28], ground_result);
|
||||
bool is_tat_data_present = mosgortrans_parse_transport_block(&data->block[16], tat_result);
|
||||
|
||||
furi_string_cat_printf(parsed_data, "\e#Troyka card\n");
|
||||
if(result1 && !furi_string_empty(metro_result)) {
|
||||
troika_render_section_header(parsed_data, "Metro", 22, 21);
|
||||
if(is_metro_data_present && !furi_string_empty(metro_result)) {
|
||||
render_section_header(parsed_data, "Metro", 22, 21);
|
||||
furi_string_cat_printf(parsed_data, "%s\n", furi_string_get_cstr(metro_result));
|
||||
}
|
||||
|
||||
if(result2 && !furi_string_empty(ground_result)) {
|
||||
troika_render_section_header(parsed_data, "Ediny", 22, 22);
|
||||
if(is_ground_data_present && !furi_string_empty(ground_result)) {
|
||||
render_section_header(parsed_data, "Ediny", 22, 22);
|
||||
furi_string_cat_printf(parsed_data, "%s\n", furi_string_get_cstr(ground_result));
|
||||
}
|
||||
|
||||
if(result3 && !furi_string_empty(tat_result)) {
|
||||
troika_render_section_header(parsed_data, "TAT", 24, 23);
|
||||
if(is_tat_data_present && !furi_string_empty(tat_result)) {
|
||||
render_section_header(parsed_data, "TAT", 24, 23);
|
||||
furi_string_cat_printf(parsed_data, "%s\n", furi_string_get_cstr(tat_result));
|
||||
}
|
||||
|
||||
|
@ -236,7 +224,7 @@ static bool troika_parse(const NfcDevice* device, FuriString* parsed_data) {
|
|||
furi_string_free(ground_result);
|
||||
furi_string_free(metro_result);
|
||||
|
||||
parsed = result1 || result2 || result3;
|
||||
parsed = is_metro_data_present || is_ground_data_present || is_tat_data_present;
|
||||
} while(false);
|
||||
|
||||
return parsed;
|
||||
|
|
97
applications/main/nfc/plugins/supported_cards/trt.c
Normal file
97
applications/main/nfc/plugins/supported_cards/trt.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
// Flipper Zero parser for for Tianjin Railway Transit (TRT)
|
||||
// https://en.wikipedia.org/wiki/Tianjin_Metro
|
||||
// Reverse engineering and parser development by @Torron (Github: @zinongli)
|
||||
|
||||
#include "nfc_supported_card_plugin.h"
|
||||
#include <flipper_application.h>
|
||||
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
|
||||
#include <bit_lib.h>
|
||||
|
||||
#define TAG "TrtParser"
|
||||
#define LATEST_SALE_MARKER 0x02
|
||||
#define FULL_SALE_TIME_STAMP_PAGE 0x09
|
||||
#define BALANCE_PAGE 0x08
|
||||
#define SALE_RECORD_TIME_STAMP_A 0x0C
|
||||
#define SALE_RECORD_TIME_STAMP_B 0x0E
|
||||
#define SALE_YEAR_OFFSET 2000
|
||||
|
||||
static bool trt_parse(const NfcDevice* device, FuriString* parsed_data) {
|
||||
furi_assert(device);
|
||||
furi_assert(parsed_data);
|
||||
|
||||
const MfUltralightData* data = nfc_device_get_data(device, NfcProtocolMfUltralight);
|
||||
|
||||
bool parsed = false;
|
||||
|
||||
do {
|
||||
uint8_t latest_sale_page = 0;
|
||||
|
||||
// Look for sale record signature
|
||||
if(data->page[SALE_RECORD_TIME_STAMP_A].data[0] == LATEST_SALE_MARKER) {
|
||||
latest_sale_page = SALE_RECORD_TIME_STAMP_A;
|
||||
} else if(data->page[SALE_RECORD_TIME_STAMP_B].data[0] == LATEST_SALE_MARKER) {
|
||||
latest_sale_page = SALE_RECORD_TIME_STAMP_B;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if the sale record was backed up
|
||||
const uint8_t* partial_record_pointer = &data->page[latest_sale_page - 1].data[0];
|
||||
const uint8_t* full_record_pointer = &data->page[FULL_SALE_TIME_STAMP_PAGE].data[0];
|
||||
uint32_t latest_sale_record = bit_lib_get_bits_32(partial_record_pointer, 3, 20);
|
||||
uint32_t latest_sale_full_record = bit_lib_get_bits_32(full_record_pointer, 0, 27);
|
||||
if(latest_sale_record != (latest_sale_full_record & 0xFFFFF))
|
||||
break; // check if the copy matches
|
||||
if((latest_sale_record == 0) || (latest_sale_full_record == 0))
|
||||
break; // prevent false positive
|
||||
|
||||
// Parse date
|
||||
// yyy yyyymmmm dddddhhh hhnnnnnn
|
||||
uint16_t sale_year = ((latest_sale_full_record & 0x7F00000) >> 20) + SALE_YEAR_OFFSET;
|
||||
uint8_t sale_month = (latest_sale_full_record & 0xF0000) >> 16;
|
||||
uint8_t sale_day = (latest_sale_full_record & 0xF800) >> 11;
|
||||
uint8_t sale_hour = (latest_sale_full_record & 0x7C0) >> 6;
|
||||
uint8_t sale_minute = latest_sale_full_record & 0x3F;
|
||||
|
||||
// Parse balance
|
||||
uint16_t balance = bit_lib_get_bits_16(&data->page[BALANCE_PAGE].data[2], 0, 16);
|
||||
uint16_t balance_yuan = balance / 100;
|
||||
uint8_t balance_cent = balance % 100;
|
||||
|
||||
// Format string for rendering
|
||||
furi_string_cat_printf(parsed_data, "\e#TRT Tianjin Metro\n");
|
||||
furi_string_cat_printf(parsed_data, "Single-Use Ticket\n");
|
||||
furi_string_cat_printf(parsed_data, "Balance: %u.%02u RMB\n", balance_yuan, balance_cent);
|
||||
furi_string_cat_printf(
|
||||
parsed_data,
|
||||
"Sale Date: \n%04u-%02d-%02d %02d:%02d",
|
||||
sale_year,
|
||||
sale_month,
|
||||
sale_day,
|
||||
sale_hour,
|
||||
sale_minute);
|
||||
parsed = true;
|
||||
} while(false);
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/* Actual implementation of app<>plugin interface */
|
||||
static const NfcSupportedCardsPlugin trt_plugin = {
|
||||
.protocol = NfcProtocolMfUltralight,
|
||||
.verify = NULL,
|
||||
.read = NULL,
|
||||
.parse = trt_parse,
|
||||
};
|
||||
|
||||
/* Plugin descriptor to comply with basic plugin specification */
|
||||
static const FlipperAppPluginDescriptor trt_plugin_descriptor = {
|
||||
.appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID,
|
||||
.ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION,
|
||||
.entry_point = &trt_plugin,
|
||||
};
|
||||
|
||||
/* Plugin entry point - must return a pointer to const descriptor */
|
||||
const FlipperAppPluginDescriptor* trt_plugin_ep(void) {
|
||||
return &trt_plugin_descriptor;
|
||||
}
|
|
@ -4489,3 +4489,9 @@ EA19E58DD046
|
|||
3F41891454EE
|
||||
7EDAE7923287
|
||||
11DDA4862A1C
|
||||
# H World Hotel Chain Room Keys
|
||||
543071543071
|
||||
5F01015F0101
|
||||
200510241234
|
||||
# iq aparts hotel
|
||||
505209266A1F
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
#include "../nfc_app_i.h"
|
||||
|
||||
#include <bit_lib/bit_lib.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <lib/nfc/protocols/mf_classic/mf_classic_poller.h>
|
||||
|
||||
#define TAG "NfcMfClassicDictAttack"
|
||||
|
||||
// TODO FL-3926: Fix lag when leaving the dictionary attack view after Hardnested
|
||||
// TODO FL-3926: Re-enters backdoor detection between user and system dictionary if no backdoor is found
|
||||
|
||||
typedef enum {
|
||||
DictAttackStateCUIDDictInProgress,
|
||||
DictAttackStateUserDictInProgress,
|
||||
DictAttackStateSystemDictInProgress,
|
||||
} DictAttackState;
|
||||
|
@ -29,7 +33,9 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
|
|||
} else if(mfc_event->type == MfClassicPollerEventTypeRequestMode) {
|
||||
const MfClassicData* mfc_data =
|
||||
nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic);
|
||||
mfc_event->data->poller_mode.mode = MfClassicPollerModeDictAttack;
|
||||
mfc_event->data->poller_mode.mode = (instance->nfc_dict_context.enhanced_dict) ?
|
||||
MfClassicPollerModeDictAttackEnhanced :
|
||||
MfClassicPollerModeDictAttackStandard;
|
||||
mfc_event->data->poller_mode.data = mfc_data;
|
||||
instance->nfc_dict_context.sectors_total =
|
||||
mf_classic_get_total_sectors_num(mfc_data->type);
|
||||
|
@ -58,6 +64,11 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context)
|
|||
instance->nfc_dict_context.sectors_read = data_update->sectors_read;
|
||||
instance->nfc_dict_context.keys_found = data_update->keys_found;
|
||||
instance->nfc_dict_context.current_sector = data_update->current_sector;
|
||||
instance->nfc_dict_context.nested_phase = data_update->nested_phase;
|
||||
instance->nfc_dict_context.prng_type = data_update->prng_type;
|
||||
instance->nfc_dict_context.backdoor = data_update->backdoor;
|
||||
instance->nfc_dict_context.nested_target_key = data_update->nested_target_key;
|
||||
instance->nfc_dict_context.msb_count = data_update->msb_count;
|
||||
view_dispatcher_send_custom_event(
|
||||
instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate);
|
||||
} else if(mfc_event->type == MfClassicPollerEventTypeNextSector) {
|
||||
|
@ -117,19 +128,75 @@ static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* instance) {
|
|||
dict_attack_set_keys_found(instance->dict_attack, mfc_dict->keys_found);
|
||||
dict_attack_set_current_dict_key(instance->dict_attack, mfc_dict->dict_keys_current);
|
||||
dict_attack_set_current_sector(instance->dict_attack, mfc_dict->current_sector);
|
||||
dict_attack_set_nested_phase(instance->dict_attack, mfc_dict->nested_phase);
|
||||
dict_attack_set_prng_type(instance->dict_attack, mfc_dict->prng_type);
|
||||
dict_attack_set_backdoor(instance->dict_attack, mfc_dict->backdoor);
|
||||
dict_attack_set_nested_target_key(instance->dict_attack, mfc_dict->nested_target_key);
|
||||
dict_attack_set_msb_count(instance->dict_attack, mfc_dict->msb_count);
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) {
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack);
|
||||
if(state == DictAttackStateCUIDDictInProgress) {
|
||||
size_t cuid_len = 0;
|
||||
const uint8_t* cuid = nfc_device_get_uid(instance->nfc_device, &cuid_len);
|
||||
FuriString* cuid_dict_path = furi_string_alloc_printf(
|
||||
"%s/mf_classic_dict_%08lx.nfc",
|
||||
EXT_PATH("nfc/assets"),
|
||||
(uint32_t)bit_lib_bytes_to_num_be(cuid + (cuid_len - 4), 4));
|
||||
|
||||
do {
|
||||
if(!keys_dict_check_presence(furi_string_get_cstr(cuid_dict_path))) {
|
||||
state = DictAttackStateUserDictInProgress;
|
||||
break;
|
||||
}
|
||||
|
||||
instance->nfc_dict_context.dict = keys_dict_alloc(
|
||||
furi_string_get_cstr(cuid_dict_path),
|
||||
KeysDictModeOpenExisting,
|
||||
sizeof(MfClassicKey));
|
||||
|
||||
if(keys_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) {
|
||||
keys_dict_free(instance->nfc_dict_context.dict);
|
||||
state = DictAttackStateUserDictInProgress;
|
||||
break;
|
||||
}
|
||||
|
||||
dict_attack_set_header(instance->dict_attack, "MF Classic CUID Dictionary");
|
||||
} while(false);
|
||||
|
||||
furi_string_free(cuid_dict_path);
|
||||
}
|
||||
if(state == DictAttackStateUserDictInProgress) {
|
||||
do {
|
||||
instance->nfc_dict_context.enhanced_dict = true;
|
||||
|
||||
if(keys_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_SYSTEM_NESTED_PATH)) {
|
||||
storage_common_remove(
|
||||
instance->storage, NFC_APP_MF_CLASSIC_DICT_SYSTEM_NESTED_PATH);
|
||||
}
|
||||
if(keys_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH)) {
|
||||
storage_common_copy(
|
||||
instance->storage,
|
||||
NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH,
|
||||
NFC_APP_MF_CLASSIC_DICT_SYSTEM_NESTED_PATH);
|
||||
}
|
||||
|
||||
if(!keys_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_PATH)) {
|
||||
state = DictAttackStateSystemDictInProgress;
|
||||
break;
|
||||
}
|
||||
|
||||
if(keys_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_NESTED_PATH)) {
|
||||
storage_common_remove(instance->storage, NFC_APP_MF_CLASSIC_DICT_USER_NESTED_PATH);
|
||||
}
|
||||
storage_common_copy(
|
||||
instance->storage,
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH,
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_NESTED_PATH);
|
||||
|
||||
instance->nfc_dict_context.dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
if(keys_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) {
|
||||
|
@ -164,7 +231,7 @@ void nfc_scene_mf_classic_dict_attack_on_enter(void* context) {
|
|||
NfcApp* instance = context;
|
||||
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager, NfcSceneMfClassicDictAttack, DictAttackStateUserDictInProgress);
|
||||
instance->scene_manager, NfcSceneMfClassicDictAttack, DictAttackStateCUIDDictInProgress);
|
||||
nfc_scene_mf_classic_dict_attack_prepare_view(instance);
|
||||
dict_attack_set_card_state(instance->dict_attack, true);
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewDictAttack);
|
||||
|
@ -193,7 +260,21 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
|
|||
scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack);
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventDictAttackComplete) {
|
||||
if(state == DictAttackStateUserDictInProgress) {
|
||||
bool ran_nested_dict = instance->nfc_dict_context.nested_phase !=
|
||||
MfClassicNestedPhaseNone;
|
||||
if(state == DictAttackStateCUIDDictInProgress) {
|
||||
nfc_poller_stop(instance->poller);
|
||||
nfc_poller_free(instance->poller);
|
||||
keys_dict_free(instance->nfc_dict_context.dict);
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager,
|
||||
NfcSceneMfClassicDictAttack,
|
||||
DictAttackStateUserDictInProgress);
|
||||
nfc_scene_mf_classic_dict_attack_prepare_view(instance);
|
||||
instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfClassic);
|
||||
nfc_poller_start(instance->poller, nfc_dict_attack_worker_callback, instance);
|
||||
consumed = true;
|
||||
} else if(state == DictAttackStateUserDictInProgress && !(ran_nested_dict)) {
|
||||
nfc_poller_stop(instance->poller);
|
||||
nfc_poller_free(instance->poller);
|
||||
keys_dict_free(instance->nfc_dict_context.dict);
|
||||
|
@ -222,7 +303,27 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
|
|||
} else if(event.event == NfcCustomEventDictAttackSkip) {
|
||||
const MfClassicData* mfc_data = nfc_poller_get_data(instance->poller);
|
||||
nfc_device_set_data(instance->nfc_device, NfcProtocolMfClassic, mfc_data);
|
||||
if(state == DictAttackStateUserDictInProgress) {
|
||||
bool ran_nested_dict = instance->nfc_dict_context.nested_phase !=
|
||||
MfClassicNestedPhaseNone;
|
||||
if(state == DictAttackStateCUIDDictInProgress) {
|
||||
if(instance->nfc_dict_context.is_card_present) {
|
||||
nfc_poller_stop(instance->poller);
|
||||
nfc_poller_free(instance->poller);
|
||||
keys_dict_free(instance->nfc_dict_context.dict);
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager,
|
||||
NfcSceneMfClassicDictAttack,
|
||||
DictAttackStateUserDictInProgress);
|
||||
nfc_scene_mf_classic_dict_attack_prepare_view(instance);
|
||||
instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfClassic);
|
||||
nfc_poller_start(instance->poller, nfc_dict_attack_worker_callback, instance);
|
||||
} else {
|
||||
nfc_scene_mf_classic_dict_attack_notify_read(instance);
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess);
|
||||
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(state == DictAttackStateUserDictInProgress && !(ran_nested_dict)) {
|
||||
if(instance->nfc_dict_context.is_card_present) {
|
||||
nfc_poller_stop(instance->poller);
|
||||
nfc_poller_free(instance->poller);
|
||||
|
@ -240,7 +341,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
|
|||
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(state == DictAttackStateSystemDictInProgress) {
|
||||
} else {
|
||||
nfc_scene_mf_classic_dict_attack_notify_read(instance);
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess);
|
||||
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||
|
@ -262,7 +363,7 @@ void nfc_scene_mf_classic_dict_attack_on_exit(void* context) {
|
|||
|
||||
dict_attack_reset(instance->dict_attack);
|
||||
scene_manager_set_scene_state(
|
||||
instance->scene_manager, NfcSceneMfClassicDictAttack, DictAttackStateUserDictInProgress);
|
||||
instance->scene_manager, NfcSceneMfClassicDictAttack, DictAttackStateCUIDDictInProgress);
|
||||
|
||||
keys_dict_free(instance->nfc_dict_context.dict);
|
||||
|
||||
|
@ -275,6 +376,20 @@ void nfc_scene_mf_classic_dict_attack_on_exit(void* context) {
|
|||
instance->nfc_dict_context.is_key_attack = false;
|
||||
instance->nfc_dict_context.key_attack_current_sector = 0;
|
||||
instance->nfc_dict_context.is_card_present = false;
|
||||
instance->nfc_dict_context.nested_phase = MfClassicNestedPhaseNone;
|
||||
instance->nfc_dict_context.prng_type = MfClassicPrngTypeUnknown;
|
||||
instance->nfc_dict_context.backdoor = MfClassicBackdoorUnknown;
|
||||
instance->nfc_dict_context.nested_target_key = 0;
|
||||
instance->nfc_dict_context.msb_count = 0;
|
||||
instance->nfc_dict_context.enhanced_dict = false;
|
||||
|
||||
// Clean up temporary files used for nested dictionary attack
|
||||
if(keys_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_NESTED_PATH)) {
|
||||
storage_common_remove(instance->storage, NFC_APP_MF_CLASSIC_DICT_USER_NESTED_PATH);
|
||||
}
|
||||
if(keys_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_SYSTEM_NESTED_PATH)) {
|
||||
storage_common_remove(instance->storage, NFC_APP_MF_CLASSIC_DICT_SYSTEM_NESTED_PATH);
|
||||
}
|
||||
|
||||
nfc_blink_stop(instance);
|
||||
notification_message(instance->notifications, &sequence_display_backlight_enforce_auto);
|
||||
|
|
|
@ -30,7 +30,7 @@ void nfc_scene_start_on_enter(void* context) {
|
|||
submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Extract MF Keys",
|
||||
"Extract MFC Keys",
|
||||
SubmenuIndexDetectReader,
|
||||
nfc_scene_start_submenu_callback,
|
||||
nfc);
|
||||
|
|
|
@ -21,6 +21,11 @@ typedef struct {
|
|||
size_t dict_keys_current;
|
||||
bool is_key_attack;
|
||||
uint8_t key_attack_current_sector;
|
||||
MfClassicNestedPhase nested_phase;
|
||||
MfClassicPrngType prng_type;
|
||||
MfClassicBackdoor backdoor;
|
||||
uint16_t nested_target_key;
|
||||
uint16_t msb_count;
|
||||
} DictAttackViewModel;
|
||||
|
||||
static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
||||
|
@ -34,9 +39,47 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
|||
} else {
|
||||
char draw_str[32] = {};
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
switch(m->nested_phase) {
|
||||
case MfClassicNestedPhaseAnalyzePRNG:
|
||||
furi_string_set(m->header, "PRNG Analysis");
|
||||
break;
|
||||
case MfClassicNestedPhaseDictAttack:
|
||||
case MfClassicNestedPhaseDictAttackVerify:
|
||||
case MfClassicNestedPhaseDictAttackResume:
|
||||
furi_string_set(m->header, "Nested Dictionary");
|
||||
break;
|
||||
case MfClassicNestedPhaseCalibrate:
|
||||
case MfClassicNestedPhaseRecalibrate:
|
||||
furi_string_set(m->header, "Calibration");
|
||||
break;
|
||||
case MfClassicNestedPhaseCollectNtEnc:
|
||||
furi_string_set(m->header, "Nonce Collection");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(m->prng_type == MfClassicPrngTypeHard) {
|
||||
furi_string_cat(m->header, " (Hard)");
|
||||
}
|
||||
|
||||
if(m->backdoor != MfClassicBackdoorNone && m->backdoor != MfClassicBackdoorUnknown) {
|
||||
if(m->nested_phase != MfClassicNestedPhaseNone) {
|
||||
furi_string_cat(m->header, " (Backdoor)");
|
||||
} else {
|
||||
furi_string_set(m->header, "Backdoor Read");
|
||||
}
|
||||
}
|
||||
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 0, AlignCenter, AlignTop, furi_string_get_cstr(m->header));
|
||||
if(m->is_key_attack) {
|
||||
canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(m->header));
|
||||
if(m->nested_phase == MfClassicNestedPhaseCollectNtEnc) {
|
||||
uint8_t nonce_sector =
|
||||
m->nested_target_key / (m->prng_type == MfClassicPrngTypeWeak ? 4 : 2);
|
||||
snprintf(draw_str, sizeof(draw_str), "Collecting from sector: %d", nonce_sector);
|
||||
canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, draw_str);
|
||||
} else if(m->is_key_attack) {
|
||||
snprintf(
|
||||
draw_str,
|
||||
sizeof(draw_str),
|
||||
|
@ -46,21 +89,48 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
|||
snprintf(draw_str, sizeof(draw_str), "Unlocking sector: %d", m->current_sector);
|
||||
}
|
||||
canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, draw_str);
|
||||
float dict_progress = m->dict_keys_total == 0 ?
|
||||
0 :
|
||||
(float)(m->dict_keys_current) / (float)(m->dict_keys_total);
|
||||
float progress = m->sectors_total == 0 ? 0 :
|
||||
((float)(m->current_sector) + dict_progress) /
|
||||
(float)(m->sectors_total);
|
||||
if(progress > 1.0f) {
|
||||
progress = 1.0f;
|
||||
}
|
||||
if(m->dict_keys_current == 0) {
|
||||
// Cause when people see 0 they think it's broken
|
||||
snprintf(draw_str, sizeof(draw_str), "%d/%zu", 1, m->dict_keys_total);
|
||||
float dict_progress = 0;
|
||||
if(m->nested_phase == MfClassicNestedPhaseAnalyzePRNG ||
|
||||
m->nested_phase == MfClassicNestedPhaseDictAttack ||
|
||||
m->nested_phase == MfClassicNestedPhaseDictAttackVerify ||
|
||||
m->nested_phase == MfClassicNestedPhaseDictAttackResume) {
|
||||
// Phase: Nested dictionary attack
|
||||
uint8_t target_sector =
|
||||
m->nested_target_key / (m->prng_type == MfClassicPrngTypeWeak ? 2 : 16);
|
||||
dict_progress = (float)(target_sector) / (float)(m->sectors_total);
|
||||
snprintf(draw_str, sizeof(draw_str), "%d/%d", target_sector, m->sectors_total);
|
||||
} else if(
|
||||
m->nested_phase == MfClassicNestedPhaseCalibrate ||
|
||||
m->nested_phase == MfClassicNestedPhaseRecalibrate ||
|
||||
m->nested_phase == MfClassicNestedPhaseCollectNtEnc) {
|
||||
// Phase: Nonce collection
|
||||
if(m->prng_type == MfClassicPrngTypeWeak) {
|
||||
uint8_t target_sector = m->nested_target_key / 4;
|
||||
dict_progress = (float)(target_sector) / (float)(m->sectors_total);
|
||||
snprintf(draw_str, sizeof(draw_str), "%d/%d", target_sector, m->sectors_total);
|
||||
} else {
|
||||
uint16_t max_msb = UINT8_MAX + 1;
|
||||
dict_progress = (float)(m->msb_count) / (float)(max_msb);
|
||||
snprintf(draw_str, sizeof(draw_str), "%d/%d", m->msb_count, max_msb);
|
||||
}
|
||||
} else {
|
||||
snprintf(
|
||||
draw_str, sizeof(draw_str), "%zu/%zu", m->dict_keys_current, m->dict_keys_total);
|
||||
dict_progress = m->dict_keys_total == 0 ?
|
||||
0 :
|
||||
(float)(m->dict_keys_current) / (float)(m->dict_keys_total);
|
||||
if(m->dict_keys_current == 0) {
|
||||
// Cause when people see 0 they think it's broken
|
||||
snprintf(draw_str, sizeof(draw_str), "%d/%zu", 1, m->dict_keys_total);
|
||||
} else {
|
||||
snprintf(
|
||||
draw_str,
|
||||
sizeof(draw_str),
|
||||
"%zu/%zu",
|
||||
m->dict_keys_current,
|
||||
m->dict_keys_total);
|
||||
}
|
||||
}
|
||||
if(dict_progress > 1.0f) {
|
||||
dict_progress = 1.0f;
|
||||
}
|
||||
elements_progress_bar_with_text(canvas, 0, 20, 128, dict_progress, draw_str);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
@ -132,6 +202,11 @@ void dict_attack_reset(DictAttack* instance) {
|
|||
model->dict_keys_total = 0;
|
||||
model->dict_keys_current = 0;
|
||||
model->is_key_attack = false;
|
||||
model->nested_phase = MfClassicNestedPhaseNone;
|
||||
model->prng_type = MfClassicPrngTypeUnknown;
|
||||
model->backdoor = MfClassicBackdoorUnknown;
|
||||
model->nested_target_key = 0;
|
||||
model->msb_count = 0;
|
||||
furi_string_reset(model->header);
|
||||
},
|
||||
false);
|
||||
|
@ -242,3 +317,41 @@ void dict_attack_reset_key_attack(DictAttack* instance) {
|
|||
with_view_model(
|
||||
instance->view, DictAttackViewModel * model, { model->is_key_attack = false; }, true);
|
||||
}
|
||||
|
||||
void dict_attack_set_nested_phase(DictAttack* instance, MfClassicNestedPhase nested_phase) {
|
||||
furi_assert(instance);
|
||||
|
||||
with_view_model(
|
||||
instance->view, DictAttackViewModel * model, { model->nested_phase = nested_phase; }, true);
|
||||
}
|
||||
|
||||
void dict_attack_set_prng_type(DictAttack* instance, MfClassicPrngType prng_type) {
|
||||
furi_assert(instance);
|
||||
|
||||
with_view_model(
|
||||
instance->view, DictAttackViewModel * model, { model->prng_type = prng_type; }, true);
|
||||
}
|
||||
|
||||
void dict_attack_set_backdoor(DictAttack* instance, MfClassicBackdoor backdoor) {
|
||||
furi_assert(instance);
|
||||
|
||||
with_view_model(
|
||||
instance->view, DictAttackViewModel * model, { model->backdoor = backdoor; }, true);
|
||||
}
|
||||
|
||||
void dict_attack_set_nested_target_key(DictAttack* instance, uint16_t nested_target_key) {
|
||||
furi_assert(instance);
|
||||
|
||||
with_view_model(
|
||||
instance->view,
|
||||
DictAttackViewModel * model,
|
||||
{ model->nested_target_key = nested_target_key; },
|
||||
true);
|
||||
}
|
||||
|
||||
void dict_attack_set_msb_count(DictAttack* instance, uint16_t msb_count) {
|
||||
furi_assert(instance);
|
||||
|
||||
with_view_model(
|
||||
instance->view, DictAttackViewModel * model, { model->msb_count = msb_count; }, true);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <gui/view.h>
|
||||
#include <lib/nfc/protocols/mf_classic/mf_classic_poller.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -45,6 +46,16 @@ void dict_attack_set_key_attack(DictAttack* instance, uint8_t sector);
|
|||
|
||||
void dict_attack_reset_key_attack(DictAttack* instance);
|
||||
|
||||
void dict_attack_set_nested_phase(DictAttack* instance, MfClassicNestedPhase nested_phase);
|
||||
|
||||
void dict_attack_set_prng_type(DictAttack* instance, MfClassicPrngType prng_type);
|
||||
|
||||
void dict_attack_set_backdoor(DictAttack* instance, MfClassicBackdoor backdoor);
|
||||
|
||||
void dict_attack_set_nested_target_key(DictAttack* instance, uint16_t target_key);
|
||||
|
||||
void dict_attack_set_msb_count(DictAttack* instance, uint16_t msb_count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -81,6 +81,7 @@ typedef enum {
|
|||
SetTypeAllmatic433,
|
||||
SetTypeAllmatic868,
|
||||
SetTypeCenturion433,
|
||||
SetTypeMonarch433,
|
||||
SetTypeSommer_FM_434,
|
||||
SetTypeSommer_FM_868,
|
||||
SetTypeSommer_FM238_434,
|
||||
|
|
|
@ -28,10 +28,6 @@ struct SubGhzFrequencyAnalyzerWorker {
|
|||
FrequencyRSSI frequency_rssi_buf;
|
||||
SubGhzSetting* setting;
|
||||
|
||||
const SubGhzDevice* radio_device;
|
||||
FuriHalSpiBusHandle* spi_bus;
|
||||
bool ext_radio;
|
||||
|
||||
float filVal;
|
||||
float trigger_level;
|
||||
|
||||
|
@ -39,16 +35,14 @@ struct SubGhzFrequencyAnalyzerWorker {
|
|||
void* context;
|
||||
};
|
||||
|
||||
static void subghz_frequency_analyzer_worker_load_registers(
|
||||
FuriHalSpiBusHandle* spi_bus,
|
||||
const uint8_t data[][2]) {
|
||||
furi_hal_spi_acquire(spi_bus);
|
||||
static void subghz_frequency_analyzer_worker_load_registers(const uint8_t data[][2]) {
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||
size_t i = 0;
|
||||
while(data[i][0]) {
|
||||
cc1101_write_reg(spi_bus, data[i][0], data[i][1]);
|
||||
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, data[i][0], data[i][1]);
|
||||
i++;
|
||||
}
|
||||
furi_hal_spi_release(spi_bus);
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||
}
|
||||
|
||||
// running average with adaptive coefficient
|
||||
|
@ -82,35 +76,29 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
|
|||
float rssi_temp = 0;
|
||||
uint32_t frequency_temp = 0;
|
||||
|
||||
FuriHalSpiBusHandle* spi_bus = instance->spi_bus;
|
||||
const SubGhzDevice* radio_device = instance->radio_device;
|
||||
|
||||
//Start CC1101
|
||||
// furi_hal_subghz_reset();
|
||||
subghz_devices_reset(radio_device);
|
||||
furi_hal_subghz_reset();
|
||||
|
||||
furi_hal_spi_acquire(spi_bus);
|
||||
cc1101_flush_rx(spi_bus);
|
||||
cc1101_flush_tx(spi_bus);
|
||||
|
||||
// TODO probably can be used device.load_preset(FuriHalSubGhzPresetCustom, ...) for external cc1101
|
||||
cc1101_write_reg(spi_bus, CC1101_IOCFG0, CC1101IocfgHW);
|
||||
cc1101_write_reg(spi_bus, CC1101_MDMCFG3,
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||
cc1101_flush_rx(&furi_hal_spi_bus_handle_subghz);
|
||||
cc1101_flush_tx(&furi_hal_spi_bus_handle_subghz);
|
||||
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW);
|
||||
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_MDMCFG3,
|
||||
0b01111111); // symbol rate
|
||||
cc1101_write_reg(
|
||||
spi_bus,
|
||||
&furi_hal_spi_bus_handle_subghz,
|
||||
CC1101_AGCCTRL2,
|
||||
0b00000111); // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAGN_TARGET 42 dB
|
||||
cc1101_write_reg(
|
||||
spi_bus,
|
||||
&furi_hal_spi_bus_handle_subghz,
|
||||
CC1101_AGCCTRL1,
|
||||
0b00001000); // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 1000 - Absolute carrier sense threshold disabled
|
||||
cc1101_write_reg(
|
||||
spi_bus,
|
||||
&furi_hal_spi_bus_handle_subghz,
|
||||
CC1101_AGCCTRL0,
|
||||
0b00110000); // 00 - No hysteresis, medium asymmetric dead zone, medium gain ; 11 - 64 samples agc; 00 - Normal AGC, 00 - 4dB boundary
|
||||
|
||||
furi_hal_spi_release(spi_bus);
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||
|
||||
furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate);
|
||||
|
||||
|
@ -123,35 +111,32 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
|
|||
|
||||
frequency_rssi.rssi_coarse = -127.0f;
|
||||
frequency_rssi.rssi_fine = -127.0f;
|
||||
// furi_hal_subghz_idle();
|
||||
subghz_devices_idle(radio_device);
|
||||
subghz_frequency_analyzer_worker_load_registers(spi_bus, subghz_preset_ook_650khz);
|
||||
furi_hal_subghz_idle();
|
||||
subghz_frequency_analyzer_worker_load_registers(subghz_preset_ook_650khz);
|
||||
|
||||
// First stage: coarse scan
|
||||
for(size_t i = 0; i < subghz_setting_get_frequency_count(instance->setting); i++) {
|
||||
uint32_t current_frequency = subghz_setting_get_frequency(instance->setting, i);
|
||||
// if(furi_hal_subghz_is_frequency_valid(current_frequency) &&
|
||||
if(subghz_devices_is_frequency_valid(radio_device, current_frequency) &&
|
||||
(current_frequency != 467750000) && (current_frequency != 464000000) &&
|
||||
!((instance->ext_radio) &&
|
||||
((current_frequency == 390000000) || (current_frequency == 312000000) ||
|
||||
(current_frequency == 312100000) || (current_frequency == 312200000) ||
|
||||
(current_frequency == 440175000)))) {
|
||||
furi_hal_spi_acquire(spi_bus);
|
||||
cc1101_switch_to_idle(spi_bus);
|
||||
frequency = cc1101_set_frequency(spi_bus, current_frequency);
|
||||
if(furi_hal_subghz_is_frequency_valid(current_frequency) &&
|
||||
(((current_frequency != 467750000) && (current_frequency != 464000000)) &&
|
||||
(current_frequency <= 920000000))) {
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||
cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
|
||||
frequency = cc1101_set_frequency(
|
||||
&furi_hal_spi_bus_handle_subghz,
|
||||
subghz_setting_get_frequency(instance->setting, i));
|
||||
|
||||
cc1101_calibrate(spi_bus);
|
||||
cc1101_calibrate(&furi_hal_spi_bus_handle_subghz);
|
||||
|
||||
furi_check(cc1101_wait_status_state(spi_bus, CC1101StateIDLE, 10000));
|
||||
furi_check(cc1101_wait_status_state(
|
||||
&furi_hal_spi_bus_handle_subghz, CC1101StateIDLE, 10000));
|
||||
|
||||
cc1101_switch_to_rx(spi_bus);
|
||||
furi_hal_spi_release(spi_bus);
|
||||
cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz);
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||
|
||||
furi_delay_ms(2);
|
||||
|
||||
// rssi = furi_hal_subghz_get_rssi();
|
||||
rssi = subghz_devices_get_rssi(radio_device);
|
||||
rssi = furi_hal_subghz_get_rssi();
|
||||
|
||||
rssi_avg += rssi;
|
||||
rssi_avg_samples++;
|
||||
|
@ -175,30 +160,28 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
|
|||
|
||||
// Second stage: fine scan
|
||||
if(frequency_rssi.rssi_coarse > instance->trigger_level) {
|
||||
// furi_hal_subghz_idle();
|
||||
subghz_devices_idle(radio_device);
|
||||
subghz_frequency_analyzer_worker_load_registers(spi_bus, subghz_preset_ook_58khz);
|
||||
furi_hal_subghz_idle();
|
||||
subghz_frequency_analyzer_worker_load_registers(subghz_preset_ook_58khz);
|
||||
//for example -0.3 ... 433.92 ... +0.3 step 20KHz
|
||||
for(uint32_t i = frequency_rssi.frequency_coarse - 300000;
|
||||
i < frequency_rssi.frequency_coarse + 300000;
|
||||
i += 20000) {
|
||||
// if(furi_hal_subghz_is_frequency_valid(i)) {
|
||||
if(subghz_devices_is_frequency_valid(radio_device, i)) {
|
||||
furi_hal_spi_acquire(spi_bus);
|
||||
cc1101_switch_to_idle(spi_bus);
|
||||
frequency = cc1101_set_frequency(spi_bus, i);
|
||||
if(furi_hal_subghz_is_frequency_valid(i)) {
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||
cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
|
||||
frequency = cc1101_set_frequency(&furi_hal_spi_bus_handle_subghz, i);
|
||||
|
||||
cc1101_calibrate(spi_bus);
|
||||
cc1101_calibrate(&furi_hal_spi_bus_handle_subghz);
|
||||
|
||||
furi_check(cc1101_wait_status_state(spi_bus, CC1101StateIDLE, 10000));
|
||||
furi_check(cc1101_wait_status_state(
|
||||
&furi_hal_spi_bus_handle_subghz, CC1101StateIDLE, 10000));
|
||||
|
||||
cc1101_switch_to_rx(spi_bus);
|
||||
furi_hal_spi_release(spi_bus);
|
||||
cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz);
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||
|
||||
furi_delay_ms(2);
|
||||
|
||||
// rssi = furi_hal_subghz_get_rssi();
|
||||
rssi = subghz_devices_get_rssi(radio_device);
|
||||
rssi = furi_hal_subghz_get_rssi();
|
||||
|
||||
FURI_LOG_T(TAG, "#:%lu:%f", frequency, (double)rssi);
|
||||
|
||||
|
@ -275,10 +258,8 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
|
|||
}
|
||||
|
||||
//Stop CC1101
|
||||
// furi_hal_subghz_idle();
|
||||
// furi_hal_subghz_sleep();
|
||||
subghz_devices_idle(radio_device);
|
||||
subghz_devices_sleep(radio_device);
|
||||
furi_hal_subghz_idle();
|
||||
furi_hal_subghz_sleep();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -287,12 +268,8 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc(void* cont
|
|||
furi_assert(context);
|
||||
SubGhzFrequencyAnalyzerWorker* instance = malloc(sizeof(SubGhzFrequencyAnalyzerWorker));
|
||||
|
||||
instance->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(instance->thread, "SubGhzFAWorker");
|
||||
furi_thread_set_stack_size(instance->thread, 2048);
|
||||
furi_thread_set_context(instance->thread, instance);
|
||||
furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread);
|
||||
|
||||
instance->thread = furi_thread_alloc_ex(
|
||||
"SubGhzFAWorker", 2048, subghz_frequency_analyzer_worker_thread, instance);
|
||||
SubGhz* subghz = context;
|
||||
instance->setting = subghz_txrx_get_setting(subghz->txrx);
|
||||
instance->trigger_level = subghz->last_settings->frequency_analyzer_trigger;
|
||||
|
@ -317,26 +294,10 @@ void subghz_frequency_analyzer_worker_set_pair_callback(
|
|||
instance->context = context;
|
||||
}
|
||||
|
||||
void subghz_frequency_analyzer_worker_start(
|
||||
SubGhzFrequencyAnalyzerWorker* instance,
|
||||
SubGhzTxRx* txrx) {
|
||||
void subghz_frequency_analyzer_worker_start(SubGhzFrequencyAnalyzerWorker* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(!instance->worker_running);
|
||||
|
||||
SubGhzRadioDeviceType radio_type = subghz_txrx_radio_device_get(txrx);
|
||||
|
||||
if(radio_type == SubGhzRadioDeviceTypeExternalCC1101) {
|
||||
instance->spi_bus = &furi_hal_spi_bus_handle_external;
|
||||
instance->ext_radio = true;
|
||||
} else if(radio_type == SubGhzRadioDeviceTypeInternal) {
|
||||
instance->spi_bus = &furi_hal_spi_bus_handle_subghz;
|
||||
instance->ext_radio = false;
|
||||
} else {
|
||||
furi_crash("Unsuported external module");
|
||||
}
|
||||
|
||||
instance->radio_device = subghz_devices_get_by_name(subghz_txrx_radio_device_get_name(txrx));
|
||||
|
||||
instance->worker_running = true;
|
||||
|
||||
furi_thread_start(instance->thread);
|
||||
|
@ -365,3 +326,33 @@ void subghz_frequency_analyzer_worker_set_trigger_level(
|
|||
float subghz_frequency_analyzer_worker_get_trigger_level(SubGhzFrequencyAnalyzerWorker* instance) {
|
||||
return instance->trigger_level;
|
||||
}
|
||||
|
||||
uint32_t subghz_frequency_analyzer_get_nearest_frequency(
|
||||
SubGhzFrequencyAnalyzerWorker* instance,
|
||||
uint32_t input) {
|
||||
uint32_t prev_freq = 0;
|
||||
uint32_t result = 0;
|
||||
uint32_t current;
|
||||
|
||||
for(size_t i = 0; i < subghz_setting_get_frequency_count(instance->setting); i++) {
|
||||
current = subghz_setting_get_frequency(instance->setting, i);
|
||||
if(current == 0) {
|
||||
continue;
|
||||
}
|
||||
if(current == input) {
|
||||
result = current;
|
||||
break;
|
||||
}
|
||||
if(current > input && prev_freq < input) {
|
||||
if(current - input < input - prev_freq) {
|
||||
result = current;
|
||||
} else {
|
||||
result = prev_freq;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev_freq = current;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -47,9 +47,7 @@ void subghz_frequency_analyzer_worker_set_pair_callback(
|
|||
* @param instance SubGhzFrequencyAnalyzerWorker instance
|
||||
* @param txrx pointer to SubGhzTxRx
|
||||
*/
|
||||
void subghz_frequency_analyzer_worker_start(
|
||||
SubGhzFrequencyAnalyzerWorker* instance,
|
||||
SubGhzTxRx* txrx);
|
||||
void subghz_frequency_analyzer_worker_start(SubGhzFrequencyAnalyzerWorker* instance);
|
||||
|
||||
/** Stop SubGhzFrequencyAnalyzerWorker
|
||||
*
|
||||
|
@ -78,3 +76,8 @@ void subghz_frequency_analyzer_worker_set_trigger_level(
|
|||
* @return RSSI trigger level
|
||||
*/
|
||||
float subghz_frequency_analyzer_worker_get_trigger_level(SubGhzFrequencyAnalyzerWorker* instance);
|
||||
|
||||
// Round up the frequency
|
||||
uint32_t subghz_frequency_analyzer_get_nearest_frequency(
|
||||
SubGhzFrequencyAnalyzerWorker* instance,
|
||||
uint32_t input);
|
||||
|
|
|
@ -1,60 +1,61 @@
|
|||
Filetype: Flipper SubGhz Keystore File
|
||||
Version: 0
|
||||
Encryption: 1
|
||||
IV: 41 72 65 20 79 6F 75 20 61 20 46 75 72 72 79 3F
|
||||
8B441920A9F30EA40001F37E0F3C0D72161467678511928D219A7DBC42F8D9B7
|
||||
1ADE5B8541491C46674EECC05A1C4297CB28259954FD7C6DA0EAADE8D57773FC
|
||||
0497A50135FA4468B49694974DAADEF2A9CC2B7BAFC8465E0AA58E940C085850
|
||||
4BC77520AE09B4F6A5A5365B6B9C16CA53566E096159A98EF0AB6E7FE5C2DD1C
|
||||
B674AC1674312E74471E44917F6FC049DAB48BBB65B84F14A4CD64223A49E93DC0C507B8E17BFFDCBB67B55F1B4091C6
|
||||
FBBE4E4F703A9C1F17268F73EC00A3F76517A4470783363102D2B7647F0F2E7F
|
||||
21BE8A51F32CE62DA6B5E207E627D224639877860C71933C4F54AC7BD742B265
|
||||
74E3EA89CC7AA99855C1BC87734506413B882CF36D68C3329022415EB29D1360
|
||||
567937E84052F230610B3A2FC26CA1BE32B9617F7554EF5E6E7CB35A76718ADA
|
||||
4C34F7FE5D6EAE40B0EB6BAB7DE4F0D059C32E4F312F9C62F2C50C54C5486276
|
||||
74C8656F8EA033C60F3183FA0923C9AF1EB6689FAACC39E6548ECE16E3312D39DCF45AC6EC70A70421FBFFA43D91E19E
|
||||
275903678A81B6E62CD2BB4C50E93CB3E4B092E2894EBAA04AC4E0244E4D5BA9FCDFC6BCF845EA41DF0691BF2AEDF300
|
||||
BFE52324D666ADEB3D33D94331376B33A3D31566331DE0F372548FE7255F8085
|
||||
8E1B2E82B4C78360B3174741FB8031EE0DFEB479859BE8708F8AF40C5228BFDF
|
||||
6014A4A9D9703DAC11DA6B93FB7A0E0E0856E9379148F3CC125D77BA4C3D4931
|
||||
B8C22EA72B35E60A7A3DD02956D2375EE7C07E243F17F413CA4AC3A1445AA250
|
||||
B545037B8798370A8638B7ADCBE9EEF748F73C89EB5E04B460057BAFA52B1D7DF29B009FBB3FA07CE87247D185BE4926
|
||||
09AEA3223E4FFB06333425BA977403E7C2F9B5F121FDA8313E73FE98D0041425
|
||||
E7A97F65883E4D3CDA02483738219E219EED0681C2BB140EF3E5D02230433D42
|
||||
4AE67B9EA288183047A9498F58978E7C41BB8905533F42FF5B94E41AFEFF0EB4907A8C472B9E32F6D659CFA6C391179B
|
||||
1F9752FBA7A7A00D518D91BA8A8C1ADEF2EDF6282A5AFB2E4332B4351CF67F18317D2BCFF2DA6B5216EA138A4CCBDB81
|
||||
EDC508FE0D0E894B529C5E4AB82A7188072592BE9D4D9A3D2485822A9F4C5A67
|
||||
780582645A71D3A9841B0E8F5E84A2285F783872102AA1A98A956B98AEA19421
|
||||
37E2858B90868BCAA6B3198C3B205DC1413A9D378AF1671BEA3B8F47FCE1C5CE
|
||||
229719C5AFE1E567B8BD5F07EFF89C30B11CB79C9C841FFE7B53404CA5422EDB
|
||||
CDA16E59B8C24DBE95ABF978CAD4D04A4F124DED1965124F92AACA4C5AEB8721
|
||||
5C61D5C655DD9EB78C4F8E965101F98D7899155D2379EF6553FA9DEA0302A232
|
||||
7D3DCFDE942398244624C7ABFE08363404BA688EDA39D45A05BB6FB982BB9042
|
||||
ECCB10BCB2A8CF2093C61634E9AFEE9B69EB4A7C8B7139061730B5FA869F65BF
|
||||
7AE6C19ED3C97F45D1167FC9EF52CCE321EA002D31D8AEA94106A2F711626551
|
||||
793A984F6EBD35253C319FAB671348A4C6843AEA7CCCD5A52ACA9BBE96484B5E
|
||||
BB3ADBB5FD60F0FB01E5A8B1610D30A24975DC67ED1B70472E509218E213393E
|
||||
BB971C6304723B9928F50FA2E5C30A48ED5527556EE1BA5A7EA75AB7A4ED4137
|
||||
489579673025F7A351072EB8D5C7FC1DBF651AA6233FB01D99DAC4BDC0A60F2F
|
||||
ACA000B78B091A9B2621A9FA1A50FA6A3B63DDDF7D966224837028F93D570C08
|
||||
C1EB4EA179EC0437D5B0E72C47AAD06803F7619C53D3D2FEF38DD3C068118766B73202B75C534C6249312245218C9285
|
||||
639C6F53600C0F01410361164FEF715DB8E08C68D68B8AE76CF2D09A0C6C4CA1
|
||||
F5F2D77DD3AF60489312055EBA3B511F7D9E312F02465639FFF3E71A862BB9EB
|
||||
3EC1F7B2C43646249C4D14B4B1B85B3416B8D3B0B8DA9E87BD6199DC27BD45C2
|
||||
AA24DB7345317FE980C917909F364EAA13591A664E0893271E9DBCC250782EA5
|
||||
32C18DBA479AD57BFF9FE7B7BD1022D4969D8E2EC99BC0799148809796E227D5
|
||||
494B44697DACDFDBBFEB0FDBEF6E9B5D7291B6CB43B4C93088F3ED8632AF23B5
|
||||
B79CC1A90C7AC36DA2F318BF69E6BB1FAC32C178453663069C0CF2C4AE77B211
|
||||
A059D006EF98446BDF9E1F5E09641A641CA88348E79499D79BCFDE6646C716A0BE2253421858D327E796EB5237B6E2C4
|
||||
9E90AE6138A3676E3E5058FF277331032CD6BBF114768104A33D684B0825C5A5
|
||||
7477B55332666FC6B1279F5FDF84DCA01176498984809B74E17AB726F888000F
|
||||
6A0300B90BC11127A031E62537468A1CA7A0775BE85ED12069074E26181FBA50
|
||||
4DAF986F9A850EB18F0FE3B88B9796D80EEC3984C92F4F8B32D513A176CCAA9A
|
||||
EB84517DCAA7D10A6E7C4D0A7995AE278AAF3FDE52DAE30C7FD3FB853C799369
|
||||
0941FB8965604ABC852B94F29396783783632E4C80AEE665E42C233B6E7AA7D0
|
||||
71FEF69734589BE3C0893A1584FC1C0A75A5D4BF88CFF323C8C68E0EEC06993C
|
||||
790A26B77912EE07BABCDF478D8E492422B73465DC209E5DBC8E31F43AA2DA7448EAB6312AC1DC4FE3F20D7A2EC93968
|
||||
CE0AA966F33B7AC9E9982D2241524F2FC7613DAAC6C5C768AAAE29A630B414CE
|
||||
93FA632D945E18DE6358D4F443CB6F023C640407B7FAD6E8AF6EF15139B044E3
|
||||
059ABA7A866A865159D4E0B3E30FA1900BAB2BAB82A1D1F9D74CAEC11FA95393
|
||||
9C5A4CF1D49E0F741577BAB868575739AEBBDC15D7178C87A46EA3B3E7E856EFD815AD5F998778E8FBAA2832F387B967
|
||||
IV: 46 75 72 72 79 20 63 68 65 63 6B 20 3F 3F 21 21
|
||||
3FF98B52C38558ECDB26C3E86D118FAC9AF22EDDDE7649CB53726855CEBCCF9E
|
||||
06B901C6E36E381B4A83554ED972288977F999C232106D337C3BE4A9A44608F8
|
||||
8153E6CAF4B272BA0EA168B9F0F29CF02CEB33E4ABBD4D5C858D1ADBFF474A25
|
||||
F61216CE3A7E500E0C9B2173F91C2E7B1BB7D7AA65D4150EAC28169116647DDD
|
||||
A3ABC262415035A190447EC9C15CFD1AB1720560AB7C82D7447215342305299732776A9A6DEA4D359C52A23BFCE6B015
|
||||
5784D0E77A55E1361F47A1F6CFFBFAF715CFCAD2BD502ED266AA86DC47F98541
|
||||
E082BF64C75023F23FB333C53F2590F408FD932EB71DF4ED4D0E0EAF2AEBD488
|
||||
EFF328889D57D9F4B9111918F9C9BC641645104223009842FFF7B6F73E24E5B7
|
||||
BDCD1DBCBCA789C5A5C3623C0A287D791F1CACCBBD7D144E2EF1F92DA5513D90
|
||||
6310362BE6ED7CB5E3F4CA84D3093DF620BABD2C9D419A2BA5AA05F241EE7592
|
||||
4C6F97C553276D5403103A6BA6C4DBBE017A9E4159E6E5AC4C28ACD645DB1E8D4551CDC228A0457BEEF49179A081E1FD
|
||||
861ECA071AEEF3854005FEC9BF22C7DB76D07B7930968314FFAC70995E28680E473F8A1A7E56E8776EDD1C6E2DD6DD26
|
||||
55ADDFBE97BCB0FB43EDEB9CAFF9F32DD788A6306D3702BC2923DA5C69F5F0A5
|
||||
AB838DA2B25547AA43DEB7FB40B15E289B9209057BE564E7CB78F0D5DCFC65FD
|
||||
21BACE924E522AD0E97F0AAF64A9DB6A5F7BA09B3A1759AAFD4016F3ADD4353D
|
||||
4B37D449E44BAE7F377EE5CE52E94882E42617417F77ECE9803D9435892167F2
|
||||
E63BA93D98BB3EEEAD34B38C5F271FB777AEABD9E6A05597AE09815E578AA811900AE9F144FBEC7DBFDDEC87D1ED368B
|
||||
7DF24DCB7D73F1638FFD22325463B23C101653EE770F086D323BE90868A7E267
|
||||
18E533990C408061309323675116429652B3F4D228F00D704310E7AB26F6BAF4
|
||||
26042EC21D73490D9E7F968EDCC4CECF3989E6E982427DEB7012478E214CED8797A9BEBC481C81E9646214809A409B4A
|
||||
AC4169C26E402720F1E2A0AD690AE2CF708CE203898BC7102178A738C70F361718E794F0D0CB1A2F1938EF35CCA11887
|
||||
6962CADB9BD1B86B779DF7F4D7E06E92EB42474C7FD9EA23879F9982D7127357
|
||||
23AEC0F6F9FF529DDDCD1CDAA77F7B136CE2CCD3AC8B949954D5D3B2ECFA8CBC
|
||||
C6A3A849BC4A8DB438065255BD387DCD77AD7E7FEB3B0E11B6D3A43279AB9087
|
||||
CCB71F8BDC8B31F36D6141B3B57BF31B7EDF72B87593B7497871F5738A0B7E00
|
||||
345FE0FAD3F60C017D9793406981878EA2226072D624208AC33682793B415C41
|
||||
78AF1FCFDB780744708DBB547F7C3F095BA5FAFB34FA83BF4323B32829836ED1
|
||||
C2F19F077E71E710D39F5F11C1FE55C2A3CD6F33384CD8603288765F266F1BDF
|
||||
084B1A9565AFC88900D0FF25413E659E17AAB649DB2B7A9F0381CB0DF6D2B8E5
|
||||
568CECD994676CF3D6B225DEF21D40787DCB41C101F52B0C5AA43ED66709D158
|
||||
0742E0AAB6504AC63A9C59FBDD980BD4C4760EFF3E556C8A6241442CDDD23A74
|
||||
37BB60EE11BEC7D25A607DE9B0B6D3EAD23321AFEB94995FAB42184A95D1CADA
|
||||
42FD71B98A3BEE9CF372B03E158D51181BFAA9CF54F7300A93FE7665402B3D1F
|
||||
9346B7D12346E264E84F91145EBF86C53DD0061E0FA6556FAE5F6FBB8CEB799E
|
||||
430B0D7FC09C09051AEB667A370E6D9D9BDF0C0C553AD2791682D43CE5DC48B7
|
||||
5BBB5129797BC07CDC1D25A8A919A637B9FFF2F920BD42D1721018ABF8D34959AF877AFF450AD91548184E1A0D991CC8
|
||||
0BC8D3E1C2D9A8FB445FC55564471007A28C09C9CE602203176F1BFF02AC6328
|
||||
1C4CA912791BCD9CB231C64AB479AF240D02EC9F431D7C479B9A172E5B97F5CD
|
||||
15A9CDF17E72255DE0942C09E67CD251C3D465246845F9C0B97A7EFEE4AF9110
|
||||
F95543395BFF39B0A093AC80D0EF1BEFA218A3769D074250414D1357105A4D34
|
||||
138D433824E691C6B67A08CF1DDE55FBCA2D65AC0B7D9320EA1FDCB1742B11BF
|
||||
3BE3A385F1C0B8922C4E23EFF6912748DF715A4546CECB5E8972C1D1E47D0D3A
|
||||
9ECA2554ED36700326F2E5140C434ADA8DFF55A53382F19541E9AAE45DA5CBF2
|
||||
5C75D528678AF199E191C49F310913F401014F97EEA5FA507C7310B48A98FDE3297EA398B08959951FF99EDDB64C5E0D
|
||||
22A9C66645B3944925A496D9F2312429CC787B6314948B482EAD9360124F59DA
|
||||
DA3A8571664DBBFC1DE97B53E7C141554A2FBCEBA980696D32409CC5ADB7FC41
|
||||
20A52AABC518FCC2FC75AE3F5CC7C4838AA4973111DA696B890D884A18098D91
|
||||
EBB7163F580A1A5D26F12FBE650A227791193BA9AFCE277584B171F2FE1C77CF
|
||||
86369EE5277CB81B9417B6232F8D994FAEAB34D0D5363B143257C62B10CACAFD
|
||||
2E2EAB32891E172A3C31D434703480E69793435BB198E6AA06AA066EE8234D85
|
||||
745FC576D77C41BAEFF15A822E6B4058A485A2CAA0A3B283928D17AC02299AD9
|
||||
1FF8D49F2F7D785D64B6FE365CD9C2BD958E9527F66BB8A85C9AEBC73ECFE064
|
||||
3CFB77F3E274C1EB2772CDFA7B5B17255C2554198BE60C058A3405AEC644FABC5AAECC8F9C7F4A4E5B2D5252E8C62628
|
||||
AE514C44B55A1A4744E1106FD226C587D1B71CA7B5DCF010265D769E22012866
|
||||
2B2D787A4B0F30CAB9CD3DBC7686165637F091B31745CAB53B369A804F76F9EE
|
||||
EA4279C80F0B4AC0B32AB9E8B8CFB9C25FF81840BEE65B2160F85E56FA576C48
|
||||
E41D853750D68643E929F94F46BCDC050040935883E9A0C45BB238CDE06340DD745BDA7D6C16AE2B028E073EDDC0FC49
|
||||
|
|
|
@ -14,8 +14,8 @@ const uint32_t radio_device_value[RADIO_DEVICE_COUNT] = {
|
|||
SubGhzRadioDeviceTypeExternalCC1101,
|
||||
};
|
||||
|
||||
#define TIMESTAMP_NAMES_COUNT 2
|
||||
const char* const timestamp_names_text[TIMESTAMP_NAMES_COUNT] = {
|
||||
#define ON_OFF_COUNT 2
|
||||
const char* const on_off_text[ON_OFF_COUNT] = {
|
||||
"OFF",
|
||||
"ON",
|
||||
};
|
||||
|
@ -81,6 +81,22 @@ static void subghz_scene_receiver_config_set_debug_pin(VariableItem* item) {
|
|||
subghz_txrx_set_debug_pin_state(subghz->txrx, index == 1);
|
||||
}
|
||||
|
||||
static void subghz_scene_reciever_config_set_ext_amp_leds_control(VariableItem* item) {
|
||||
SubGhz* subghz = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(item, on_off_text[index]);
|
||||
subghz->last_settings->leds_and_amp = index == 1;
|
||||
// Set globally in furi hal
|
||||
furi_hal_subghz_set_ext_leds_and_amp(subghz->last_settings->leds_and_amp);
|
||||
subghz_last_settings_save(subghz->last_settings);
|
||||
// reinit external device
|
||||
const SubGhzRadioDeviceType current = subghz_txrx_radio_device_get(subghz->txrx);
|
||||
if(current != SubGhzRadioDeviceTypeInternal) {
|
||||
subghz_txrx_radio_device_set(subghz->txrx, SubGhzRadioDeviceTypeInternal);
|
||||
subghz_txrx_radio_device_set(subghz->txrx, current);
|
||||
}
|
||||
}
|
||||
|
||||
static void subghz_scene_receiver_config_set_debug_counter(VariableItem* item) {
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
|
@ -92,7 +108,7 @@ static void subghz_scene_receiver_config_set_timestamp_file_names(VariableItem*
|
|||
SubGhz* subghz = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, timestamp_names_text[index]);
|
||||
variable_item_set_current_value_text(item, on_off_text[index]);
|
||||
|
||||
subghz->last_settings->protocol_file_names = (index == 1);
|
||||
subghz_last_settings_save(subghz->last_settings);
|
||||
|
@ -123,12 +139,12 @@ void subghz_scene_radio_settings_on_enter(void* context) {
|
|||
item = variable_item_list_add(
|
||||
variable_item_list,
|
||||
"Protocol Names",
|
||||
TIMESTAMP_NAMES_COUNT,
|
||||
ON_OFF_COUNT,
|
||||
subghz_scene_receiver_config_set_timestamp_file_names,
|
||||
subghz);
|
||||
value_index = subghz->last_settings->protocol_file_names;
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, timestamp_names_text[value_index]);
|
||||
variable_item_set_current_value_text(item, on_off_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
variable_item_list,
|
||||
|
@ -146,6 +162,16 @@ void subghz_scene_radio_settings_on_enter(void* context) {
|
|||
variable_item_set_current_value_text(item, debug_counter_text[value_index]);
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
item = variable_item_list_add(
|
||||
variable_item_list,
|
||||
"Ext Amp & LEDs",
|
||||
ON_OFF_COUNT,
|
||||
subghz_scene_reciever_config_set_ext_amp_leds_control,
|
||||
subghz);
|
||||
value_index = subghz->last_settings->leds_and_amp ? 1 : 0;
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, on_off_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
variable_item_list,
|
||||
"Debug Pin",
|
||||
|
|
|
@ -28,6 +28,7 @@ static const char* submenu_names[SetTypeMAX] = {
|
|||
[SetTypeAllmatic433] = "KL: Allmatic 433MHz",
|
||||
[SetTypeAllmatic868] = "KL: Allmatic 868MHz",
|
||||
[SetTypeCenturion433] = "KL: Centurion 433MHz",
|
||||
[SetTypeMonarch433] = "KL: Monarch 433MHz",
|
||||
[SetTypeSommer_FM_434] = "KL: Sommer 434MHz",
|
||||
[SetTypeSommer_FM_868] = "KL: Sommer 868MHz",
|
||||
[SetTypeSommer_FM238_434] = "KL: Sommer fm2 434Mhz",
|
||||
|
@ -417,6 +418,16 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||
.keeloq.cnt = 0x03,
|
||||
.keeloq.manuf = "Centurion"};
|
||||
break;
|
||||
case SetTypeMonarch433:
|
||||
gen_info = (GenInfo){
|
||||
.type = GenKeeloq,
|
||||
.mod = "AM650",
|
||||
.freq = 433920000,
|
||||
.keeloq.serial = (key & 0x0000FFFF),
|
||||
.keeloq.btn = 0x0A,
|
||||
.keeloq.cnt = 0x03,
|
||||
.keeloq.manuf = "Monarch"};
|
||||
break;
|
||||
case SetTypeElmesElectronic:
|
||||
gen_info = (GenInfo){
|
||||
.type = GenKeeloq,
|
||||
|
|
|
@ -197,6 +197,10 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
|
|||
subghz->last_settings = subghz_last_settings_alloc();
|
||||
size_t preset_count = subghz_setting_get_preset_count(setting);
|
||||
subghz_last_settings_load(subghz->last_settings, preset_count);
|
||||
|
||||
// Set LED and Amp GPIO control state
|
||||
furi_hal_subghz_set_ext_leds_and_amp(subghz->last_settings->leds_and_amp);
|
||||
|
||||
if(!alloc_for_tx_only) {
|
||||
subghz_txrx_set_preset_internal(
|
||||
subghz->txrx, subghz->last_settings->frequency, subghz->last_settings->preset_index);
|
||||
|
|
|
@ -27,6 +27,9 @@ void subghz_dangerous_freq() {
|
|||
SubGhzLastSettings* last_settings = subghz_last_settings_alloc();
|
||||
subghz_last_settings_load(last_settings, 0);
|
||||
|
||||
// Set LED and Amp GPIO control state
|
||||
furi_hal_subghz_set_ext_leds_and_amp(last_settings->leds_and_amp);
|
||||
|
||||
subghz_last_settings_free(last_settings);
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#define SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD "RSSI"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD "DelOldSignals"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_HOPPING_THRESHOLD "HoppingThreshold"
|
||||
#define SUBGHZ_LAST_SETTING_FIELD_LED_AND_POWER_AMP "LedAndPowerAmp"
|
||||
|
||||
SubGhzLastSettings* subghz_last_settings_alloc(void) {
|
||||
SubGhzLastSettings* instance = malloc(sizeof(SubGhzLastSettings));
|
||||
|
@ -42,6 +43,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
|
|||
instance->filter = SubGhzProtocolFlag_Decodable;
|
||||
instance->rssi = SUBGHZ_RAW_THRESHOLD_MIN;
|
||||
instance->hopping_threshold = -90.0f;
|
||||
instance->leds_and_amp = true;
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
|
@ -123,6 +125,13 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
|
|||
1)) {
|
||||
flipper_format_rewind(fff_data_file);
|
||||
}
|
||||
if(!flipper_format_read_bool(
|
||||
fff_data_file,
|
||||
SUBGHZ_LAST_SETTING_FIELD_LED_AND_POWER_AMP,
|
||||
&instance->leds_and_amp,
|
||||
1)) {
|
||||
flipper_format_rewind(fff_data_file);
|
||||
}
|
||||
|
||||
} while(0);
|
||||
} else {
|
||||
|
@ -219,6 +228,10 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) {
|
|||
1)) {
|
||||
break;
|
||||
}
|
||||
if(!flipper_format_write_bool(
|
||||
file, SUBGHZ_LAST_SETTING_FIELD_LED_AND_POWER_AMP, &instance->leds_and_amp, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
saved = true;
|
||||
} while(0);
|
||||
|
|
|
@ -25,6 +25,7 @@ typedef struct {
|
|||
float rssi;
|
||||
bool delete_old_signals;
|
||||
float hopping_threshold;
|
||||
bool leds_and_amp;
|
||||
} SubGhzLastSettings;
|
||||
|
||||
SubGhzLastSettings* subghz_last_settings_alloc(void);
|
||||
|
|
|
@ -20,71 +20,6 @@
|
|||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
#endif
|
||||
|
||||
static const uint32_t subghz_frequency_list[] = {
|
||||
/* 300 - 348 */
|
||||
300000000,
|
||||
302757000,
|
||||
303875000,
|
||||
303900000,
|
||||
304250000,
|
||||
307000000,
|
||||
307500000,
|
||||
307800000,
|
||||
309000000,
|
||||
310000000,
|
||||
312000000,
|
||||
312100000,
|
||||
312200000,
|
||||
313000000,
|
||||
313850000,
|
||||
314000000,
|
||||
314350000,
|
||||
314980000,
|
||||
315000000,
|
||||
318000000,
|
||||
330000000,
|
||||
345000000,
|
||||
348000000,
|
||||
350000000,
|
||||
|
||||
/* 387 - 464 */
|
||||
387000000,
|
||||
390000000,
|
||||
418000000,
|
||||
430000000,
|
||||
430500000,
|
||||
431000000,
|
||||
431500000,
|
||||
433075000, /* LPD433 first */
|
||||
433220000,
|
||||
433420000,
|
||||
433657070,
|
||||
433889000,
|
||||
433920000, /* LPD433 mid */
|
||||
434075000,
|
||||
434176948,
|
||||
434190000,
|
||||
434390000,
|
||||
434420000,
|
||||
434620000,
|
||||
434775000, /* LPD433 last channels */
|
||||
438900000,
|
||||
440175000,
|
||||
464000000,
|
||||
467750000,
|
||||
|
||||
/* 779 - 928 */
|
||||
779000000,
|
||||
868350000,
|
||||
868400000,
|
||||
868800000,
|
||||
868950000,
|
||||
906400000,
|
||||
915000000,
|
||||
925000000,
|
||||
928000000,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SubGhzFrequencyAnalyzerStatusIDLE,
|
||||
} SubGhzFrequencyAnalyzerStatus;
|
||||
|
@ -225,7 +160,7 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel
|
|||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
canvas_draw_str(canvas, 0, 7, model->is_ext_radio ? "Ext" : "Int");
|
||||
//canvas_draw_str(canvas, 0, 7, model->is_ext_radio ? "Ext" : "Int");
|
||||
canvas_draw_str(canvas, 20, 7, "Frequency Analyzer");
|
||||
|
||||
// RSSI
|
||||
|
@ -278,34 +213,6 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel
|
|||
elements_button_right(canvas, "+T");
|
||||
}
|
||||
|
||||
uint32_t subghz_frequency_find_correct(uint32_t input) {
|
||||
uint32_t prev_freq = 0;
|
||||
uint32_t result = 0;
|
||||
uint32_t current;
|
||||
|
||||
for(size_t i = 0; i < ARRAY_SIZE(subghz_frequency_list) - 1; i++) {
|
||||
current = subghz_frequency_list[i];
|
||||
if(current == 0) {
|
||||
continue;
|
||||
}
|
||||
if(current == input) {
|
||||
result = current;
|
||||
break;
|
||||
}
|
||||
if(current > input && prev_freq < input) {
|
||||
if(current - input < input - prev_freq) {
|
||||
result = current;
|
||||
} else {
|
||||
result = prev_freq;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev_freq = current;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzFrequencyAnalyzer* instance = (SubGhzFrequencyAnalyzer*)context;
|
||||
|
@ -347,7 +254,9 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
|
|||
instance->selected_index = (instance->selected_index + 1) % instance->max_index;
|
||||
need_redraw = true;
|
||||
}
|
||||
} else if(event->key == InputKeyOk) {
|
||||
} else if(
|
||||
(event->type != InputTypeRelease && event->type != InputTypeRepeat) &&
|
||||
event->key == InputKeyOk) {
|
||||
need_redraw = true;
|
||||
bool updated = false;
|
||||
uint32_t frequency_to_save;
|
||||
|
@ -364,7 +273,8 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
|
|||
} else if(
|
||||
(model->show_frame && model->signal) ||
|
||||
(!model->show_frame && model->signal)) {
|
||||
frequency_candidate = subghz_frequency_find_correct(model->frequency);
|
||||
frequency_candidate = subghz_frequency_analyzer_get_nearest_frequency(
|
||||
instance->worker, model->frequency);
|
||||
}
|
||||
|
||||
frequency_candidate = frequency_candidate == 0 ||
|
||||
|
@ -372,7 +282,8 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
|
|||
instance->txrx, frequency_candidate) ||
|
||||
prev_freq_to_save == frequency_candidate ?
|
||||
0 :
|
||||
subghz_frequency_find_correct(frequency_candidate);
|
||||
subghz_frequency_analyzer_get_nearest_frequency(
|
||||
instance->worker, frequency_candidate);
|
||||
if(frequency_candidate > 0 && frequency_candidate != model->frequency_to_save) {
|
||||
model->frequency_to_save = frequency_candidate;
|
||||
updated = true;
|
||||
|
@ -445,7 +356,8 @@ void subghz_frequency_analyzer_pair_callback(
|
|||
SubGhzFrequencyAnalyzerModel * model,
|
||||
{
|
||||
bool in_array = false;
|
||||
uint32_t normal_frequency = subghz_frequency_find_correct(model->frequency);
|
||||
uint32_t normal_frequency = subghz_frequency_analyzer_get_nearest_frequency(
|
||||
instance->worker, model->frequency);
|
||||
for(size_t i = 0; i < MAX_HISTORY; i++) {
|
||||
if(model->history_frequency[i] == normal_frequency) {
|
||||
in_array = true;
|
||||
|
@ -544,7 +456,7 @@ void subghz_frequency_analyzer_enter(void* context) {
|
|||
(SubGhzFrequencyAnalyzerWorkerPairCallback)subghz_frequency_analyzer_pair_callback,
|
||||
instance);
|
||||
|
||||
subghz_frequency_analyzer_worker_start(instance->worker, instance->txrx);
|
||||
subghz_frequency_analyzer_worker_start(instance->worker);
|
||||
|
||||
instance->rssi_last = 0;
|
||||
instance->selected_index = 0;
|
||||
|
|
|
@ -445,13 +445,11 @@ static void bt_change_profile(Bt* bt, BtMessage* message) {
|
|||
*message->profile_instance = NULL;
|
||||
}
|
||||
}
|
||||
if(message->lock) api_lock_unlock(message->lock);
|
||||
}
|
||||
|
||||
static void bt_close_connection(Bt* bt, BtMessage* message) {
|
||||
static void bt_close_connection(Bt* bt) {
|
||||
bt_close_rpc_connection(bt);
|
||||
furi_hal_bt_stop_advertising();
|
||||
if(message->lock) api_lock_unlock(message->lock);
|
||||
}
|
||||
|
||||
static void bt_apply_settings(Bt* bt) {
|
||||
|
@ -499,19 +497,13 @@ static void bt_load_settings(Bt* bt) {
|
|||
}
|
||||
|
||||
static void bt_handle_get_settings(Bt* bt, BtMessage* message) {
|
||||
furi_assert(message->lock);
|
||||
*message->data.settings = bt->bt_settings;
|
||||
api_lock_unlock(message->lock);
|
||||
}
|
||||
|
||||
static void bt_handle_set_settings(Bt* bt, BtMessage* message) {
|
||||
furi_assert(message->lock);
|
||||
bt->bt_settings = *message->data.csettings;
|
||||
|
||||
bt_apply_settings(bt);
|
||||
bt_settings_save(&bt->bt_settings);
|
||||
|
||||
api_lock_unlock(message->lock);
|
||||
}
|
||||
|
||||
static void bt_handle_reload_keys_settings(Bt* bt) {
|
||||
|
@ -576,6 +568,12 @@ int32_t bt_srv(void* p) {
|
|||
while(1) {
|
||||
furi_check(
|
||||
furi_message_queue_get(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk);
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"call %d, lock 0x%p, result 0x%p",
|
||||
message.type,
|
||||
(void*)message.lock,
|
||||
(void*)message.result);
|
||||
if(message.type == BtMessageTypeUpdateStatus) {
|
||||
// Update view ports
|
||||
bt_statusbar_update(bt);
|
||||
|
@ -599,7 +597,7 @@ int32_t bt_srv(void* p) {
|
|||
} else if(message.type == BtMessageTypeSetProfile) {
|
||||
bt_change_profile(bt, &message);
|
||||
} else if(message.type == BtMessageTypeDisconnect) {
|
||||
bt_close_connection(bt, &message);
|
||||
bt_close_connection(bt);
|
||||
} else if(message.type == BtMessageTypeForgetBondedDevices) {
|
||||
bt_keys_storage_delete(bt->keys_storage);
|
||||
} else if(message.type == BtMessageTypeGetSettings) {
|
||||
|
@ -609,6 +607,8 @@ int32_t bt_srv(void* p) {
|
|||
} else if(message.type == BtMessageTypeReloadKeysSettings) {
|
||||
bt_handle_reload_keys_settings(bt);
|
||||
}
|
||||
|
||||
if(message.lock) api_lock_unlock(message.lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <task_control_block.h>
|
||||
#include <time.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <notification/notification_app.h>
|
||||
#include <loader/loader.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <lib/toolbox/strint.h>
|
||||
|
@ -326,13 +327,24 @@ void cli_command_sysctl(Cli* cli, FuriString* args, void* context) {
|
|||
void cli_command_vibro(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(cli);
|
||||
UNUSED(context);
|
||||
|
||||
if(!furi_string_cmp(args, "0")) {
|
||||
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
notification_message_block(notification, &sequence_reset_vibro);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
} else if(!furi_string_cmp(args, "1")) {
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) {
|
||||
printf("Flipper is in stealth mode. Unmute the device to control vibration.");
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
notification_message_block(notification, &sequence_set_vibro_on);
|
||||
if(notification->settings.vibro_on) {
|
||||
notification_message_block(notification, &sequence_set_vibro_on);
|
||||
} else {
|
||||
printf("Vibro is disabled in settings. Enable it to control vibration.");
|
||||
}
|
||||
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
} else {
|
||||
cli_print_usage("vibro", "<1|0>", furi_string_get_cstr(args));
|
||||
|
|
|
@ -523,7 +523,7 @@ int32_t desktop_srv(void* p) {
|
|||
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
|
||||
if(desktop_pin_code_is_set()) {
|
||||
desktop_lock(desktop);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,11 +54,14 @@ bool dialogs_app_process_module_file_browser(const DialogsAppMessageDataFileBrow
|
|||
ret = file_browser_context->result;
|
||||
|
||||
view_holder_set_view(view_holder, NULL);
|
||||
view_holder_free(view_holder);
|
||||
file_browser_stop(file_browser);
|
||||
|
||||
file_browser_free(file_browser);
|
||||
view_holder_free(view_holder);
|
||||
|
||||
api_lock_free(file_browser_context->lock);
|
||||
free(file_browser_context);
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -212,7 +212,7 @@ static void dolphin_update_clear_limits_timer_period(void* context) {
|
|||
FURI_LOG_D(TAG, "Daily limits reset in %lu ms", time_to_clear_limits);
|
||||
}
|
||||
|
||||
static bool dolphin_process_event(FuriEventLoopObject* object, void* context) {
|
||||
static void dolphin_process_event(FuriEventLoopObject* object, void* context) {
|
||||
UNUSED(object);
|
||||
|
||||
Dolphin* dolphin = context;
|
||||
|
@ -264,8 +264,6 @@ static bool dolphin_process_event(FuriEventLoopObject* object, void* context) {
|
|||
}
|
||||
|
||||
dolphin_event_release(&event);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dolphin_storage_callback(const void* message, void* context) {
|
||||
|
|
|
@ -520,9 +520,21 @@ void canvas_draw_xbm(
|
|||
size_t height,
|
||||
const uint8_t* bitmap) {
|
||||
furi_check(canvas);
|
||||
canvas_draw_xbm_ex(canvas, x, y, width, height, IconRotation0, bitmap);
|
||||
}
|
||||
|
||||
void canvas_draw_xbm_ex(
|
||||
Canvas* canvas,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
size_t width,
|
||||
size_t height,
|
||||
IconRotation rotation,
|
||||
const uint8_t* bitmap_data) {
|
||||
furi_check(canvas);
|
||||
x += canvas->offset_x;
|
||||
y += canvas->offset_y;
|
||||
canvas_draw_u8g2_bitmap(&canvas->fb, x, y, width, height, bitmap, IconRotation0);
|
||||
canvas_draw_u8g2_bitmap(&canvas->fb, x, y, width, height, bitmap_data, rotation);
|
||||
}
|
||||
|
||||
void canvas_draw_glyph(Canvas* canvas, int32_t x, int32_t y, uint16_t ch) {
|
||||
|
|
|
@ -296,6 +296,25 @@ void canvas_draw_xbm(
|
|||
size_t height,
|
||||
const uint8_t* bitmap);
|
||||
|
||||
/** Draw rotated XBM bitmap
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param[in] width bitmap width
|
||||
* @param[in] height bitmap height
|
||||
* @param[in] rotation bitmap rotation
|
||||
* @param bitmap_data pointer to XBM bitmap data
|
||||
*/
|
||||
void canvas_draw_xbm_ex(
|
||||
Canvas* canvas,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
size_t width,
|
||||
size_t height,
|
||||
IconRotation rotation,
|
||||
const uint8_t* bitmap_data);
|
||||
|
||||
/** Draw dot at x,y
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
|
|
|
@ -65,13 +65,18 @@ void text_input_set_result_callback(
|
|||
size_t text_buffer_size,
|
||||
bool clear_default_text);
|
||||
|
||||
/**
|
||||
* @brief Sets the minimum length of a TextInput
|
||||
* @param [in] text_input TextInput
|
||||
* @param [in] minimum_length Minimum input length
|
||||
*/
|
||||
void text_input_set_minimum_length(TextInput* text_input, size_t minimum_length);
|
||||
|
||||
void text_input_set_validator(
|
||||
TextInput* text_input,
|
||||
TextInputValidatorCallback callback,
|
||||
void* callback_context);
|
||||
|
||||
void text_input_set_minimum_length(TextInput* text_input, size_t minimum_length);
|
||||
|
||||
TextInputValidatorCallback text_input_get_validator_callback(TextInput* text_input);
|
||||
|
||||
void* text_input_get_validator_callback_context(TextInput* text_input);
|
||||
|
|
|
@ -5,6 +5,12 @@
|
|||
#define VIEW_DISPATCHER_QUEUE_LEN (16U)
|
||||
|
||||
ViewDispatcher* view_dispatcher_alloc(void) {
|
||||
ViewDispatcher* dispatcher = view_dispatcher_alloc_ex(furi_event_loop_alloc());
|
||||
dispatcher->is_event_loop_owned = true;
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
ViewDispatcher* view_dispatcher_alloc_ex(FuriEventLoop* loop) {
|
||||
ViewDispatcher* view_dispatcher = malloc(sizeof(ViewDispatcher));
|
||||
|
||||
view_dispatcher->view_port = view_port_alloc();
|
||||
|
@ -16,7 +22,7 @@ ViewDispatcher* view_dispatcher_alloc(void) {
|
|||
|
||||
ViewDict_init(view_dispatcher->views);
|
||||
|
||||
view_dispatcher->event_loop = furi_event_loop_alloc();
|
||||
view_dispatcher->event_loop = loop;
|
||||
|
||||
view_dispatcher->input_queue =
|
||||
furi_message_queue_alloc(VIEW_DISPATCHER_QUEUE_LEN, sizeof(InputEvent));
|
||||
|
@ -57,7 +63,7 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher) {
|
|||
furi_message_queue_free(view_dispatcher->input_queue);
|
||||
furi_message_queue_free(view_dispatcher->event_queue);
|
||||
|
||||
furi_event_loop_free(view_dispatcher->event_loop);
|
||||
if(view_dispatcher->is_event_loop_owned) furi_event_loop_free(view_dispatcher->event_loop);
|
||||
// Free dispatcher
|
||||
free(view_dispatcher);
|
||||
}
|
||||
|
@ -85,6 +91,7 @@ void view_dispatcher_set_tick_event_callback(
|
|||
ViewDispatcherTickEventCallback callback,
|
||||
uint32_t tick_period) {
|
||||
furi_check(view_dispatcher);
|
||||
furi_check(view_dispatcher->is_event_loop_owned);
|
||||
view_dispatcher->tick_event_callback = callback;
|
||||
view_dispatcher->tick_period = tick_period;
|
||||
}
|
||||
|
@ -106,11 +113,12 @@ void view_dispatcher_run(ViewDispatcher* view_dispatcher) {
|
|||
uint32_t tick_period = view_dispatcher->tick_period == 0 ? FuriWaitForever :
|
||||
view_dispatcher->tick_period;
|
||||
|
||||
furi_event_loop_tick_set(
|
||||
view_dispatcher->event_loop,
|
||||
tick_period,
|
||||
view_dispatcher_handle_tick_event,
|
||||
view_dispatcher);
|
||||
if(view_dispatcher->is_event_loop_owned)
|
||||
furi_event_loop_tick_set(
|
||||
view_dispatcher->event_loop,
|
||||
tick_period,
|
||||
view_dispatcher_handle_tick_event,
|
||||
view_dispatcher);
|
||||
|
||||
furi_event_loop_run(view_dispatcher->event_loop);
|
||||
|
||||
|
@ -368,7 +376,7 @@ void view_dispatcher_update(View* view, void* context) {
|
|||
}
|
||||
}
|
||||
|
||||
bool view_dispatcher_run_event_callback(FuriEventLoopObject* object, void* context) {
|
||||
void view_dispatcher_run_event_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_assert(context);
|
||||
ViewDispatcher* instance = context;
|
||||
furi_assert(instance->event_queue == object);
|
||||
|
@ -376,11 +384,9 @@ bool view_dispatcher_run_event_callback(FuriEventLoopObject* object, void* conte
|
|||
uint32_t event;
|
||||
furi_check(furi_message_queue_get(instance->event_queue, &event, 0) == FuriStatusOk);
|
||||
view_dispatcher_handle_custom_event(instance, event);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool view_dispatcher_run_input_callback(FuriEventLoopObject* object, void* context) {
|
||||
void view_dispatcher_run_input_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_assert(context);
|
||||
ViewDispatcher* instance = context;
|
||||
furi_assert(instance->input_queue == object);
|
||||
|
@ -388,6 +394,4 @@ bool view_dispatcher_run_input_callback(FuriEventLoopObject* object, void* conte
|
|||
InputEvent input;
|
||||
furi_check(furi_message_queue_get(instance->input_queue, &input, 0) == FuriStatusOk);
|
||||
view_dispatcher_handle_input(instance, &input);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,15 @@ typedef void (*ViewDispatcherTickEventCallback)(void* context);
|
|||
*/
|
||||
ViewDispatcher* view_dispatcher_alloc(void);
|
||||
|
||||
/** Allocate ViewDispatcher instance with an externally owned event loop. If
|
||||
* this constructor is used instead of `view_dispatcher_alloc`, the burden of
|
||||
* freeing the event loop is placed on the caller.
|
||||
*
|
||||
* @param loop pointer to FuriEventLoop instance
|
||||
* @return pointer to ViewDispatcher instance
|
||||
*/
|
||||
ViewDispatcher* view_dispatcher_alloc_ex(FuriEventLoop* loop);
|
||||
|
||||
/** Free ViewDispatcher instance
|
||||
*
|
||||
* @warning All added views MUST be removed using view_dispatcher_remove_view()
|
||||
|
@ -97,6 +106,10 @@ void view_dispatcher_set_navigation_event_callback(
|
|||
|
||||
/** Set tick event handler
|
||||
*
|
||||
* @warning Requires the event loop to be owned by the view dispatcher, i.e.
|
||||
* it should have been instantiated with `view_dispatcher_alloc`, not
|
||||
* `view_dispatcher_alloc_ex`.
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param callback ViewDispatcherTickEventCallback
|
||||
* @param tick_period callback call period
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
DICT_DEF2(ViewDict, uint32_t, M_DEFAULT_OPLIST, View*, M_PTR_OPLIST) // NOLINT
|
||||
|
||||
struct ViewDispatcher {
|
||||
bool is_event_loop_owned;
|
||||
FuriEventLoop* event_loop;
|
||||
FuriMessageQueue* input_queue;
|
||||
FuriMessageQueue* event_queue;
|
||||
|
@ -56,7 +57,7 @@ void view_dispatcher_set_current_view(ViewDispatcher* view_dispatcher, View* vie
|
|||
void view_dispatcher_update(View* view, void* context);
|
||||
|
||||
/** ViewDispatcher run event loop event callback */
|
||||
bool view_dispatcher_run_event_callback(FuriEventLoopObject* object, void* context);
|
||||
void view_dispatcher_run_event_callback(FuriEventLoopObject* object, void* context);
|
||||
|
||||
/** ViewDispatcher run event loop input callback */
|
||||
bool view_dispatcher_run_input_callback(FuriEventLoopObject* object, void* context);
|
||||
void view_dispatcher_run_input_callback(FuriEventLoopObject* object, void* context);
|
||||
|
|
|
@ -309,12 +309,14 @@ static void loader_applications_closed_callback(void* context) {
|
|||
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
||||
}
|
||||
|
||||
static void loader_thread_state_callback(FuriThreadState thread_state, void* context) {
|
||||
static void
|
||||
loader_thread_state_callback(FuriThread* thread, FuriThreadState thread_state, void* context) {
|
||||
UNUSED(thread);
|
||||
furi_assert(context);
|
||||
|
||||
Loader* loader = context;
|
||||
|
||||
if(thread_state == FuriThreadStateStopped) {
|
||||
Loader* loader = context;
|
||||
|
||||
LoaderMessage message;
|
||||
message.type = LoaderMessageTypeAppClosed;
|
||||
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
||||
|
|
|
@ -593,3 +593,7 @@ const NotificationSequence sequence_lcd_contrast_update = {
|
|||
&message_lcd_contrast_update,
|
||||
NULL,
|
||||
};
|
||||
|
||||
const NotificationSequence sequence_empty = {
|
||||
NULL,
|
||||
};
|
||||
|
|
|
@ -145,6 +145,9 @@ extern const NotificationSequence sequence_audiovisual_alert;
|
|||
// LCD
|
||||
extern const NotificationSequence sequence_lcd_contrast_update;
|
||||
|
||||
// Wait for notification queue become empty
|
||||
extern const NotificationSequence sequence_empty;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -380,7 +380,7 @@ static void power_handle_reboot(PowerBootMode mode) {
|
|||
furi_hal_power_reset();
|
||||
}
|
||||
|
||||
static bool power_message_callback(FuriEventLoopObject* object, void* context) {
|
||||
static void power_message_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_assert(context);
|
||||
Power* power = context;
|
||||
|
||||
|
@ -412,8 +412,6 @@ static bool power_message_callback(FuriEventLoopObject* object, void* context) {
|
|||
if(msg.lock) {
|
||||
api_lock_unlock(msg.lock);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void power_tick_callback(void* context) {
|
||||
|
|
|
@ -104,19 +104,12 @@ static int32_t region_load_file(void* context) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void region_loader_pending_callback(void* context, uint32_t arg) {
|
||||
UNUSED(arg);
|
||||
|
||||
FuriThread* loader = context;
|
||||
furi_thread_join(loader);
|
||||
furi_thread_free(loader);
|
||||
}
|
||||
|
||||
static void region_loader_state_callback(FuriThreadState state, void* context) {
|
||||
static void
|
||||
region_loader_release_callback(FuriThread* thread, FuriThreadState state, void* context) {
|
||||
UNUSED(context);
|
||||
|
||||
if(state == FuriThreadStateStopped) {
|
||||
furi_timer_pending_callback(region_loader_pending_callback, furi_thread_get_current(), 0);
|
||||
furi_thread_free(thread);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +119,7 @@ static void region_storage_callback(const void* message, void* context) {
|
|||
|
||||
if(event->type == StorageEventTypeCardMount) {
|
||||
FuriThread* loader = furi_thread_alloc_ex(NULL, 2048, region_load_file, NULL);
|
||||
furi_thread_set_state_callback(loader, region_loader_state_callback);
|
||||
furi_thread_set_state_callback(loader, region_loader_release_callback);
|
||||
furi_thread_start(loader);
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue