mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-13 13:09:49 +04:00
Compare commits
132 Commits
un1-9b1384
...
un1-3a767c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
107d574c02 | ||
|
|
84204a3233 | ||
|
|
48691b2296 | ||
|
|
3a767c9c02 | ||
|
|
1a4d928e5c | ||
|
|
a8858e38b5 | ||
|
|
120b5d7c90 | ||
|
|
b7a6d18186 | ||
|
|
8d8481b17f | ||
|
|
ca8217b692 | ||
|
|
361895c689 | ||
|
|
789230458b | ||
|
|
6f77f537e3 | ||
|
|
b6254227b9 | ||
|
|
8323877120 | ||
|
|
f99c1a8c0a | ||
|
|
c41555b579 | ||
|
|
97b27261d5 | ||
|
|
1853359d78 | ||
|
|
ed2c607dd3 | ||
|
|
bd54c2b342 | ||
|
|
53aa5c71a0 | ||
|
|
a3932cfa6d | ||
|
|
1d787e6da8 | ||
|
|
10b0a611cf | ||
|
|
f537ccfe14 | ||
|
|
d37dbb29bf | ||
|
|
0ee4573a65 | ||
|
|
311b60f815 | ||
|
|
9ff35c9fc3 | ||
|
|
f14874b0e0 | ||
|
|
6c7611c57e | ||
|
|
4d388f4bde | ||
|
|
613c729025 | ||
|
|
079cadaeda | ||
|
|
0c0fb57410 | ||
|
|
e7a5d19f9c | ||
|
|
8e9043003f | ||
|
|
b67aaad6d5 | ||
|
|
e4c6158d65 | ||
|
|
23217f4a6a | ||
|
|
4fcb90928c | ||
|
|
68da151320 | ||
|
|
f70ec8f70e | ||
|
|
5e2a90c6f1 | ||
|
|
5272b81ae6 | ||
|
|
782593eafc | ||
|
|
d76ba20652 | ||
|
|
611b7e15ed | ||
|
|
274f17ed5a | ||
|
|
f09c5889dd | ||
|
|
39f936ce12 | ||
|
|
1350dcaf63 | ||
|
|
4629aee29c | ||
|
|
ffa3ff5e7c | ||
|
|
bacc8fa669 | ||
|
|
9c748860bb | ||
|
|
79c4b617c1 | ||
|
|
194727515b | ||
|
|
c714a32ea5 | ||
|
|
689da15346 | ||
|
|
1a4a6d4625 | ||
|
|
99a7d06f71 | ||
|
|
db4976c501 | ||
|
|
fc62762ce4 | ||
|
|
a6597da4a5 | ||
|
|
ab5bcd71f5 | ||
|
|
eb28dc2e20 | ||
|
|
92db5e1afe | ||
|
|
885bb0c730 | ||
|
|
71f4bd0a7c | ||
|
|
66e361714f | ||
|
|
9bd6d956ca | ||
|
|
293d5f722d | ||
|
|
04f522487e | ||
|
|
ab4bb55d0f | ||
|
|
64edddeabf | ||
|
|
a0819df874 | ||
|
|
24265204b3 | ||
|
|
e828d15fe3 | ||
|
|
6c2cf68077 | ||
|
|
f6d38939c2 | ||
|
|
f9d3d6bf5c | ||
|
|
33176220f6 | ||
|
|
b31e4a36a8 | ||
|
|
ecbe42744d | ||
|
|
7abc49ea21 | ||
|
|
5b6f2cb80d | ||
|
|
1f68cf09eb | ||
|
|
273871013e | ||
|
|
ce7b943793 | ||
|
|
7e20df7e93 | ||
|
|
9ec0835012 | ||
|
|
432782344a | ||
|
|
94f440d286 | ||
|
|
64ee9dd674 | ||
|
|
3327093dae | ||
|
|
029f82dc82 | ||
|
|
803422c18e | ||
|
|
7c54fcf60a | ||
|
|
3a985eff4d | ||
|
|
11e73cc670 | ||
|
|
b0daa601ad | ||
|
|
baffcc5cf4 | ||
|
|
9bfb641d3e | ||
|
|
f92127c0a7 | ||
|
|
545dabadb7 | ||
|
|
ddd5d5a535 | ||
|
|
a7a9c38036 | ||
|
|
56907f0c9f | ||
|
|
73c28437d6 | ||
|
|
57328761cf | ||
|
|
9317ded1a9 | ||
|
|
8992f8ac36 | ||
|
|
9829145d8c | ||
|
|
5b4e732fa3 | ||
|
|
df4755bc06 | ||
|
|
84e2e321b4 | ||
|
|
4e1470cef2 | ||
|
|
cfc0383b96 | ||
|
|
0a6d775fa7 | ||
|
|
fdb181b158 | ||
|
|
71c27de8cc | ||
|
|
9609751517 | ||
|
|
2a452063c6 | ||
|
|
2e993b0a58 | ||
|
|
e243a0e0e4 | ||
|
|
9eb9a44ee4 | ||
|
|
3aed4de1b4 | ||
|
|
33fbf268b7 | ||
|
|
36784f95c8 | ||
|
|
be942ef7b2 |
@@ -36,6 +36,7 @@ steps:
|
|||||||
- mkdir -p sd-card/nfc/assets
|
- mkdir -p sd-card/nfc/assets
|
||||||
- mkdir -p sd-card/infrared/assets
|
- mkdir -p sd-card/infrared/assets
|
||||||
- mkdir -p sd-card/unirf
|
- mkdir -p sd-card/unirf
|
||||||
|
- mkdir -p sd-card/rfidfuzzer
|
||||||
- mkdir -p sd-card/badusb/layouts
|
- mkdir -p sd-card/badusb/layouts
|
||||||
- cp assets/resources/badusb/layouts/* sd-card/badusb/layouts/
|
- cp assets/resources/badusb/layouts/* sd-card/badusb/layouts/
|
||||||
- cp assets/resources/subghz/assets/dangerous_settings sd-card/subghz/assets/dangerous_settings
|
- cp assets/resources/subghz/assets/dangerous_settings sd-card/subghz/assets/dangerous_settings
|
||||||
@@ -44,8 +45,11 @@ steps:
|
|||||||
- cp assets/resources/nfc/assets/mf_classic_dict.nfc sd-card/nfc/assets/mf_classic_dict.nfc
|
- cp assets/resources/nfc/assets/mf_classic_dict.nfc sd-card/nfc/assets/mf_classic_dict.nfc
|
||||||
- cp assets/resources/infrared/assets/tv.ir sd-card/infrared/assets/tv.ir
|
- cp assets/resources/infrared/assets/tv.ir sd-card/infrared/assets/tv.ir
|
||||||
- cp assets/resources/infrared/assets/ac.ir sd-card/infrared/assets/ac.ir
|
- cp assets/resources/infrared/assets/ac.ir sd-card/infrared/assets/ac.ir
|
||||||
|
- cp assets/resources/infrared/assets/fans.ir sd-card/infrared/assets/fans.ir
|
||||||
|
- cp assets/resources/infrared/assets/projectors.ir sd-card/infrared/assets/projectors.ir
|
||||||
- cp assets/resources/infrared/assets/audio.ir sd-card/infrared/assets/audio.ir
|
- cp assets/resources/infrared/assets/audio.ir sd-card/infrared/assets/audio.ir
|
||||||
- cp assets/resources/unirf/unirf_map_example.txt sd-card/unirf/unirf_map_example.txt
|
- cp assets/resources/unirf/unirf_map_example.txt sd-card/unirf/unirf_map_example.txt
|
||||||
|
- cp assets/resources/rfidfuzzer/example_uids.txt sd-card/rfidfuzzer/example_uids.txt
|
||||||
- cp assets/resources/Manifest sd-card/Manifest
|
- cp assets/resources/Manifest sd-card/Manifest
|
||||||
- zip -r artifacts-default/sd-card-${DRONE_TAG}.zip sd-card
|
- zip -r artifacts-default/sd-card-${DRONE_TAG}.zip sd-card
|
||||||
- rm -rf sd-card
|
- rm -rf sd-card
|
||||||
@@ -114,9 +118,7 @@ steps:
|
|||||||
|
|
||||||
[-Install via Web Updater-](https://my.flipp.dev/?url=https://unleashedflip.com/builds/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})"
|
[-Install via Web Updater-](https://my.flipp.dev/?url=https://unleashedflip.com/builds/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})"
|
||||||
document:
|
document:
|
||||||
- artifacts-default/flipper-z-f7-full-${DRONE_TAG}.dfu
|
- artifacts-default/flipper-z-f7-update-${DRONE_TAG}.tgz
|
||||||
- artifacts-default/flipper-z-f7-update-${DRONE_TAG}.zip
|
|
||||||
- artifacts-default/sd-card-${DRONE_TAG}.zip
|
|
||||||
|
|
||||||
- name: "Send discord notification"
|
- name: "Send discord notification"
|
||||||
image: appleboy/drone-discord
|
image: appleboy/drone-discord
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -51,3 +51,7 @@ build/
|
|||||||
|
|
||||||
# openocd output file
|
# openocd output file
|
||||||
openocd.log
|
openocd.log
|
||||||
|
|
||||||
|
# PVS Studio temporary files
|
||||||
|
.PVS-Studio/
|
||||||
|
PVS-Studio.log
|
||||||
|
|||||||
22
.pvsconfig
Normal file
22
.pvsconfig
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# MLib macros we can't do much about.
|
||||||
|
//-V:M_EACH:1048,1044
|
||||||
|
//-V:ARRAY_DEF:760,747,568,776,729,712,654
|
||||||
|
//-V:LIST_DEF:760,747,568,712,729,654,776
|
||||||
|
//-V:BPTREE_DEF2:779,1086,557,773,512
|
||||||
|
//-V:DICT_DEF2:779,524,776,760,1044,1001,729,590,568,747,685
|
||||||
|
//-V:ALGO_DEF:1048,747,1044
|
||||||
|
|
||||||
|
# Non-severe malloc/null pointer deref warnings
|
||||||
|
//-V::522:2,3
|
||||||
|
|
||||||
|
# Warning about headers with copyleft license
|
||||||
|
//-V::1042
|
||||||
|
|
||||||
|
# Potentially null argument warnings
|
||||||
|
//-V:memset:575
|
||||||
|
//-V:memcpy:575
|
||||||
|
//-V:strcpy:575
|
||||||
|
//-V:strchr:575
|
||||||
|
|
||||||
|
# For loop warning on M_FOREACH
|
||||||
|
//-V:for:1044
|
||||||
1
.pvsoptions
Normal file
1
.pvsoptions
Normal file
@@ -0,0 +1 @@
|
|||||||
|
--rules-config .pvsconfig -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/STM32CubeWB -e lib/u8g2 -e */arm-none-eabi/*
|
||||||
16
CHANGELOG.md
16
CHANGELOG.md
@@ -1,16 +1,12 @@
|
|||||||
### New changes
|
### New changes
|
||||||
* Wifi Marauder app update (by @0xchocolate)
|
* WAV Player, Arkanoid, TicTacToe, Barcode generator - plugins enabled and included in releases again
|
||||||
* Updated Universal remote assets (by @Amec0e)
|
* Debug apps disabled in release build
|
||||||
* Fixed music player
|
* WAV Player moved to Games menu
|
||||||
* Fixed typos in subghz encoders
|
* OFW: Lib: update LFS to v2.5.0, lower update free page limit
|
||||||
* OFW: New NFC info screens
|
|
||||||
* OFW: U2F fixes
|
|
||||||
|
|
||||||
**Note: Prefer installing using web updater or by self update package, all needed assets will be installed**
|
**Note: To avoid issues prefer installing using web updater or by self update package, all needed assets will be installed**
|
||||||
|
|
||||||
**Build naming has been changed - all same as before but `cg - codegrabber` changed to `un - unleashed`**
|
Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip` or `.tgz` for iOS mobile app
|
||||||
|
|
||||||
Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip`
|
|
||||||
|
|
||||||
DFU for update using qFlipper - `flipper-z-f7-full-(version).dfu`
|
DFU for update using qFlipper - `flipper-z-f7-full-(version).dfu`
|
||||||
|
|
||||||
|
|||||||
38
ReadMe.md
38
ReadMe.md
@@ -1,11 +1,13 @@
|
|||||||
# Flipper Zero Unleashed Firmware
|
<h3 align="center">
|
||||||
|
<a href="https://github.com/Eng1n33r/flipperzero-firmware">
|
||||||
|
<img src="https://user-images.githubusercontent.com/10697207/186202043-26947e28-b1cc-459a-8f20-ffcc7fc0c71c.png" align="center" alt="fzCUSTOM" border="0">
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
|
||||||
<img src="https://i.ibb.co/wQ12PVc/fzCUSTOM.png" alt="fzCUSTOM" border="0">
|
### Welcome to Flipper Zero Unleashed Firmware repo!
|
||||||
|
|
||||||
Welcome to Flipper Zero's Custom Firmware repo!
|
|
||||||
Our goal is to make any features possible in this device without any limitations!
|
Our goal is to make any features possible in this device without any limitations!
|
||||||
|
|
||||||
Please help us implement emulation for all subghz dynamic (rolling code) protocols and static code brute-force app!
|
Please help us implement emulation for all subghz dynamic (rolling code) protocols and static code brute-force plugin!
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@@ -29,18 +31,20 @@ Our Discord Community:
|
|||||||
* Extra SubGHz frequencies + extra Mifare Classic keys
|
* Extra SubGHz frequencies + extra Mifare Classic keys
|
||||||
* Picopass/iClass plugin included in releases
|
* Picopass/iClass plugin included in releases
|
||||||
* Recompiled IR TV Universal Remote for ALL buttons
|
* Recompiled IR TV Universal Remote for ALL buttons
|
||||||
* Universal A/C and Audio(soundbars, etc.) remote
|
* Universal remote for Projectors, Fans, A/Cs and Audio(soundbars, etc.)
|
||||||
|
* BadUSB keyboard layouts
|
||||||
|
* Customizable Flipper name
|
||||||
* Other small fixes and changes throughout
|
* Other small fixes and changes throughout
|
||||||
|
|
||||||
See changelog in releases for latest updates!
|
See changelog in releases for latest updates!
|
||||||
|
|
||||||
### Current modified and new SubGhz protocols list:
|
### Current modified and new SubGHz protocols list:
|
||||||
- HCS101
|
- HCS101
|
||||||
- An-Motors
|
- An-Motors
|
||||||
- CAME Atomo
|
- CAME Atomo
|
||||||
- FAAC SLH (Spa) [if cloning existing remote - external seed calculation required]
|
- FAAC SLH (Spa) [External seed calculation required]
|
||||||
- BFT Mitto [if cloning existing remote - external seed calculation required]
|
- BFT Mitto [External seed calculation required]
|
||||||
- Keeloq (+ proper manufacturer codes selection) [Not ALL systems supported yet!]
|
- Keeloq [Not ALL systems supported yet!]
|
||||||
- Nice Flor S
|
- Nice Flor S
|
||||||
- Security+ v1 & v2
|
- Security+ v1 & v2
|
||||||
- Star Line
|
- Star Line
|
||||||
@@ -51,21 +55,18 @@ See changelog in releases for latest updates!
|
|||||||
* DOGE: `D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`
|
* DOGE: `D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`
|
||||||
* LTC: `ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`
|
* LTC: `ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`
|
||||||
|
|
||||||
**Big thanks to all sponsors!**
|
|
||||||
|
|
||||||
### Community apps included:
|
### Community apps included:
|
||||||
|
|
||||||
- ESP8266 Deauther plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module)
|
- ESP8266 Deauther plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module)
|
||||||
- WiFi Scanner plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module)
|
- WiFi Scanner plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module)
|
||||||
- Dec/Hex Converter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff/tree/main/applications/dec_hex_converter)
|
- MultiConverter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff)
|
||||||
- WAV player plugin (fixed) [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player)
|
- WAV player plugin (fixed) [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player)
|
||||||
- UPC-A Barcode generator plugin [(by McAzzaMan)](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator)
|
- UPC-A Barcode generator plugin [(by McAzzaMan)](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator)
|
||||||
- GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin)
|
- GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin)
|
||||||
- ESP32: WiFi Marauder companion plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion)
|
- ESP32: WiFi Marauder companion plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion)
|
||||||
- NRF24: Sniffer & MouseJacker (with changes) [(by mothball187)](https://github.com/mothball187/flipperzero-nrf24/tree/main/mousejacker)
|
- NRF24: Sniffer & MouseJacker (with changes) [(by mothball187)](https://github.com/mothball187/flipperzero-nrf24/tree/main/mousejacker)
|
||||||
- HID Analyzer [(by Ownasaurus)](https://github.com/Ownasaurus/flipperzero-firmware/tree/hid-analyzer/applications/hid_analyzer)
|
- Simple Clock (fixed) [(Original by CompaqDisc)](https://gist.github.com/CompaqDisc/4e329c501bd03c1e801849b81f48ea61)
|
||||||
- Simple Clock (fixed) !! New version WIP, wait for updates !! [(Original by CompaqDisc)](https://gist.github.com/CompaqDisc/4e329c501bd03c1e801849b81f48ea61)
|
- UniversalRF Remix / Sub-GHz Remote [(by ESurge)](https://github.com/ESurge/flipperzero-firmware-unirfremix)[(updated and all protocol support added by darmiel & xMasterX)](https://github.com/darmiel/flipper-playlist/tree/feat/unirf-protocols)
|
||||||
- UniversalRF Remix (with changes)(only RAW subghz files) [(by ESurge)(Original UniversalRF by jimilinuxguy)](https://github.com/ESurge/flipperzero-firmware-unirfremix)
|
|
||||||
- Tetris (with fixes) [(by jeffplang)](https://github.com/jeffplang/flipperzero-firmware/tree/tetris_game/applications/tetris_game)
|
- Tetris (with fixes) [(by jeffplang)](https://github.com/jeffplang/flipperzero-firmware/tree/tetris_game/applications/tetris_game)
|
||||||
- Spectrum Analyzer (with changes) [(by jolcese)](https://github.com/jolcese/flipperzero-firmware/tree/spectrum/applications/spectrum_analyzer) - [Ultra Narrow mode & scan channels non-consecutively](https://github.com/theY4Kman/flipperzero-firmware/commits?author=theY4Kman)
|
- Spectrum Analyzer (with changes) [(by jolcese)](https://github.com/jolcese/flipperzero-firmware/tree/spectrum/applications/spectrum_analyzer) - [Ultra Narrow mode & scan channels non-consecutively](https://github.com/theY4Kman/flipperzero-firmware/commits?author=theY4Kman)
|
||||||
- Arkanoid (with fixes) [(by gotnull)](https://github.com/gotnull/flipperzero-firmware-wPlugins)
|
- Arkanoid (with fixes) [(by gotnull)](https://github.com/gotnull/flipperzero-firmware-wPlugins)
|
||||||
@@ -87,10 +88,12 @@ See changelog in releases for latest updates!
|
|||||||
|
|
||||||
### **Plugins**
|
### **Plugins**
|
||||||
|
|
||||||
## [- Configure UniversalRF Remix App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/UniRFRemix.md)
|
## [- Configure Sub-GHz Remote App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)
|
||||||
|
|
||||||
## [- Barcode Generator](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/BarcodeGenerator.md)
|
## [- Barcode Generator](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/BarcodeGenerator.md)
|
||||||
|
|
||||||
|
## [- Multi Converter](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/MultiConverter.md)
|
||||||
|
|
||||||
## [- WAV Player sample files & how to convert](https://github.com/UberGuidoZ/Flipper/tree/main/Wav_Player#readme)
|
## [- WAV Player sample files & how to convert](https://github.com/UberGuidoZ/Flipper/tree/main/Wav_Player#readme)
|
||||||
|
|
||||||
### **Plugins that works with external hardware**
|
### **Plugins that works with external hardware**
|
||||||
@@ -142,7 +145,6 @@ See changelog in releases for latest updates!
|
|||||||
- `assets` - Assets used by applications and services
|
- `assets` - Assets used by applications and services
|
||||||
- `furi` - Furi Core: os level primitives and helpers
|
- `furi` - Furi Core: os level primitives and helpers
|
||||||
- `debug` - Debug tool: GDB-plugins, SVD-file and etc
|
- `debug` - Debug tool: GDB-plugins, SVD-file and etc
|
||||||
- `docker` - Docker image sources (used for firmware build automation)
|
|
||||||
- `documentation` - Documentation generation system configs and input files
|
- `documentation` - Documentation generation system configs and input files
|
||||||
- `firmware` - Firmware source code
|
- `firmware` - Firmware source code
|
||||||
- `lib` - Our and 3rd party libraries, drivers and etc...
|
- `lib` - Our and 3rd party libraries, drivers and etc...
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Main Fipper Build System entry point
|
# Main Flipper Build System entry point
|
||||||
#
|
#
|
||||||
# This file is evaluated by scons (the build system) every time fbt is invoked.
|
# This file is evaluated by scons (the build system) every time fbt is invoked.
|
||||||
# Scons constructs all referenced environments & their targets' dependency
|
# Scons constructs all referenced environments & their targets' dependency
|
||||||
@@ -15,7 +15,7 @@ DefaultEnvironment(tools=[])
|
|||||||
# Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15)
|
# Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15)
|
||||||
|
|
||||||
|
|
||||||
# This environment is created only for loading options & validating file/dir existance
|
# This environment is created only for loading options & validating file/dir existence
|
||||||
fbt_variables = SConscript("site_scons/commandline.scons")
|
fbt_variables = SConscript("site_scons/commandline.scons")
|
||||||
cmd_environment = Environment(tools=[], variables=fbt_variables)
|
cmd_environment = Environment(tools=[], variables=fbt_variables)
|
||||||
Help(fbt_variables.GenerateHelpText(cmd_environment))
|
Help(fbt_variables.GenerateHelpText(cmd_environment))
|
||||||
|
|||||||
@@ -29,23 +29,13 @@ bool archive_app_is_available(void* context, const char* path) {
|
|||||||
|
|
||||||
if(app == ArchiveAppTypeU2f) {
|
if(app == ArchiveAppTypeU2f) {
|
||||||
bool file_exists = false;
|
bool file_exists = false;
|
||||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
File* file = storage_file_alloc(fs_api);
|
|
||||||
|
|
||||||
file_exists =
|
if(storage_file_exists(storage, ANY_PATH("u2f/key.u2f"))) {
|
||||||
storage_file_open(file, ANY_PATH("u2f/key.u2f"), FSAM_READ, FSOM_OPEN_EXISTING);
|
file_exists = storage_file_exists(storage, ANY_PATH("u2f/cnt.u2f"));
|
||||||
if(file_exists) {
|
|
||||||
storage_file_close(file);
|
|
||||||
file_exists =
|
|
||||||
storage_file_open(file, ANY_PATH("u2f/cnt.u2f"), FSAM_READ, FSOM_OPEN_EXISTING);
|
|
||||||
if(file_exists) {
|
|
||||||
storage_file_close(file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
storage_file_free(file);
|
|
||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
|
||||||
return file_exists;
|
return file_exists;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -77,14 +77,24 @@ static void archive_long_load_cb(void* context) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void archive_file_browser_set_callbacks(ArchiveBrowserView* browser) {
|
static void archive_file_browser_set_path(
|
||||||
|
ArchiveBrowserView* browser,
|
||||||
|
string_t path,
|
||||||
|
const char* filter_ext,
|
||||||
|
bool skip_assets) {
|
||||||
furi_assert(browser);
|
furi_assert(browser);
|
||||||
|
if(!browser->worker_running) {
|
||||||
file_browser_worker_set_callback_context(browser->worker, browser);
|
browser->worker = file_browser_worker_alloc(path, filter_ext, skip_assets);
|
||||||
file_browser_worker_set_folder_callback(browser->worker, archive_folder_open_cb);
|
file_browser_worker_set_callback_context(browser->worker, browser);
|
||||||
file_browser_worker_set_list_callback(browser->worker, archive_list_load_cb);
|
file_browser_worker_set_folder_callback(browser->worker, archive_folder_open_cb);
|
||||||
file_browser_worker_set_item_callback(browser->worker, archive_list_item_cb);
|
file_browser_worker_set_list_callback(browser->worker, archive_list_load_cb);
|
||||||
file_browser_worker_set_long_load_callback(browser->worker, archive_long_load_cb);
|
file_browser_worker_set_item_callback(browser->worker, archive_list_item_cb);
|
||||||
|
file_browser_worker_set_long_load_callback(browser->worker, archive_long_load_cb);
|
||||||
|
browser->worker_running = true;
|
||||||
|
} else {
|
||||||
|
furi_assert(browser->worker);
|
||||||
|
file_browser_worker_set_config(browser->worker, path, filter_ext, skip_assets);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool archive_is_item_in_array(ArchiveBrowserViewModel* model, uint32_t idx) {
|
bool archive_is_item_in_array(ArchiveBrowserViewModel* model, uint32_t idx) {
|
||||||
@@ -438,8 +448,8 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
|
|||||||
tab = archive_get_tab(browser);
|
tab = archive_get_tab(browser);
|
||||||
if(archive_is_dir_exists(browser->path)) {
|
if(archive_is_dir_exists(browser->path)) {
|
||||||
bool skip_assets = (strcmp(archive_get_tab_ext(tab), "*") == 0) ? false : true;
|
bool skip_assets = (strcmp(archive_get_tab_ext(tab), "*") == 0) ? false : true;
|
||||||
file_browser_worker_set_config(
|
archive_file_browser_set_path(
|
||||||
browser->worker, browser->path, archive_get_tab_ext(tab), skip_assets);
|
browser, browser->path, archive_get_tab_ext(tab), skip_assets);
|
||||||
tab_empty = false; // Empty check will be performed later
|
tab_empty = false; // Empty check will be performed later
|
||||||
} else {
|
} else {
|
||||||
tab_empty = true;
|
tab_empty = true;
|
||||||
|
|||||||
@@ -87,4 +87,3 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key);
|
|||||||
void archive_enter_dir(ArchiveBrowserView* browser, string_t name);
|
void archive_enter_dir(ArchiveBrowserView* browser, string_t name);
|
||||||
void archive_leave_dir(ArchiveBrowserView* browser);
|
void archive_leave_dir(ArchiveBrowserView* browser);
|
||||||
void archive_refresh_dir(ArchiveBrowserView* browser);
|
void archive_refresh_dir(ArchiveBrowserView* browser);
|
||||||
void archive_file_browser_set_callbacks(ArchiveBrowserView* browser);
|
|
||||||
|
|||||||
@@ -82,9 +82,8 @@ uint16_t archive_favorites_count(void* context) {
|
|||||||
static bool archive_favourites_rescan() {
|
static bool archive_favourites_rescan() {
|
||||||
string_t buffer;
|
string_t buffer;
|
||||||
string_init(buffer);
|
string_init(buffer);
|
||||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
File* file = storage_file_alloc(fs_api);
|
File* file = storage_file_alloc(storage);
|
||||||
File* fav_item_file = storage_file_alloc(fs_api);
|
|
||||||
|
|
||||||
bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||||
if(result) {
|
if(result) {
|
||||||
@@ -101,13 +100,8 @@ static bool archive_favourites_rescan() {
|
|||||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
|
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bool file_exists = storage_file_open(
|
if(storage_file_exists(storage, string_get_cstr(buffer))) {
|
||||||
fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING);
|
|
||||||
if(file_exists) {
|
|
||||||
storage_file_close(fav_item_file);
|
|
||||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
|
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
|
||||||
} else {
|
|
||||||
storage_file_close(fav_item_file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,12 +110,11 @@ static bool archive_favourites_rescan() {
|
|||||||
string_clear(buffer);
|
string_clear(buffer);
|
||||||
|
|
||||||
storage_file_close(file);
|
storage_file_close(file);
|
||||||
storage_common_remove(fs_api, ARCHIVE_FAV_PATH);
|
storage_common_remove(storage, ARCHIVE_FAV_PATH);
|
||||||
storage_common_rename(fs_api, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
storage_common_rename(storage, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||||
storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH);
|
storage_common_remove(storage, ARCHIVE_FAV_TEMP_PATH);
|
||||||
|
|
||||||
storage_file_free(file);
|
storage_file_free(file);
|
||||||
storage_file_free(fav_item_file);
|
|
||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -131,9 +124,8 @@ bool archive_favorites_read(void* context) {
|
|||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
|
|
||||||
ArchiveBrowserView* browser = context;
|
ArchiveBrowserView* browser = context;
|
||||||
Storage* fs_api = furi_record_open(RECORD_STORAGE);
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
File* file = storage_file_alloc(fs_api);
|
File* file = storage_file_alloc(storage);
|
||||||
File* fav_item_file = storage_file_alloc(fs_api);
|
|
||||||
|
|
||||||
string_t buffer;
|
string_t buffer;
|
||||||
FileInfo file_info;
|
FileInfo file_info;
|
||||||
@@ -163,16 +155,12 @@ bool archive_favorites_read(void* context) {
|
|||||||
need_refresh = true;
|
need_refresh = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bool file_exists = storage_file_open(
|
if(storage_file_exists(storage, string_get_cstr(buffer))) {
|
||||||
fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING);
|
storage_common_stat(storage, string_get_cstr(buffer), &file_info);
|
||||||
if(file_exists) {
|
|
||||||
storage_common_stat(fs_api, string_get_cstr(buffer), &file_info);
|
|
||||||
storage_file_close(fav_item_file);
|
|
||||||
archive_add_file_item(
|
archive_add_file_item(
|
||||||
browser, (file_info.flags & FSF_DIRECTORY), string_get_cstr(buffer));
|
browser, (file_info.flags & FSF_DIRECTORY), string_get_cstr(buffer));
|
||||||
file_count++;
|
file_count++;
|
||||||
} else {
|
} else {
|
||||||
storage_file_close(fav_item_file);
|
|
||||||
need_refresh = true;
|
need_refresh = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,7 +171,6 @@ bool archive_favorites_read(void* context) {
|
|||||||
storage_file_close(file);
|
storage_file_close(file);
|
||||||
string_clear(buffer);
|
string_clear(buffer);
|
||||||
storage_file_free(file);
|
storage_file_free(file);
|
||||||
storage_file_free(fav_item_file);
|
|
||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
|
||||||
archive_set_item_count(browser, file_count);
|
archive_set_item_count(browser, file_count);
|
||||||
|
|||||||
@@ -370,18 +370,15 @@ ArchiveBrowserView* browser_alloc() {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
browser->worker = file_browser_worker_alloc(browser->path, "*", false);
|
|
||||||
archive_file_browser_set_callbacks(browser);
|
|
||||||
|
|
||||||
file_browser_worker_set_callback_context(browser->worker, browser);
|
|
||||||
|
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
void browser_free(ArchiveBrowserView* browser) {
|
void browser_free(ArchiveBrowserView* browser) {
|
||||||
furi_assert(browser);
|
furi_assert(browser);
|
||||||
|
|
||||||
file_browser_worker_free(browser->worker);
|
if(browser->worker_running) {
|
||||||
|
file_browser_worker_free(browser->worker);
|
||||||
|
}
|
||||||
|
|
||||||
with_view_model(
|
with_view_model(
|
||||||
browser->view, (ArchiveBrowserViewModel * model) {
|
browser->view, (ArchiveBrowserViewModel * model) {
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ typedef enum {
|
|||||||
struct ArchiveBrowserView {
|
struct ArchiveBrowserView {
|
||||||
View* view;
|
View* view;
|
||||||
BrowserWorker* worker;
|
BrowserWorker* worker;
|
||||||
|
bool worker_running;
|
||||||
ArchiveBrowserViewCallback callback;
|
ArchiveBrowserViewCallback callback;
|
||||||
void* context;
|
void* context;
|
||||||
string_t path;
|
string_t path;
|
||||||
|
|||||||
0
applications/bad_usb/views/bad_usb_view.h
Executable file → Normal file
0
applications/bad_usb/views/bad_usb_view.h
Executable file → Normal file
@@ -3,7 +3,7 @@
|
|||||||
#include <applications/cli/cli.h>
|
#include <applications/cli/cli.h>
|
||||||
#include <lib/toolbox/args.h>
|
#include <lib/toolbox/args.h>
|
||||||
|
|
||||||
#include "ble.h"
|
#include <ble/ble.h>
|
||||||
#include "bt_settings.h"
|
#include "bt_settings.h"
|
||||||
#include "bt_service/bt.h"
|
#include "bt_service/bt.h"
|
||||||
|
|
||||||
|
|||||||
0
applications/bt/bt_debug_app/views/bt_carrier_test.c
Executable file → Normal file
0
applications/bt/bt_debug_app/views/bt_carrier_test.c
Executable file → Normal file
0
applications/bt/bt_debug_app/views/bt_test.c
Executable file → Normal file
0
applications/bt/bt_debug_app/views/bt_test.c
Executable file → Normal file
0
applications/bt/bt_debug_app/views/bt_test.h
Executable file → Normal file
0
applications/bt/bt_debug_app/views/bt_test.h
Executable file → Normal file
6
applications/bt/bt_hid_app/bt_hid.c
Executable file → Normal file
6
applications/bt/bt_hid_app/bt_hid.c
Executable file → Normal file
@@ -89,8 +89,7 @@ BtHid* bt_hid_app_alloc() {
|
|||||||
app->submenu, "Keynote", BtHidSubmenuIndexKeynote, bt_hid_submenu_callback, app);
|
app->submenu, "Keynote", BtHidSubmenuIndexKeynote, bt_hid_submenu_callback, app);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
app->submenu, "Keyboard", BtHidSubmenuIndexKeyboard, bt_hid_submenu_callback, app);
|
app->submenu, "Keyboard", BtHidSubmenuIndexKeyboard, bt_hid_submenu_callback, app);
|
||||||
submenu_add_item(
|
submenu_add_item(app->submenu, "Media", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app);
|
||||||
app->submenu, "Media Player", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app);
|
|
||||||
submenu_add_item(app->submenu, "Mouse", BtHidSubmenuIndexMouse, bt_hid_submenu_callback, app);
|
submenu_add_item(app->submenu, "Mouse", BtHidSubmenuIndexMouse, bt_hid_submenu_callback, app);
|
||||||
view_set_previous_callback(submenu_get_view(app->submenu), bt_hid_exit);
|
view_set_previous_callback(submenu_get_view(app->submenu), bt_hid_exit);
|
||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
@@ -134,7 +133,8 @@ BtHid* bt_hid_app_alloc() {
|
|||||||
app->view_dispatcher, BtHidViewMouse, bt_hid_mouse_get_view(app->bt_hid_mouse));
|
app->view_dispatcher, BtHidViewMouse, bt_hid_mouse_get_view(app->bt_hid_mouse));
|
||||||
|
|
||||||
// TODO switch to menu after Media is done
|
// TODO switch to menu after Media is done
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewKeynote);
|
app->view_id = BtHidViewSubmenu;
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id);
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|||||||
7
applications/bt/bt_hid_app/views/bt_hid_keynote.c
Executable file → Normal file
7
applications/bt/bt_hid_app/views/bt_hid_keynote.c
Executable file → Normal file
@@ -43,7 +43,10 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) {
|
|||||||
}
|
}
|
||||||
canvas_set_font(canvas, FontPrimary);
|
canvas_set_font(canvas, FontPrimary);
|
||||||
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Keynote");
|
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Keynote");
|
||||||
|
|
||||||
|
canvas_draw_icon(canvas, 68, 2, &I_Pin_back_arrow_10x8);
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
elements_multiline_text_aligned(canvas, 127, 3, AlignRight, AlignTop, "Hold to exit");
|
||||||
|
|
||||||
// Up
|
// Up
|
||||||
canvas_draw_icon(canvas, 21, 24, &I_Button_18x18);
|
canvas_draw_icon(canvas, 21, 24, &I_Button_18x18);
|
||||||
@@ -97,8 +100,8 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) {
|
|||||||
elements_slightly_rounded_box(canvas, 66, 47, 60, 13);
|
elements_slightly_rounded_box(canvas, 66, 47, 60, 13);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 110, 49, &I_Ok_btn_9x9);
|
canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8);
|
||||||
elements_multiline_text_aligned(canvas, 76, 56, AlignLeft, AlignBottom, "Back");
|
elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Back");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bt_hid_keynote_process(BtHidKeynote* bt_hid_keynote, InputEvent* event) {
|
static void bt_hid_keynote_process(BtHidKeynote* bt_hid_keynote, InputEvent* event) {
|
||||||
|
|||||||
14
applications/bt/bt_hid_app/views/bt_hid_media.c
Executable file → Normal file
14
applications/bt/bt_hid_app/views/bt_hid_media.c
Executable file → Normal file
@@ -49,7 +49,9 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) {
|
|||||||
|
|
||||||
// Up
|
// Up
|
||||||
if(model->up_pressed) {
|
if(model->up_pressed) {
|
||||||
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13);
|
||||||
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 96, 12, &I_Volup_8x6);
|
canvas_draw_icon(canvas, 96, 12, &I_Volup_8x6);
|
||||||
@@ -57,7 +59,9 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) {
|
|||||||
|
|
||||||
// Down
|
// Down
|
||||||
if(model->down_pressed) {
|
if(model->down_pressed) {
|
||||||
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13);
|
||||||
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 96, 45, &I_Voldwn_6x6);
|
canvas_draw_icon(canvas, 96, 45, &I_Voldwn_6x6);
|
||||||
@@ -65,7 +69,9 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) {
|
|||||||
|
|
||||||
// Left
|
// Left
|
||||||
if(model->left_pressed) {
|
if(model->left_pressed) {
|
||||||
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13);
|
||||||
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
bt_hid_media_draw_arrow(canvas, 82, 31, CanvasDirectionRightToLeft);
|
bt_hid_media_draw_arrow(canvas, 82, 31, CanvasDirectionRightToLeft);
|
||||||
@@ -74,7 +80,9 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) {
|
|||||||
|
|
||||||
// Right
|
// Right
|
||||||
if(model->right_pressed) {
|
if(model->right_pressed) {
|
||||||
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13);
|
||||||
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
bt_hid_media_draw_arrow(canvas, 112, 31, CanvasDirectionLeftToRight);
|
bt_hid_media_draw_arrow(canvas, 112, 31, CanvasDirectionLeftToRight);
|
||||||
@@ -89,6 +97,12 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) {
|
|||||||
bt_hid_media_draw_arrow(canvas, 96, 31, CanvasDirectionLeftToRight);
|
bt_hid_media_draw_arrow(canvas, 96, 31, CanvasDirectionLeftToRight);
|
||||||
canvas_draw_line(canvas, 100, 29, 100, 33);
|
canvas_draw_line(canvas, 100, 29, 100, 33);
|
||||||
canvas_draw_line(canvas, 102, 29, 102, 33);
|
canvas_draw_line(canvas, 102, 29, 102, 33);
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
|
// Exit
|
||||||
|
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bt_hid_media_process_press(BtHidMedia* bt_hid_media, InputEvent* event) {
|
static void bt_hid_media_process_press(BtHidMedia* bt_hid_media, InputEvent* event) {
|
||||||
|
|||||||
@@ -36,7 +36,11 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) {
|
|||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
|
||||||
if(model->left_mouse_held == true) {
|
if(model->left_mouse_held == true) {
|
||||||
elements_multiline_text_aligned(canvas, 0, 60, AlignLeft, AlignBottom, "Selecting...");
|
elements_multiline_text_aligned(canvas, 0, 62, AlignLeft, AlignBottom, "Selecting...");
|
||||||
|
} else {
|
||||||
|
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keypad circles
|
// Keypad circles
|
||||||
@@ -44,7 +48,9 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) {
|
|||||||
|
|
||||||
// Up
|
// Up
|
||||||
if(model->up_pressed) {
|
if(model->up_pressed) {
|
||||||
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 81, 9, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 81, 9, &I_Pressed_Button_13x13);
|
||||||
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up7x9);
|
canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up7x9);
|
||||||
@@ -52,7 +58,9 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) {
|
|||||||
|
|
||||||
// Down
|
// Down
|
||||||
if(model->down_pressed) {
|
if(model->down_pressed) {
|
||||||
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 81, 41, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 81, 41, &I_Pressed_Button_13x13);
|
||||||
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 84, 43, &I_Pin_arrow_down_7x9);
|
canvas_draw_icon(canvas, 84, 43, &I_Pin_arrow_down_7x9);
|
||||||
@@ -60,7 +68,9 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) {
|
|||||||
|
|
||||||
// Left
|
// Left
|
||||||
if(model->left_pressed) {
|
if(model->left_pressed) {
|
||||||
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 65, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 65, 25, &I_Pressed_Button_13x13);
|
||||||
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 67, 28, &I_Pin_arrow_left_9x7);
|
canvas_draw_icon(canvas, 67, 28, &I_Pin_arrow_left_9x7);
|
||||||
@@ -68,7 +78,9 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) {
|
|||||||
|
|
||||||
// Right
|
// Right
|
||||||
if(model->right_pressed) {
|
if(model->right_pressed) {
|
||||||
|
canvas_set_bitmap_mode(canvas, 1);
|
||||||
canvas_draw_icon(canvas, 97, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 97, 25, &I_Pressed_Button_13x13);
|
||||||
|
canvas_set_bitmap_mode(canvas, 0);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 99, 28, &I_Pin_arrow_right_9x7);
|
canvas_draw_icon(canvas, 99, 28, &I_Pin_arrow_right_9x7);
|
||||||
@@ -76,18 +88,17 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) {
|
|||||||
|
|
||||||
// Ok
|
// Ok
|
||||||
if(model->left_mouse_pressed) {
|
if(model->left_mouse_pressed) {
|
||||||
canvas_draw_icon(canvas, 81, 25, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 81, 25, &I_Ok_btn_pressed_13x13);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
} else {
|
||||||
|
canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 83, 27, &I_Ok_btn_9x9);
|
|
||||||
canvas_set_color(canvas, ColorBlack);
|
|
||||||
|
|
||||||
// Back
|
// Back
|
||||||
if(model->right_mouse_pressed) {
|
if(model->right_mouse_pressed) {
|
||||||
canvas_draw_icon(canvas, 108, 48, &I_Pressed_Button_13x13);
|
canvas_draw_icon(canvas, 108, 48, &I_Ok_btn_pressed_13x13);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
} else {
|
||||||
|
canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9);
|
||||||
}
|
}
|
||||||
canvas_draw_icon(canvas, 110, 50, &I_Ok_btn_9x9);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bt_hid_mouse_process(BtHidMouse* bt_hid_mouse, InputEvent* event) {
|
static void bt_hid_mouse_process(BtHidMouse* bt_hid_mouse, InputEvent* event) {
|
||||||
|
|||||||
0
applications/bt/bt_settings_app/bt_settings_app.c
Executable file → Normal file
0
applications/bt/bt_settings_app/bt_settings_app.c
Executable file → Normal file
0
applications/bt/bt_settings_app/bt_settings_app.h
Executable file → Normal file
0
applications/bt/bt_settings_app/bt_settings_app.h
Executable file → Normal file
0
applications/bt/bt_settings_app/scenes/bt_settings_scene_config.h
Executable file → Normal file
0
applications/bt/bt_settings_app/scenes/bt_settings_scene_config.h
Executable file → Normal file
0
applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c
Executable file → Normal file
0
applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c
Executable file → Normal file
0
applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c
Executable file → Normal file
0
applications/bt/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c
Executable file → Normal file
0
applications/bt/bt_settings_app/scenes/bt_settings_scene_start.c
Executable file → Normal file
0
applications/bt/bt_settings_app/scenes/bt_settings_scene_start.c
Executable file → Normal file
@@ -281,6 +281,9 @@ void cli_command_free(Cli* cli, string_t args, void* context) {
|
|||||||
printf("Total heap size: %d\r\n", memmgr_get_total_heap());
|
printf("Total heap size: %d\r\n", memmgr_get_total_heap());
|
||||||
printf("Minimum heap size: %d\r\n", memmgr_get_minimum_free_heap());
|
printf("Minimum heap size: %d\r\n", memmgr_get_minimum_free_heap());
|
||||||
printf("Maximum heap block: %d\r\n", memmgr_heap_get_max_free_block());
|
printf("Maximum heap block: %d\r\n", memmgr_heap_get_max_free_block());
|
||||||
|
|
||||||
|
printf("Pool free: %d\r\n", memmgr_pool_get_free());
|
||||||
|
printf("Maximum pool block: %d\r\n", memmgr_pool_get_max_block());
|
||||||
}
|
}
|
||||||
|
|
||||||
void cli_command_free_blocks(Cli* cli, string_t args, void* context) {
|
void cli_command_free_blocks(Cli* cli, string_t args, void* context) {
|
||||||
|
|||||||
0
applications/cli/cli_i.h
Executable file → Normal file
0
applications/cli/cli_i.h
Executable file → Normal file
@@ -1,404 +0,0 @@
|
|||||||
#include <furi.h>
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <input/input.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#define DEC_HEX_CONVERTER_NUMBER_DIGITS 9
|
|
||||||
#define DEC_HEX_CONVERTER_KEYS 18
|
|
||||||
#define DEC_HEX_CONVERTER_KEY_DEL 16
|
|
||||||
// #define DEC_HEX_CONVERTER_KEY_SWAP 17 // actually not used...
|
|
||||||
|
|
||||||
#define DEC_HEX_CONVERTER_CHAR_DEL '<'
|
|
||||||
#define DEC_HEX_CONVERTER_CHAR_SWAP 's'
|
|
||||||
#define DEC_HEX_CONVERTER_CHAR_MODE '#'
|
|
||||||
#define DEC_HEX_CONVERTER_CHAR_OVERFLOW '#'
|
|
||||||
|
|
||||||
#define DEC_HEX_CONVERTER_KEY_FRAME_MARGIN 3
|
|
||||||
#define DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT 8
|
|
||||||
|
|
||||||
#define DEC_HEX_MAX_SUPORTED_DEC_INT 999999999
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
EventTypeKey,
|
|
||||||
} EventType;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
InputEvent input;
|
|
||||||
EventType type;
|
|
||||||
} DecHexConverterEvent;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ModeDec,
|
|
||||||
ModeHex,
|
|
||||||
} Mode;
|
|
||||||
|
|
||||||
// setting up one char array next to the other one causes the canvas_draw_str to display both of them
|
|
||||||
// when addressing the first one if there's no string terminator or similar indicator. Adding a \0 seems
|
|
||||||
// to work fine to prevent that, so add a final last char outside the size constants (added on init
|
|
||||||
// and NEVER changed nor referenced again)
|
|
||||||
//
|
|
||||||
// (as a reference, canvas_draw_str ends up calling u8g2_DrawStr from u8g2_font.c,
|
|
||||||
// that finally ends up calling u8g2_draw_string)
|
|
||||||
typedef struct {
|
|
||||||
char dec_number[DEC_HEX_CONVERTER_NUMBER_DIGITS + 1];
|
|
||||||
char hex_number[DEC_HEX_CONVERTER_NUMBER_DIGITS + 1];
|
|
||||||
Mode mode; // dec / hex
|
|
||||||
int8_t cursor; // position on keyboard (includes digit letters and other options)
|
|
||||||
int8_t digit_pos; // current digit on selected mode
|
|
||||||
} DecHexConverterState;
|
|
||||||
|
|
||||||
// move cursor left / right (TODO: implement menu nav in a more "standard" and reusable way?)
|
|
||||||
void dec_hex_converter_logic_move_cursor_lr(
|
|
||||||
DecHexConverterState* const dec_hex_converter_state,
|
|
||||||
int8_t d) {
|
|
||||||
dec_hex_converter_state->cursor += d;
|
|
||||||
|
|
||||||
if(dec_hex_converter_state->cursor > DEC_HEX_CONVERTER_KEYS - 1)
|
|
||||||
dec_hex_converter_state->cursor = 0;
|
|
||||||
else if(dec_hex_converter_state->cursor < 0)
|
|
||||||
dec_hex_converter_state->cursor = DEC_HEX_CONVERTER_KEYS - 1;
|
|
||||||
|
|
||||||
// if we're moving left / right to the letters keys on ModeDec just go to the closest available key
|
|
||||||
if(dec_hex_converter_state->mode == ModeDec) {
|
|
||||||
if(dec_hex_converter_state->cursor == 10)
|
|
||||||
dec_hex_converter_state->cursor = 16;
|
|
||||||
else if(dec_hex_converter_state->cursor == 15)
|
|
||||||
dec_hex_converter_state->cursor = 9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// move cursor up / down; there're two lines, so we basically toggle
|
|
||||||
void dec_hex_converter_logic_move_cursor_ud(DecHexConverterState* const dec_hex_converter_state) {
|
|
||||||
if(dec_hex_converter_state->cursor < 9) {
|
|
||||||
// move to second line ("down")
|
|
||||||
dec_hex_converter_state->cursor += 9;
|
|
||||||
|
|
||||||
// if we're reaching the letter keys while ModeDec, just move left / right for the first available key
|
|
||||||
if(dec_hex_converter_state->mode == ModeDec &&
|
|
||||||
(dec_hex_converter_state->cursor >= 10 && dec_hex_converter_state->cursor <= 15)) {
|
|
||||||
if(dec_hex_converter_state->cursor <= 12)
|
|
||||||
dec_hex_converter_state->cursor = 9;
|
|
||||||
else
|
|
||||||
dec_hex_converter_state->cursor = 16;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// move to first line ("up")
|
|
||||||
dec_hex_converter_state->cursor -= 9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch number from current mode and modifies the destination one, RM dnt stel pls
|
|
||||||
// (if destination is shorter than the output value, overried with "-" chars or something similar)
|
|
||||||
void dec_hex_converter_logic_convert_number(DecHexConverterState* const dec_hex_converter_state) {
|
|
||||||
char* s_ptr;
|
|
||||||
char* d_ptr;
|
|
||||||
|
|
||||||
char dest[DEC_HEX_CONVERTER_NUMBER_DIGITS];
|
|
||||||
int i = 0; // current index on destination array
|
|
||||||
|
|
||||||
if(dec_hex_converter_state->mode == ModeDec) {
|
|
||||||
// DEC to HEX cannot overflow if they're, at least, the same size
|
|
||||||
|
|
||||||
s_ptr = dec_hex_converter_state->dec_number;
|
|
||||||
d_ptr = dec_hex_converter_state->hex_number;
|
|
||||||
|
|
||||||
int a = atoi(s_ptr);
|
|
||||||
int r;
|
|
||||||
while(a != 0) {
|
|
||||||
r = a % 16;
|
|
||||||
dest[i] = r + (r < 10 ? '0' : ('A' - 10));
|
|
||||||
a /= 16;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
s_ptr = dec_hex_converter_state->hex_number;
|
|
||||||
d_ptr = dec_hex_converter_state->dec_number;
|
|
||||||
|
|
||||||
int a = strtol(s_ptr, NULL, 16);
|
|
||||||
if(a > DEC_HEX_MAX_SUPORTED_DEC_INT) {
|
|
||||||
// draw all "###" if there's an overflow
|
|
||||||
for(int j = 0; j < DEC_HEX_CONVERTER_NUMBER_DIGITS; j++) {
|
|
||||||
d_ptr[j] = DEC_HEX_CONVERTER_CHAR_OVERFLOW;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
while(a > 0) {
|
|
||||||
dest[i++] = (a % 10) + '0';
|
|
||||||
a /= 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// dest is reversed, copy to destination pointer and append empty chars at the end
|
|
||||||
for(int j = 0; j < DEC_HEX_CONVERTER_NUMBER_DIGITS; j++) {
|
|
||||||
if(i >= 1)
|
|
||||||
d_ptr[j] = dest[--i];
|
|
||||||
else
|
|
||||||
d_ptr[j] = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// change from DEC to HEX or HEX to DEC, set the digit_pos to the last position not empty on the destination mode
|
|
||||||
void dec_hex_converter_logic_swap_mode(DecHexConverterState* const dec_hex_converter_state) {
|
|
||||||
char* n_ptr;
|
|
||||||
if(dec_hex_converter_state->mode == ModeDec) {
|
|
||||||
dec_hex_converter_state->mode = ModeHex;
|
|
||||||
n_ptr = dec_hex_converter_state->hex_number;
|
|
||||||
} else {
|
|
||||||
dec_hex_converter_state->mode = ModeDec;
|
|
||||||
n_ptr = dec_hex_converter_state->dec_number;
|
|
||||||
}
|
|
||||||
|
|
||||||
dec_hex_converter_state->digit_pos = DEC_HEX_CONVERTER_NUMBER_DIGITS;
|
|
||||||
for(int i = 0; i < DEC_HEX_CONVERTER_NUMBER_DIGITS; i++) {
|
|
||||||
if(n_ptr[i] == ' ') {
|
|
||||||
dec_hex_converter_state->digit_pos = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// removes the number on current digit on current mode
|
|
||||||
static void
|
|
||||||
dec_hex_converter_logic_del_number(DecHexConverterState* const dec_hex_converter_state) {
|
|
||||||
if(dec_hex_converter_state->digit_pos > 0) dec_hex_converter_state->digit_pos--;
|
|
||||||
|
|
||||||
if(dec_hex_converter_state->mode == ModeDec) {
|
|
||||||
dec_hex_converter_state->dec_number[dec_hex_converter_state->digit_pos] = ' ';
|
|
||||||
} else {
|
|
||||||
dec_hex_converter_state->hex_number[dec_hex_converter_state->digit_pos] = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// append a number to the digit on the current mode
|
|
||||||
static void dec_hex_converter_logic_add_number(
|
|
||||||
DecHexConverterState* const dec_hex_converter_state,
|
|
||||||
int8_t number) {
|
|
||||||
// ignore HEX values on DEC mode (probably button nav will be disabled too, so cannot reach);
|
|
||||||
// also do not add anything if we're out of bound
|
|
||||||
if((number > 9 && dec_hex_converter_state->mode == ModeDec) ||
|
|
||||||
dec_hex_converter_state->digit_pos >= DEC_HEX_CONVERTER_NUMBER_DIGITS)
|
|
||||||
return;
|
|
||||||
|
|
||||||
char* s_ptr;
|
|
||||||
|
|
||||||
if(dec_hex_converter_state->mode == ModeDec) {
|
|
||||||
s_ptr = dec_hex_converter_state->dec_number;
|
|
||||||
} else {
|
|
||||||
s_ptr = dec_hex_converter_state->hex_number;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(number < 10) {
|
|
||||||
s_ptr[dec_hex_converter_state->digit_pos] = number + '0';
|
|
||||||
} else {
|
|
||||||
s_ptr[dec_hex_converter_state->digit_pos] = (number - 10) + 'A'; // A-F (HEX only)
|
|
||||||
}
|
|
||||||
|
|
||||||
dec_hex_converter_state->digit_pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------
|
|
||||||
|
|
||||||
static void dec_hex_converter_render_callback(Canvas* const canvas, void* ctx) {
|
|
||||||
const DecHexConverterState* dec_hex_converter_state = acquire_mutex((ValueMutex*)ctx, 25);
|
|
||||||
if(dec_hex_converter_state == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas_set_color(canvas, ColorBlack);
|
|
||||||
|
|
||||||
// DEC
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_str(canvas, 2, 10, "DEC: ");
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_str(canvas, 2 + 30, 10, dec_hex_converter_state->dec_number);
|
|
||||||
|
|
||||||
// HEX
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_str(canvas, 2, 10 + 12, "HEX: ");
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_str(canvas, 2 + 30, 10 + 12, dec_hex_converter_state->hex_number);
|
|
||||||
|
|
||||||
// current mode indicator
|
|
||||||
// char buffer[4];
|
|
||||||
// snprintf(buffer, sizeof(buffer), "%u", dec_hex_converter_state->digit_pos); // debug: show digit position instead of selected mode
|
|
||||||
if(dec_hex_converter_state->mode == ModeDec) {
|
|
||||||
canvas_draw_glyph(canvas, 128 - 10, 10, DEC_HEX_CONVERTER_CHAR_MODE);
|
|
||||||
} else {
|
|
||||||
canvas_draw_glyph(canvas, 128 - 10, 10 + 12, DEC_HEX_CONVERTER_CHAR_MODE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw the line
|
|
||||||
canvas_draw_line(canvas, 2, 25, 128 - 3, 25);
|
|
||||||
|
|
||||||
// draw the keyboard
|
|
||||||
uint8_t _x = 5;
|
|
||||||
uint8_t _y = 25 + 15; // line + 10
|
|
||||||
|
|
||||||
for(int i = 0; i < DEC_HEX_CONVERTER_KEYS; i++) {
|
|
||||||
char g;
|
|
||||||
if(i < 10)
|
|
||||||
g = (i + '0');
|
|
||||||
else if(i < 16)
|
|
||||||
g = ((i - 10) + 'A');
|
|
||||||
else if(i == 16)
|
|
||||||
g = DEC_HEX_CONVERTER_CHAR_DEL; // '<'
|
|
||||||
else
|
|
||||||
g = DEC_HEX_CONVERTER_CHAR_SWAP; // 's'
|
|
||||||
|
|
||||||
uint8_t g_w = canvas_glyph_width(canvas, g);
|
|
||||||
|
|
||||||
// disable letters on DEC mode (but keep the previous width for visual purposes - show "blank keys")
|
|
||||||
if(dec_hex_converter_state->mode == ModeDec && i > 9 && i < 16) g = ' ';
|
|
||||||
|
|
||||||
if(dec_hex_converter_state->cursor == i) {
|
|
||||||
canvas_draw_box(
|
|
||||||
canvas,
|
|
||||||
_x - DEC_HEX_CONVERTER_KEY_FRAME_MARGIN,
|
|
||||||
_y - (DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN),
|
|
||||||
DEC_HEX_CONVERTER_KEY_FRAME_MARGIN + g_w + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN,
|
|
||||||
DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2);
|
|
||||||
canvas_set_color(canvas, ColorWhite);
|
|
||||||
canvas_draw_glyph(canvas, _x, _y, g);
|
|
||||||
canvas_set_color(canvas, ColorBlack);
|
|
||||||
} else {
|
|
||||||
canvas_draw_frame(
|
|
||||||
canvas,
|
|
||||||
_x - DEC_HEX_CONVERTER_KEY_FRAME_MARGIN,
|
|
||||||
_y - (DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN),
|
|
||||||
DEC_HEX_CONVERTER_KEY_FRAME_MARGIN + g_w + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN,
|
|
||||||
DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2);
|
|
||||||
canvas_draw_glyph(canvas, _x, _y, g);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(i < 8) {
|
|
||||||
_x += g_w + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2 + 2;
|
|
||||||
} else if(i == 8) {
|
|
||||||
_y += (DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2) + 3;
|
|
||||||
_x = 7; // some padding at the beginning on second line
|
|
||||||
} else {
|
|
||||||
_x += g_w + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2 + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
release_mutex((ValueMutex*)ctx, dec_hex_converter_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dec_hex_converter_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
|
||||||
furi_assert(event_queue);
|
|
||||||
|
|
||||||
DecHexConverterEvent event = {.type = EventTypeKey, .input = *input_event};
|
|
||||||
furi_message_queue_put(event_queue, &event, FuriWaitForever);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dec_hex_converter_init(DecHexConverterState* const dec_hex_converter_state) {
|
|
||||||
dec_hex_converter_state->mode = ModeDec;
|
|
||||||
dec_hex_converter_state->digit_pos = 0;
|
|
||||||
|
|
||||||
dec_hex_converter_state->dec_number[DEC_HEX_CONVERTER_NUMBER_DIGITS] = '\0'; // null terminator
|
|
||||||
dec_hex_converter_state->hex_number[DEC_HEX_CONVERTER_NUMBER_DIGITS] = '\0'; // null terminator
|
|
||||||
|
|
||||||
for(int i = 0; i < DEC_HEX_CONVERTER_NUMBER_DIGITS; i++) {
|
|
||||||
dec_hex_converter_state->dec_number[i] = ' ';
|
|
||||||
dec_hex_converter_state->hex_number[i] = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// main entry point
|
|
||||||
int32_t dec_hex_converter_app(void* p) {
|
|
||||||
UNUSED(p);
|
|
||||||
|
|
||||||
// get event queue
|
|
||||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(DecHexConverterEvent));
|
|
||||||
|
|
||||||
// allocate state
|
|
||||||
DecHexConverterState* dec_hex_converter_state = malloc(sizeof(DecHexConverterState));
|
|
||||||
|
|
||||||
// set mutex for plugin state (different threads can access it)
|
|
||||||
ValueMutex state_mutex;
|
|
||||||
if(!init_mutex(&state_mutex, dec_hex_converter_state, sizeof(dec_hex_converter_state))) {
|
|
||||||
FURI_LOG_E("DecHexConverter", "cannot create mutex\r\n");
|
|
||||||
furi_message_queue_free(event_queue);
|
|
||||||
free(dec_hex_converter_state);
|
|
||||||
return 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
// register callbacks for drawing and input processing
|
|
||||||
ViewPort* view_port = view_port_alloc();
|
|
||||||
view_port_draw_callback_set(view_port, dec_hex_converter_render_callback, &state_mutex);
|
|
||||||
view_port_input_callback_set(view_port, dec_hex_converter_input_callback, event_queue);
|
|
||||||
|
|
||||||
// open GUI and register view_port
|
|
||||||
Gui* gui = furi_record_open(RECORD_GUI);
|
|
||||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
|
||||||
|
|
||||||
dec_hex_converter_init(dec_hex_converter_state);
|
|
||||||
|
|
||||||
// main loop
|
|
||||||
DecHexConverterEvent event;
|
|
||||||
for(bool processing = true; processing;) {
|
|
||||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
|
||||||
DecHexConverterState* dec_hex_converter_state =
|
|
||||||
(DecHexConverterState*)acquire_mutex_block(&state_mutex);
|
|
||||||
|
|
||||||
if(event_status == FuriStatusOk) {
|
|
||||||
// press events
|
|
||||||
if(event.type == EventTypeKey) {
|
|
||||||
if(event.input.type == InputTypePress) {
|
|
||||||
switch(event.input.key) {
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
case InputKeyUp:
|
|
||||||
case InputKeyDown:
|
|
||||||
dec_hex_converter_logic_move_cursor_ud(dec_hex_converter_state);
|
|
||||||
break;
|
|
||||||
case InputKeyRight:
|
|
||||||
dec_hex_converter_logic_move_cursor_lr(dec_hex_converter_state, 1);
|
|
||||||
break;
|
|
||||||
case InputKeyLeft:
|
|
||||||
dec_hex_converter_logic_move_cursor_lr(dec_hex_converter_state, -1);
|
|
||||||
break;
|
|
||||||
case InputKeyOk:
|
|
||||||
if(dec_hex_converter_state->cursor < DEC_HEX_CONVERTER_KEY_DEL) {
|
|
||||||
// positions from 0 to 15 works as regular numbers (DEC / HEX where applicable)
|
|
||||||
// (logic won't allow add numbers > 9 on ModeDec)
|
|
||||||
dec_hex_converter_logic_add_number(
|
|
||||||
dec_hex_converter_state, dec_hex_converter_state->cursor);
|
|
||||||
} else if(dec_hex_converter_state->cursor == DEC_HEX_CONVERTER_KEY_DEL) {
|
|
||||||
// del
|
|
||||||
dec_hex_converter_logic_del_number(dec_hex_converter_state);
|
|
||||||
} else {
|
|
||||||
// swap
|
|
||||||
dec_hex_converter_logic_swap_mode(dec_hex_converter_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
dec_hex_converter_logic_convert_number(dec_hex_converter_state);
|
|
||||||
break;
|
|
||||||
case InputKeyBack:
|
|
||||||
processing = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// event timeout
|
|
||||||
}
|
|
||||||
|
|
||||||
view_port_update(view_port);
|
|
||||||
release_mutex(&state_mutex, dec_hex_converter_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
view_port_enabled_set(view_port, false);
|
|
||||||
gui_remove_view_port(gui, view_port);
|
|
||||||
furi_record_close(RECORD_GUI);
|
|
||||||
view_port_free(view_port);
|
|
||||||
furi_message_queue_free(event_queue);
|
|
||||||
delete_mutex(&state_mutex);
|
|
||||||
free(dec_hex_converter_state);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -220,8 +220,7 @@ static bool animation_manager_check_blocking(AnimationManager* animation_manager
|
|||||||
furi_assert(blocking_animation);
|
furi_assert(blocking_animation);
|
||||||
animation_manager->sd_shown_sd_ok = true;
|
animation_manager->sd_shown_sd_ok = true;
|
||||||
} else if(!animation_manager->sd_shown_no_db) {
|
} else if(!animation_manager->sd_shown_no_db) {
|
||||||
bool db_exists = storage_common_stat(storage, EXT_PATH("Manifest"), NULL) == FSE_OK;
|
if(!storage_file_exists(storage, EXT_PATH("Manifest"))) {
|
||||||
if(!db_exists) {
|
|
||||||
blocking_animation = animation_storage_find_animation(NO_DB_ANIMATION_NAME);
|
blocking_animation = animation_storage_find_animation(NO_DB_ANIMATION_NAME);
|
||||||
furi_assert(blocking_animation);
|
furi_assert(blocking_animation);
|
||||||
animation_manager->sd_shown_no_db = true;
|
animation_manager->sd_shown_no_db = true;
|
||||||
|
|||||||
@@ -94,6 +94,10 @@ bool slideshow_is_loaded(Slideshow* slideshow) {
|
|||||||
return slideshow->loaded;
|
return slideshow->loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool slideshow_is_one_page(Slideshow* slideshow) {
|
||||||
|
return slideshow->loaded && (slideshow->icon.frame_count == 1);
|
||||||
|
}
|
||||||
|
|
||||||
bool slideshow_advance(Slideshow* slideshow) {
|
bool slideshow_advance(Slideshow* slideshow) {
|
||||||
uint8_t next_frame = slideshow->current_frame + 1;
|
uint8_t next_frame = slideshow->current_frame + 1;
|
||||||
if(next_frame < slideshow->icon.frame_count) {
|
if(next_frame < slideshow->icon.frame_count) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ Slideshow* slideshow_alloc();
|
|||||||
void slideshow_free(Slideshow* slideshow);
|
void slideshow_free(Slideshow* slideshow);
|
||||||
bool slideshow_load(Slideshow* slideshow, const char* fspath);
|
bool slideshow_load(Slideshow* slideshow, const char* fspath);
|
||||||
bool slideshow_is_loaded(Slideshow* slideshow);
|
bool slideshow_is_loaded(Slideshow* slideshow);
|
||||||
|
bool slideshow_is_one_page(Slideshow* slideshow);
|
||||||
void slideshow_goback(Slideshow* slideshow);
|
void slideshow_goback(Slideshow* slideshow);
|
||||||
bool slideshow_advance(Slideshow* slideshow);
|
bool slideshow_advance(Slideshow* slideshow);
|
||||||
void slideshow_draw(Slideshow* slideshow, Canvas* canvas, uint8_t x, uint8_t y);
|
void slideshow_draw(Slideshow* slideshow, Canvas* canvas, uint8_t x, uint8_t y);
|
||||||
|
|||||||
@@ -23,11 +23,12 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
|||||||
const Version* ver;
|
const Version* ver;
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
|
|
||||||
static const char* headers[] = {"FW Version Info:", "Dolphin Info:"};
|
static const char* headers[] = {"Device Info:", "Dolphin Info:"};
|
||||||
|
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
canvas_set_font(canvas, FontPrimary);
|
canvas_set_font(canvas, FontPrimary);
|
||||||
canvas_draw_str(canvas, 2, 9 + STATUS_BAR_Y_SHIFT, headers[m->screen]);
|
canvas_draw_str_aligned(
|
||||||
|
canvas, 64, 1 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignTop, headers[m->screen]);
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
|
||||||
if(m->screen != DesktopViewStatsMeta) {
|
if(m->screen != DesktopViewStatsMeta) {
|
||||||
@@ -44,7 +45,7 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
|||||||
furi_hal_version_get_hw_region_name(),
|
furi_hal_version_get_hw_region_name(),
|
||||||
furi_hal_region_get_name(),
|
furi_hal_region_get_name(),
|
||||||
my_name ? my_name : "Unknown");
|
my_name ? my_name : "Unknown");
|
||||||
canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer);
|
canvas_draw_str(canvas, 0, 19 + STATUS_BAR_Y_SHIFT, buffer);
|
||||||
|
|
||||||
ver = furi_hal_version_get_firmware_version();
|
ver = furi_hal_version_get_firmware_version();
|
||||||
const BleGlueC2Info* c2_ver = NULL;
|
const BleGlueC2Info* c2_ver = NULL;
|
||||||
@@ -52,7 +53,7 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
|||||||
c2_ver = ble_glue_get_c2_info();
|
c2_ver = ble_glue_get_c2_info();
|
||||||
#endif
|
#endif
|
||||||
if(!ver) {
|
if(!ver) {
|
||||||
canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, "No info");
|
canvas_draw_str(canvas, 0, 30 + STATUS_BAR_Y_SHIFT, "No info");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +63,7 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
|||||||
"%s [%s]",
|
"%s [%s]",
|
||||||
version_get_version(ver),
|
version_get_version(ver),
|
||||||
version_get_builddate(ver));
|
version_get_builddate(ver));
|
||||||
canvas_draw_str(canvas, 5, 28 + STATUS_BAR_Y_SHIFT, buffer);
|
canvas_draw_str(canvas, 0, 30 + STATUS_BAR_Y_SHIFT, buffer);
|
||||||
|
|
||||||
snprintf(
|
snprintf(
|
||||||
buffer,
|
buffer,
|
||||||
@@ -72,11 +73,11 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
|||||||
version_get_githash(ver),
|
version_get_githash(ver),
|
||||||
version_get_gitbranchnum(ver),
|
version_get_gitbranchnum(ver),
|
||||||
c2_ver ? c2_ver->StackTypeString : "<none>");
|
c2_ver ? c2_ver->StackTypeString : "<none>");
|
||||||
canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer);
|
canvas_draw_str(canvas, 0, 40 + STATUS_BAR_Y_SHIFT, buffer);
|
||||||
|
|
||||||
snprintf(
|
snprintf(
|
||||||
buffer, sizeof(buffer), "[%d] %s", version_get_target(ver), version_get_gitbranch(ver));
|
buffer, sizeof(buffer), "[%d] %s", version_get_target(ver), version_get_gitbranch(ver));
|
||||||
canvas_draw_str(canvas, 5, 50 + STATUS_BAR_Y_SHIFT, buffer);
|
canvas_draw_str(canvas, 0, 50 + STATUS_BAR_Y_SHIFT, buffer);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
|
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
|
||||||
|
|||||||
@@ -35,8 +35,9 @@ static bool desktop_view_slideshow_input(InputEvent* event, void* context) {
|
|||||||
furi_assert(event);
|
furi_assert(event);
|
||||||
DesktopSlideshowView* instance = context;
|
DesktopSlideshowView* instance = context;
|
||||||
|
|
||||||
|
DesktopSlideshowViewModel* model = view_get_model(instance->view);
|
||||||
|
bool update_view = false;
|
||||||
if(event->type == InputTypeShort) {
|
if(event->type == InputTypeShort) {
|
||||||
DesktopSlideshowViewModel* model = view_get_model(instance->view);
|
|
||||||
bool end_slideshow = false;
|
bool end_slideshow = false;
|
||||||
switch(event->key) {
|
switch(event->key) {
|
||||||
case InputKeyLeft:
|
case InputKeyLeft:
|
||||||
@@ -54,15 +55,18 @@ static bool desktop_view_slideshow_input(InputEvent* event, void* context) {
|
|||||||
if(end_slideshow) {
|
if(end_slideshow) {
|
||||||
instance->callback(DesktopSlideshowCompleted, instance->context);
|
instance->callback(DesktopSlideshowCompleted, instance->context);
|
||||||
}
|
}
|
||||||
view_commit_model(instance->view, true);
|
update_view = true;
|
||||||
} else if(event->key == InputKeyOk) {
|
} else if(event->key == InputKeyOk) {
|
||||||
if(event->type == InputTypePress) {
|
if(event->type == InputTypePress) {
|
||||||
furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_SHORT);
|
furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_SHORT);
|
||||||
} else if(event->type == InputTypeRelease) {
|
} else if(event->type == InputTypeRelease) {
|
||||||
furi_timer_stop(instance->timer);
|
furi_timer_stop(instance->timer);
|
||||||
furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG);
|
/*if(!slideshow_is_one_page(model->slideshow)) {
|
||||||
|
furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG);
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
view_commit_model(instance->view, update_view);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -79,12 +83,12 @@ static void desktop_view_slideshow_enter(void* context) {
|
|||||||
instance->timer =
|
instance->timer =
|
||||||
furi_timer_alloc(desktop_first_start_timer_callback, FuriTimerTypeOnce, instance);
|
furi_timer_alloc(desktop_first_start_timer_callback, FuriTimerTypeOnce, instance);
|
||||||
|
|
||||||
furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG);
|
|
||||||
|
|
||||||
DesktopSlideshowViewModel* model = view_get_model(instance->view);
|
DesktopSlideshowViewModel* model = view_get_model(instance->view);
|
||||||
model->slideshow = slideshow_alloc();
|
model->slideshow = slideshow_alloc();
|
||||||
if(!slideshow_load(model->slideshow, SLIDESHOW_FS_PATH)) {
|
if(!slideshow_load(model->slideshow, SLIDESHOW_FS_PATH)) {
|
||||||
instance->callback(DesktopSlideshowCompleted, instance->context);
|
instance->callback(DesktopSlideshowCompleted, instance->context);
|
||||||
|
} else if(!slideshow_is_one_page(model->slideshow)) {
|
||||||
|
furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG);
|
||||||
}
|
}
|
||||||
view_commit_model(instance->view, false);
|
view_commit_model(instance->view, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
#define DOLPHIN_STATE_PATH INT_PATH(DOLPHIN_STATE_FILE_NAME)
|
#define DOLPHIN_STATE_PATH INT_PATH(DOLPHIN_STATE_FILE_NAME)
|
||||||
#define DOLPHIN_STATE_HEADER_MAGIC 0xD0
|
#define DOLPHIN_STATE_HEADER_MAGIC 0xD0
|
||||||
#define DOLPHIN_STATE_HEADER_VERSION 0x01
|
#define DOLPHIN_STATE_HEADER_VERSION 0x01
|
||||||
#define LEVEL2_THRESHOLD 735
|
#define LEVEL2_THRESHOLD 300
|
||||||
#define LEVEL3_THRESHOLD 2940
|
#define LEVEL3_THRESHOLD 1800
|
||||||
#define BUTTHURT_MAX 14
|
#define BUTTHURT_MAX 14
|
||||||
#define BUTTHURT_MIN 0
|
#define BUTTHURT_MIN 0
|
||||||
|
|
||||||
|
|||||||
8
applications/flipfrid/LICENSE.md
Normal file
8
applications/flipfrid/LICENSE.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||||
|
* @G4N4P4T1 wrote this file. As long as you retain this notice you
|
||||||
|
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||||
|
* this stuff is worth it, you can buy me a beer in return.
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
21
applications/flipfrid/README.md
Normal file
21
applications/flipfrid/README.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Flipfrid
|
||||||
|
|
||||||
|
Basic EM4100 Fuzzer
|
||||||
|
|
||||||
|
## Why
|
||||||
|
|
||||||
|
Flipfrid is a simple Rfid fuzzer using EM4100 protocol (125khz).
|
||||||
|
Objective is to provide a simple to use fuzzer to test readers by emulating various cards.
|
||||||
|
|
||||||
|
EM4100 cards use a 1 byte customer id and 4 bytes card id.
|
||||||
|
|
||||||
|
## How
|
||||||
|
|
||||||
|
There is 4 modes :
|
||||||
|
- Default key loop over 16 factory/default keys and emulate each one after one ;
|
||||||
|
- BF customer id. just an iteration from 0X00 to 0XFF on the first byte ;
|
||||||
|
- Load Dump file : Load an existing EM4100 dump generated by Flipperzero, select an index and bruteforce from 0X00 to 0XFF;
|
||||||
|
- Uids list: loop over a text file (one uid per line)
|
||||||
|
|
||||||
|
TODO :
|
||||||
|
- blank screen on back press
|
||||||
10
applications/flipfrid/application.fam
Normal file
10
applications/flipfrid/application.fam
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
App(
|
||||||
|
appid="flipfrid",
|
||||||
|
name="RFID Fuzzer",
|
||||||
|
apptype=FlipperAppType.PLUGIN,
|
||||||
|
entry_point="flipfrid_start",
|
||||||
|
cdefines=["APP_FLIP_FRID"],
|
||||||
|
requires=["gui"],
|
||||||
|
stack_size=1 * 1024,
|
||||||
|
order=29,
|
||||||
|
)
|
||||||
258
applications/flipfrid/flipfrid.c
Normal file
258
applications/flipfrid/flipfrid.c
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
#include "flipfrid.h"
|
||||||
|
|
||||||
|
#include "scene/flipfrid_scene_entrypoint.h"
|
||||||
|
#include "scene/flipfrid_scene_load_file.h"
|
||||||
|
#include "scene/flipfrid_scene_select_field.h"
|
||||||
|
#include "scene/flipfrid_scene_run_attack.h"
|
||||||
|
#include "scene/flipfrid_scene_load_custom_uids.h"
|
||||||
|
|
||||||
|
#define RFIDFUZZER_APP_FOLDER "/ext/rfidfuzzer"
|
||||||
|
|
||||||
|
static void flipfrid_draw_callback(Canvas* const canvas, void* ctx) {
|
||||||
|
FlipFridState* flipfrid_state = (FlipFridState*)acquire_mutex((ValueMutex*)ctx, 100);
|
||||||
|
|
||||||
|
if(flipfrid_state == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw correct Canvas
|
||||||
|
switch(flipfrid_state->current_scene) {
|
||||||
|
case NoneScene:
|
||||||
|
case SceneEntryPoint:
|
||||||
|
flipfrid_scene_entrypoint_on_draw(canvas, flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneSelectFile:
|
||||||
|
flipfrid_scene_load_file_on_draw(canvas, flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneSelectField:
|
||||||
|
flipfrid_scene_select_field_on_draw(canvas, flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneAttack:
|
||||||
|
flipfrid_scene_run_attack_on_draw(canvas, flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneLoadCustomUids:
|
||||||
|
flipfrid_scene_load_custom_uids_on_draw(canvas, flipfrid_state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
release_mutex((ValueMutex*)ctx, flipfrid_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
||||||
|
furi_assert(event_queue);
|
||||||
|
|
||||||
|
FlipFridEvent event = {
|
||||||
|
.evt_type = EventTypeKey, .key = input_event->key, .input_type = input_event->type};
|
||||||
|
furi_message_queue_put(event_queue, &event, 25);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flipfrid_timer_callback(FuriMessageQueue* event_queue) {
|
||||||
|
furi_assert(event_queue);
|
||||||
|
FlipFridEvent event = {
|
||||||
|
.evt_type = EventTypeTick, .key = InputKeyUp, .input_type = InputTypeRelease};
|
||||||
|
furi_message_queue_put(event_queue, &event, 25);
|
||||||
|
}
|
||||||
|
|
||||||
|
FlipFridState* flipfrid_alloc() {
|
||||||
|
FlipFridState* flipfrid = malloc(sizeof(FlipFridState));
|
||||||
|
string_init(flipfrid->notification_msg);
|
||||||
|
string_init(flipfrid->attack_name);
|
||||||
|
|
||||||
|
flipfrid->previous_scene = NoneScene;
|
||||||
|
flipfrid->current_scene = SceneEntryPoint;
|
||||||
|
flipfrid->is_running = true;
|
||||||
|
flipfrid->is_attacking = false;
|
||||||
|
flipfrid->key_index = 0;
|
||||||
|
flipfrid->menu_index = 0;
|
||||||
|
|
||||||
|
flipfrid->attack = FlipFridAttackDefaultValues;
|
||||||
|
flipfrid->notify = furi_record_open(RECORD_NOTIFICATION);
|
||||||
|
|
||||||
|
flipfrid->data[0] = 0x00;
|
||||||
|
flipfrid->data[1] = 0x00;
|
||||||
|
flipfrid->data[2] = 0x00;
|
||||||
|
flipfrid->data[3] = 0x00;
|
||||||
|
flipfrid->data[4] = 0x00;
|
||||||
|
|
||||||
|
flipfrid->payload[0] = 0x00;
|
||||||
|
flipfrid->payload[1] = 0x00;
|
||||||
|
flipfrid->payload[2] = 0x00;
|
||||||
|
flipfrid->payload[3] = 0x00;
|
||||||
|
flipfrid->payload[4] = 0x00;
|
||||||
|
|
||||||
|
//Dialog
|
||||||
|
flipfrid->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||||
|
|
||||||
|
return flipfrid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_free(FlipFridState* flipfrid) {
|
||||||
|
//Dialog
|
||||||
|
furi_record_close(RECORD_DIALOGS);
|
||||||
|
notification_message(flipfrid->notify, &sequence_blink_stop);
|
||||||
|
|
||||||
|
// Strings
|
||||||
|
string_clear(flipfrid->notification_msg);
|
||||||
|
string_clear(flipfrid->attack_name);
|
||||||
|
|
||||||
|
free(flipfrid->data);
|
||||||
|
free(flipfrid->payload);
|
||||||
|
|
||||||
|
// The rest
|
||||||
|
free(flipfrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ENTRYPOINT
|
||||||
|
int32_t flipfrid_start(void* p) {
|
||||||
|
UNUSED(p);
|
||||||
|
// Input
|
||||||
|
FURI_LOG_I(TAG, "Initializing input");
|
||||||
|
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(FlipFridEvent));
|
||||||
|
FlipFridState* flipfrid_state = flipfrid_alloc();
|
||||||
|
ValueMutex flipfrid_state_mutex;
|
||||||
|
|
||||||
|
// Mutex
|
||||||
|
FURI_LOG_I(TAG, "Initializing flipfrid mutex");
|
||||||
|
if(!init_mutex(&flipfrid_state_mutex, flipfrid_state, sizeof(FlipFridState))) {
|
||||||
|
FURI_LOG_E(TAG, "cannot create mutex\r\n");
|
||||||
|
furi_message_queue_free(event_queue);
|
||||||
|
furi_record_close(RECORD_NOTIFICATION);
|
||||||
|
furi_record_close(RECORD_DIALOGS);
|
||||||
|
free(flipfrid_state);
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
if(!storage_simply_mkdir(storage, RFIDFUZZER_APP_FOLDER)) {
|
||||||
|
FURI_LOG_E(TAG, "Could not create folder %s", RFIDFUZZER_APP_FOLDER);
|
||||||
|
}
|
||||||
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
|
||||||
|
// Configure view port
|
||||||
|
FURI_LOG_I(TAG, "Initializing viewport");
|
||||||
|
ViewPort* view_port = view_port_alloc();
|
||||||
|
view_port_draw_callback_set(view_port, flipfrid_draw_callback, &flipfrid_state_mutex);
|
||||||
|
view_port_input_callback_set(view_port, flipfrid_input_callback, event_queue);
|
||||||
|
|
||||||
|
// Configure timer
|
||||||
|
FURI_LOG_I(TAG, "Initializing timer");
|
||||||
|
FuriTimer* timer =
|
||||||
|
furi_timer_alloc(flipfrid_timer_callback, FuriTimerTypePeriodic, event_queue);
|
||||||
|
furi_timer_start(timer, furi_kernel_get_tick_frequency() / 10); // 10 times per second
|
||||||
|
|
||||||
|
// Register view port in GUI
|
||||||
|
FURI_LOG_I(TAG, "Initializing gui");
|
||||||
|
Gui* gui = (Gui*)furi_record_open(RECORD_GUI);
|
||||||
|
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||||
|
|
||||||
|
// Init values
|
||||||
|
FlipFridEvent event;
|
||||||
|
while(flipfrid_state->is_running) {
|
||||||
|
// Get next event
|
||||||
|
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25);
|
||||||
|
if(event_status == FuriStatusOk) {
|
||||||
|
if(event.evt_type == EventTypeKey) {
|
||||||
|
//Handle event key
|
||||||
|
switch(flipfrid_state->current_scene) {
|
||||||
|
case NoneScene:
|
||||||
|
case SceneEntryPoint:
|
||||||
|
flipfrid_scene_entrypoint_on_event(event, flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneSelectFile:
|
||||||
|
flipfrid_scene_load_file_on_event(event, flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneSelectField:
|
||||||
|
flipfrid_scene_select_field_on_event(event, flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneAttack:
|
||||||
|
flipfrid_scene_run_attack_on_event(event, flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneLoadCustomUids:
|
||||||
|
flipfrid_scene_load_custom_uids_on_event(event, flipfrid_state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(event.evt_type == EventTypeTick) {
|
||||||
|
//Handle event tick
|
||||||
|
if(flipfrid_state->current_scene != flipfrid_state->previous_scene) {
|
||||||
|
// Trigger Exit Scene
|
||||||
|
switch(flipfrid_state->previous_scene) {
|
||||||
|
case SceneEntryPoint:
|
||||||
|
flipfrid_scene_entrypoint_on_exit(flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneSelectFile:
|
||||||
|
flipfrid_scene_load_file_on_exit(flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneSelectField:
|
||||||
|
flipfrid_scene_select_field_on_exit(flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneAttack:
|
||||||
|
flipfrid_scene_run_attack_on_exit(flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneLoadCustomUids:
|
||||||
|
flipfrid_scene_load_custom_uids_on_exit(flipfrid_state);
|
||||||
|
break;
|
||||||
|
case NoneScene:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger Entry Scene
|
||||||
|
switch(flipfrid_state->current_scene) {
|
||||||
|
case NoneScene:
|
||||||
|
case SceneEntryPoint:
|
||||||
|
flipfrid_scene_entrypoint_on_enter(flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneSelectFile:
|
||||||
|
flipfrid_scene_load_file_on_enter(flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneSelectField:
|
||||||
|
flipfrid_scene_select_field_on_enter(flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneAttack:
|
||||||
|
flipfrid_scene_run_attack_on_enter(flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneLoadCustomUids:
|
||||||
|
flipfrid_scene_load_custom_uids_on_enter(flipfrid_state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
flipfrid_state->previous_scene = flipfrid_state->current_scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger Tick Scene
|
||||||
|
switch(flipfrid_state->current_scene) {
|
||||||
|
case NoneScene:
|
||||||
|
case SceneEntryPoint:
|
||||||
|
flipfrid_scene_entrypoint_on_tick(flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneSelectFile:
|
||||||
|
flipfrid_scene_load_file_on_tick(flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneSelectField:
|
||||||
|
flipfrid_scene_select_field_on_tick(flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneAttack:
|
||||||
|
flipfrid_scene_run_attack_on_tick(flipfrid_state);
|
||||||
|
break;
|
||||||
|
case SceneLoadCustomUids:
|
||||||
|
flipfrid_scene_load_custom_uids_on_tick(flipfrid_state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
view_port_update(view_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
furi_timer_stop(timer);
|
||||||
|
furi_timer_free(timer);
|
||||||
|
|
||||||
|
FURI_LOG_I(TAG, "Cleaning up");
|
||||||
|
gui_remove_view_port(gui, view_port);
|
||||||
|
view_port_free(view_port);
|
||||||
|
furi_message_queue_free(event_queue);
|
||||||
|
furi_record_close(RECORD_GUI);
|
||||||
|
furi_record_close(RECORD_NOTIFICATION);
|
||||||
|
flipfrid_free(flipfrid_state);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
76
applications/flipfrid/flipfrid.h
Normal file
76
applications/flipfrid/flipfrid.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <furi.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <gui/modules/submenu.h>
|
||||||
|
#include "m-string.h"
|
||||||
|
#include <dialogs/dialogs.h>
|
||||||
|
#include <notification/notification.h>
|
||||||
|
#include <notification/notification_messages.h>
|
||||||
|
#include <toolbox/stream/stream.h>
|
||||||
|
#include <flipper_format/flipper_format_i.h>
|
||||||
|
|
||||||
|
#include <toolbox/stream/stream.h>
|
||||||
|
#include <toolbox/stream/string_stream.h>
|
||||||
|
#include <toolbox/stream/file_stream.h>
|
||||||
|
#include <toolbox/stream/buffered_file_stream.h>
|
||||||
|
|
||||||
|
#include <lib/lfrfid/lfrfid_worker.h>
|
||||||
|
#include <lfrfid/protocols/lfrfid_protocols.h>
|
||||||
|
|
||||||
|
#define TAG "FlipFrid"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FlipFridAttackDefaultValues,
|
||||||
|
FlipFridAttackBfCustomerId,
|
||||||
|
FlipFridAttackLoadFile,
|
||||||
|
FlipFridAttackLoadFileCustomUids,
|
||||||
|
} FlipFridAttacks;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NoneScene,
|
||||||
|
SceneEntryPoint,
|
||||||
|
SceneSelectFile,
|
||||||
|
SceneSelectField,
|
||||||
|
SceneAttack,
|
||||||
|
SceneLoadCustomUids,
|
||||||
|
} FlipFridScene;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EventTypeTick,
|
||||||
|
EventTypeKey,
|
||||||
|
} EventType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EventType evt_type;
|
||||||
|
InputKey key;
|
||||||
|
InputType input_type;
|
||||||
|
} FlipFridEvent;
|
||||||
|
|
||||||
|
// STRUCTS
|
||||||
|
typedef struct {
|
||||||
|
bool is_running;
|
||||||
|
bool is_attacking;
|
||||||
|
FlipFridScene current_scene;
|
||||||
|
FlipFridScene previous_scene;
|
||||||
|
NotificationApp* notify;
|
||||||
|
u_int8_t menu_index;
|
||||||
|
|
||||||
|
string_t data_str;
|
||||||
|
uint8_t data[5];
|
||||||
|
uint8_t payload[5];
|
||||||
|
uint8_t attack_step;
|
||||||
|
FlipFridAttacks attack;
|
||||||
|
string_t attack_name;
|
||||||
|
|
||||||
|
DialogsApp* dialogs;
|
||||||
|
string_t notification_msg;
|
||||||
|
uint8_t key_index;
|
||||||
|
LFRFIDWorker* worker;
|
||||||
|
ProtocolDict* dict;
|
||||||
|
ProtocolId protocol;
|
||||||
|
|
||||||
|
// Used for custom dictionnary
|
||||||
|
Stream* uids_stream;
|
||||||
|
} FlipFridState;
|
||||||
123
applications/flipfrid/scene/flipfrid_scene_entrypoint.c
Normal file
123
applications/flipfrid/scene/flipfrid_scene_entrypoint.c
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
#include "flipfrid_scene_entrypoint.h"
|
||||||
|
|
||||||
|
string_t menu_items[4];
|
||||||
|
|
||||||
|
void flipfrid_scene_entrypoint_menu_callback(FlipFridState* context, uint32_t index) {
|
||||||
|
switch(index) {
|
||||||
|
case FlipFridAttackDefaultValues:
|
||||||
|
context->attack = FlipFridAttackDefaultValues;
|
||||||
|
context->current_scene = SceneAttack;
|
||||||
|
string_set_str(context->attack_name, "Default Values");
|
||||||
|
break;
|
||||||
|
case FlipFridAttackBfCustomerId:
|
||||||
|
context->attack = FlipFridAttackBfCustomerId;
|
||||||
|
context->current_scene = SceneAttack;
|
||||||
|
string_set_str(context->attack_name, "Bad Customer ID");
|
||||||
|
break;
|
||||||
|
case FlipFridAttackLoadFile:
|
||||||
|
context->attack = FlipFridAttackLoadFile;
|
||||||
|
context->current_scene = SceneSelectFile;
|
||||||
|
string_set_str(context->attack_name, "Load File");
|
||||||
|
break;
|
||||||
|
case FlipFridAttackLoadFileCustomUids:
|
||||||
|
context->attack = FlipFridAttackLoadFileCustomUids;
|
||||||
|
context->current_scene = SceneLoadCustomUids;
|
||||||
|
string_set_str(context->attack_name, "Load Custom UIDs");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) {
|
||||||
|
// Clear the previous payload
|
||||||
|
context->payload[0] = 0x00;
|
||||||
|
context->payload[1] = 0x00;
|
||||||
|
context->payload[2] = 0x00;
|
||||||
|
context->payload[3] = 0x00;
|
||||||
|
context->payload[4] = 0x00;
|
||||||
|
|
||||||
|
context->menu_index = 0;
|
||||||
|
for(uint32_t i = 0; i < 4; i++) {
|
||||||
|
string_init(menu_items[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
string_set(menu_items[0], "Default Values");
|
||||||
|
string_set(menu_items[1], "BF Customer ID");
|
||||||
|
string_set(menu_items[2], "Load File");
|
||||||
|
string_set(menu_items[3], "Load uids from file");
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_entrypoint_on_exit(FlipFridState* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
for(uint32_t i = 0; i < 4; i++) {
|
||||||
|
string_clear(menu_items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_entrypoint_on_tick(FlipFridState* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||||
|
if(event.evt_type == EventTypeKey) {
|
||||||
|
if(event.input_type == InputTypeShort) {
|
||||||
|
switch(event.key) {
|
||||||
|
case InputKeyDown:
|
||||||
|
if(context->menu_index < FlipFridAttackLoadFileCustomUids) {
|
||||||
|
context->menu_index++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case InputKeyUp:
|
||||||
|
if(context->menu_index > FlipFridAttackDefaultValues) {
|
||||||
|
context->menu_index--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case InputKeyLeft:
|
||||||
|
case InputKeyRight:
|
||||||
|
break;
|
||||||
|
case InputKeyOk:
|
||||||
|
flipfrid_scene_entrypoint_menu_callback(context, context->menu_index);
|
||||||
|
break;
|
||||||
|
case InputKeyBack:
|
||||||
|
context->is_running = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||||
|
canvas_clear(canvas);
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
|
// Title
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignTop, "RFID Fuzzer");
|
||||||
|
|
||||||
|
if(context->menu_index > FlipFridAttackDefaultValues) {
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
canvas_draw_str_aligned(
|
||||||
|
canvas,
|
||||||
|
64,
|
||||||
|
24,
|
||||||
|
AlignCenter,
|
||||||
|
AlignTop,
|
||||||
|
string_get_cstr(menu_items[context->menu_index - 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
canvas_draw_str_aligned(
|
||||||
|
canvas, 64, 36, AlignCenter, AlignTop, string_get_cstr(menu_items[context->menu_index]));
|
||||||
|
|
||||||
|
if(context->menu_index < FlipFridAttackLoadFileCustomUids) {
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
canvas_draw_str_aligned(
|
||||||
|
canvas,
|
||||||
|
64,
|
||||||
|
48,
|
||||||
|
AlignCenter,
|
||||||
|
AlignTop,
|
||||||
|
string_get_cstr(menu_items[context->menu_index + 1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
8
applications/flipfrid/scene/flipfrid_scene_entrypoint.h
Normal file
8
applications/flipfrid/scene/flipfrid_scene_entrypoint.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../flipfrid.h"
|
||||||
|
|
||||||
|
void flipfrid_scene_entrypoint_on_enter(FlipFridState* context);
|
||||||
|
void flipfrid_scene_entrypoint_on_exit(FlipFridState* context);
|
||||||
|
void flipfrid_scene_entrypoint_on_tick(FlipFridState* context);
|
||||||
|
void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* context);
|
||||||
|
void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context);
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#include "flipfrid_scene_load_custom_uids.h"
|
||||||
|
#include "flipfrid_scene_run_attack.h"
|
||||||
|
#include "flipfrid_scene_entrypoint.h"
|
||||||
|
|
||||||
|
#define LFRFID_UIDS_EXTENSION ".txt"
|
||||||
|
#define RFIDFUZZER_APP_PATH_FOLDER "/ext/rfidfuzzer"
|
||||||
|
|
||||||
|
bool flipfrid_load_uids(FlipFridState* context, const char* file_path) {
|
||||||
|
bool result = false;
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
context->uids_stream = buffered_file_stream_alloc(storage);
|
||||||
|
result =
|
||||||
|
buffered_file_stream_open(context->uids_stream, file_path, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||||
|
// Close if loading fails
|
||||||
|
if(!result) {
|
||||||
|
buffered_file_stream_close(context->uids_stream);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool flipfrid_load_custom_uids_from_file(FlipFridState* context) {
|
||||||
|
// Input events and views are managed by file_select
|
||||||
|
string_t uid_path;
|
||||||
|
string_init(uid_path);
|
||||||
|
string_set_str(uid_path, RFIDFUZZER_APP_PATH_FOLDER);
|
||||||
|
|
||||||
|
bool res = dialog_file_browser_show(
|
||||||
|
context->dialogs, uid_path, uid_path, LFRFID_UIDS_EXTENSION, true, &I_125_10px, false);
|
||||||
|
|
||||||
|
if(res) {
|
||||||
|
res = flipfrid_load_uids(context, string_get_cstr(uid_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
string_clear(uid_path);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_load_custom_uids_on_enter(FlipFridState* context) {
|
||||||
|
if(flipfrid_load_custom_uids_from_file(context)) {
|
||||||
|
// Force context loading
|
||||||
|
flipfrid_scene_run_attack_on_enter(context);
|
||||||
|
context->current_scene = SceneAttack;
|
||||||
|
} else {
|
||||||
|
flipfrid_scene_entrypoint_on_enter(context);
|
||||||
|
context->current_scene = SceneEntryPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_load_custom_uids_on_exit(FlipFridState* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_load_custom_uids_on_tick(FlipFridState* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_load_custom_uids_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||||
|
if(event.evt_type == EventTypeKey) {
|
||||||
|
if(event.input_type == InputTypeShort) {
|
||||||
|
switch(event.key) {
|
||||||
|
case InputKeyDown:
|
||||||
|
case InputKeyUp:
|
||||||
|
case InputKeyLeft:
|
||||||
|
case InputKeyRight:
|
||||||
|
case InputKeyOk:
|
||||||
|
case InputKeyBack:
|
||||||
|
context->current_scene = SceneEntryPoint;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_load_custom_uids_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(canvas);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../flipfrid.h"
|
||||||
|
|
||||||
|
void flipfrid_scene_load_custom_uids_on_enter(FlipFridState* context);
|
||||||
|
void flipfrid_scene_load_custom_uids_on_exit(FlipFridState* context);
|
||||||
|
void flipfrid_scene_load_custom_uids_on_tick(FlipFridState* context);
|
||||||
|
void flipfrid_scene_load_custom_uids_on_event(FlipFridEvent event, FlipFridState* context);
|
||||||
|
void flipfrid_scene_load_custom_uids_on_draw(Canvas* canvas, FlipFridState* context);
|
||||||
|
bool flipfrid_load_custom_uids_from_file(FlipFridState* context);
|
||||||
146
applications/flipfrid/scene/flipfrid_scene_load_file.c
Normal file
146
applications/flipfrid/scene/flipfrid_scene_load_file.c
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
#include "flipfrid_scene_load_file.h"
|
||||||
|
#include "flipfrid_scene_entrypoint.h"
|
||||||
|
|
||||||
|
#define LFRFID_APP_EXTENSION ".rfid"
|
||||||
|
#define LFRFID_APP_PATH_FOLDER "/ext/lfrfid"
|
||||||
|
|
||||||
|
bool flipfrid_load(FlipFridState* context, const char* file_path) {
|
||||||
|
bool result = false;
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||||
|
string_t temp_str;
|
||||||
|
string_init(temp_str);
|
||||||
|
do {
|
||||||
|
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
|
||||||
|
FURI_LOG_E(TAG, "Error open file %s", file_path);
|
||||||
|
string_reset(context->notification_msg);
|
||||||
|
string_set_str(context->notification_msg, "Error open file");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileType
|
||||||
|
if(!flipper_format_read_string(fff_data_file, "Filetype", temp_str)) {
|
||||||
|
FURI_LOG_E(TAG, "Missing or incorrect Filetype");
|
||||||
|
string_reset(context->notification_msg);
|
||||||
|
string_set_str(context->notification_msg, "Missing or incorrect Filetypes");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
FURI_LOG_I(TAG, "Filetype: %s", string_get_cstr(temp_str));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key type
|
||||||
|
if(!flipper_format_read_string(fff_data_file, "Key type", temp_str)) {
|
||||||
|
FURI_LOG_E(TAG, "Missing or incorrect Key type");
|
||||||
|
string_reset(context->notification_msg);
|
||||||
|
string_set_str(context->notification_msg, "Missing or incorrect Key type");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
FURI_LOG_I(TAG, "Key type: %s", string_get_cstr(temp_str));
|
||||||
|
if(strcmp(string_get_cstr(temp_str), "EM4100") != 0) {
|
||||||
|
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||||
|
string_reset(context->notification_msg);
|
||||||
|
string_set_str(context->notification_msg, "Unsupported Key type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data
|
||||||
|
if(!flipper_format_read_string(fff_data_file, "Data", context->data_str)) {
|
||||||
|
FURI_LOG_E(TAG, "Missing or incorrect Data");
|
||||||
|
string_reset(context->notification_msg);
|
||||||
|
string_set_str(context->notification_msg, "Missing or incorrect Key");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
FURI_LOG_I(TAG, "Key: %s", string_get_cstr(context->data_str));
|
||||||
|
|
||||||
|
// Check data size
|
||||||
|
if(string_size(context->data_str) != 14) {
|
||||||
|
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||||
|
string_reset(context->notification_msg);
|
||||||
|
string_set_str(context->notification_msg, "Incorrect Key length");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// String to uint8_t
|
||||||
|
for(uint8_t i = 0; i < 5; i++) {
|
||||||
|
char temp_str2[3];
|
||||||
|
temp_str2[0] = string_get_cstr(context->data_str)[i * 3];
|
||||||
|
temp_str2[1] = string_get_cstr(context->data_str)[i * 3 + 1];
|
||||||
|
temp_str2[2] = '\0';
|
||||||
|
context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
} while(0);
|
||||||
|
string_clear(temp_str);
|
||||||
|
flipper_format_free(fff_data_file);
|
||||||
|
if(result) {
|
||||||
|
FURI_LOG_I(TAG, "Loaded successfully");
|
||||||
|
string_reset(context->notification_msg);
|
||||||
|
string_set_str(context->notification_msg, "Source loaded.");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_load_file_on_enter(FlipFridState* context) {
|
||||||
|
if(flipfrid_load_protocol_from_file(context)) {
|
||||||
|
context->current_scene = SceneSelectField;
|
||||||
|
} else {
|
||||||
|
flipfrid_scene_entrypoint_on_enter(context);
|
||||||
|
context->current_scene = SceneEntryPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_load_file_on_exit(FlipFridState* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_load_file_on_tick(FlipFridState* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_load_file_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||||
|
if(event.evt_type == EventTypeKey) {
|
||||||
|
if(event.input_type == InputTypeShort) {
|
||||||
|
switch(event.key) {
|
||||||
|
case InputKeyDown:
|
||||||
|
case InputKeyUp:
|
||||||
|
case InputKeyLeft:
|
||||||
|
case InputKeyRight:
|
||||||
|
case InputKeyOk:
|
||||||
|
case InputKeyBack:
|
||||||
|
context->current_scene = SceneEntryPoint;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_load_file_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool flipfrid_load_protocol_from_file(FlipFridState* context) {
|
||||||
|
string_t user_file_path;
|
||||||
|
string_init(user_file_path);
|
||||||
|
string_set_str(user_file_path, LFRFID_APP_PATH_FOLDER);
|
||||||
|
|
||||||
|
// Input events and views are managed by file_select
|
||||||
|
bool res = dialog_file_browser_show(
|
||||||
|
context->dialogs,
|
||||||
|
user_file_path,
|
||||||
|
user_file_path,
|
||||||
|
LFRFID_APP_EXTENSION,
|
||||||
|
true,
|
||||||
|
&I_125_10px,
|
||||||
|
true);
|
||||||
|
|
||||||
|
if(res) {
|
||||||
|
res = flipfrid_load(context, string_get_cstr(user_file_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
string_clear(user_file_path);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
9
applications/flipfrid/scene/flipfrid_scene_load_file.h
Normal file
9
applications/flipfrid/scene/flipfrid_scene_load_file.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../flipfrid.h"
|
||||||
|
|
||||||
|
void flipfrid_scene_load_file_on_enter(FlipFridState* context);
|
||||||
|
void flipfrid_scene_load_file_on_exit(FlipFridState* context);
|
||||||
|
void flipfrid_scene_load_file_on_tick(FlipFridState* context);
|
||||||
|
void flipfrid_scene_load_file_on_event(FlipFridEvent event, FlipFridState* context);
|
||||||
|
void flipfrid_scene_load_file_on_draw(Canvas* canvas, FlipFridState* context);
|
||||||
|
bool flipfrid_load_protocol_from_file(FlipFridState* context);
|
||||||
212
applications/flipfrid/scene/flipfrid_scene_run_attack.c
Normal file
212
applications/flipfrid/scene/flipfrid_scene_run_attack.c
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
#include "flipfrid_scene_run_attack.h"
|
||||||
|
|
||||||
|
uint8_t counter = 0;
|
||||||
|
#define TIME_BETWEEN_CARDS 5
|
||||||
|
uint8_t id_list[16][5] = {
|
||||||
|
{0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||||
|
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||||
|
{0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||||
|
{0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22
|
||||||
|
{0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33
|
||||||
|
{0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44
|
||||||
|
{0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55
|
||||||
|
{0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66
|
||||||
|
{0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77
|
||||||
|
{0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||||
|
{0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||||
|
{0x12, 0x34, 0x56, 0x78, 0x9A}, // Incremental UID
|
||||||
|
{0x04, 0xd0, 0x9b, 0x0d, 0x6a}, // From arha
|
||||||
|
{0x34, 0x00, 0x29, 0x3d, 0x9e}, // From arha
|
||||||
|
{0x04, 0xdf, 0x00, 0x00, 0x01}, // From arha
|
||||||
|
{0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha
|
||||||
|
};
|
||||||
|
|
||||||
|
void flipfrid_scene_run_attack_on_enter(FlipFridState* context) {
|
||||||
|
context->attack_step = 0;
|
||||||
|
context->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
|
||||||
|
context->worker = lfrfid_worker_alloc(context->dict);
|
||||||
|
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100");
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_run_attack_on_exit(FlipFridState* context) {
|
||||||
|
lfrfid_worker_stop(context->worker);
|
||||||
|
lfrfid_worker_stop_thread(context->worker);
|
||||||
|
lfrfid_worker_free(context->worker);
|
||||||
|
protocol_dict_free(context->dict);
|
||||||
|
notification_message(context->notify, &sequence_blink_stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_run_attack_on_tick(FlipFridState* context) {
|
||||||
|
if(context->is_attacking) {
|
||||||
|
if(1 == counter) {
|
||||||
|
protocol_dict_set_data(context->dict, context->protocol, context->payload, 5);
|
||||||
|
lfrfid_worker_free(context->worker);
|
||||||
|
context->worker = lfrfid_worker_alloc(context->dict);
|
||||||
|
lfrfid_worker_start_thread(context->worker);
|
||||||
|
lfrfid_worker_emulate_start(context->worker, context->protocol);
|
||||||
|
} else if(0 == counter) {
|
||||||
|
lfrfid_worker_stop(context->worker);
|
||||||
|
lfrfid_worker_stop_thread(context->worker);
|
||||||
|
switch(context->attack) {
|
||||||
|
case FlipFridAttackDefaultValues:
|
||||||
|
context->payload[0] = id_list[context->attack_step][0];
|
||||||
|
context->payload[1] = id_list[context->attack_step][1];
|
||||||
|
context->payload[2] = id_list[context->attack_step][2];
|
||||||
|
context->payload[3] = id_list[context->attack_step][3];
|
||||||
|
context->payload[4] = id_list[context->attack_step][4];
|
||||||
|
|
||||||
|
if(context->attack_step == 15) {
|
||||||
|
context->attack_step = 0;
|
||||||
|
counter = 0;
|
||||||
|
context->is_attacking = false;
|
||||||
|
notification_message(context->notify, &sequence_blink_stop);
|
||||||
|
notification_message(context->notify, &sequence_single_vibro);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
context->attack_step++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FlipFridAttackBfCustomerId:
|
||||||
|
context->payload[0] = context->attack_step;
|
||||||
|
context->payload[1] = 0x00;
|
||||||
|
context->payload[2] = 0x00;
|
||||||
|
context->payload[3] = 0x00;
|
||||||
|
context->payload[4] = 0x00;
|
||||||
|
|
||||||
|
if(context->attack_step == 255) {
|
||||||
|
context->attack_step = 0;
|
||||||
|
counter = 0;
|
||||||
|
context->is_attacking = false;
|
||||||
|
notification_message(context->notify, &sequence_blink_stop);
|
||||||
|
notification_message(context->notify, &sequence_single_vibro);
|
||||||
|
} else {
|
||||||
|
context->attack_step++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FlipFridAttackLoadFile:
|
||||||
|
context->payload[0] = context->data[0];
|
||||||
|
context->payload[1] = context->data[1];
|
||||||
|
context->payload[2] = context->data[2];
|
||||||
|
context->payload[3] = context->data[3];
|
||||||
|
context->payload[4] = context->data[4];
|
||||||
|
|
||||||
|
context->payload[context->key_index] = context->attack_step;
|
||||||
|
|
||||||
|
if(context->attack_step == 255) {
|
||||||
|
context->attack_step = 0;
|
||||||
|
counter = 0;
|
||||||
|
context->is_attacking = false;
|
||||||
|
notification_message(context->notify, &sequence_blink_stop);
|
||||||
|
notification_message(context->notify, &sequence_single_vibro);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
context->attack_step++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FlipFridAttackLoadFileCustomUids:
|
||||||
|
while(true) {
|
||||||
|
string_reset(context->data_str);
|
||||||
|
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||||
|
context->attack_step = 0;
|
||||||
|
counter = 0;
|
||||||
|
context->is_attacking = false;
|
||||||
|
notification_message(context->notify, &sequence_blink_stop);
|
||||||
|
notification_message(context->notify, &sequence_single_vibro);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if(string_get_char(context->data_str, 0) == '#') continue;
|
||||||
|
if(string_size(context->data_str) != 11) continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FURI_LOG_D(TAG, string_get_cstr(context->data_str));
|
||||||
|
|
||||||
|
// string is valid, parse it in context->payload
|
||||||
|
for(uint8_t i = 0; i < 5; i++) {
|
||||||
|
char temp_str[3];
|
||||||
|
temp_str[0] = string_get_cstr(context->data_str)[i * 2];
|
||||||
|
temp_str[1] = string_get_cstr(context->data_str)[i * 2 + 1];
|
||||||
|
temp_str[2] = '\0';
|
||||||
|
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(counter > TIME_BETWEEN_CARDS) {
|
||||||
|
counter = 0;
|
||||||
|
} else {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_run_attack_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||||
|
if(event.evt_type == EventTypeKey) {
|
||||||
|
if(event.input_type == InputTypeShort) {
|
||||||
|
switch(event.key) {
|
||||||
|
case InputKeyDown:
|
||||||
|
case InputKeyUp:
|
||||||
|
case InputKeyLeft:
|
||||||
|
case InputKeyRight:
|
||||||
|
break;
|
||||||
|
case InputKeyOk:
|
||||||
|
counter = 0;
|
||||||
|
if(!context->is_attacking) {
|
||||||
|
notification_message(context->notify, &sequence_blink_start_blue);
|
||||||
|
context->is_attacking = true;
|
||||||
|
} else {
|
||||||
|
context->is_attacking = false;
|
||||||
|
notification_message(context->notify, &sequence_blink_stop);
|
||||||
|
notification_message(context->notify, &sequence_single_vibro);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case InputKeyBack:
|
||||||
|
if(context->attack == FlipFridAttackLoadFileCustomUids) {
|
||||||
|
buffered_file_stream_close(context->uids_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
context->attack_step = 0;
|
||||||
|
context->is_attacking = false;
|
||||||
|
string_reset(context->notification_msg);
|
||||||
|
context->current_scene = SceneEntryPoint;
|
||||||
|
notification_message(context->notify, &sequence_blink_stop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||||
|
canvas_clear(canvas);
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
|
// Frame
|
||||||
|
canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||||
|
|
||||||
|
// Title
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
canvas_draw_str_aligned(
|
||||||
|
canvas, 64, 8, AlignCenter, AlignTop, string_get_cstr(context->attack_name));
|
||||||
|
|
||||||
|
char uid[16];
|
||||||
|
snprintf(
|
||||||
|
uid,
|
||||||
|
sizeof(uid),
|
||||||
|
"%02X:%02X:%02X:%02X:%02X",
|
||||||
|
context->payload[0],
|
||||||
|
context->payload[1],
|
||||||
|
context->payload[2],
|
||||||
|
context->payload[3],
|
||||||
|
context->payload[4]);
|
||||||
|
canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignTop, uid);
|
||||||
|
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
char start_stop_msg[20];
|
||||||
|
if(context->is_attacking) {
|
||||||
|
snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to stop ");
|
||||||
|
} else {
|
||||||
|
snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to start ");
|
||||||
|
}
|
||||||
|
canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignTop, start_stop_msg);
|
||||||
|
}
|
||||||
8
applications/flipfrid/scene/flipfrid_scene_run_attack.h
Normal file
8
applications/flipfrid/scene/flipfrid_scene_run_attack.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../flipfrid.h"
|
||||||
|
|
||||||
|
void flipfrid_scene_run_attack_on_enter(FlipFridState* context);
|
||||||
|
void flipfrid_scene_run_attack_on_exit(FlipFridState* context);
|
||||||
|
void flipfrid_scene_run_attack_on_tick(FlipFridState* context);
|
||||||
|
void flipfrid_scene_run_attack_on_event(FlipFridEvent event, FlipFridState* context);
|
||||||
|
void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context);
|
||||||
121
applications/flipfrid/scene/flipfrid_scene_select_field.c
Normal file
121
applications/flipfrid/scene/flipfrid_scene_select_field.c
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
#include "flipfrid_scene_select_field.h"
|
||||||
|
|
||||||
|
void flipfrid_center_displayed_key(FlipFridState* context, uint8_t index) {
|
||||||
|
const char* key_cstr = string_get_cstr(context->data_str);
|
||||||
|
uint8_t str_index = (index * 3);
|
||||||
|
|
||||||
|
char display_menu[17] = {
|
||||||
|
'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'};
|
||||||
|
|
||||||
|
if(index > 1) {
|
||||||
|
display_menu[0] = key_cstr[str_index - 6];
|
||||||
|
display_menu[1] = key_cstr[str_index - 5];
|
||||||
|
} else {
|
||||||
|
display_menu[0] = ' ';
|
||||||
|
display_menu[1] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(index > 0) {
|
||||||
|
display_menu[3] = key_cstr[str_index - 3];
|
||||||
|
display_menu[4] = key_cstr[str_index - 2];
|
||||||
|
} else {
|
||||||
|
display_menu[3] = ' ';
|
||||||
|
display_menu[4] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
display_menu[7] = key_cstr[str_index];
|
||||||
|
display_menu[8] = key_cstr[str_index + 1];
|
||||||
|
|
||||||
|
if((str_index + 4) <= (uint8_t)strlen(key_cstr)) {
|
||||||
|
display_menu[11] = key_cstr[str_index + 3];
|
||||||
|
display_menu[12] = key_cstr[str_index + 4];
|
||||||
|
} else {
|
||||||
|
display_menu[11] = ' ';
|
||||||
|
display_menu[12] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if((str_index + 8) <= (uint8_t)strlen(key_cstr)) {
|
||||||
|
display_menu[14] = key_cstr[str_index + 6];
|
||||||
|
display_menu[15] = key_cstr[str_index + 7];
|
||||||
|
} else {
|
||||||
|
display_menu[14] = ' ';
|
||||||
|
display_menu[15] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
string_reset(context->notification_msg);
|
||||||
|
string_set_str(context->notification_msg, display_menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_select_field_on_enter(FlipFridState* context) {
|
||||||
|
string_clear(context->notification_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_select_field_on_exit(FlipFridState* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_select_field_on_tick(FlipFridState* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_select_field_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||||
|
if(event.evt_type == EventTypeKey) {
|
||||||
|
if(event.input_type == InputTypeShort) {
|
||||||
|
const char* key_cstr = string_get_cstr(context->data_str);
|
||||||
|
|
||||||
|
// don't look, it's ugly but I'm a python dev so...
|
||||||
|
uint8_t nb_bytes = 0;
|
||||||
|
for(uint8_t i = 0; i < strlen(key_cstr); i++) {
|
||||||
|
if(' ' == key_cstr[i]) {
|
||||||
|
nb_bytes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(event.key) {
|
||||||
|
case InputKeyDown:
|
||||||
|
case InputKeyUp:
|
||||||
|
break;
|
||||||
|
case InputKeyLeft:
|
||||||
|
if(context->key_index > 0) {
|
||||||
|
context->key_index = context->key_index - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case InputKeyRight:
|
||||||
|
if(context->key_index < nb_bytes) {
|
||||||
|
context->key_index = context->key_index + 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case InputKeyOk:
|
||||||
|
string_reset(context->notification_msg);
|
||||||
|
context->current_scene = SceneAttack;
|
||||||
|
break;
|
||||||
|
case InputKeyBack:
|
||||||
|
string_reset(context->notification_msg);
|
||||||
|
context->current_scene = SceneSelectFile;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||||
|
canvas_clear(canvas);
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
|
// Frame
|
||||||
|
canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||||
|
|
||||||
|
// Title
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignTop, "Use < > to select byte.");
|
||||||
|
|
||||||
|
char msg_index[18];
|
||||||
|
snprintf(msg_index, sizeof(msg_index), "Field index : %d", context->key_index);
|
||||||
|
canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignTop, msg_index);
|
||||||
|
|
||||||
|
flipfrid_center_displayed_key(context, context->key_index);
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
canvas_draw_str_aligned(
|
||||||
|
canvas, 64, 40, AlignCenter, AlignTop, string_get_cstr(context->notification_msg));
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../flipfrid.h"
|
||||||
|
|
||||||
|
void flipfrid_scene_select_field_on_enter(FlipFridState* context);
|
||||||
|
void flipfrid_scene_select_field_on_exit(FlipFridState* context);
|
||||||
|
void flipfrid_scene_select_field_on_tick(FlipFridState* context);
|
||||||
|
void flipfrid_scene_select_field_on_event(FlipFridEvent event, FlipFridState* context);
|
||||||
|
void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context);
|
||||||
|
void center_displayed_key(FlipFridState* context, uint8_t index);
|
||||||
0
applications/gpio/views/gpio_test.c
Executable file → Normal file
0
applications/gpio/views/gpio_test.c
Executable file → Normal file
0
applications/gpio/views/gpio_test.h
Executable file → Normal file
0
applications/gpio/views/gpio_test.h
Executable file → Normal file
0
applications/gpio/views/gpio_usb_uart.h
Executable file → Normal file
0
applications/gpio/views/gpio_usb_uart.h
Executable file → Normal file
0
applications/gui/canvas.h
Executable file → Normal file
0
applications/gui/canvas.h
Executable file → Normal file
@@ -83,6 +83,15 @@ ButtonPanel* button_panel_alloc() {
|
|||||||
return button_panel;
|
return button_panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void button_panel_reset_selection(ButtonPanel* button_panel) {
|
||||||
|
with_view_model(
|
||||||
|
button_panel->view, (ButtonPanelModel * model) {
|
||||||
|
model->selected_item_x = 0;
|
||||||
|
model->selected_item_y = 0;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t reserve_y) {
|
void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t reserve_y) {
|
||||||
furi_check(reserve_x > 0);
|
furi_check(reserve_x > 0);
|
||||||
furi_check(reserve_y > 0);
|
furi_check(reserve_y > 0);
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ void button_panel_free(ButtonPanel* button_panel);
|
|||||||
*/
|
*/
|
||||||
void button_panel_reset(ButtonPanel* button_panel);
|
void button_panel_reset(ButtonPanel* button_panel);
|
||||||
|
|
||||||
|
/** Resets selected_item_x and selected_item_y.
|
||||||
|
*
|
||||||
|
* @param button_panel ButtonPanel instance
|
||||||
|
*/
|
||||||
|
void button_panel_reset_selection(ButtonPanel* button_panel);
|
||||||
|
|
||||||
/** Reserve space for adding items.
|
/** Reserve space for adding items.
|
||||||
*
|
*
|
||||||
* One does not simply use button_panel_add_item() without this function. It
|
* One does not simply use button_panel_add_item() without this function. It
|
||||||
|
|||||||
0
applications/gui/modules/dialog_ex.c
Executable file → Normal file
0
applications/gui/modules/dialog_ex.c
Executable file → Normal file
@@ -99,6 +99,11 @@ static bool browser_folder_check_and_switch(string_t path) {
|
|||||||
FileInfo file_info;
|
FileInfo file_info;
|
||||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
bool is_root = false;
|
bool is_root = false;
|
||||||
|
|
||||||
|
if(string_search_rchar(path, '/') == 0) {
|
||||||
|
is_root = true;
|
||||||
|
}
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
// Check if folder is existing and navigate back if not
|
// Check if folder is existing and navigate back if not
|
||||||
if(storage_common_stat(storage, string_get_cstr(path), &file_info) == FSE_OK) {
|
if(storage_common_stat(storage, string_get_cstr(path), &file_info) == FSE_OK) {
|
||||||
|
|||||||
0
applications/gui/modules/menu.h
Executable file → Normal file
0
applications/gui/modules/menu.h
Executable file → Normal file
0
applications/gui/modules/text_box.c
Executable file → Normal file
0
applications/gui/modules/text_box.c
Executable file → Normal file
0
applications/gui/modules/text_box.h
Executable file → Normal file
0
applications/gui/modules/text_box.h
Executable file → Normal file
0
applications/gui/modules/variable_item_list.h
Executable file → Normal file
0
applications/gui/modules/variable_item_list.h
Executable file → Normal file
4
applications/gui/modules/widget.h
Executable file → Normal file
4
applications/gui/modules/widget.h
Executable file → Normal file
@@ -115,8 +115,8 @@ void widget_add_text_box_element(
|
|||||||
* @param[in] text Formatted text. Default format: align left, Secondary font.
|
* @param[in] text Formatted text. Default format: align left, Secondary font.
|
||||||
* The following formats are available:
|
* The following formats are available:
|
||||||
* "\e#Bold text" - sets bold font before until next '\n' symbol
|
* "\e#Bold text" - sets bold font before until next '\n' symbol
|
||||||
* "\ecBold text" - sets center horizontal align before until next '\n' symbol
|
* "\ecCenter-aligned text" - sets center horizontal align until the next '\n' symbol
|
||||||
* "\erBold text" - sets right horizontal align before until next '\n' symbol
|
* "\erRight-aligned text" - sets right horizontal align until the next '\n' symbol
|
||||||
*/
|
*/
|
||||||
void widget_add_text_scroll_element(
|
void widget_add_text_scroll_element(
|
||||||
Widget* widget,
|
Widget* widget,
|
||||||
|
|||||||
0
applications/gui/modules/widget_elements/widget_element_frame.c
Executable file → Normal file
0
applications/gui/modules/widget_elements/widget_element_frame.c
Executable file → Normal file
0
applications/gui/modules/widget_elements/widget_element_i.h
Executable file → Normal file
0
applications/gui/modules/widget_elements/widget_element_i.h
Executable file → Normal file
0
applications/gui/modules/widget_elements/widget_element_string.c
Executable file → Normal file
0
applications/gui/modules/widget_elements/widget_element_string.c
Executable file → Normal file
0
applications/gui/scene_manager.c
Executable file → Normal file
0
applications/gui/scene_manager.c
Executable file → Normal file
0
applications/gui/scene_manager.h
Executable file → Normal file
0
applications/gui/scene_manager.h
Executable file → Normal file
0
applications/gui/scene_manager_i.h
Executable file → Normal file
0
applications/gui/scene_manager_i.h
Executable file → Normal file
0
applications/gui/view_dispatcher.h
Executable file → Normal file
0
applications/gui/view_dispatcher.h
Executable file → Normal file
@@ -1,9 +0,0 @@
|
|||||||
App(
|
|
||||||
appid="hid_analyzer",
|
|
||||||
name="HID Analyzer",
|
|
||||||
apptype=FlipperAppType.PLUGIN,
|
|
||||||
entry_point="hid_analyzer_app",
|
|
||||||
cdefines=["APP_HID_ANALYZER"],
|
|
||||||
stack_size=2 * 1024,
|
|
||||||
order=40,
|
|
||||||
)
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
#include "decoder_hid.h"
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
constexpr uint32_t clocks_in_us = 64;
|
|
||||||
|
|
||||||
constexpr uint32_t jitter_time_us = 20;
|
|
||||||
constexpr uint32_t min_time_us = 64;
|
|
||||||
constexpr uint32_t max_time_us = 80;
|
|
||||||
|
|
||||||
constexpr uint32_t min_time = (min_time_us - jitter_time_us) * clocks_in_us;
|
|
||||||
constexpr uint32_t mid_time = ((max_time_us - min_time_us) / 2 + min_time_us) * clocks_in_us;
|
|
||||||
constexpr uint32_t max_time = (max_time_us + jitter_time_us) * clocks_in_us;
|
|
||||||
|
|
||||||
bool DecoderHID::read(uint8_t* data, uint8_t data_size) {
|
|
||||||
bool result = false;
|
|
||||||
furi_assert(data_size >= 3);
|
|
||||||
|
|
||||||
if(ready) {
|
|
||||||
result = true;
|
|
||||||
hid.decode(
|
|
||||||
reinterpret_cast<const uint8_t*>(&stored_data), sizeof(uint32_t) * 3, data, data_size);
|
|
||||||
ready = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DecoderHID::process_front(bool polarity, uint32_t time) {
|
|
||||||
if(ready) return;
|
|
||||||
|
|
||||||
if(polarity == true) {
|
|
||||||
last_pulse_time = time;
|
|
||||||
} else {
|
|
||||||
last_pulse_time += time;
|
|
||||||
|
|
||||||
if(last_pulse_time > min_time && last_pulse_time < max_time) {
|
|
||||||
bool pulse;
|
|
||||||
|
|
||||||
if(last_pulse_time < mid_time) {
|
|
||||||
// 6 pulses
|
|
||||||
pulse = false;
|
|
||||||
} else {
|
|
||||||
// 5 pulses
|
|
||||||
pulse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(last_pulse == pulse) {
|
|
||||||
pulse_count++;
|
|
||||||
|
|
||||||
if(pulse) {
|
|
||||||
if(pulse_count > 4) {
|
|
||||||
pulse_count = 0;
|
|
||||||
store_data(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(pulse_count > 5) {
|
|
||||||
pulse_count = 0;
|
|
||||||
store_data(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(last_pulse) {
|
|
||||||
if(pulse_count > 2) {
|
|
||||||
store_data(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(pulse_count > 3) {
|
|
||||||
store_data(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pulse_count = 0;
|
|
||||||
last_pulse = pulse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DecoderHID::DecoderHID() {
|
|
||||||
reset_state();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DecoderHID::store_data(bool data) {
|
|
||||||
stored_data[0] = (stored_data[0] << 1) | ((stored_data[1] >> 31) & 1);
|
|
||||||
stored_data[1] = (stored_data[1] << 1) | ((stored_data[2] >> 31) & 1);
|
|
||||||
stored_data[2] = (stored_data[2] << 1) | data;
|
|
||||||
|
|
||||||
if(hid.can_be_decoded(reinterpret_cast<const uint8_t*>(&stored_data), sizeof(uint32_t) * 3)) {
|
|
||||||
ready = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DecoderHID::reset_state() {
|
|
||||||
last_pulse = false;
|
|
||||||
pulse_count = 0;
|
|
||||||
ready = false;
|
|
||||||
last_pulse_time = 0;
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <atomic>
|
|
||||||
#include "protocols/protocol_hid.h"
|
|
||||||
|
|
||||||
class DecoderHID {
|
|
||||||
public:
|
|
||||||
bool read(uint8_t* data, uint8_t data_size);
|
|
||||||
void process_front(bool polarity, uint32_t time);
|
|
||||||
DecoderHID();
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t last_pulse_time = 0;
|
|
||||||
bool last_pulse;
|
|
||||||
uint8_t pulse_count;
|
|
||||||
|
|
||||||
uint32_t stored_data[3] = {0, 0, 0};
|
|
||||||
void store_data(bool data);
|
|
||||||
|
|
||||||
std::atomic<bool> ready;
|
|
||||||
|
|
||||||
void reset_state();
|
|
||||||
ProtocolHID hid;
|
|
||||||
};
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
#include "hid_reader.h"
|
|
||||||
#include <furi.h>
|
|
||||||
#include <furi_hal.h>
|
|
||||||
#include <stm32wbxx_ll_cortex.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief private violation assistant for HIDReader
|
|
||||||
*/
|
|
||||||
struct HIDReaderAccessor {
|
|
||||||
static void decode(HIDReader& hid_reader, bool polarity) {
|
|
||||||
hid_reader.decode(polarity);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void HIDReader::decode(bool polarity) {
|
|
||||||
uint32_t current_dwt_value = DWT->CYCCNT;
|
|
||||||
uint32_t period = current_dwt_value - last_dwt_value;
|
|
||||||
last_dwt_value = current_dwt_value;
|
|
||||||
|
|
||||||
decoder_hid.process_front(polarity, period);
|
|
||||||
|
|
||||||
detect_ticks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HIDReader::switch_timer_elapsed() {
|
|
||||||
const uint32_t seconds_to_switch = furi_kernel_get_tick_frequency() * 2.0f;
|
|
||||||
return (furi_get_tick() - switch_os_tick_last) > seconds_to_switch;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDReader::switch_timer_reset() {
|
|
||||||
switch_os_tick_last = furi_get_tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDReader::switch_mode() {
|
|
||||||
switch(type) {
|
|
||||||
case Type::Normal:
|
|
||||||
type = Type::Indala;
|
|
||||||
furi_hal_rfid_change_read_config(62500.0f, 0.25f);
|
|
||||||
break;
|
|
||||||
case Type::Indala:
|
|
||||||
type = Type::Normal;
|
|
||||||
furi_hal_rfid_change_read_config(125000.0f, 0.5f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch_timer_reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void comparator_trigger_callback(bool level, void* comp_ctx) {
|
|
||||||
HIDReader* _this = static_cast<HIDReader*>(comp_ctx);
|
|
||||||
|
|
||||||
HIDReaderAccessor::decode(*_this, !level);
|
|
||||||
}
|
|
||||||
|
|
||||||
HIDReader::HIDReader() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDReader::start() {
|
|
||||||
type = Type::Normal;
|
|
||||||
|
|
||||||
furi_hal_rfid_pins_read();
|
|
||||||
furi_hal_rfid_tim_read(125000, 0.5);
|
|
||||||
furi_hal_rfid_tim_read_start();
|
|
||||||
start_comparator();
|
|
||||||
|
|
||||||
switch_timer_reset();
|
|
||||||
last_read_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDReader::start_forced(HIDReader::Type _type) {
|
|
||||||
start();
|
|
||||||
if(_type == Type::Indala) {
|
|
||||||
switch_mode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDReader::stop() {
|
|
||||||
furi_hal_rfid_pins_reset();
|
|
||||||
furi_hal_rfid_tim_read_stop();
|
|
||||||
furi_hal_rfid_tim_reset();
|
|
||||||
stop_comparator();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HIDReader::read(LfrfidKeyType* _type, uint8_t* data, uint8_t data_size, bool switch_enable) {
|
|
||||||
bool result = false;
|
|
||||||
bool something_read = false;
|
|
||||||
|
|
||||||
if(decoder_hid.read(data, data_size)) {
|
|
||||||
*_type = LfrfidKeyType::KeyH10301; // should be an OK temp
|
|
||||||
something_read = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// validation
|
|
||||||
if(something_read) {
|
|
||||||
switch_timer_reset();
|
|
||||||
|
|
||||||
if(last_read_type == *_type && memcmp(last_read_data, data, data_size) == 0) {
|
|
||||||
last_read_count = last_read_count + 1;
|
|
||||||
|
|
||||||
if(last_read_count > 2) {
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
last_read_type = *_type;
|
|
||||||
memcpy(last_read_data, data, data_size);
|
|
||||||
last_read_count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mode switching
|
|
||||||
if(switch_enable && switch_timer_elapsed()) {
|
|
||||||
switch_mode();
|
|
||||||
last_read_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HIDReader::detect() {
|
|
||||||
bool detected = false;
|
|
||||||
if(detect_ticks > 10) {
|
|
||||||
detected = true;
|
|
||||||
}
|
|
||||||
detect_ticks = 0;
|
|
||||||
|
|
||||||
return detected;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HIDReader::any_read() {
|
|
||||||
return last_read_count > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDReader::start_comparator(void) {
|
|
||||||
furi_hal_rfid_comp_set_callback(comparator_trigger_callback, this);
|
|
||||||
last_dwt_value = DWT->CYCCNT;
|
|
||||||
|
|
||||||
furi_hal_rfid_comp_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDReader::stop_comparator(void) {
|
|
||||||
furi_hal_rfid_comp_stop();
|
|
||||||
furi_hal_rfid_comp_set_callback(NULL, NULL);
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "decoder_hid.h"
|
|
||||||
#include "key_info.h"
|
|
||||||
|
|
||||||
//#define RFID_GPIO_DEBUG 1
|
|
||||||
|
|
||||||
class HIDReader {
|
|
||||||
public:
|
|
||||||
enum class Type : uint8_t {
|
|
||||||
Normal,
|
|
||||||
Indala,
|
|
||||||
};
|
|
||||||
|
|
||||||
HIDReader();
|
|
||||||
void start();
|
|
||||||
void start_forced(HIDReader::Type type);
|
|
||||||
void stop();
|
|
||||||
bool read(LfrfidKeyType* _type, uint8_t* data, uint8_t data_size, bool switch_enable = true);
|
|
||||||
|
|
||||||
bool detect();
|
|
||||||
bool any_read();
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend struct HIDReaderAccessor;
|
|
||||||
|
|
||||||
DecoderHID decoder_hid;
|
|
||||||
|
|
||||||
uint32_t last_dwt_value;
|
|
||||||
|
|
||||||
void start_comparator(void);
|
|
||||||
void stop_comparator(void);
|
|
||||||
|
|
||||||
void decode(bool polarity);
|
|
||||||
|
|
||||||
uint32_t detect_ticks;
|
|
||||||
|
|
||||||
uint32_t switch_os_tick_last;
|
|
||||||
bool switch_timer_elapsed();
|
|
||||||
void switch_timer_reset();
|
|
||||||
void switch_mode();
|
|
||||||
|
|
||||||
LfrfidKeyType last_read_type;
|
|
||||||
uint8_t last_read_data[LFRFID_KEY_SIZE];
|
|
||||||
uint8_t last_read_count;
|
|
||||||
|
|
||||||
Type type = Type::Normal;
|
|
||||||
};
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#include "hid_worker.h"
|
|
||||||
|
|
||||||
HIDWorker::HIDWorker() {
|
|
||||||
}
|
|
||||||
|
|
||||||
HIDWorker::~HIDWorker() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDWorker::start_read() {
|
|
||||||
reader.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HIDWorker::read() {
|
|
||||||
static const uint8_t data_size = LFRFID_KEY_SIZE;
|
|
||||||
uint8_t data[data_size] = {0};
|
|
||||||
LfrfidKeyType type;
|
|
||||||
|
|
||||||
bool result = reader.read(&type, data, data_size);
|
|
||||||
|
|
||||||
if(result) {
|
|
||||||
key.set_type(type);
|
|
||||||
key.set_data(data, data_size);
|
|
||||||
};
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HIDWorker::detect() {
|
|
||||||
return reader.detect();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HIDWorker::any_read() {
|
|
||||||
return reader.any_read();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDWorker::stop_read() {
|
|
||||||
reader.stop();
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "key_info.h"
|
|
||||||
#include "rfid_key.h"
|
|
||||||
#include "hid_reader.h"
|
|
||||||
|
|
||||||
class HIDWorker {
|
|
||||||
public:
|
|
||||||
HIDWorker();
|
|
||||||
~HIDWorker();
|
|
||||||
|
|
||||||
void start_read();
|
|
||||||
bool read();
|
|
||||||
bool detect();
|
|
||||||
bool any_read();
|
|
||||||
void stop_read();
|
|
||||||
|
|
||||||
RfidKey key;
|
|
||||||
|
|
||||||
private:
|
|
||||||
HIDReader reader;
|
|
||||||
};
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
static const uint8_t LFRFID_KEY_SIZE = 8;
|
|
||||||
static const uint8_t LFRFID_KEY_NAME_SIZE = 22;
|
|
||||||
|
|
||||||
enum class LfrfidKeyType : uint8_t {
|
|
||||||
KeyEM4100,
|
|
||||||
KeyH10301,
|
|
||||||
KeyI40134,
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* lfrfid_key_get_type_string(LfrfidKeyType type);
|
|
||||||
const char* lfrfid_key_get_manufacturer_string(LfrfidKeyType type);
|
|
||||||
bool lfrfid_key_get_string_type(const char* string, LfrfidKeyType* type);
|
|
||||||
uint8_t lfrfid_key_get_type_data_count(LfrfidKeyType type);
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This code tries to fit the periods into a given number of cycles (phases) by taking cycles from the next cycle of periods.
|
|
||||||
*/
|
|
||||||
class OscFSK {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Get next period
|
|
||||||
* @param bit bit value
|
|
||||||
* @param period return period
|
|
||||||
* @return bool whether to advance to the next bit
|
|
||||||
*/
|
|
||||||
bool next(bool bit, uint16_t* period);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FSK ocillator constructor
|
|
||||||
*
|
|
||||||
* @param freq_low bit 0 freq
|
|
||||||
* @param freq_hi bit 1 freq
|
|
||||||
* @param osc_phase_max max oscillator phase
|
|
||||||
*/
|
|
||||||
OscFSK(uint16_t freq_low, uint16_t freq_hi, uint16_t osc_phase_max);
|
|
||||||
|
|
||||||
private:
|
|
||||||
const uint16_t freq[2];
|
|
||||||
const uint16_t osc_phase_max;
|
|
||||||
int32_t osc_phase_current;
|
|
||||||
};
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "stdint.h"
|
|
||||||
#include "stdbool.h"
|
|
||||||
|
|
||||||
class ProtocolGeneric {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Get the encoded data size
|
|
||||||
*
|
|
||||||
* @return uint8_t size of encoded data in bytes
|
|
||||||
*/
|
|
||||||
virtual uint8_t get_encoded_data_size() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the decoded data size
|
|
||||||
*
|
|
||||||
* @return uint8_t size of decoded data in bytes
|
|
||||||
*/
|
|
||||||
virtual uint8_t get_decoded_data_size() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief encode decoded data
|
|
||||||
*
|
|
||||||
* @param decoded_data
|
|
||||||
* @param decoded_data_size
|
|
||||||
* @param encoded_data
|
|
||||||
* @param encoded_data_size
|
|
||||||
*/
|
|
||||||
virtual void encode(
|
|
||||||
const uint8_t* decoded_data,
|
|
||||||
const uint8_t decoded_data_size,
|
|
||||||
uint8_t* encoded_data,
|
|
||||||
const uint8_t encoded_data_size) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief decode encoded data
|
|
||||||
*
|
|
||||||
* @param encoded_data
|
|
||||||
* @param encoded_data_size
|
|
||||||
* @param decoded_data
|
|
||||||
* @param decoded_data_size
|
|
||||||
*/
|
|
||||||
virtual void decode(
|
|
||||||
const uint8_t* encoded_data,
|
|
||||||
const uint8_t encoded_data_size,
|
|
||||||
uint8_t* decoded_data,
|
|
||||||
const uint8_t decoded_data_size) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief fast check that data can be correctly decoded
|
|
||||||
*
|
|
||||||
* @param encoded_data
|
|
||||||
* @param encoded_data_size
|
|
||||||
* @return true - can be correctly decoded
|
|
||||||
* @return false - cannot be correctly decoded
|
|
||||||
*/
|
|
||||||
virtual bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) = 0;
|
|
||||||
|
|
||||||
virtual ~ProtocolGeneric(){};
|
|
||||||
};
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
#include "protocol_hid.h"
|
|
||||||
#include <furi.h>
|
|
||||||
|
|
||||||
typedef uint32_t HIDCardData;
|
|
||||||
constexpr uint8_t HIDCount = 3;
|
|
||||||
constexpr uint8_t HIDBitSize = sizeof(HIDCardData) * 8;
|
|
||||||
|
|
||||||
uint8_t ProtocolHID::get_encoded_data_size() {
|
|
||||||
return sizeof(HIDCardData) * HIDCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ProtocolHID::get_decoded_data_size() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProtocolHID::encode(
|
|
||||||
const uint8_t* decoded_data,
|
|
||||||
const uint8_t decoded_data_size,
|
|
||||||
uint8_t* encoded_data,
|
|
||||||
const uint8_t encoded_data_size) {
|
|
||||||
UNUSED(decoded_data);
|
|
||||||
UNUSED(decoded_data_size);
|
|
||||||
UNUSED(encoded_data);
|
|
||||||
UNUSED(encoded_data_size);
|
|
||||||
// bob!
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProtocolHID::decode(
|
|
||||||
const uint8_t* encoded_data,
|
|
||||||
const uint8_t encoded_data_size,
|
|
||||||
uint8_t* decoded_data,
|
|
||||||
const uint8_t decoded_data_size) {
|
|
||||||
furi_check(decoded_data_size >= get_decoded_data_size());
|
|
||||||
furi_check(encoded_data_size >= get_encoded_data_size());
|
|
||||||
|
|
||||||
// header check
|
|
||||||
int16_t second1pos = find_second_1(encoded_data);
|
|
||||||
|
|
||||||
if((*(encoded_data + 1) & 0b1100) != 0x08) {
|
|
||||||
*decoded_data = 37;
|
|
||||||
} else {
|
|
||||||
*decoded_data = (36 - (second1pos - 8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t ProtocolHID::find_second_1(const uint8_t* encoded_data) {
|
|
||||||
if((*(encoded_data + 1) & 0b11) == 0b10) {
|
|
||||||
return 8;
|
|
||||||
} else {
|
|
||||||
for(int8_t i = 3; i >= 0; i--) {
|
|
||||||
if(((*(encoded_data + 0) >> (2 * i)) & 0b11) == 0b10) {
|
|
||||||
return (12 - i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(int8_t i = 3; i >= 0; i--) {
|
|
||||||
if(((*(encoded_data + 7) >> (2 * i)) & 0b11) == 0b10) {
|
|
||||||
return (16 - i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(int8_t i = 3; i >= 2; i--) {
|
|
||||||
if(((*(encoded_data + 6) >> (2 * i)) & 0b11) == 0b10) {
|
|
||||||
return (20 - i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProtocolHID::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) {
|
|
||||||
furi_check(encoded_data_size >= get_encoded_data_size());
|
|
||||||
|
|
||||||
const HIDCardData* card_data = reinterpret_cast<const HIDCardData*>(encoded_data);
|
|
||||||
|
|
||||||
// header check
|
|
||||||
int16_t second1pos = -1;
|
|
||||||
// packet pre-preamble
|
|
||||||
if(*(encoded_data + 3) != 0x1D) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// packet preamble
|
|
||||||
if(*(encoded_data + 2) != 0x55) { // first four 0s mandatory in preamble
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((*(encoded_data + 1) & 0xF0) != 0x50) { // next two 0s mandatory in preamble
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((*(encoded_data + 1) & 0b1100) != 0x08) { // if it's not a 1...
|
|
||||||
// either it's a 37-bit or invalid
|
|
||||||
// so just continue with the manchester encoding checks
|
|
||||||
} else { // it is a 1. so it could be anywhere between 26 and 36 bit encoding. or invalid.
|
|
||||||
// we need to find the location of the second 1
|
|
||||||
second1pos = find_second_1(encoded_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(second1pos == -1) {
|
|
||||||
// we're 37 bit or invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
// data decoding. ensure all is properly manchester encoded
|
|
||||||
uint32_t result = 0;
|
|
||||||
|
|
||||||
// decode from word 0
|
|
||||||
// coded with 01 = 0, 10 = 1 transitions
|
|
||||||
for(int8_t i = 11; i >= 0; i--) {
|
|
||||||
switch((*(card_data + 0) >> (2 * i)) & 0b11) {
|
|
||||||
case 0b01:
|
|
||||||
result = (result << 1) | 0;
|
|
||||||
break;
|
|
||||||
case 0b10:
|
|
||||||
result = (result << 1) | 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode from word 1
|
|
||||||
// coded with 01 = 0, 10 = 1 transitions
|
|
||||||
for(int8_t i = 15; i >= 0; i--) {
|
|
||||||
switch((*(card_data + 1) >> (2 * i)) & 0b11) {
|
|
||||||
case 0b01:
|
|
||||||
result = (result << 1) | 0;
|
|
||||||
break;
|
|
||||||
case 0b10:
|
|
||||||
result = (result << 1) | 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode from word 2
|
|
||||||
// coded with 01 = 0, 10 = 1 transitions
|
|
||||||
for(int8_t i = 15; i >= 0; i--) {
|
|
||||||
switch((*(card_data + 2) >> (2 * i)) & 0b11) {
|
|
||||||
case 0b01:
|
|
||||||
result = (result << 1) | 0;
|
|
||||||
break;
|
|
||||||
case 0b10:
|
|
||||||
result = (result << 1) | 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "protocol_generic.h"
|
|
||||||
|
|
||||||
class ProtocolHID : public ProtocolGeneric {
|
|
||||||
public:
|
|
||||||
uint8_t get_encoded_data_size() final;
|
|
||||||
uint8_t get_decoded_data_size() final;
|
|
||||||
|
|
||||||
void encode(
|
|
||||||
const uint8_t* decoded_data,
|
|
||||||
const uint8_t decoded_data_size,
|
|
||||||
uint8_t* encoded_data,
|
|
||||||
const uint8_t encoded_data_size) final;
|
|
||||||
|
|
||||||
void decode(
|
|
||||||
const uint8_t* encoded_data,
|
|
||||||
const uint8_t encoded_data_size,
|
|
||||||
uint8_t* decoded_data,
|
|
||||||
const uint8_t decoded_data_size) final;
|
|
||||||
|
|
||||||
bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int16_t find_second_1(const uint8_t* encoded_data);
|
|
||||||
};
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "stdint.h"
|
|
||||||
|
|
||||||
class PulseJoiner {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Push timer pulse. First negative pulse is ommited.
|
|
||||||
*
|
|
||||||
* @param polarity pulse polarity: true = high2low, false = low2high
|
|
||||||
* @param period overall period time in timer clicks
|
|
||||||
* @param pulse pulse time in timer clicks
|
|
||||||
*
|
|
||||||
* @return true - next pulse can and must be popped immediatly
|
|
||||||
*/
|
|
||||||
bool push_pulse(bool polarity, uint16_t period, uint16_t pulse);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the next timer pulse. Call only if push_pulse returns true.
|
|
||||||
*
|
|
||||||
* @param period overall period time in timer clicks
|
|
||||||
* @param pulse pulse time in timer clicks
|
|
||||||
*/
|
|
||||||
void pop_pulse(uint16_t* period, uint16_t* pulse);
|
|
||||||
|
|
||||||
PulseJoiner();
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Pulse {
|
|
||||||
bool polarity;
|
|
||||||
uint16_t time;
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t pulse_index = 0;
|
|
||||||
static const uint8_t pulse_max = 6;
|
|
||||||
Pulse pulses[pulse_max];
|
|
||||||
};
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "key_info.h"
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
class RfidKey {
|
|
||||||
public:
|
|
||||||
RfidKey();
|
|
||||||
~RfidKey();
|
|
||||||
|
|
||||||
void set_type(LfrfidKeyType type);
|
|
||||||
void set_data(const uint8_t* data, const uint8_t data_size);
|
|
||||||
void set_name(const char* name);
|
|
||||||
|
|
||||||
LfrfidKeyType get_type();
|
|
||||||
const uint8_t* get_data();
|
|
||||||
const char* get_type_text();
|
|
||||||
uint8_t get_type_data_count() const;
|
|
||||||
char* get_name();
|
|
||||||
uint8_t get_name_length();
|
|
||||||
void clear();
|
|
||||||
RfidKey& operator=(const RfidKey& rhs);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::array<uint8_t, LFRFID_KEY_SIZE> data;
|
|
||||||
LfrfidKeyType type;
|
|
||||||
char name[LFRFID_KEY_NAME_SIZE + 1];
|
|
||||||
};
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <furi_hal.h>
|
|
||||||
#include "key_info.h"
|
|
||||||
#include "encoder_generic.h"
|
|
||||||
#include "encoder_emmarin.h"
|
|
||||||
#include "encoder_hid_h10301.h"
|
|
||||||
#include "encoder_indala_40134.h"
|
|
||||||
#include "pulse_joiner.h"
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
class RfidTimerEmulator {
|
|
||||||
public:
|
|
||||||
RfidTimerEmulator();
|
|
||||||
~RfidTimerEmulator();
|
|
||||||
void start(LfrfidKeyType type, const uint8_t* data, uint8_t data_size);
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
private:
|
|
||||||
EncoderGeneric* current_encoder = nullptr;
|
|
||||||
|
|
||||||
std::map<LfrfidKeyType, EncoderGeneric*> encoders = {
|
|
||||||
{LfrfidKeyType::KeyEM4100, new EncoderEM()},
|
|
||||||
{LfrfidKeyType::KeyH10301, new EncoderHID_H10301()},
|
|
||||||
{LfrfidKeyType::KeyI40134, new EncoderIndala_40134()},
|
|
||||||
};
|
|
||||||
|
|
||||||
PulseJoiner pulse_joiner;
|
|
||||||
static void timer_update_callback(void* ctx);
|
|
||||||
};
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "stdint.h"
|
|
||||||
|
|
||||||
class RfidWriter {
|
|
||||||
public:
|
|
||||||
RfidWriter();
|
|
||||||
~RfidWriter();
|
|
||||||
void start();
|
|
||||||
void stop();
|
|
||||||
void write_em(const uint8_t em_data[5]);
|
|
||||||
void write_hid(const uint8_t hid_data[3]);
|
|
||||||
void write_indala(const uint8_t indala_data[3]);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void write_gap(uint32_t gap_time);
|
|
||||||
void write_bit(bool value);
|
|
||||||
void write_byte(uint8_t value);
|
|
||||||
void write_block(uint8_t page, uint8_t block, bool lock_bit, uint32_t data);
|
|
||||||
void write_reset();
|
|
||||||
};
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "stdint.h"
|
|
||||||
#include <list>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
class TickSequencer {
|
|
||||||
public:
|
|
||||||
TickSequencer();
|
|
||||||
~TickSequencer();
|
|
||||||
|
|
||||||
void tick();
|
|
||||||
void reset();
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
void do_every_tick(uint32_t tick_count, std::function<void(void)> fn);
|
|
||||||
void do_after_tick(uint32_t tick_count, std::function<void(void)> fn);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::list<std::pair<uint32_t, std::function<void(void)> > > list;
|
|
||||||
std::list<std::pair<uint32_t, std::function<void(void)> > >::iterator list_it;
|
|
||||||
|
|
||||||
uint32_t tick_count;
|
|
||||||
|
|
||||||
void do_nothing();
|
|
||||||
};
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#include "hid_analyzer_app.h"
|
|
||||||
#include "scene/hid_analyzer_app_scene_read.h"
|
|
||||||
#include "scene/hid_analyzer_app_scene_read_success.h"
|
|
||||||
|
|
||||||
HIDApp::HIDApp()
|
|
||||||
: scene_controller{this}
|
|
||||||
, notification{"notification"}
|
|
||||||
, storage{"storage"}
|
|
||||||
, dialogs{"dialogs"}
|
|
||||||
, text_store(40) {
|
|
||||||
}
|
|
||||||
|
|
||||||
HIDApp::~HIDApp() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDApp::run(void* _args) {
|
|
||||||
UNUSED(_args);
|
|
||||||
|
|
||||||
view_controller.attach_to_gui(ViewDispatcherTypeFullscreen);
|
|
||||||
scene_controller.add_scene(SceneType::Read, new HIDAppSceneRead());
|
|
||||||
scene_controller.add_scene(SceneType::ReadSuccess, new HIDAppSceneReadSuccess());
|
|
||||||
scene_controller.process(100, SceneType::Read);
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
#include <generic_scene.hpp>
|
|
||||||
#include <scene_controller.hpp>
|
|
||||||
#include <view_controller.hpp>
|
|
||||||
#include <record_controller.hpp>
|
|
||||||
#include <text_store.h>
|
|
||||||
|
|
||||||
#include <view_modules/submenu_vm.h>
|
|
||||||
#include <view_modules/popup_vm.h>
|
|
||||||
#include <view_modules/dialog_ex_vm.h>
|
|
||||||
#include <view_modules/text_input_vm.h>
|
|
||||||
#include <view_modules/byte_input_vm.h>
|
|
||||||
#include "view/container_vm.h"
|
|
||||||
|
|
||||||
#include <notification/notification_messages.h>
|
|
||||||
#include <storage/storage.h>
|
|
||||||
#include <dialogs/dialogs.h>
|
|
||||||
|
|
||||||
#include "helpers/hid_worker.h"
|
|
||||||
|
|
||||||
class HIDApp {
|
|
||||||
public:
|
|
||||||
enum class EventType : uint8_t {
|
|
||||||
GENERIC_EVENT_ENUM_VALUES,
|
|
||||||
Next,
|
|
||||||
MenuSelected,
|
|
||||||
Stay,
|
|
||||||
Retry,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SceneType : uint8_t {
|
|
||||||
GENERIC_SCENE_ENUM_VALUES,
|
|
||||||
Read,
|
|
||||||
ReadSuccess,
|
|
||||||
};
|
|
||||||
|
|
||||||
class Event {
|
|
||||||
public:
|
|
||||||
union {
|
|
||||||
int32_t menu_index;
|
|
||||||
} payload;
|
|
||||||
|
|
||||||
EventType type;
|
|
||||||
};
|
|
||||||
|
|
||||||
HIDApp();
|
|
||||||
~HIDApp();
|
|
||||||
|
|
||||||
void run(void* args);
|
|
||||||
|
|
||||||
// private:
|
|
||||||
SceneController<GenericScene<HIDApp>, HIDApp> scene_controller;
|
|
||||||
ViewController<HIDApp, SubmenuVM, PopupVM, DialogExVM, TextInputVM, ByteInputVM, ContainerVM>
|
|
||||||
view_controller;
|
|
||||||
RecordController<NotificationApp> notification;
|
|
||||||
RecordController<Storage> storage;
|
|
||||||
RecordController<DialogsApp> dialogs;
|
|
||||||
TextStore text_store;
|
|
||||||
|
|
||||||
HIDWorker worker;
|
|
||||||
};
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#include "hid_analyzer_app.h"
|
|
||||||
|
|
||||||
// app enter function
|
|
||||||
extern "C" int32_t hid_analyzer_app(void* args) {
|
|
||||||
HIDApp* app = new HIDApp();
|
|
||||||
app->run(args);
|
|
||||||
delete app;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#include "hid_analyzer_app_scene_read.h"
|
|
||||||
#include <dolphin/dolphin.h>
|
|
||||||
|
|
||||||
void HIDAppSceneRead::on_enter(HIDApp* app, bool /* need_restore */) {
|
|
||||||
auto popup = app->view_controller.get<PopupVM>();
|
|
||||||
|
|
||||||
DOLPHIN_DEED(DolphinDeedRfidRead);
|
|
||||||
popup->set_header("Searching for\nLF HID RFID", 89, 34, AlignCenter, AlignTop);
|
|
||||||
popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61);
|
|
||||||
|
|
||||||
app->view_controller.switch_to<PopupVM>();
|
|
||||||
app->worker.start_read();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HIDAppSceneRead::on_event(HIDApp* app, HIDApp::Event* event) {
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event->type == HIDApp::EventType::Tick) {
|
|
||||||
if(app->worker.read()) {
|
|
||||||
DOLPHIN_DEED(DolphinDeedRfidReadSuccess);
|
|
||||||
notification_message(app->notification, &sequence_success);
|
|
||||||
app->scene_controller.switch_to_next_scene(HIDApp::SceneType::ReadSuccess);
|
|
||||||
} else {
|
|
||||||
if(app->worker.any_read()) {
|
|
||||||
notification_message(app->notification, &sequence_blink_green_10);
|
|
||||||
} else if(app->worker.detect()) {
|
|
||||||
notification_message(app->notification, &sequence_blink_cyan_10);
|
|
||||||
} else {
|
|
||||||
notification_message(app->notification, &sequence_blink_cyan_10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDAppSceneRead::on_exit(HIDApp* app) {
|
|
||||||
app->view_controller.get<PopupVM>()->clean();
|
|
||||||
app->worker.stop_read();
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../hid_analyzer_app.h"
|
|
||||||
|
|
||||||
class HIDAppSceneRead : public GenericScene<HIDApp> {
|
|
||||||
public:
|
|
||||||
void on_enter(HIDApp* app, bool need_restore) final;
|
|
||||||
bool on_event(HIDApp* app, HIDApp::Event* event) final;
|
|
||||||
void on_exit(HIDApp* app) final;
|
|
||||||
};
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
#include "hid_analyzer_app_scene_read_success.h"
|
|
||||||
#include "../view/elements/button_element.h"
|
|
||||||
#include "../view/elements/icon_element.h"
|
|
||||||
#include "../view/elements/string_element.h"
|
|
||||||
|
|
||||||
void HIDAppSceneReadSuccess::on_enter(HIDApp* app, bool /* need_restore */) {
|
|
||||||
string_init(string[0]);
|
|
||||||
string_init(string[1]);
|
|
||||||
string_init(string[2]);
|
|
||||||
|
|
||||||
auto container = app->view_controller.get<ContainerVM>();
|
|
||||||
|
|
||||||
auto button = container->add<ButtonElement>();
|
|
||||||
button->set_type(ButtonElement::Type::Left, "Retry");
|
|
||||||
button->set_callback(app, HIDAppSceneReadSuccess::back_callback);
|
|
||||||
|
|
||||||
auto icon = container->add<IconElement>();
|
|
||||||
icon->set_icon(3, 12, &I_RFIDBigChip_37x36);
|
|
||||||
|
|
||||||
auto header = container->add<StringElement>();
|
|
||||||
header->set_text("HID", 89, 3, 0, AlignCenter);
|
|
||||||
|
|
||||||
// auto line_1_text = container->add<StringElement>();
|
|
||||||
auto line_2_text = container->add<StringElement>();
|
|
||||||
// auto line_3_text = container->add<StringElement>();
|
|
||||||
|
|
||||||
// auto line_1_value = container->add<StringElement>();
|
|
||||||
auto line_2_value = container->add<StringElement>();
|
|
||||||
// auto line_3_value = container->add<StringElement>();
|
|
||||||
|
|
||||||
const uint8_t* data = app->worker.key.get_data();
|
|
||||||
|
|
||||||
// line_1_text->set_text("Hi:", 65, 23, 0, AlignRight, AlignBottom, FontSecondary);
|
|
||||||
line_2_text->set_text("Bit:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary);
|
|
||||||
// line_3_text->set_text("Bye:", 65, 47, 0, AlignRight, AlignBottom, FontSecondary);
|
|
||||||
|
|
||||||
string_printf(string[1], "%u", data[0]);
|
|
||||||
|
|
||||||
// line_1_value->set_text(
|
|
||||||
// string_get_cstr(string[0]), 68, 23, 0, AlignLeft, AlignBottom, FontSecondary);
|
|
||||||
line_2_value->set_text(
|
|
||||||
string_get_cstr(string[1]), 68, 35, 0, AlignLeft, AlignBottom, FontSecondary);
|
|
||||||
// line_3_value->set_text(
|
|
||||||
// string_get_cstr(string[2]), 68, 47, 0, AlignLeft, AlignBottom, FontSecondary);
|
|
||||||
|
|
||||||
app->view_controller.switch_to<ContainerVM>();
|
|
||||||
|
|
||||||
notification_message_block(app->notification, &sequence_set_green_255);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HIDAppSceneReadSuccess::on_event(HIDApp* app, HIDApp::Event* event) {
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event->type == HIDApp::EventType::Retry) {
|
|
||||||
app->scene_controller.search_and_switch_to_previous_scene({HIDApp::SceneType::Read});
|
|
||||||
consumed = true;
|
|
||||||
} else if(event->type == HIDApp::EventType::Back) {
|
|
||||||
app->scene_controller.search_and_switch_to_previous_scene({HIDApp::SceneType::Read});
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDAppSceneReadSuccess::on_exit(HIDApp* app) {
|
|
||||||
notification_message_block(app->notification, &sequence_reset_green);
|
|
||||||
app->view_controller.get<ContainerVM>()->clean();
|
|
||||||
string_clear(string[0]);
|
|
||||||
string_clear(string[1]);
|
|
||||||
string_clear(string[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDAppSceneReadSuccess::back_callback(void* context) {
|
|
||||||
HIDApp* app = static_cast<HIDApp*>(context);
|
|
||||||
HIDApp::Event event;
|
|
||||||
event.type = HIDApp::EventType::Retry;
|
|
||||||
app->view_controller.send_event(&event);
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../hid_analyzer_app.h"
|
|
||||||
|
|
||||||
class HIDAppSceneReadSuccess : public GenericScene<HIDApp> {
|
|
||||||
public:
|
|
||||||
void on_enter(HIDApp* app, bool need_restore) final;
|
|
||||||
bool on_event(HIDApp* app, HIDApp::Event* event) final;
|
|
||||||
void on_exit(HIDApp* app) final;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void back_callback(void* context);
|
|
||||||
|
|
||||||
string_t string[3];
|
|
||||||
};
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <view_modules/generic_view_module.h>
|
|
||||||
|
|
||||||
class ContainerVM : public GenericViewModule {
|
|
||||||
public:
|
|
||||||
ContainerVM();
|
|
||||||
~ContainerVM() final;
|
|
||||||
View* get_view() final;
|
|
||||||
void clean() final;
|
|
||||||
|
|
||||||
template <typename T> T* add();
|
|
||||||
|
|
||||||
private:
|
|
||||||
View* view;
|
|
||||||
static void view_draw_callback(Canvas* canvas, void* model);
|
|
||||||
static bool view_input_callback(InputEvent* event, void* context);
|
|
||||||
};
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "generic_element.h"
|
|
||||||
|
|
||||||
typedef void (*ButtonElementCallback)(void* context);
|
|
||||||
|
|
||||||
class ButtonElement : public GenericElement {
|
|
||||||
public:
|
|
||||||
ButtonElement();
|
|
||||||
~ButtonElement() final;
|
|
||||||
void draw(Canvas* canvas) final;
|
|
||||||
bool input(InputEvent* event) final;
|
|
||||||
|
|
||||||
enum class Type : uint8_t {
|
|
||||||
Left,
|
|
||||||
Center,
|
|
||||||
Right,
|
|
||||||
};
|
|
||||||
|
|
||||||
void set_type(Type type, const char* text);
|
|
||||||
void set_callback(void* context, ButtonElementCallback callback);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Type type = Type::Left;
|
|
||||||
const char* text = nullptr;
|
|
||||||
|
|
||||||
void* context = nullptr;
|
|
||||||
ButtonElementCallback callback = nullptr;
|
|
||||||
};
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <gui/view.h>
|
|
||||||
|
|
||||||
class GenericElement {
|
|
||||||
public:
|
|
||||||
GenericElement(){};
|
|
||||||
virtual ~GenericElement(){};
|
|
||||||
virtual void draw(Canvas* canvas) = 0;
|
|
||||||
virtual bool input(InputEvent* event) = 0;
|
|
||||||
|
|
||||||
// TODO that must be accessible only to ContainerVMData
|
|
||||||
void set_parent_view(View* view);
|
|
||||||
|
|
||||||
// TODO that must be accessible only to inheritors
|
|
||||||
void lock_model();
|
|
||||||
void unlock_model(bool need_redraw);
|
|
||||||
|
|
||||||
private:
|
|
||||||
View* view = nullptr;
|
|
||||||
};
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "generic_element.h"
|
|
||||||
|
|
||||||
class IconElement : public GenericElement {
|
|
||||||
public:
|
|
||||||
IconElement();
|
|
||||||
~IconElement() final;
|
|
||||||
void draw(Canvas* canvas) final;
|
|
||||||
bool input(InputEvent* event) final;
|
|
||||||
|
|
||||||
void set_icon(uint8_t x = 0, uint8_t y = 0, const Icon* icon = NULL);
|
|
||||||
|
|
||||||
private:
|
|
||||||
const Icon* icon = NULL;
|
|
||||||
uint8_t x = 0;
|
|
||||||
uint8_t y = 0;
|
|
||||||
};
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user