1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-13 13:09:49 +04:00

Compare commits

...

132 Commits

Author SHA1 Message Date
MX
107d574c02 added rfid fuzzer example to sdcard.zip 2022-09-05 22:28:41 +03:00
MX
84204a3233 return some plugins back 2022-09-05 22:10:31 +03:00
MX
48691b2296 Merge branch 'fz-dev' into dev 2022-09-05 20:53:59 +03:00
あく
3a767c9c02 [FL-2794] Lib: update LFS to v2.5.0, lower update free page limit (#1706)
* Lib: update lfs to v2.5.0

* Storage: set minimum free pages for update on internal storage to 3

* Updater: lower min int free space limit

* lfs: disabled debug and trace logs by default

Co-authored-by: hedger <hedger@nanode.su>
2022-09-05 20:40:20 +03:00
MX
1a4d928e5c fix rfid fuzzer gui 2022-09-05 20:01:26 +03:00
MX
a8858e38b5 Merge branch 'fz-dev' into dev 2022-09-05 19:23:34 +03:00
MX
120b5d7c90 update changelog and readme 2022-09-05 19:00:33 +03:00
Max Andreev
b7a6d18186 Fix CI/CD in tags #1703 2022-09-05 22:40:54 +09:00
VVX7
8d8481b17f fix buffer overflow in mifar ul load (#1697)
Co-authored-by: gornekich <n.gorbadey@gmail.com>
2022-09-05 20:42:59 +09:00
MX
ca8217b692 some fixes for rfid fuzzer 2022-09-05 14:05:43 +03:00
MX
361895c689 Merge pull request #55 from Ganapati/dev
Fix memory issues and add new attack
2022-09-05 13:20:45 +03:00
Ganapati
789230458b Increase time between card to handle slow readers 2022-09-05 09:39:11 +02:00
Ganapati
6f77f537e3 Fi memory issues ad add new attack 2022-09-04 23:32:58 +02:00
MX
b6254227b9 debug pack 2022-09-03 23:47:15 +03:00
MX
8323877120 formatted, attempt to fix rfid fuzzer crash
crash doesn’t fixed with this commit
2022-09-03 23:10:07 +03:00
MX
f99c1a8c0a Merge pull request #54 from Ganapati/dev
FlipFrid - upgrade
2022-09-03 19:22:53 +03:00
MX
c41555b579 Merge branch 'fz-dev' into dev 2022-09-03 16:30:13 +03:00
Dig
97b27261d5 fbt: fbtenv_chck_many_source, fix typos + grep logic (#1699)
Co-authored-by: あく <alleteam@gmail.com>
2022-09-03 21:53:43 +09:00
gornekich
1853359d78 [FL-2759], [FL-2766] NFC collect params for mfkey32 attack (#1643)
* nfc: start nfc over rpc
* nfc: add detect reader state
* nfc: add reader analyzer
* nfc: rework reader analyzer
* reader_analyzer: print collected nonces to debug
* reader analyzer: add save on SD card
* reader_analyzer: separate mfkey related part to different file
* mfkey32: add logic for collecting parameters
* nfc: rework pcap with reader analyzer
* nfc: add logger for reader
* nfc: clean up
* nfc: add detect reader view
* nfc: add detect reader and mfkey nonces scenes
* nfc: add mfkey comlplete scene
* nfc: add new assets
* nfc: fix gui
* nfc: fix iso14443-4 UID emulation
* nfc: add no sd card notification
* nfc: fix grammar

Co-authored-by: あく <alleteam@gmail.com>
2022-09-03 21:25:36 +09:00
Georgii Surkov
ed2c607dd3 [FL-2776] IR CLI Decode Command (#1692)
* Add decode option to Infrared app
* Implement saving results to file
* Refactor code
* Correct formatting
* Refactor code
* Better command line arguments handling
* Accept generic IR files
* Remove unneeded define

Co-authored-by: あく <alleteam@gmail.com>
2022-09-03 19:46:07 +09:00
Max Andreev
bd54c2b342 Fix CI/CD (#1698)
* Test
newline
commit

* Test
newline
commit

* Fix some
variables
and test newline "quotted" commit
2022-09-03 19:18:24 +09:00
Max Andreev
53aa5c71a0 Amap workflow, "toolchain improvements" (#1685)
* fix quotes in amap
* try to fix quotes
* try to read "commit_message"
* Add new actions anv parser
* fix amap_anayse
* fix script ssl error
* test build with new get commit details method
* fix build.yml
* add fbt envs to get_env.py
* fix envs
* using new commit info "way"
* try to fix report link in PR page
* fix "pvs_studio.yml" again
* fix vars
* fix "build.yml"

Co-authored-by: あく <alleteam@gmail.com>
2022-09-03 16:09:03 +09:00
Skorpionm
a3932cfa6d [FL-2787] SubGhz: add protocol Clemsa, fix decoder BETT (#1696)
* SubGhz: add protocol Clemsa
* SubGhz: fix decoder BETT protocol

Co-authored-by: あく <alleteam@gmail.com>
2022-09-03 15:19:01 +09:00
Sebastian Mauer
1d787e6da8 Add support for Keri tags (#1689)
Co-authored-by: SG <who.just.the.doctor@gmail.com>
2022-09-02 21:36:13 +10:00
Sebastian Mauer
10b0a611cf Add support for Gallagher tags (#1680)
* Add Gallagher protocol
2022-09-02 21:15:34 +10:00
Ganapati
f537ccfe14 Fix warnings 2022-09-01 17:46:08 +02:00
Ganapati
d37dbb29bf Rewrite plugin + new file attack 2022-09-01 17:03:18 +02:00
Skorpionm
0ee4573a65 SubGhz: add protocol Intertechno_V3 (#1622)
* SubGhz: add decode Intertechno_V3
* SubGhz: add encoder Intertechno V3
* SubGhz: add uni_test Intertechno V3
* SubGhz: fix syntax
* SubGhz: add Intertechno V3 dimming mode
* SubGhz: fix parsing event Magellen protocol
* SubGhz: fix syntax
* SubGhz: fix encoder dimm mode

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2022-08-31 23:27:34 +09:00
Skorpionm
311b60f815 [FL-2771] SubGhz: add protocol Prastel #1674
Co-authored-by: あく <alleteam@gmail.com>
2022-08-31 23:21:36 +09:00
MX
9ff35c9fc3 update audio asset, fix some things
audio asset by @Amec0e
2022-08-31 01:37:01 +03:00
MX
f14874b0e0 update docs and fix led in subghz decode scene 2022-08-30 23:14:43 +03:00
MX
6c7611c57e Fix (LF RFID -> Add manually) names again
remove N/A for PAC (and future protocols with N/A manufacturer)
2022-08-30 21:56:59 +03:00
MX
4d388f4bde SubGhz: add protocol Intertechno_V3 - OFW PR 1622
by Skorpionm
2022-08-30 21:55:25 +03:00
MX
613c729025 Fix displaying LFRFID protocol names - OFW PR 1682
by Astrrra
2022-08-30 21:29:13 +03:00
MX
079cadaeda SubGhz: add protocol Prastel - OFW PR 1674
by Skorpionm
2022-08-30 21:25:08 +03:00
MX
0c0fb57410 Merge branch 'fz-dev' into dev 2022-08-30 21:23:28 +03:00
Skorpionm
e7a5d19f9c [FL-2778] SubGhz: fix CLI "subghz tx" (#1681)
* SubGhz: fix CLI "subghz tx"
* Fix qoutes in amap workflow
* Github: fix step naming
* fix quotes in PR name again

Co-authored-by: あく <alleteam@gmail.com>
Co-authored-by: DrunkBatya <drunkbatya.js@gmail.com>
2022-08-31 00:22:24 +09:00
Eric Betts
8e9043003f Picopass write (#1658)
* [picopass] Prevent false success with non-standard key
* UI for writing
* worker function for write
* Update write command value
* Show card read failure message

Co-authored-by: あく <alleteam@gmail.com>
2022-08-30 22:59:34 +09:00
MX
b67aaad6d5 fix text 2022-08-30 15:33:51 +03:00
Foul
e4c6158d65 Update comment in SConstruct (#1684)
* Update SConstruct: fix Typo
* Grammar in SConstruct

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2022-08-30 21:15:14 +09:00
MX
23217f4a6a update audio manifest
by @Amec0e
2022-08-30 14:37:44 +03:00
Max Lapan
4fcb90928c ST25TB type is not handled (#1679)
We search for ST25TB type cards, but not handling them being found.
As a result, such cards are detected as NFC-A with 8-byte UID, which lead
to read error on emulation attempt.

Co-authored-by: gornekich <n.gorbadey@gmail.com>
2022-08-30 20:33:05 +09:00
MX
68da151320 Merge branch 'fz-dev' into dev 2022-08-30 13:16:08 +03:00
MX
f70ec8f70e update assets and subghz settings
assets by @Amec0e
2022-08-30 13:15:46 +03:00
Georgii Surkov
5e2a90c6f1 [FL-2773] Fix crash after cancelling Learn New Remote #1675
Co-authored-by: あく <alleteam@gmail.com>
2022-08-30 18:22:14 +09:00
MX
5272b81ae6 Merge branch 'fz-dev' into dev 2022-08-30 11:42:39 +03:00
MX
782593eafc Merge pull request #52 from Kavitate/patch-2
Updated BarcodeGenerator.md
2022-08-30 11:22:13 +03:00
Sebastian Mauer
d76ba20652 Add support for Pyramid tags (#1676)
* Add support for Pyramid tags
* Also add additional checks for AWID decoder to avoid missdetection

* lfrfid worker: reset GPIO_LOAD pin
* lfrfid: protocol viking, format
* lfrfid: protocol pyramid, format
* lfrfid: protocol paradox, format
* lfrfid: protocol jablotron, format
* lfrfid: protocol em4100, format
* lfrfid: increase reading time by 0.5s since protocol viking takes longer to read

Co-authored-by: SG <who.just.the.doctor@gmail.com>
2022-08-30 02:31:28 +10:00
Walter Doekes
611b7e15ed Remove execute permissions from *.c and *.h files (#1651)
* Add permission fix (no execute bit for source files) to fbt lint|format
* Remove execute bit from 59 source files using fbt format
* Also list which permissions are unwanted in lint.py
* Also remove exec permissions from lib/../rfal_nfc.c

Co-authored-by: あく <alleteam@gmail.com>
2022-08-30 01:20:57 +09:00
Sebastian Mauer
274f17ed5a Add support for Viking tags (#1668)
* Add support for Viking tags
Fix blocks_to_write for T5577
2022-08-30 01:19:56 +10:00
Sebastian Mauer
f09c5889dd Add support for Jablotron tags (#1657)
* Add support for Jablotron tags
2022-08-30 01:15:27 +10:00
Sebastian Mauer
39f936ce12 Add support for Paradox tags (#1655)
* Add support for Paradox tags
2022-08-30 01:08:10 +10:00
Sebastian Mauer
1350dcaf63 Add support for PAC/Stanley tags (#1648)
* Add support for PAC/Stanley tags
* Address review comments
2022-08-30 01:04:17 +10:00
Kavitate
4629aee29c Updated BarcodeGenerator.md
Fixed minor spelling and grammatical errors. Also updated the first image to reflect the current correct image.
2022-08-29 09:46:26 -05:00
Himura Kazuto
ffa3ff5e7c Remove obsolete info from docs (#1672) 2022-08-29 00:39:08 +09:00
MX
bacc8fa669 Merge pull request #51 from mothball187/nrfsniffer-improvements
tweak sniff parameters for more speed and reliability
2022-08-28 05:59:06 +03:00
MX
9c748860bb disable wav player, use standard icon in receiver 2022-08-28 05:58:53 +03:00
mothball187
79c4b617c1 tweak sniff parameters for more speed and reliability. clear sniff data on stop or exit. replace preamble GUI option with sample time option 2022-08-27 19:47:10 -07:00
MX
194727515b subghz decode raw gui
by qistoph
2022-08-28 04:46:59 +03:00
MX
c714a32ea5 Merge branch 'fz-dev' into dev 2022-08-27 16:17:16 +03:00
Max Andreev
689da15346 workflows and fbtenv improovements (#1661)
* add --restore option, improove clearing
* fix trap
* fix unset
* fix fbtenv clearing
* disabling pvs studio and amap analyses in forks, fbtenv.sh fixes
* fbtenv fix

Co-authored-by: あく <alleteam@gmail.com>
2022-08-27 21:38:13 +09:00
Skorpionm
1a4a6d4625 [FL-2769] SubGhz: out debug data to external pin #1665
Co-authored-by: あく <alleteam@gmail.com>
2022-08-27 17:06:25 +09:00
SG
99a7d06f71 Speedup SD card & enlarge your RAM. (#1649)
* FuriHal: sram2 memory manager
* FuriHal: sram2 memory allocator
* FuriHal: allow NULL buffers for txrx in spi hal
* SD card: sector cache
* FuriHal: fix init in memory hal
* RPC: STARTUP instead SERVICE
* Memory: pool "free" command
* Thread: service can be statically allocated in a memory pool

Co-authored-by: あく <alleteam@gmail.com>
2022-08-27 13:25:47 +09:00
MX
db4976c501 update ac asset
by @Amec0e
2022-08-27 05:15:49 +03:00
MX
fc62762ce4 fix assets header, doesnt affect bruteforce work 2022-08-27 04:41:35 +03:00
MX
a6597da4a5 Merge remote-tracking branch 'origin/dev' into dev 2022-08-27 03:16:37 +03:00
MX
ab5bcd71f5 update assets and changelog 2022-08-27 03:15:59 +03:00
MX
eb28dc2e20 Merge pull request #50 from darmiel/fix/infrared-buttons
fix[infrared]: fixed crash if button out of bounds and sending wrong signals
2022-08-27 03:06:15 +03:00
Daniel
92db5e1afe Merge remote-tracking branch 'origin/fix/infrared-buttons' into fix/infrared-buttons 2022-08-27 01:39:36 +02:00
Daniel
885bb0c730 fix[infrared]: clear records on remote switch 2022-08-27 01:39:06 +02:00
Daniel
71f4bd0a7c Merge branch 'Eng1n33r:dev' into fix/infrared-buttons 2022-08-27 01:06:33 +02:00
MX
66e361714f Merge branch 'fz-dev' into dev 2022-08-27 02:06:06 +03:00
Daniel
9bd6d956ca fix[infrared]: select first button on remote change 2022-08-27 00:46:34 +02:00
MX
293d5f722d update changelog & docs 2022-08-26 20:15:15 +03:00
MX
04f522487e Universal remote for fans, new buttons for AC
updated assets by @Amec0e
2022-08-26 20:02:25 +03:00
Yukai Li
ab4bb55d0f nfc: Change furi_assert to furi_crash for default switch cases (#1662)
* nfc: Change furi_assert to furi_crash for default switch cases
* Nfc: change MiFare Ultralight crash message

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2022-08-26 01:07:54 +09:00
MX
64edddeabf new spectrum analyzer icon
by @Svaarich
2022-08-25 17:39:55 +03:00
MX
a0819df874 update changelog 2022-08-25 14:36:51 +03:00
MX
24265204b3 Merge pull request #49 from darmiel/feat/stealth-frequency-analyzer
feat[freq-analzer]: add stealth modes for frequency analyzer
2022-08-25 14:12:51 +03:00
Daniel
e828d15fe3 feat[freq-analzer]: added ui for feedbacl level 2022-08-25 08:57:31 +02:00
MX
6c2cf68077 update tv asset
by @Amec0e
2022-08-25 05:31:47 +03:00
MX
f6d38939c2 hide txt extension in unirf browser 2022-08-25 05:13:08 +03:00
MX
f9d3d6bf5c fix unirf crash, fix keeloq seed display, fix flipfrid
and add new unirf icon(animated) by Svarich
2022-08-25 03:21:44 +03:00
Daniel
33176220f6 feat[freq-analzer]: added feedback levels 0, 1, 2
0 - no feedback
1 - vibro only
2 - vibro and beep
switch the modes with the "UP" key
2022-08-25 01:24:11 +02:00
MX
b31e4a36a8 Merge pull request #48 from Ganapati/dev
Add flipfrid application
2022-08-24 23:16:46 +03:00
MX
ecbe42744d Merge pull request #47 from darmiel/feat/unirf-protocols
feat[unirfremix]: allow to send dynamic protocols
2022-08-24 23:16:13 +03:00
MX
7abc49ea21 Implement TX while button is hold, other small changes
Repeat functionality removed since all buttons adds event in queue to be executed after tx is finished
2022-08-24 23:14:33 +03:00
MX
5b6f2cb80d Merge branch 'dev' into feat/unirf-protocols 2022-08-24 23:11:17 +03:00
MX
1f68cf09eb Merge branch 'fz-dev' into dev 2022-08-24 23:10:57 +03:00
Gana (@G4N4P4T1)
273871013e Add flipfrid application 2022-08-24 18:14:03 +02:00
Skorpionm
ce7b943793 [FL-2764] SubGhz: fix CAME, Chamberlain potocol (#1650)
* SubGhz: fix guard time CAME potocol
* SubGhz: fix file upload Chamberlain
* Github: fix spelling

Co-authored-by: あく <alleteam@gmail.com>
2022-08-25 00:14:27 +09:00
SG
7e20df7e93 LFRFID RC fixes (#1652)
* lfrid: fix write validation
* lfrid app: restore key data after write
2022-08-24 23:41:59 +09:00
Daniel
9ec0835012 fix[unirf]: removed leftover debug messages 2022-08-24 14:36:50 +02:00
Daniel
432782344a feat[unirf]: blinking on send
* fixed a HardFault when trying to `subghz_protocol_decoder_base_get_string`
* don't enter `power_suppress_charge` for each sending individually
2022-08-24 14:28:27 +02:00
MX
94f440d286 update readme/changelog & some fixes 2022-08-24 03:55:13 +03:00
Daniel Statzner
64ee9dd674 Merge branch 'Eng1n33r:dev' into feat/unirf-protocols 2022-08-23 22:39:45 +02:00
MX
3327093dae Merge branch 'fz-dev' into dev 2022-08-23 23:01:33 +03:00
MX
029f82dc82 new universal projector remote and assets update
assets by @Amec0e
2022-08-23 22:59:49 +03:00
Daniel
803422c18e fix[unirf]: fixed dynamic protocol, refactoring 2022-08-23 20:47:54 +02:00
Max Andreev
7c54fcf60a fix fbtenv.sh under zsh (#1645)
* fix fbtenv under ZSH, some improovements, add amap workflow timeout
* fix copy .map file in build.yml
2022-08-24 02:57:59 +09:00
MX
3a985eff4d rename unirf / update readme 2022-08-23 19:32:09 +03:00
MX
11e73cc670 Merge branch 'fz-dev' into dev 2022-08-23 19:20:06 +03:00
Nikolay Minaylov
b0daa601ad [FL-2727, FL-2749] New icon in BLE remote app #1644
Co-authored-by: あく <alleteam@gmail.com>
2022-08-24 01:18:28 +09:00
MX
baffcc5cf4 added multiconverter / removed hid analyzer
hid analyzer won't needed anymore because of new lfrfid system adds support for multiple hid protocols
2022-08-23 19:14:30 +03:00
SG
9bfb641d3e [FL-2529][FL-1628] New LF-RFID subsystem (#1601)
* Makefile: unit tests pack
* RFID: pulse joiner and its unit test
* Move pulse protocol helpers to appropriate place
* Drop pulse_joiner tests
* Generic protocol, protocols dictionary, unit test
* Protocol dict unit test
* iButton: protocols dictionary
* Lib: varint
* Lib: profiler
* Unit test: varint
* rfid: worker mockup
* LFRFID: em4100 unit test
* Storage: file_exist function
* rfid: fsk osc
* rfid: generic fsk demodulator
* rfid: protocol em4100
* rfid: protocol h10301
* rfid: protocol io prox xsf
* Unit test: rfid protocols
* rfid: new hal
* rfid: raw worker
* Unit test: fix error output
* rfid: worker
* rfid: plain c cli
* fw: migrate to scons
* lfrfid: full io prox support
* unit test: io prox protocol
* SubGHZ: move bit defines to source
* FSK oscillator: level duration compability
* libs: bit manipulation library
* lfrfid: ioprox protocol, use bit library and new level duration method of FSK ocillator
* bit lib: unit tests
* Bit lib: parity tests, remove every nth bit, copy bits
* Lfrfid: awid protocol
* bit lib: uint16 and uint32 getters, unit tests
* lfrfid: FDX-B read, draft version
* Minunit: better memeq assert
* bit lib: reverse, print, print regions
* Protocol dict: get protocol features, get protocol validate count
* lfrfid worker: improved read
* lfrfid raw worker: psk support
* Cli: rfid plain C cli
* protocol AWID: render
* protocol em4100: render
* protocol h10301: render
* protocol indala26: support every indala 26 scramble
* Protocol IO Prox: render
* Protocol FDX-B: advanced read
* lfrfid: remove unused test function
* lfrfid: fix os primitives
* bit lib: crc16 and unit tests
* FDX-B: save data
* lfrfid worker: increase stream size. Alloc raw worker only when needed.
* lfrfid: indala26 emulation
* lfrfid: prepare to write
* lfrfid: fdx-b emulation
* lfrfid: awid, ioprox write
* lfrfid: write t55xx w\o validation
* lfrfid: better t55xx block0 handling
* lfrfid: use new t5577 functions in worker
* lfrfid: improve protocol description
* lfrfid: write and verify
* lfrfid: delete cpp cli
* lfrfid: improve worker usage
* lfrfid-app: step to new worker
* lfrfid: old indala (I40134) load fallback
* lfrfid: indala26, recover wrong synced data
* lfrfid: remove old worker
* lfrfid app: dummy read screen
* lfrfid app: less dummy read screen
* lfrfid: generic 96-bit HID protocol (covers up to HID 37-bit)
* rename
* lfrfid: improve indala26 read
* lfrfid: generic 192-bit HID protocol (covers all HID extended)
* lfrfid: TODO about HID render
* lfrfid: new protocol FDX-A
* lfrfid-app: correct worker stop on exit
* misc fixes
* lfrfid: FDX-A and HID distinguishability has been fixed.
* lfrfid: decode HID size header and render it (#1612)
* lfrfid: rename HID96 and HID192 to HIDProx and HIDExt
* lfrfid: extra actions scene
* lfrfid: decode generic HID Proximity size lazily (#1618)
* lib: stream of data buffers concept
* lfrfid: raw file helper
* lfrfid: changed raw worker api
* lfrfid: packed varint pair
* lfrfid: read stream speedup
* lfrfid app: show read mode
* Documentation
* lfrfid app: raw read gui
* lfrfid app: storage check for raw read
* memleak fix
* review fixes
* lfrfid app: read blink color
* lfrfid app: reset key name after read
* review fixes
* lfrfid app: fix copypasted text
* review fixes
* lfrfid: disable debug gpio
* lfrfid: card detection events
* lfrfid: change validation color from magenta to green
* Update core_defines.
* lfrfid: prefix fdx-b id by zeroes
* lfrfid: parse up to 43-bit HID Proximity keys (#1640)
* Fbt: downgrade toolchain and fix PS1
* lfrfid: fix unit tests
* lfrfid app: remove printf
* lfrfid: indala26, use bit 55 as data
* lfrfid: indala26, better brief format
* lfrfid: indala26, loading fallback
* lfrfid: read timing tuning

Co-authored-by: James Ide <ide@users.noreply.github.com>
Co-authored-by: あく <alleteam@gmail.com>
2022-08-24 00:57:39 +09:00
Eric Betts
f92127c0a7 Picopass load/info/delete (#1562)
* increase stack size
* rfalPicoPassPollerWriteBlock
* UI for loading picopass
* Move picopass parsing and add delete, delete success

Co-authored-by: あく <alleteam@gmail.com>
2022-08-23 22:19:17 +09:00
Daniel
545dabadb7 refactor[unirf]: moved environment to struct 2022-08-23 14:48:08 +02:00
Max Andreev
ddd5d5a535 fix Amap reports outside pull-request (#1642) 2022-08-23 20:48:39 +09:00
Max Andreev
a7a9c38036 Amap and PVS Studio reports in CI/CD (#1526) 2022-08-23 20:29:26 +09:00
MX
56907f0c9f Merge branch 'fz-dev' into dev 2022-08-23 11:11:11 +03:00
Daniel
73c28437d6 fix[unirf]: display decoded after sending 2022-08-23 09:13:41 +02:00
Skorpionm
57328761cf [FL-2757] SubGhz: add protocol Magellen (#1633)
* SubGhz: add decoder Paradox Wireless
* SubGhz: fix syntax
* SubGhz: rename paradox_wireless -> magellen, add encoder Magellen, parse event
* SuBghz: add unit_test Magellen

Co-authored-by: あく <alleteam@gmail.com>
2022-08-23 03:01:42 +09:00
Nikolay Minaylov
9317ded1a9 [FL-2749] New power off screen #1637
Co-authored-by: あく <alleteam@gmail.com>
2022-08-23 02:54:01 +09:00
gornekich
8992f8ac36 Fix mifare ultralight/ntag unlock #1624
Co-authored-by: あく <alleteam@gmail.com>
2022-08-23 02:14:31 +09:00
hedger
9829145d8c fbt: fixed include paths; added PVS-Studio configuration (#1615)
* fbt: fixed include paths for generated version header
* lib: STM32CubeWB: refactored & cleaned up WPAN include paths
* hal: linter fixes for new headers
* fbt: added version_json target
* Added .pvsconfig; split common_defines.h into 2 files
* Added PVS-Studio basic configuration files; updated .gitignore

Co-authored-by: あく <alleteam@gmail.com>
2022-08-23 02:06:17 +09:00
Nikolay Minaylov
5b4e732fa3 [FL-2737] Dolphin level thresholds update #1610
Co-authored-by: あく <alleteam@gmail.com>
2022-08-23 01:53:51 +09:00
Nikolay Minaylov
df4755bc06 [FL-2727] BLE Remote UI fixes #1609
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2022-08-23 01:41:41 +09:00
Nikolay Minaylov
84e2e321b4 RPC: more asserts and checks (#1606)
Co-authored-by: あく <alleteam@gmail.com>
2022-08-23 01:36:45 +09:00
Lesha Lomalkin
4e1470cef2 slideshow.py: add return code on error (#1636)
* slideshow.py: add return code on error
* Scripts: remove dead code

Co-authored-by: Lesha Lomalkin <info@lomalkin.ru>
Co-authored-by: あく <alleteam@gmail.com>
2022-08-23 01:24:08 +09:00
Nikolay Minaylov
cfc0383b96 Archive: dont start browser worker on favourites tab (#1628)
Co-authored-by: あく <alleteam@gmail.com>
2022-08-23 01:19:03 +09:00
Anna Prosvetova
0a6d775fa7 Github: Update CODEOWNERS (#1631) 2022-08-21 21:51:04 +09:00
Max Andreev
fdb181b158 Fix BT Remote 'stay' button on first launch bug (#1626) 2022-08-19 20:31:45 +09:00
Daniel
71c27de8cc fix[unirf]: load environment mf codes 2022-08-19 03:38:35 +02:00
MX
9609751517 Merge branch 'fz-dev' into dev 2022-08-19 02:42:01 +03:00
Nikolay Minaylov
2a452063c6 [FL-2747, FL-2745] Browser worker fix, Device Info screen update #1620
Co-authored-by: あく <alleteam@gmail.com>
2022-08-19 01:54:17 +09:00
hedger
2e993b0a58 [FL-2748] disabled automatic poweroff for single-frame slideshows #1621 2022-08-19 01:46:43 +09:00
Astra
e243a0e0e4 Add MFC 1/4K 4/7bUID to "Add Manually" (#1584)
* Add MFC 1/4K 4/7bUID to the "Add Manually" section
* Small cleanup
* Improve readability
* Fix comment on the text box element
* Review fixes
2022-08-18 21:43:28 +09:00
Daniel
9eb9a44ee4 Merge remote-tracking branch 'upstream/dev' into feat/unirf-protocols 2022-08-18 01:46:57 +02:00
Daniel
3aed4de1b4 fix[unirf]: passed wrong FlipperFormat 2022-08-15 20:52:04 +02:00
Daniel
33fbf268b7 fix[unirf]: close fff_file 2022-08-14 23:52:05 +02:00
Daniel
36784f95c8 refactor[unirf]: dynamic protocol updates 2022-08-14 23:26:49 +02:00
Daniel
be942ef7b2 feat[unirfremix]: allow protocols other than raw 2022-08-12 01:55:19 +02:00
543 changed files with 23850 additions and 8204 deletions

View File

@@ -36,6 +36,7 @@ steps:
- mkdir -p sd-card/nfc/assets
- mkdir -p sd-card/infrared/assets
- mkdir -p sd-card/unirf
- mkdir -p sd-card/rfidfuzzer
- mkdir -p 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
@@ -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/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/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/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
- zip -r artifacts-default/sd-card-${DRONE_TAG}.zip 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})"
document:
- artifacts-default/flipper-z-f7-full-${DRONE_TAG}.dfu
- artifacts-default/flipper-z-f7-update-${DRONE_TAG}.zip
- artifacts-default/sd-card-${DRONE_TAG}.zip
- artifacts-default/flipper-z-f7-update-${DRONE_TAG}.tgz
- name: "Send discord notification"
image: appleboy/drone-discord

4
.gitignore vendored
View File

@@ -51,3 +51,7 @@ build/
# openocd output file
openocd.log
# PVS Studio temporary files
.PVS-Studio/
PVS-Studio.log

22
.pvsconfig Normal file
View 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
View 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/*

View File

@@ -1,16 +1,12 @@
### New changes
* Wifi Marauder app update (by @0xchocolate)
* Updated Universal remote assets (by @Amec0e)
* Fixed music player
* Fixed typos in subghz encoders
* OFW: New NFC info screens
* OFW: U2F fixes
* WAV Player, Arkanoid, TicTacToe, Barcode generator - plugins enabled and included in releases again
* Debug apps disabled in release build
* WAV Player moved to Games menu
* OFW: Lib: update LFS to v2.5.0, lower update free page limit
**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`
Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip` or `.tgz` for iOS mobile app
DFU for update using qFlipper - `flipper-z-f7-full-(version).dfu`

View File

@@ -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's Custom Firmware repo!
### Welcome to Flipper Zero Unleashed Firmware repo!
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>
@@ -29,18 +31,20 @@ Our Discord Community:
* Extra SubGHz frequencies + extra Mifare Classic keys
* Picopass/iClass plugin included in releases
* 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
See changelog in releases for latest updates!
### Current modified and new SubGhz protocols list:
### Current modified and new SubGHz protocols list:
- HCS101
- An-Motors
- CAME Atomo
- FAAC SLH (Spa) [if cloning existing remote - external seed calculation required]
- BFT Mitto [if cloning existing remote - external seed calculation required]
- Keeloq (+ proper manufacturer codes selection) [Not ALL systems supported yet!]
- FAAC SLH (Spa) [External seed calculation required]
- BFT Mitto [External seed calculation required]
- Keeloq [Not ALL systems supported yet!]
- Nice Flor S
- Security+ v1 & v2
- Star Line
@@ -51,21 +55,18 @@ See changelog in releases for latest updates!
* DOGE: `D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`
* LTC: `ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`
**Big thanks to all sponsors!**
### Community apps included:
- 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)
- 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)
- 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)
- 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)
- HID Analyzer [(by Ownasaurus)](https://github.com/Ownasaurus/flipperzero-firmware/tree/hid-analyzer/applications/hid_analyzer)
- Simple Clock (fixed) !! New version WIP, wait for updates !! [(Original by CompaqDisc)](https://gist.github.com/CompaqDisc/4e329c501bd03c1e801849b81f48ea61)
- UniversalRF Remix (with changes)(only RAW subghz files) [(by ESurge)(Original UniversalRF by jimilinuxguy)](https://github.com/ESurge/flipperzero-firmware-unirfremix)
- Simple Clock (fixed) [(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)
- 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)
- Arkanoid (with fixes) [(by gotnull)](https://github.com/gotnull/flipperzero-firmware-wPlugins)
@@ -87,10 +88,12 @@ See changelog in releases for latest updates!
### **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)
## [- 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)
### **Plugins that works with external hardware**
@@ -142,7 +145,6 @@ See changelog in releases for latest updates!
- `assets` - Assets used by applications and services
- `furi` - Furi Core: os level primitives and helpers
- `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
- `firmware` - Firmware source code
- `lib` - Our and 3rd party libraries, drivers and etc...

View File

@@ -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.
# 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)
# 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")
cmd_environment = Environment(tools=[], variables=fbt_variables)
Help(fbt_variables.GenerateHelpText(cmd_environment))

View File

@@ -29,23 +29,13 @@ bool archive_app_is_available(void* context, const char* path) {
if(app == ArchiveAppTypeU2f) {
bool file_exists = false;
Storage* fs_api = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(fs_api);
Storage* storage = furi_record_open(RECORD_STORAGE);
file_exists =
storage_file_open(file, ANY_PATH("u2f/key.u2f"), FSAM_READ, FSOM_OPEN_EXISTING);
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);
}
if(storage_file_exists(storage, ANY_PATH("u2f/key.u2f"))) {
file_exists = storage_file_exists(storage, ANY_PATH("u2f/cnt.u2f"));
}
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
return file_exists;
} else {
return false;

View File

@@ -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);
if(!browser->worker_running) {
browser->worker = file_browser_worker_alloc(path, filter_ext, skip_assets);
file_browser_worker_set_callback_context(browser->worker, browser);
file_browser_worker_set_folder_callback(browser->worker, archive_folder_open_cb);
file_browser_worker_set_list_callback(browser->worker, archive_list_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) {
@@ -438,8 +448,8 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
tab = archive_get_tab(browser);
if(archive_is_dir_exists(browser->path)) {
bool skip_assets = (strcmp(archive_get_tab_ext(tab), "*") == 0) ? false : true;
file_browser_worker_set_config(
browser->worker, browser->path, archive_get_tab_ext(tab), skip_assets);
archive_file_browser_set_path(
browser, browser->path, archive_get_tab_ext(tab), skip_assets);
tab_empty = false; // Empty check will be performed later
} else {
tab_empty = true;

View File

@@ -87,4 +87,3 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key);
void archive_enter_dir(ArchiveBrowserView* browser, string_t name);
void archive_leave_dir(ArchiveBrowserView* browser);
void archive_refresh_dir(ArchiveBrowserView* browser);
void archive_file_browser_set_callbacks(ArchiveBrowserView* browser);

View File

@@ -82,9 +82,8 @@ uint16_t archive_favorites_count(void* context) {
static bool archive_favourites_rescan() {
string_t buffer;
string_init(buffer);
Storage* fs_api = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(fs_api);
File* fav_item_file = storage_file_alloc(fs_api);
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
if(result) {
@@ -101,13 +100,8 @@ static bool archive_favourites_rescan() {
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
}
} else {
bool file_exists = storage_file_open(
fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING);
if(file_exists) {
storage_file_close(fav_item_file);
if(storage_file_exists(storage, 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);
storage_file_close(file);
storage_common_remove(fs_api, ARCHIVE_FAV_PATH);
storage_common_rename(fs_api, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH);
storage_common_remove(storage, ARCHIVE_FAV_PATH);
storage_common_rename(storage, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
storage_common_remove(storage, ARCHIVE_FAV_TEMP_PATH);
storage_file_free(file);
storage_file_free(fav_item_file);
furi_record_close(RECORD_STORAGE);
return result;
@@ -131,9 +124,8 @@ bool archive_favorites_read(void* context) {
furi_assert(context);
ArchiveBrowserView* browser = context;
Storage* fs_api = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(fs_api);
File* fav_item_file = storage_file_alloc(fs_api);
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
string_t buffer;
FileInfo file_info;
@@ -163,16 +155,12 @@ bool archive_favorites_read(void* context) {
need_refresh = true;
}
} else {
bool file_exists = storage_file_open(
fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING);
if(file_exists) {
storage_common_stat(fs_api, string_get_cstr(buffer), &file_info);
storage_file_close(fav_item_file);
if(storage_file_exists(storage, string_get_cstr(buffer))) {
storage_common_stat(storage, string_get_cstr(buffer), &file_info);
archive_add_file_item(
browser, (file_info.flags & FSF_DIRECTORY), string_get_cstr(buffer));
file_count++;
} else {
storage_file_close(fav_item_file);
need_refresh = true;
}
}
@@ -183,7 +171,6 @@ bool archive_favorites_read(void* context) {
storage_file_close(file);
string_clear(buffer);
storage_file_free(file);
storage_file_free(fav_item_file);
furi_record_close(RECORD_STORAGE);
archive_set_item_count(browser, file_count);

View File

@@ -370,18 +370,15 @@ ArchiveBrowserView* browser_alloc() {
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;
}
void browser_free(ArchiveBrowserView* browser) {
furi_assert(browser);
if(browser->worker_running) {
file_browser_worker_free(browser->worker);
}
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {

View File

@@ -74,6 +74,7 @@ typedef enum {
struct ArchiveBrowserView {
View* view;
BrowserWorker* worker;
bool worker_running;
ArchiveBrowserViewCallback callback;
void* context;
string_t path;

0
applications/bad_usb/views/bad_usb_view.h Executable file → Normal file
View File

View File

@@ -3,7 +3,7 @@
#include <applications/cli/cli.h>
#include <lib/toolbox/args.h>
#include "ble.h"
#include <ble/ble.h>
#include "bt_settings.h"
#include "bt_service/bt.h"

0
applications/bt/bt_debug_app/views/bt_carrier_test.c Executable file → Normal file
View File

0
applications/bt/bt_debug_app/views/bt_test.c Executable file → Normal file
View File

0
applications/bt/bt_debug_app/views/bt_test.h Executable file → Normal file
View File

6
applications/bt/bt_hid_app/bt_hid.c Executable file → Normal file
View File

@@ -89,8 +89,7 @@ BtHid* bt_hid_app_alloc() {
app->submenu, "Keynote", BtHidSubmenuIndexKeynote, bt_hid_submenu_callback, app);
submenu_add_item(
app->submenu, "Keyboard", BtHidSubmenuIndexKeyboard, bt_hid_submenu_callback, app);
submenu_add_item(
app->submenu, "Media Player", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app);
submenu_add_item(app->submenu, "Media", BtHidSubmenuIndexMedia, 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_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));
// 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;
}

7
applications/bt/bt_hid_app/views/bt_hid_keynote.c Executable file → Normal file
View File

@@ -43,7 +43,10 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) {
}
canvas_set_font(canvas, FontPrimary);
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);
elements_multiline_text_aligned(canvas, 127, 3, AlignRight, AlignTop, "Hold to exit");
// Up
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);
canvas_set_color(canvas, ColorWhite);
}
canvas_draw_icon(canvas, 110, 49, &I_Ok_btn_9x9);
elements_multiline_text_aligned(canvas, 76, 56, AlignLeft, AlignBottom, "Back");
canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8);
elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Back");
}
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
View File

@@ -49,7 +49,9 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) {
// Up
if(model->up_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
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
if(model->down_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
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
if(model->left_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
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
if(model->right_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
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);
canvas_draw_line(canvas, 100, 29, 100, 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) {

View File

@@ -36,7 +36,11 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) {
canvas_set_font(canvas, FontSecondary);
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
@@ -44,7 +48,9 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) {
// Up
if(model->up_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 81, 9, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
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
if(model->down_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 81, 41, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
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
if(model->left_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 65, 25, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
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
if(model->right_pressed) {
canvas_set_bitmap_mode(canvas, 1);
canvas_draw_icon(canvas, 97, 25, &I_Pressed_Button_13x13);
canvas_set_bitmap_mode(canvas, 0);
canvas_set_color(canvas, ColorWhite);
}
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
if(model->left_mouse_pressed) {
canvas_draw_icon(canvas, 81, 25, &I_Pressed_Button_13x13);
canvas_set_color(canvas, ColorWhite);
canvas_draw_icon(canvas, 81, 25, &I_Ok_btn_pressed_13x13);
} 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
if(model->right_mouse_pressed) {
canvas_draw_icon(canvas, 108, 48, &I_Pressed_Button_13x13);
canvas_set_color(canvas, ColorWhite);
canvas_draw_icon(canvas, 108, 48, &I_Ok_btn_pressed_13x13);
} 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) {

0
applications/bt/bt_settings_app/bt_settings_app.c Executable file → Normal file
View File

0
applications/bt/bt_settings_app/bt_settings_app.h Executable file → Normal file
View File

View File

View File

View 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("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("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) {

0
applications/cli/cli_i.h Executable file → Normal file
View File

View 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;
}

View File

@@ -220,8 +220,7 @@ static bool animation_manager_check_blocking(AnimationManager* animation_manager
furi_assert(blocking_animation);
animation_manager->sd_shown_sd_ok = true;
} else if(!animation_manager->sd_shown_no_db) {
bool db_exists = storage_common_stat(storage, EXT_PATH("Manifest"), NULL) == FSE_OK;
if(!db_exists) {
if(!storage_file_exists(storage, EXT_PATH("Manifest"))) {
blocking_animation = animation_storage_find_animation(NO_DB_ANIMATION_NAME);
furi_assert(blocking_animation);
animation_manager->sd_shown_no_db = true;

View File

@@ -94,6 +94,10 @@ bool slideshow_is_loaded(Slideshow* slideshow) {
return slideshow->loaded;
}
bool slideshow_is_one_page(Slideshow* slideshow) {
return slideshow->loaded && (slideshow->icon.frame_count == 1);
}
bool slideshow_advance(Slideshow* slideshow) {
uint8_t next_frame = slideshow->current_frame + 1;
if(next_frame < slideshow->icon.frame_count) {

View File

@@ -9,6 +9,7 @@ Slideshow* slideshow_alloc();
void slideshow_free(Slideshow* slideshow);
bool slideshow_load(Slideshow* slideshow, const char* fspath);
bool slideshow_is_loaded(Slideshow* slideshow);
bool slideshow_is_one_page(Slideshow* slideshow);
void slideshow_goback(Slideshow* slideshow);
bool slideshow_advance(Slideshow* slideshow);
void slideshow_draw(Slideshow* slideshow, Canvas* canvas, uint8_t x, uint8_t y);

View File

@@ -23,11 +23,12 @@ void desktop_debug_render(Canvas* canvas, void* model) {
const Version* ver;
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_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);
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_region_get_name(),
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();
const BleGlueC2Info* c2_ver = NULL;
@@ -52,7 +53,7 @@ void desktop_debug_render(Canvas* canvas, void* model) {
c2_ver = ble_glue_get_c2_info();
#endif
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;
}
@@ -62,7 +63,7 @@ void desktop_debug_render(Canvas* canvas, void* model) {
"%s [%s]",
version_get_version(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(
buffer,
@@ -72,11 +73,11 @@ void desktop_debug_render(Canvas* canvas, void* model) {
version_get_githash(ver),
version_get_gitbranchnum(ver),
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(
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 {
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);

View File

@@ -35,8 +35,9 @@ static bool desktop_view_slideshow_input(InputEvent* event, void* context) {
furi_assert(event);
DesktopSlideshowView* instance = context;
if(event->type == InputTypeShort) {
DesktopSlideshowViewModel* model = view_get_model(instance->view);
bool update_view = false;
if(event->type == InputTypeShort) {
bool end_slideshow = false;
switch(event->key) {
case InputKeyLeft:
@@ -54,15 +55,18 @@ static bool desktop_view_slideshow_input(InputEvent* event, void* context) {
if(end_slideshow) {
instance->callback(DesktopSlideshowCompleted, instance->context);
}
view_commit_model(instance->view, true);
update_view = true;
} else if(event->key == InputKeyOk) {
if(event->type == InputTypePress) {
furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_SHORT);
} else if(event->type == InputTypeRelease) {
furi_timer_stop(instance->timer);
/*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;
}
@@ -79,12 +83,12 @@ static void desktop_view_slideshow_enter(void* context) {
instance->timer =
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);
model->slideshow = slideshow_alloc();
if(!slideshow_load(model->slideshow, SLIDESHOW_FS_PATH)) {
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 File

@@ -14,8 +14,8 @@
#define DOLPHIN_STATE_PATH INT_PATH(DOLPHIN_STATE_FILE_NAME)
#define DOLPHIN_STATE_HEADER_MAGIC 0xD0
#define DOLPHIN_STATE_HEADER_VERSION 0x01
#define LEVEL2_THRESHOLD 735
#define LEVEL3_THRESHOLD 2940
#define LEVEL2_THRESHOLD 300
#define LEVEL3_THRESHOLD 1800
#define BUTTHURT_MAX 14
#define BUTTHURT_MIN 0

View 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.
* ----------------------------------------------------------------------------
*/

View 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

View 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,
)

View 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;
}

View 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;

View 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]));
}
}

View 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);

View File

@@ -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);
}

View File

@@ -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);

View 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;
}

View 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);

View 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);
}

View 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);

View 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));
}

View File

@@ -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
View File

0
applications/gpio/views/gpio_test.h Executable file → Normal file
View File

0
applications/gpio/views/gpio_usb_uart.h Executable file → Normal file
View File

0
applications/gui/canvas.h Executable file → Normal file
View File

View File

@@ -83,6 +83,15 @@ ButtonPanel* button_panel_alloc() {
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) {
furi_check(reserve_x > 0);
furi_check(reserve_y > 0);

View File

@@ -35,6 +35,12 @@ void button_panel_free(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.
*
* One does not simply use button_panel_add_item() without this function. It

0
applications/gui/modules/dialog_ex.c Executable file → Normal file
View File

View File

@@ -99,6 +99,11 @@ static bool browser_folder_check_and_switch(string_t path) {
FileInfo file_info;
Storage* storage = furi_record_open(RECORD_STORAGE);
bool is_root = false;
if(string_search_rchar(path, '/') == 0) {
is_root = true;
}
while(1) {
// Check if folder is existing and navigate back if not
if(storage_common_stat(storage, string_get_cstr(path), &file_info) == FSE_OK) {

0
applications/gui/modules/menu.h Executable file → Normal file
View File

0
applications/gui/modules/text_box.c Executable file → Normal file
View File

0
applications/gui/modules/text_box.h Executable file → Normal file
View File

0
applications/gui/modules/variable_item_list.h Executable file → Normal file
View File

4
applications/gui/modules/widget.h Executable file → Normal file
View File

@@ -115,8 +115,8 @@ void widget_add_text_box_element(
* @param[in] text Formatted text. Default format: align left, Secondary font.
* The following formats are available:
* "\e#Bold text" - sets bold font before until next '\n' symbol
* "\ecBold text" - sets center horizontal align before until next '\n' symbol
* "\erBold text" - sets right horizontal align before until next '\n' symbol
* "\ecCenter-aligned text" - sets center horizontal align until the next '\n' symbol
* "\erRight-aligned text" - sets right horizontal align until the next '\n' symbol
*/
void widget_add_text_scroll_element(
Widget* widget,

View File

View File

View File

0
applications/gui/scene_manager.c Executable file → Normal file
View File

0
applications/gui/scene_manager.h Executable file → Normal file
View File

0
applications/gui/scene_manager_i.h Executable file → Normal file
View File

0
applications/gui/view_dispatcher.h Executable file → Normal file
View File

View 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,
)

View File

@@ -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;
}

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -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();
}

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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;
};

View File

@@ -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(){};
};

View File

@@ -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;
}

View File

@@ -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);
};

View File

@@ -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];
};

View File

@@ -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];
};

View File

@@ -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);
};

View File

@@ -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();
};

View File

@@ -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();
};

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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];
};

View File

@@ -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);
};

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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