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

Compare commits

...

433 Commits

Author SHA1 Message Date
gid9798
226e300a16 Readme: fix typo & small fixes 2023-09-11 13:56:50 +03:00
gid9798
d49246048d Readme: instructions block systematized & cleanup 2023-09-11 13:08:09 +03:00
MX
a90ebd7b53 Update changelog 2023-09-08 15:53:15 +03:00
MX
b1b35e87f9 update readme, docs, fix build versions 2023-09-07 14:46:06 +03:00
MX
1df2fc035f New bt beacon api
by Willy-JL
2023-09-07 13:45:37 +03:00
MX
45fd5ef9d8 Subghz fix path reset on save name exit 2023-09-05 19:28:47 +03:00
MX
cfa95c757e Merge branch 'ofw_dev' into dev 2023-09-05 16:32:16 +03:00
Astra
600b2ce627 [FL-3566] iButton: Return to the file selection if file is corrupted (#3040)
Co-authored-by: あく <alleteam@gmail.com>
2023-09-05 22:24:50 +09:00
MX
fdb9748acc Merge branch 'ofw_dev' into dev 2023-09-05 16:22:49 +03:00
MX
d40f664342 API for BLE Beacon app
thanks to Willy-JL
2023-09-05 16:22:14 +03:00
Astra
8cbb757533 [FL-3583]Account for the "-" in line carry-over (#3038)
Co-authored-by: あく <alleteam@gmail.com>
2023-09-05 22:13:50 +09:00
hedger
452e27b05e github: workflow improvements (#3032)
* github: compact build: status reporting step
* github: build: matrix strategy
* debugging
* github: added version_token to /uploadfiles request
* github: reworked main build flow
* github: suppressed non-zero cp status
* github: build: fixed comment lookup; experimental changes to apps build order
* github: removed summary step for compact builds; united map analyzer steps
* fbt: added get_apiversion target; moved ext apps processing logic to AppBuildset
* ufbt: added missing global
* fbt: Moved incompatible app list to firmware config output
* fbt: cleaner extapps processing
* github: build: added automation for SDK publishing
2023-09-05 20:49:39 +09:00
MX
b3cce2351a Some faac fixes 2023-09-05 14:40:49 +03:00
MX
1859b06b6a oops 2023-09-05 05:59:21 +03:00
MX
1653abe0ef Remove unused table 2023-09-05 05:51:21 +03:00
MMX
c7b2e85e13 Merge pull request #585 from Eng1n33r/dev
FAAC SLH better UI/UX.
2023-09-05 05:45:24 +03:00
MX
b24fba6ad7 just in case 2023-09-05 05:44:09 +03:00
MX
ffc6f726f0 fix small bug 2023-09-05 05:43:06 +03:00
MX
0eb06ba2b7 Actually working progmode, new add manually options + bonus fixes 2023-09-05 05:31:03 +03:00
Eng1n33r
2a789ae1c1 faac beta-3 2023-09-04 23:55:08 +03:00
Eng1n33r
062faa4a84 Merge branch 'DarkFlippers:dev' into dev 2023-09-04 23:19:53 +03:00
MX
1cafa9a46b Fix naming var 2023-09-04 23:15:23 +03:00
MX
654b3245c2 fix module p2 2023-09-04 23:14:07 +03:00
MX
99eb10d6e7 fix module p1 2023-09-04 23:11:40 +03:00
Eng1n33r
e878ed7547 Merge branch 'DarkFlippers:dev' into dev 2023-09-04 22:52:42 +03:00
MMX
ac4177c248 Merge pull request #592 from DarkFlippers/subghz_remote_submodule
SubGHz Remote: submodule
2023-09-04 22:42:21 +03:00
MX
e6f9563bbc Merge branch 'dev' into eng_dev 2023-09-04 22:40:50 +03:00
MX
2b383ebcee Keyboard ok to toggle select all in cursor mode
by Willy-JL
2023-09-04 21:19:35 +03:00
Eng1n33r
cfc5caca63 Merge branch 'DarkFlippers:dev' into dev 2023-09-04 20:50:46 +03:00
MX
9c6e20356f Merge branch 'ofw-dev' into dev 2023-09-04 16:47:08 +03:00
Sergey Gavrilov
0b806c2360 Storage: force mount (#3033)
* Storage: count opened files
* Storage: sd mount
* Storage: prompt to mount SD card if not mounted
* F18: update API
* F18: update API version
* Fix logger naming scheme
* Storage: storage_files_count -> storage_open_files_count

Co-authored-by: あく <alleteam@gmail.com>
2023-09-04 14:10:07 +09:00
Linn Dahlgren
ce89240f6f [DOC] Remove defunct link in ReadMe.md (#3036) 2023-09-04 12:37:12 +09:00
Eng1n33r
686fab7296 Merge remote-tracking branch 'origin/dev' into dev
faac prg mode beta-2
2023-09-02 22:04:36 +03:00
MX
7d2deb5939 add some non working code 2023-09-02 21:45:51 +03:00
Eng1n33r
06a528f497 FAAC SLH prog mode [beta] 2023-09-02 19:00:45 +03:00
MX
265d2592e7 proper check 2023-09-02 16:26:19 +03:00
MX
72e6f5f59e fix 2023-09-02 16:02:32 +03:00
MX
3898e6e71d Fixes and de-kostilying 2023-09-02 16:00:24 +03:00
MX
17269a5386 Merge remote-tracking branch 'Eng1n33r/dev' into eng_dev 2023-09-02 15:59:51 +03:00
Eng1n33r
a2bcf67f7f Merge remote-tracking branch 'DarkFlippers/dev' into dev 2023-09-02 15:22:21 +03:00
MX
bd2cfb55df Merge branch 'dev' into eng_dev 2023-09-02 14:28:49 +03:00
MMX
0c7689831e Merge pull request #594 from amec0e/dev
Updated Infrared Assets
2023-09-02 14:27:08 +03:00
MX
ec9df8711a fmt + fix subrem 2023-09-02 14:26:32 +03:00
MX
15c480b68a Merge branch 'ofw-dev' into dev 2023-09-02 13:33:32 +03:00
amec0e
a8456208da Update tv.ir
New additions
2023-09-01 22:36:42 +01:00
amec0e
7ecd5684cb Update projectors.ir
New additions
2023-09-01 22:36:21 +01:00
amec0e
832d861b9d Update fans.ir
New additions
2023-09-01 22:35:58 +01:00
amec0e
7a0c896626 Update audio.ir
New additions
2023-09-01 22:35:31 +01:00
Max
52b5966262 Add File Naming setting for more detailed naming (#3002)
* added filename mode setting
* added furi_flag checks for when filename_mode is set
* changed naming for ibutton, lfrfid and subghz
* requested changes from PR
* Lib: gather all naming bits and pieces under name generator module. Properly bump api version. FuriHal: fix RTC flag enum.
* PR requested changes
* bug fix for arg type
* added functionality for other application scenes
* Lib: cleanup name generator API, simplify usage. Sync API symbols.
* Lib: proper size type in name_generator. Cleanup.
* FuriHal: cleanup rtc api usage across firmware

Co-authored-by: あく <alleteam@gmail.com>
2023-09-01 14:57:49 +09:00
Astra
e5fdb2e069 [FL-3314] Disconnect from BLE on protobuf error (#2955)
* Disconnect from BLE on protobuf error
* Set profile instead of disconnecting and add logging

Co-authored-by: あく <alleteam@gmail.com>
2023-09-01 13:54:12 +09:00
hedger
5eeb672dd4 github: workflow trigger optimizations (#3030) 2023-09-01 12:09:48 +09:00
suaveolent
d8d2b360cb Add support for Mifare Classic 4k SAK 0x38 ATQA 0x02, 0x04, 0x08 (#3009)
Co-authored-by: suaveolent <suaveolent@users.noreply.github.com>
Co-authored-by: あく <alleteam@gmail.com>
2023-09-01 11:22:29 +09:00
あく
7531e18020 Move roadmap link to readme (#3014)
Co-authored-by: hedger <hedger@users.noreply.github.com>
2023-09-01 06:00:40 +04:00
あく
f218c41d83 Undo some TODO (#3024)
* TODO FL-3497: impossible to fix with current memory allocator

* TODO FL-3497: removed, requires radically different settings approach

* TODO FL-3514: removed, yes we should

* TODO FL-3498: implemented, guarding view port access with mutex.

* TODO FL-3515: removed, questionable but ok

* TODO FL-3510: removed, comment added

* TODO FL-3500: refactored, store pin numbers in GpioPinRecord, fix gpio app crash caused by incorrect gpio_pins traversal.

* Format Sources

* TODO FL-3505: removed, mutex alone is not going to fix issue with WPAN architecture

* TODO FL-3506: removed, change ownership by copy is good

* TODO FL-3519: documentation and link to source added

* Lib: remove unneded total sum from comment in bq27220

---------

Co-authored-by: hedger <hedger@users.noreply.github.com>
2023-09-01 05:54:52 +04:00
Astra
7aa55ebc6c [FL-3543] Check the filetype of the update manifest (#3025)
Co-authored-by: あく <alleteam@gmail.com>
2023-09-01 10:47:02 +09:00
Sergey Gavrilov
809418b9da [FL-3563] StorageListRequest: size filter (#3018)
* Protobuf: size filter
* Update protobuf
* Scripts: types for fwflash.py
* RPC: handle fliter for StorageListRequest
* RPC: StorageListRequest tests for filtering
* Fix unit tests configuration
* Assets: sync protobuf with upstream

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2023-09-01 10:23:37 +09:00
Eng1n33r
b91f8d009e Fix KL unknown mf cnt bug 2023-08-31 22:39:22 +03:00
Skorpionm
aa1c1fd905 [FL-3582] SubGhz: heap overflow text error (#3021) 2023-08-29 20:55:36 +09:00
gid9798
cb5c5c08f6 SubGHz Remote: submodule 2023-08-29 13:37:15 +03:00
Astra
c6be6f487a [FL-3495] Remove the TODO for GPIO settings save/load (#3015)
Co-authored-by: あく <alleteam@gmail.com>
2023-08-29 13:39:34 +09:00
gornekich
5eb045e25f nfc: add rfal wrong state error handling (#3017) 2023-08-29 13:31:40 +09:00
Eng1n33r
04b2771e3b Merge branch 'DarkFlippers:dev' into dev 2023-08-28 13:23:07 +03:00
MX
5bd868665e fix timer icons in ir remote
icons by @Svaarich
2023-08-28 05:50:32 +03:00
MX
46e74b3823 remake fix in ofw way
view_dispatcher will skip on _run and free will be called, then app will exit same as normal
2023-08-28 05:48:40 +03:00
Eng1n33r
a772408ee6 Good Monday
[SubGhz / RadioSettings] More flexible rolling counter rate;
Remove unused stuff & small UI revisal
2023-08-28 00:02:48 +03:00
MX
416a02fc5b Merge branch 'ofw-dev' into dev 2023-08-27 02:43:56 +03:00
あく
cf74dd2599 Rfid: fix crash on broken key launch from archive (#3012) 2023-08-25 21:00:00 +04:00
Astra
66d26c16cd [FL-3580] AC OFF button (#3010)
Co-authored-by: あく <alleteam@gmail.com>
2023-08-26 01:09:40 +09:00
hedger
c3aa151712 github: Check for todos (#3011) 2023-08-25 23:38:41 +09:00
Eng1n33r
ce1336c0ed fix anomaly 2023-08-24 22:14:00 +03:00
Eng1n33r
32fb94f5db Cnt value edit [in progress] 2023-08-24 19:23:05 +03:00
Eng1n33r
f93aab9b22 Merge branch 'DarkFlippers:dev' into dev 2023-08-24 16:03:07 +03:00
MX
742c4ae834 added patreon link 2023-08-24 04:51:44 +03:00
MX
6609a64307 Remake custom universal remotes to use new design
New icons by @Svaarich
2023-08-24 03:31:42 +03:00
Eng1n33r
09aabff55b EditCnt rework [in progress] 2023-08-24 00:00:28 +03:00
MX
0660329ae5 Merge branch 'ofw-dev' into dev 2023-08-23 23:47:03 +03:00
MX
b5426197f5 fix 0xFFFF counter value being skipped 2023-08-23 23:40:13 +03:00
Skorpionm
940ec36a0b SubGhz: fix todo (#2984)
* [FL-3501] SubGhz: fix Handle multiple external cc1101 modules
* [FL-3502] SubGhz: fix Protocol not found error message
* [FL-3503] SubGhz: fix Handle rx buffer overflow
* {FL-3520] SubGhz: Handle RX buffer overflow with external cc1101
* [FL-3548] SubGhz: Security+ 2.0 counter start value
* [FL-3552] Sub-GHz: Check saved file
* [FL-3555] [FL-3554] Sub-GHz: RX buffer overflow handling and check that buffer has been properly written
* [FL-3557] Sub-GHz: No optimization required
* [FL-3558] Sub-GHz: Keeloq 0 discriminator
* [FL-3559] Sub-GHz: Keeloq unknown learning
* [FL-3560] Sub-GHz: callback for updating keeloq data on display
* SubGhz: fix RXFIFO_OVERFLOW

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2023-08-24 04:51:32 +09:00
Astra
60182aa2cd [FL-3564] New IR universal remote graphics (#3006)
* New IR universal remote layout
* Remove redundant checks

Co-authored-by: あく <alleteam@gmail.com>
2023-08-24 03:24:47 +09:00
hedger
56b5b35236 Intelligent probing with warnings for fwflash.py (#3005)
* scripts: fwflash: intelligent probing with warnings
* scripts: fwflash: better texting

Co-authored-by: あく <alleteam@gmail.com>
2023-08-24 03:04:12 +09:00
Nikolay Minaylov
b368660d48 More apps moved to apps repo (#2978)
* Clock, music player, snake game removed
* Music player, picopass assets removed

Co-authored-by: あく <alleteam@gmail.com>
2023-08-24 02:50:17 +09:00
Eng1n33r
091d32ed7a Merge branch 'DarkFlippers:dev' into dev 2023-08-23 20:35:41 +03:00
MX
52654d018e picopass assets moved into app 2023-08-23 20:09:29 +03:00
MX
8df9947d42 Merge branch 'ofw-dev' into dev 2023-08-23 19:49:00 +03:00
あく
d808884b97 FuriHal: explicitly pull display pins at early init stage, move PUPD config to early stage (#3004)
Co-authored-by: hedger <hedger@users.noreply.github.com>
2023-08-23 20:17:39 +04:00
Eng1n33r
6042254861 Merge branch 'DarkFlippers:dev' into dev 2023-08-23 17:59:56 +03:00
Synthethics
beeeb9bbdc Update tv.ir (#2942)
* Update tv.ir: Added VOX Electronics LED 43ADS316B TV Remote.
* Assets: reorder and tag new tv remote
* Assets: cleanup infrared universal tv

Co-authored-by: あく <alleteam@gmail.com>
2023-08-23 22:50:19 +09:00
Konstantin Volkov
4ade0fc76d [FL-3421] Unit bench: multiple attempts to find flipper (#2960)
* Unit bench: added retry count for finding flipper for reboot/reboot2dfu and power off scripts. Changed returns to sys.exit() since scripts are being used standalone
* fixed typo in await flipper and changed debug level to info for searching flipper in power.py
* reversed return operator instead of sys.exit, changed app.py exit behavior
* test run to see if exit(1) fails the run
* reversed test changes, fixed flipper name and increased await flipper timeout
* await after flash increase
* increased serial timeout
* increased serial timeout, apparently it is for entire run

Co-authored-by: doomwastaken <k.volkov@flipperdevices.com>
Co-authored-by: あく <alleteam@gmail.com>
2023-08-23 21:51:02 +09:00
Nikolay Minaylov
15f92f765d [FL-3479] Desktop: more favorites, configurable dummy mode (#2972)
* Desktop: more favorite app shortcuts
* Making PVS happy
* Desktop settings submenu fix

Co-authored-by: あく <alleteam@gmail.com>
2023-08-23 21:26:47 +09:00
MX
821f03b230 Merge branch 'ofw-dev' into dev 2023-08-23 15:08:54 +03:00
MX
ad723217e6 fix subghz loading 2023-08-23 15:08:29 +03:00
Eng1n33r
df5b2cbddd fix misspelling 2023-08-22 23:58:49 +03:00
Dzhos Oleksii
dc7517e5fd Fix display last symbol in multiline text (#2967)
* Revert submodules
* Compare without round
* Gui: slightly more integer logic in elements_get_max_chars_to_fit

Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: あく <alleteam@gmail.com>
2023-08-23 04:15:38 +09:00
MX
20593d56c0 Merge branch 'ofw-dev' into dev 2023-08-22 21:53:50 +03:00
Astra
27b2808ade [FL-3481] Properly reset the NFC device data (#2980)
Co-authored-by: あく <alleteam@gmail.com>
2023-08-23 03:40:05 +09:00
hedger
ace0901125 [FL-3486,FL-3392] fbt: various improvements and bug fixes (#2982)
* fbt: extapps: compact debug format for .faps
* fbt: sdk: fixed symbol cache regen logic for removed-only symbols
* lib: elf_file: early .fap file handle release
* fbt: extapps: added FAP_VERSION define for application environments
* github: added appsymbols artifact
* api: updates for f18
* github: fixed early fap_dist
* fbt: added flash_dap
* ufbt: added flash_dap
* fbt: reworked flash target; scripts: program.py->fwflash.py and changes
* vscode: updated configuration
* scripts: fwflash.py: ugly fixes for ufbt
* scripts: fwflash.py: cleanup
* fbt: flash: always use .elf file
* scripts: fwflash: fixed elf file path

Co-authored-by: あく <alleteam@gmail.com>
2023-08-23 03:33:10 +09:00
Nikolay Minaylov
991e58e405 Littlefs updated to v2.7.0 (#2986)
Co-authored-by: あく <alleteam@gmail.com>
2023-08-23 03:08:58 +09:00
Astra
e353433cd8 [FL-3488] Assign tickets to all TODO items (#2988)
Co-authored-by: あく <alleteam@gmail.com>
2023-08-23 02:56:27 +09:00
hedger
200c44bdca loader: restored support for debug apps (#2993)
* fbt: restored loader support for debug apps (no GUI tho)
* desktop: fixed code for handling autorun apps
* loader: fixed autorun app messing up last update stage
* Loader: handle status without message

Co-authored-by: あく <alleteam@gmail.com>
2023-08-23 02:38:45 +09:00
Eng1n33r
67a0136e81 microfix 2023-08-22 20:33:36 +03:00
Eng1n33r
2b5ad4f5af Correct counter work. FAAC SLH bugfix. 2023-08-22 20:22:49 +03:00
hedger
35cdefa1ca Removed explicit dependency on scons for external scripting (#2999) 2023-08-23 02:11:53 +09:00
Eng1n33r
f14ed73dfd Merge branch 'DarkFlippers:dev' into dev 2023-08-21 23:22:46 +03:00
MX
9bf1433334 fix non capital letters 2023-08-21 22:09:40 +03:00
MX
35c413b8a6 remove duplicate discord invite 2023-08-21 22:07:32 +03:00
MMX
34712b0c3b Merge pull request #586 from DarkFlippers/readme_and_changelog
Readme & Changelog fixes
2023-08-21 22:04:10 +03:00
gid9798
486542fe14 Readme - community links
Changelog - version table
2023-08-21 22:01:11 +03:00
Eng1n33r
69debc36a0 FAAC SLH 0x0 seed new "smart logic"
Comeback
2023-08-21 04:18:47 +03:00
Eng1n33r
2fabb0b589 Merge branch 'DarkFlippers:dev' into dev 2023-08-20 16:33:27 +03:00
MMX
c05a766651 Merge pull request #583 from OperKH/fix-sub-ghz-remote
Fix Sub-GHz Remote folder name
2023-08-20 16:03:43 +03:00
Aleksandr Zhytnyk
ac9234563a Fix Sub-GHz Remote folder name 2023-08-20 12:24:49 +03:00
Eng1n33r
b07b6dc857 Merge branch 'DarkFlippers:dev' into dev 2023-08-20 11:54:42 +03:00
MX
c70edf6dc9 update changelog and settings naming 2023-08-20 05:34:54 +03:00
MX
8a3d8bdee7 out of memory message 2023-08-20 04:21:09 +03:00
Eng1n33r
535bf35e23 Merge branch 'DarkFlippers:dev' into dev 2023-08-20 01:44:08 +03:00
MMX
362aa68038 Merge pull request #581 from amec0e/dev
Updated Infrared Assets Pack
2023-08-20 01:33:31 +03:00
MMX
f17b941f7d Merge pull request #578 from DarkFlippers/desktop_favorite_port
Desktop favorite port
2023-08-20 01:32:36 +03:00
MX
830eb0e5f6 Merge branch 'dev' into desktop_favorite_port 2023-08-19 23:34:08 +03:00
amec0e
38607d8dbe Update tv.ir
No new additions
2023-08-19 20:02:23 +01:00
amec0e
fe095df06a Update projectors.ir
New additions
2023-08-19 20:01:49 +01:00
amec0e
d728c140d8 Update fans.ir
New additions
2023-08-19 20:01:22 +01:00
amec0e
4f6fd2e9bc Update audio.ir
No new additions
2023-08-19 20:00:47 +01:00
Eng1n33r
d7a579e713 Merge branch 'DarkFlippers:dev' into dev 2023-08-19 00:08:09 +03:00
MX
26e5ae7476 RXFIFO_OVERFLOW still breaks esubghz_chat 2023-08-18 23:50:38 +03:00
Eng1n33r
2458cb2b96 Allow 0x0 seed for testing 2023-08-18 22:35:13 +03:00
Eng1n33r
3da9cb1b81 Merge remote-tracking branch 'origin/dev' into dev 2023-08-18 22:01:40 +03:00
MX
5924c3dd2c disable 0 seed in add manually 2023-08-18 21:04:59 +03:00
Eng1n33r
5cfc8fc536 Merge remote-tracking branch 'origin/dev' into dev 2023-08-18 21:01:12 +03:00
SkorP
03d3482357 SubGhz: fix RXFIFO_OVERFLOW 2023-08-18 17:14:50 +03:00
Eng1n33r
0af8bd1e8b Test FAAC 0x0 seed 2023-08-18 16:41:35 +03:00
gid9798
6330012b1d Desktop: fix lock timer after rebooting 2023-08-18 11:27:12 +03:00
gid9798
b1b00d4fa7 Desktop favorites: Return none and add lock in dummy 2023-08-18 11:23:35 +03:00
MX
7a80aaa5c8 readme fixes part 1
thanks @gid9798
2023-08-17 19:04:09 +03:00
MX
3584e0da46 Fix FAAC counter fix seed being not removed from RAM 2023-08-17 17:33:21 +03:00
SkorP
e1c83692c3 [FL-3552] Sub-GHz: Check saved file 2023-08-17 16:02:39 +03:00
MX
3507c89dbb fix faac add manually cnt 2023-08-17 16:02:32 +03:00
SkorP
6e2bcd9d00 {FL-3520] SubGhz: Handle RX buffer overflow with external cc1101 2023-08-17 14:43:53 +03:00
gid9798
f73f369952 Desktop favorites pt2 2023-08-17 13:40:55 +03:00
gid9798
3990c93013 Desktop favorites pt1 2023-08-17 13:04:40 +03:00
MX
4d5a900352 fix again 2023-08-17 04:44:17 +03:00
MX
e830dc1636 hotfix builds 2023-08-17 04:35:10 +03:00
MX
2d6bd46326 fix links 2023-08-17 04:21:05 +03:00
MX
0805754589 fix typo 2023-08-17 04:03:16 +03:00
MX
d627b53510 update changelog 2023-08-17 04:02:45 +03:00
MMX
69cabfb496 Merge pull request #577 from Leptopt1los/dev
ac.ir: Legion LE-F30RH-IN added
2023-08-17 04:01:23 +03:00
leptoptilos
b235c8abe9 ac.ir: Legion LE-F30RH-IN added 2023-08-17 09:53:40 +09:00
MX
0934b3f791 fix later 2023-08-17 03:24:14 +03:00
MX
fec80da3f4 subghz - fix check, fix typos
temporarily replace with internal check, commented code in function added TODO comment
2023-08-17 03:01:40 +03:00
MX
e892c977f3 Merge remote-tracking branch 'flipperdevices/subghz/fix_todo' into dev 2023-08-17 02:26:21 +03:00
MX
15ac511dea Merge branch 'ofw-dev' into dev 2023-08-16 16:52:43 +03:00
あく
b90e2ca342 SubGhz: add timeout to subghz_hal_async_tx_test_run (#2975)
* SubGhz: add timeout to subghz_hal_async_tx_test_run

* Removed full API from unit_test build config

---------

Co-authored-by: hedger <hedger@nanode.su>
Co-authored-by: hedger <hedger@users.noreply.github.com>
2023-08-16 13:16:42 +04:00
SkorP
aad06fdd43 SubGhz: fix PVS 2023-08-16 11:04:56 +04:00
SkorP
d4bc0cc10c [FL-3503] SubGhz: fix Handle rx buffer overflow 2023-08-16 10:57:48 +04:00
SkorP
0ecec8a711 [FL-3502] SubGhz: fix Protocol not found error message 2023-08-16 10:46:08 +04:00
SkorP
9d7396ee63 [FL-3501] SubGhz: fix Handle multiple external cc1101 modules 2023-08-16 10:17:21 +04:00
dogtopus
a7f0f5ad27 Improve vscode clangd experience (#2431)
* Improve vscode clangd experience

- Resolve and use absolute path for the toolchain. This allows clangd to use compile_commands.json file without running under fbtenv, simplifies setup for vscode clangd extension. As a side effect, a rebuild is needed to update compile_commands.json after moving the source tree.
- Add the recommended default settings of the extension to settings.json.

* Use build/latest for compile-commands-dir

This makes it behave closer to c-cpp-properties.

* Reformat crosscc.py

This is a PEP-8 violation but black seems to enforce it

* Bypass --query-driver

This has some security implications as it grants clangd the ability to execute any executables anywhere while trying to probe a compiler based on CDB. However it's very hard to do this the safe and intended way without resorting to config generation due to reason listed in #2431. Besides that we already have workspace trust so what could go wrong? ;)

* Add an option for vscode_dist to switch between clangd and cpptools

This will install different extensions.json tuned for either clangd or cpptools based on user selection. It will also install c_cpp_properties.json when using cpptools since clangd doesn't use this file.

The root .gitignore now also doesn't accidentally ignore everything under the .vscode directory.

* Use absolute path for .vscode gitignore

Turns out the previously used "relative" paths aren't even valid gitignore patterns and to actually do what it means one needs to use the absolute paths instead.

* Handle variable parsing in commandline.scons

commandline.scons is the place where all other command line parsing happens. Move LANG_SERVER variable parsing there and add a constraint to make the code more consistent.

---------

Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: hedger <hedger@nanode.su>
2023-08-16 05:23:09 +04:00
MX
146ae8c3bf Do not crash with fatal error on wrong ir frequency
TODO: actually use infrared_signal_is_valid check!
2023-08-15 21:09:25 +03:00
MX
aeadaef7c9 remove old vars 2023-08-15 08:37:56 +03:00
MX
fb2c65721b fix somfy telis wrong frequency in add manually 2023-08-14 17:55:26 +03:00
Astra
830e202bb1 Properly reset the NFC device data 2023-08-14 17:49:09 +03:00
MMX
9e3868887c Merge pull request #574 from DarkFlippers/nfc_mfclassic_custom_uid
NFC app: MF Custom UID, fix SAK & ATQA save
2023-08-14 17:24:59 +03:00
gid9798
f18df25a96 NFC app: MF Custom UID, fix SAK & ATQA save 2023-08-14 15:33:03 +03:00
MX
7bd8846288 small fix for random uid 2023-08-14 03:52:22 +03:00
MMX
196edb5d05 Merge pull request #571 from DarkFlippers/nfc_mfclassic_custom_uid
NFC App: Add manual MF Classic custom UID
2023-08-14 03:11:20 +03:00
MX
8c0e0c78f2 fix missing upload 2023-08-13 22:27:48 +03:00
MX
71b610c87e update changelog 2023-08-13 04:51:59 +03:00
MX
4f148079d5 rgb patch color fixes 2023-08-13 04:51:33 +03:00
MX
80c0301316 update changelog, readme and sync anims 2023-08-13 03:53:09 +03:00
MX
4d772ed67e clean build - only main apps build 2023-08-13 03:12:19 +03:00
MX
ff17f33a36 testing dev build bundles 2023-08-13 01:24:00 +03:00
MX
9fb20438c7 remove wrong path 2023-08-12 21:39:47 +03:00
MX
28a05d8f6b finish moving apps 2023-08-12 04:47:18 +03:00
MX
773a5e382f remove base apps pack 2023-08-12 04:43:23 +03:00
MX
4164932044 remove 2023-08-11 23:23:06 +03:00
MX
751cb9f5d6 totp update 2023-08-11 23:20:38 +03:00
MX
8d8102b4f9 merge fixes 2023-08-11 18:24:51 +03:00
MX
4b81046b6f Merge branch 'ofw-dev' into dev 2023-08-11 18:08:12 +03:00
MX
f069cdb7e6 Merge branch 'ofw-dev' into dev 2023-08-11 18:01:50 +03:00
Sergey Gavrilov
43ba76a37f uFBT: devboard_flash to update WiFi devboard (#2969)
* uFBT: devboard_flash to update WiFi devboard
* uFBT: help
2023-08-11 17:56:27 +03:00
Sergey Gavrilov
3aad84aa70 FBT: devboard_flash to update WiFi devboard (#2968) 2023-08-11 17:56:13 +03:00
あく
dc2d12d468 Scripts: OB recovery (#2964)
* Scripts: OB recovery
* Scripts: slightly different ob
* Scripts: remove excessive return
* Scripts: simplifying work with registers
* Make PVS happy

Co-authored-by: SG <who.just.the.doctor@gmail.com>
2023-08-11 17:56:02 +03:00
MX
09d5b3b1ed Expose additional functions of the crypto engine to user (#2923)
* Allow loading user supplied keys and add CTR mode
* Add GCM mode to furi_hal_crypto
* Split up CTR and GCM code, add flag for adv crypto
* Add convenience functions for GCM crypto
* Run fbt format
* Update GCM to support additional auth data
* Update APIs
* FuriHal: update crypto documentation, method names and usage
* Clean up code for key (un)loading, GCM and CTR
  - get rid of goto
  - do not use furi_hal_bt_is_alive() when not using secure enclave
  - give defines a type and wrap in ()
* Add unit test for CTR and GCM crypto
* FuriHal: const in crypto unit tests, cortex timer for crypto operations timeouts
* FuriHal: update crypto docs

Co-authored-by: twisted_pear <twstd@posteo.net>
Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: あく <alleteam@gmail.com>
2023-08-11 17:55:40 +03:00
47LeCoste
5f48968a05 BadUSB: qFlipper install script for MacOS (#2915)
* Create Install_qFlipper_macOS.txt
* BadUSB: qFlipper mac install routine improvements

Co-authored-by: あく <alleteam@gmail.com>
2023-08-11 17:54:32 +03:00
Hugo Blanc
3a36d5ea6d feat(infrared): add universal remote (#2818)
* feat(infrared): add universal remote
* fix: fix channel commands names

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2023-08-11 02:34:51 +09:00
Astra
12d9b1069c [FL-3480] Add the Sad song animation (#2973)
Co-authored-by: あく <alleteam@gmail.com>
2023-08-11 01:31:01 +09:00
hedger
7178bd20cf ufbt: fixed FAP_SRC_DIR (#2970)
* fbt, ufbt: fixed "_appdir" internal property and FAP_SRC_DIR not working in ufbt environment
* fbt, ufbt: reworked CompileIcons(); added app's own root to app's #include path
* fbt: cleaner resolve_real_dir_node

Co-authored-by: あく <alleteam@gmail.com>
2023-08-11 01:21:56 +09:00
MMX
f75fcd4e34 UI: Clock on Desktop (#2891)
* Clock on desktop
* Gui: gui_active_view_port_count
* Gui: move gui_active_view_port_count to private header, update docs
* Desktop: simplify desktop clock code
* Desktop: refactor clock
* Desktop: optimize clock code
* Desktop: 3rd cleanup round
* Desktop: 4th cleanup round, missing bits and pieces

Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: あく <alleteam@gmail.com>
2023-08-11 01:10:15 +09:00
Sergey Gavrilov
498aee20a2 uFBT: devboard_flash to update WiFi devboard (#2969)
* uFBT: devboard_flash to update WiFi devboard
* uFBT: help
2023-08-10 21:29:44 +09:00
gid9798
ee64a962d9 NFC App: Add scene for MF Classic custom UID 2023-08-10 14:48:42 +03:00
Sergey Gavrilov
c40e4ba01e FBT: devboard_flash to update WiFi devboard (#2968) 2023-08-10 18:53:12 +09:00
あく
2702c00ba4 Scripts: OB recovery (#2964)
* Scripts: OB recovery
* Scripts: slightly different ob
* Scripts: remove excessive return
* Scripts: simplifying work with registers
* Make PVS happy

Co-authored-by: SG <who.just.the.doctor@gmail.com>
2023-08-10 19:45:17 +10:00
twisted-pear
c976ff11bf Expose additional functions of the crypto engine to user (#2923)
* Allow loading user supplied keys and add CTR mode
* Add GCM mode to furi_hal_crypto
* Split up CTR and GCM code, add flag for adv crypto
* Add convenience functions for GCM crypto
* Run fbt format
* Update GCM to support additional auth data
* Update APIs
* FuriHal: update crypto documentation, method names and usage
* Clean up code for key (un)loading, GCM and CTR
  - get rid of goto
  - do not use furi_hal_bt_is_alive() when not using secure enclave
  - give defines a type and wrap in ()
* Add unit test for CTR and GCM crypto
* FuriHal: const in crypto unit tests, cortex timer for crypto operations timeouts
* FuriHal: update crypto docs

Co-authored-by: twisted_pear <twstd@posteo.net>
Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: あく <alleteam@gmail.com>
2023-08-10 17:44:46 +09:00
Nikolay Minaylov
fb63e53d9a [FL-3435] External apps removed (#2934)
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2023-08-10 06:18:40 +09:00
47LeCoste
1078625775 BadUSB: qFlipper install script for MacOS (#2915)
* Create Install_qFlipper_macOS.txt
* BadUSB: qFlipper mac install routine improvements

Co-authored-by: あく <alleteam@gmail.com>
2023-08-10 06:10:04 +09:00
MX
7027f6a4c4 Merge branch 'ofw-dev' into dev 2023-08-09 15:05:12 +03:00
Astra
a39ef50fdb [FL-3433] Add compressor.h to the SDK (#2962) 2023-08-09 16:52:41 +09:00
Alexandre L
d9e931b7b7 fbt: Fix building using path with space (#2948)
* fbt: Fix building on Windows using path with space
* scripts: Fixed formatting

---------

Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: hedger <hedger@nanode.su>
2023-08-09 04:46:07 +04:00
Robin Gareus
98d4309b61 IR Universal Audio Remote: add NAD C316BEE (#2954)
Remote control "NAD Amp1" https://nad.de/product/nad-c316bee-v2-vollverstaerker/

Co-authored-by: あく <alleteam@gmail.com>
2023-08-09 06:44:45 +09:00
Sergey Gavrilov
00cdc3d1cb [FL-3461] RPC: md5 in storage list (#2929)
* Protobuf: update
* Toolbox: md5 for file. Unit-Tests: test md5_calc.
* Storage RPC, CLI, unit tests: use new md5_calc
* Protobuf: update
* RPC, StorageList: append md5 info to file
* fbt: attempt to fix shallow submodule checkouts
* pvs: make happy
* Protobuf: update to latest release

Co-authored-by: hedger <hedger@nanode.su>
Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2023-08-09 06:34:54 +09:00
gid9798
8936c02487 NFC App: Add manual MF Classic custom UID 2023-08-08 14:16:35 +03:00
Derek Jamison
e9f1af44f2 Fixes #2957 - subghz decode_raw (#2958)
* Fixes #2957 - subghz decode_raw
* SubGhz: proper decode_raw fix

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2023-08-08 17:03:39 +09:00
Astra
ab006361cc Update the application catalog link in the readme (#2959) 2023-08-08 15:35:51 +09:00
Astra
1e4af1d550 FDX-B temperature in system units (#2941)
* FDX-B temperature now uses system units
* LF-RFID: wrap floats in fdx-b temperature conversion

Co-authored-by: あく <alleteam@gmail.com>
2023-08-07 19:28:47 +09:00
Nikolay Minaylov
4c771b66dc [FL-3471] Infrared: buttons move feature rework (#2949) 2023-08-07 18:18:46 +09:00
MX
20a6aa078c update changelog 2023-08-05 19:09:32 +03:00
MMX
3c298d7d83 Merge pull request #570 from amec0e/dev
Updated infrared assets
2023-08-05 18:41:07 +03:00
amec0e
e01e6f163c Update tv.ir
Updated last checked
2023-08-05 15:37:47 +01:00
amec0e
6f37f01b20 Update projectors.ir
Updated last checked
2023-08-05 15:36:45 +01:00
amec0e
d11fdca903 Update fans.ir
New additions
2023-08-05 15:36:21 +01:00
amec0e
e50cab3da1 Update audio.ir
Updated last checked
2023-08-05 15:35:47 +01:00
MX
49d2b31446 Add extra symbol, upd readme, upd codeowners 2023-08-05 15:25:06 +03:00
MX
c1438ce850 remove unused variable 2023-08-05 15:08:56 +03:00
MX
0f61a8eb46 upd changelog 2023-08-05 14:28:24 +03:00
MX
6ef1847e4d Merge remote-tracking branch 'origin/dev' into dev 2023-08-05 14:27:11 +03:00
MX
f70d2b5ae7 revert old nfc debug defines was used to save space 2023-08-05 14:25:16 +03:00
MMX
4951efff4d Merge pull request #569 from Leptopt1los/dev
ac.ir update
2023-08-05 14:19:00 +03:00
MX
07f6859a80 update changelog 2023-08-05 14:16:02 +03:00
MX
d30510f700 upd subbrute 2023-08-05 14:02:32 +03:00
nminaylov
becc8edd8c IR: buttons move feature rework 2023-08-05 14:00:57 +03:00
Astra
d09cf6c692 FDX-B temperature now uses system units 2023-08-05 14:00:48 +03:00
MX
afa7bd7f79 Update TOTP
https://github.com/akopachov/flipper-zero_authenticator
2023-08-05 13:57:55 +03:00
leptoptilos
eb54fef384 ac.ir: Ghost samples deleted 2023-08-05 18:55:52 +09:00
leptoptilos
fe630362a8 ac.ir: Tosot deleted (duplicate) 2023-08-05 18:52:58 +09:00
leptoptilos
66deaad4f4 ac.ir: Modified LG General signal. 'Off' now becomes 'raw', Cool_lo set to 16 2023-08-05 18:44:47 +09:00
MX
74ffb02b56 Merge branch 'ofw-dev' into dev 2023-08-02 19:09:48 +03:00
Lesha Lomalkin
c7648eb932 fbtenv: add additional environ variable to control execution flow (#2938)
* fbtenv: add flags FBT_PRESERVE_TAR, FBT_SKIP_CHECK_SOURCED for usage with external tools
* fbtenv: beautify, add info to fbtenv_print_config section if FBT_VERBOSE
* fbtenv: fixes

Co-authored-by: あく <alleteam@gmail.com>
2023-08-03 00:38:51 +09:00
erikj95
cf6706c42e NFC CLI: Fix multiple apdu commands from not working when one of them gives an empty response (#2922)
* NFC CLI: Fix multiple apdu commands from not working when one of them gives an empty response
* Make PVS happy

Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: あく <alleteam@gmail.com>
2023-08-03 00:24:02 +09:00
AloneLiberty
a7aef0bfc2 NFC: Fix MFC key invalidation (#2912)
* NFC: Fix key invalidation (again~)
* NFC: shouldn't be there
This code get called each time we check for B key

Co-authored-by: あく <alleteam@gmail.com>
2023-08-03 00:06:38 +09:00
Astra
3e8e999909 [FL-3470] Rename Applications to Apps (#2939)
* Applications are now apps
* Desktop: Apps in settings

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2023-08-02 23:58:59 +09:00
MX
3a5ed704fd Merge branch 'ofw-dev' into dev 2023-08-02 16:09:16 +03:00
Andrey Zakharov
7a45db3881 Fix about screen (#2907)
* Fix about screen
* About: use COUNT_OF

Co-authored-by: Andrey Zakharov <andzhr@yandex.ru>
Co-authored-by: あく <alleteam@gmail.com>
2023-08-02 14:19:00 +09:00
Skorpionm
9fd9dd85e3 SubGhz: change CC1101_ext TIM17 resolution to 2µs (#2909)
* SubGhz: change the operation of the TIM17 timer in CC1101_ext to 2µs
* SubGhz: remove special characters

Co-authored-by: あく <alleteam@gmail.com>
2023-08-02 13:45:39 +09:00
minchogaydarov
313e9c3d89 Add Daikin FTXC35DV1B ac remote (#2913)
Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: あく <alleteam@gmail.com>
2023-08-02 13:32:12 +09:00
Leopold
c72531edc6 change FuriThreadPriorityIsr to 31 (configMAX_PRIORITIES-1) (#2920)
* change FuriThreadPriorityIsr to 31 (configMAX_PRIORITIES-1)
* Furi: less hardcoded max priority, fix spelling
* Format sources

Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: あく <alleteam@gmail.com>
2023-08-02 13:23:04 +09:00
Astra
035e447009 [FL-3462] External apps icounter (#2928)
Co-authored-by: あく <alleteam@gmail.com>
2023-08-02 12:58:39 +09:00
plgcoder
be86b0f38a Overly missed feature: Infrared: move button (change button order in a remote) (#2894)
* Feature: Infrared: move button (change button order in a remote)
* little fix in furi_assert (case Move button to the end)
2023-08-02 12:43:36 +09:00
Astra
a677b2bcc2 [FL-3469] Move U2F path to ext (#2935)
Co-authored-by: あく <alleteam@gmail.com>
2023-08-02 00:50:17 +09:00
hedger
17bcfee224 [FL-3441] faploader: always create app dir, even if it doesn't have subdirs (#2901)
Co-authored-by: あく <alleteam@gmail.com>
2023-08-02 00:43:14 +09:00
Astro
1536f7a643 Update audio.ir (#2897)
* Update audio.ir: added Panasonic SA-PM193 codes to universal remote
* Update audio.ir: added play/pause code as Pause button

Co-authored-by: あく <alleteam@gmail.com>
2023-08-01 22:33:17 +09:00
Francis
67ca96ea96 Added French Canadian layout (#2896)
French Canadian layout for Windows

Co-authored-by: あく <alleteam@gmail.com>
2023-08-01 18:45:39 +09:00
MMX
fe7a1c2fcc SubGHz - Keeloq: Read Centurion Nova remotes (#2892)
Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: あく <alleteam@gmail.com>
2023-08-01 18:32:24 +09:00
MMX
aadb72af53 UI: New way to input bytes in byte_input (#2890)
* New byte input UI option
* Gui: reformat and cleanup byte_input docs, make PVS happy

Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: あく <alleteam@gmail.com>
2023-08-01 18:09:30 +09:00
Dzhos Oleksii
68eb1ecebb [FL-3385] New RTC flags in device info (#2884)
* Add new rtc flags to device info
* FuriHal: bump info version
* Fix local
* Rework device info by hierarchy filtering

Co-authored-by: あく <alleteam@gmail.com>
2023-08-01 17:20:30 +09:00
Nikolay Minaylov
a2a4fa8cda [FL-3408, FL-3429, FL-3430] Backlight notification fix (#2878)
* Notifications: display brightness override fix
* FuriHalVersionColor update
* float comparison fix

Co-authored-by: あく <alleteam@gmail.com>
2023-08-01 16:56:11 +09:00
MX
5d21da1737 fix 2023-07-31 01:21:17 +03:00
MMX
7413f707ed Merge pull request #564 from DarkFlippers/cc1101_power_amp
Init config for external radio driver
2023-07-31 00:25:32 +03:00
gid9798
c6b6aec057 replace power amp in driver 2023-07-30 12:12:59 +03:00
MX
c3f7a0d128 update changelog 2023-07-29 05:52:40 +03:00
MX
2c656f9c49 Update wifi marauder 2023-07-29 05:21:58 +03:00
MX
913efab179 Merge branch 'ofw-dev' into dev 2023-07-29 04:16:09 +03:00
MMX
03b950999c Merge pull request #562 from CodyTolene/ct/camera-suite-update
Update '[ESP32] Camera Suite' to v1.1.0
2023-07-29 04:15:21 +03:00
MMX
62e817f183 Merge pull request #559 from Z3BRO/dev
SubGHz External High Power
2023-07-29 04:14:34 +03:00
MX
0f9c6ba847 Remake it more properly
still has problems, need to rewrite subghz_devices tx/rx switch code, checking strcmp every time is not good too, but better than loading whole config from microsd
2023-07-29 03:51:46 +03:00
Cody Tolene
e698d6274f Update to match changes from here: https://github.com/flipperdevices/flipper-application-catalog/pull/90 2023-07-28 17:49:42 -05:00
Max Andreev
ff2e1acfdb Fix fbtenv restore (#2924) 2023-07-28 23:45:27 +04:00
Cody Tolene
d4ff1e3a50 Update '[ESP32] Camera Suite' to v1.1.0 2023-07-27 22:25:37 -05:00
Z3BRO
58beca313d SubGHz External High Power 2023-07-27 17:25:32 +02:00
MX
99b203e25c update changelog 2023-07-25 04:44:31 +03:00
MX
2446c5c02b Fix PR #557 issues and run fbt format 2023-07-25 04:37:34 +03:00
MMX
8e20aa6780 Merge pull request #557 from ALEEF02/analyzer-decoder
SubGHz Analyzer - Modulation switching
2023-07-25 04:34:51 +03:00
MX
6f40a06869 play pause buttons for universal projector remote 2023-07-25 04:25:57 +03:00
MX
8a249c48c5 fix daewoo 2023-07-25 04:19:37 +03:00
MMX
e686561c77 Merge pull request #556 from amec0e/dev
Updated infrared assets
2023-07-25 04:18:55 +03:00
MX
3fcf0da1ec just in case 2023-07-25 03:35:50 +03:00
ALEEF02
2c8ac7f775 Expand straggling 'mod' instances 2023-07-24 18:48:44 -04:00
ALEEF02
dbb1ab8693 Expand 'mod' to 'modulation' in all instances for consistency 2023-07-24 18:38:32 -04:00
ALEEF02
eed85f019c Typo fixes and cleanup 2023-07-24 18:34:40 -04:00
MX
f1a353d942 fix 5 plugins ui update 2023-07-25 00:11:56 +03:00
ALEEF02
9fa45850d2 Merge branch 'analyzer-decoder' of https://github.com/ALEEF02/unleashed-firmware-subghz-analyzer into analyzer-decoder 2023-07-24 17:11:11 -04:00
ALEEF02
2dc5d49be1 Add switching of modulations on long-press of OK 2023-07-24 17:08:44 -04:00
amec0e
8c3d648814 Update tv.ir
Added new Daewoo parsed codes
2023-07-24 21:02:57 +01:00
amec0e
5cfcbe1a2a Update projectors.ir
New additions
2023-07-24 21:01:18 +01:00
amec0e
73fc7146c8 Update fans.ir
New additions
2023-07-24 21:00:49 +01:00
amec0e
5d14f6048a Update audio.ir
New additions
2023-07-24 21:00:29 +01:00
amec0e
725d623855 Update ac.ir
New additions
2023-07-24 21:00:01 +01:00
MX
c447dc45f1 Temp fix for badbt on macOS 2023-07-24 14:24:03 +03:00
MX
14e44b6f88 Update totp 2023-07-24 13:47:44 +03:00
MX
a0f59f6094 update changelog 2023-07-24 01:47:57 +03:00
MX
bb4bd28fe1 Temp revert due to external module issues 2023-07-24 01:15:55 +03:00
MX
171e147a9d OFW PR 2907: Fix about screen
by andzhr
2023-07-24 00:31:53 +03:00
MX
7933bd9788 add xiaomi tv and daikin ac
daikin ac from ofw pr 2913 by
minchogaydarov
2023-07-24 00:13:56 +03:00
MX
b7b03f2108 Doom fixes and updates 2023-07-24 00:01:18 +03:00
MX
a7304bd9a8 upd spectrum desc 2023-07-22 21:04:04 +03:00
MX
9b88bda88b ufbt fixes subbrute 2023-07-22 20:56:33 +03:00
MX
823094bf79 ufbt fixes protoview 2023-07-22 20:48:20 +03:00
MMX
0470d681a2 Merge pull request #553 from ALEEF02/dev
SubGhz Analyzer PRECISE hstep fix
2023-07-22 20:30:56 +03:00
MX
5c5e68a5ce Update LightMeter 2023-07-22 20:30:21 +03:00
SkorP
0d84dceaae SubGhz: change the operation of the TIM17 timer in CC1101_ext to 2µs 2023-07-22 19:20:58 +03:00
AloneLiberty
b58be2bf1e NFC: Fix key invalidation (again~) 2023-07-22 19:20:49 +03:00
ALEEF02
27dc328614 Fix steps for PRECISE. Give ULTRANARROW #.# labels 2023-07-21 15:06:36 -04:00
Anthony Ford
8dc6a3c113 Merge pull request #1 from DarkFlippers/dev
Merge in Spectrum Analyzer changes
2023-07-20 18:02:43 -04:00
MX
906de7d9e7 fix PR #550 2023-07-20 22:00:49 +03:00
MX
3f08d861e9 fbt format 2023-07-20 21:54:36 +03:00
MMX
be358f98eb Merge pull request #550 from ALEEF02/spectrum-analyzer
Add a Precise mode
2023-07-20 21:54:03 +03:00
MX
9ec25a2681 fix issue #551 2023-07-20 21:53:02 +03:00
MMX
7d0c62f726 Merge pull request #552 from DarkFlippers/hid_app_KB_assets
Hid app kb assets
2023-07-20 21:50:34 +03:00
gid9798
2ab7548175 HID app: rename assets 2023-07-20 20:54:32 +03:00
gid9798
99d8164065 HID app: KB assets 2023-07-20 20:47:29 +03:00
ALEEF02
676c59cd31 Add a Precise mode 2023-07-19 21:55:36 -04:00
MX
0bb1e8902e replace fm15k with am_q modulation 2023-07-20 01:32:01 +03:00
MX
0b29fb4ffa Update changelog 2023-07-20 00:22:29 +03:00
MX
92b280291d barcode gen, embed files 2023-07-20 00:13:49 +03:00
hedger
9fa3375b0a faploader: always create app dir, even if it doesn't have subdirs 2023-07-20 00:09:06 +03:00
MX
0835124a02 subbrute updates 2023-07-19 21:14:13 +03:00
MX
44721727af Update changelog 2023-07-19 03:57:50 +03:00
MMX
80df63ce29 Merge pull request #549 from DarkFlippers/archive
Archive Cut/Copy/Past & NewDir
2023-07-19 03:54:29 +03:00
MX
3635a3b71f fix typo 2023-07-19 01:48:21 +03:00
gid9798
7d81d3bee0 Merge remote-tracking branch 'UFW/dev' into archive 2023-07-18 23:49:03 +03:00
gid9798
c0eebcb540 Archive: Cut/Copy/Past & NewDir 2023-07-18 23:46:28 +03:00
MX
3c32075919 add fbt format and clear to quick tasks 2023-07-18 22:55:46 +03:00
MX
2f532a547e Merge branch 'ofw-dev' into dev 2023-07-18 22:53:16 +03:00
あく
76e97b8d35 [FL-3051] Gauge initialization routine refactoring, new DataMemory layout, configuration update (#2887)
* FuriHal: refactor power gauge config

* Format sources and move gauge DM load to separate method

* FuriHal: bq27220 refactoring part 1

* Power: use SYSDWN battery status flag for system shutdown

* Libs: bq27220 read DM before write, fix incorrect shift

* FuriHal: cleanup gauge config, add flags, add ptr DM type, update symbols

* FuriHal: 2 stage gauge DM verification and update, better detection routine

* FuriHal: update gauge configuration, lower sleep current and deadband

* FuriHal: gauge and charger health reporting

* Lib: cleanup bq27220 sources

* FuriHal: correct documentation for furi_hal_power_is_shutdown_requested

* FuriHal: proper gauge config for f7
2023-07-18 14:46:38 +04:00
hedger
309f65e401 [FL-3437] fbt: build target for faps (#2888)
* fbt: added build target for faps. Usage: ./fbt build APPSRC=<appid>
* Updated docs & vscode config
* Code cleanup
2023-07-18 13:39:30 +04:00
MX
12f7edb56a Update changelog 2023-07-18 02:59:45 +03:00
MX
bb6d3cb796 NRF24 plugins updates
Updates by Sil333033 with some changes, furi_hal speaker direct calls was removed and replaced with notification service to avoid bypassing of user set silent mode
2023-07-18 02:53:30 +03:00
MX
e2028eb731 Fix menu 2023-07-17 22:12:34 +03:00
MX
6870304a73 Move subghz into internal memory
we have no free ram :((((
2023-07-17 20:37:30 +03:00
MX
2c8350818c Merge branch 'ofw-dev' into dev 2023-07-17 20:33:26 +03:00
Dzhos Oleksii
9bb04832a8 IButton: on delete scene key name not fully display if so long (#2882)
Co-authored-by: あく <alleteam@gmail.com>
2023-07-17 12:03:27 +04:00
hedger
20f6394ad8 [FL-3431] Radio headers in SDK (#2881) 2023-07-17 11:51:15 +04:00
gid9798
da919372e2 Archive separate menu 2023-07-16 20:28:15 +03:00
MMX
3ad10aaa48 Merge pull request #546 from amec0e/dev
Update ac.ir
2023-07-14 18:52:00 +03:00
amec0e
6afbd97d81 Update ac.ir
Renamed a few entries, added compatibility comment and added new Shivaki captures to ensure swing was and is off
2023-07-14 16:23:20 +01:00
MX
bb9ba09b6d update docs 2023-07-14 17:53:32 +03:00
MMX
b663726576 Merge pull request #545 from DarkFlippers/subrem_app
SubRem app Improvement
2023-07-14 17:11:09 +03:00
MX
635c824b1b Merge branch 'ofw-dev' into dev 2023-07-14 16:53:45 +03:00
MX
d74dc11775 Add extra symbols for nfc maker and wifi marauder keyboard 2023-07-14 16:52:51 +03:00
hedger
f2324e4d1c [FL-3377] Update error code descriptions (#2875)
* updater: added update error code descriptions
* updater: separate ram/flash messages
* updater: extra pre-update checks
* updater: fixed string comparison
* updater: Additional logging

Co-authored-by: あく <alleteam@gmail.com>
2023-07-14 17:45:16 +04:00
MX
61a66c52c6 Revert "merge changes"
This reverts commit f998948623.
2023-07-14 16:39:07 +03:00
DEXV
af64ae0e40 Badusb: Ducky script to auto install qFlipper (#2346)
* Badusb:Script to auto install/update qFlipper
* Update Install_qFlipper_windows.txt
2023-07-14 16:43:13 +04:00
gid9798
8e2371d0c9 SubRem: small fix 2023-07-14 14:28:46 +03:00
gid9798
b3810ec573 SubRem: archive browser 2023-07-14 14:16:37 +03:00
gid9798
f49cad314e SubRem: swap apps 2023-07-14 12:59:58 +03:00
gid9798
521ef5659f SubRem Configurator: add TX 2023-07-14 12:28:09 +03:00
Nikolay Minaylov
e073c603a4 [FL-3334] Storage: explosive rename fix (#2876)
Co-authored-by: あく <alleteam@gmail.com>
2023-07-14 13:16:22 +04:00
MX
523f522de0 revert archive fixes temporarily 2023-07-14 04:40:22 +03:00
MX
dd26ec22c3 remove all possible leftovers 2023-07-14 04:08:20 +03:00
MX
fe95845fa0 trying to find where issue is hiding 2023-07-14 04:06:15 +03:00
MX
52c30f50ec update changelog and readme 2023-07-14 03:07:35 +03:00
MX
0a45cba2bf Update NFC Maker
by Willy-JL
2023-07-14 01:18:35 +03:00
MX
af23870d3b make multi_fuzzer submodule 2023-07-13 23:54:50 +03:00
MX
090a912f93 remove 2023-07-13 23:53:46 +03:00
MX
ec588935b5 fbt format 2023-07-13 23:33:40 +03:00
MX
fd778be03c Update lightmeter 2023-07-13 23:32:41 +03:00
MMX
0cbbe1ac0a Merge pull request #544 from amec0e/dev
Updated Infrared Assets
2023-07-13 23:24:49 +03:00
MX
3f7337cd13 cleanup to automerge 2023-07-13 23:24:38 +03:00
MMX
53b27e18c3 Merge pull request #543 from DarkFlippers/submenu_fix_vertical
GUI module: SubMenu fix vertical orientation
2023-07-13 23:23:19 +03:00
MX
015350c692 fix 2023-07-13 23:22:55 +03:00
MX
65bbaca380 Merge branch 'ofw-dev' into dev 2023-07-13 22:40:35 +03:00
amec0e
705d6265d1 Update ac.ir
New captures for Tosot and Chigo (fixed swing on) and Added LG PC07SQR
2023-07-13 18:37:04 +01:00
amec0e
d64d797bcc Update fans.ir
New additions
2023-07-13 18:35:12 +01:00
amec0e
59d56186aa Update projectors.ir
Updated last checked
2023-07-13 18:33:54 +01:00
amec0e
34abfcb454 Update tv.ir
Updated last checked
2023-07-13 18:33:26 +01:00
amec0e
a7b3f9df4c Update audio.ir
New additions
2023-07-13 18:32:54 +01:00
Andrey Zakharov
6605740ce9 Add LG A/C IR signals to universal remote (#2871)
Co-authored-by: Andrey Zakharov <andzhr@yandex.ru>
Co-authored-by: あく <alleteam@gmail.com>
2023-07-13 16:09:04 +04:00
Sergey Gavrilov
8dc1edac18 Loader: good looking error messages (#2873)
* Loader: special error for unknown external app
* Loader: update special error
* Loader: beautify GUI errors, remove redundant logs
* Loader: fix gui error vertical position
* Desktop settings: add external menu apps
* Desktop: smaller settings struct and fix incorrect behavior with ext apps

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2023-07-13 16:02:59 +04:00
あく
b55d97f827 Desktop,Cli: add uptime info (#2874) 2023-07-13 21:02:08 +10:00
gid9798
d3c0fbef3b GUI module: SubMenu fix vertical orientation 2023-07-13 13:31:01 +03:00
MX
ea357b8eaf upd ofw anims list 2023-07-13 12:48:26 +03:00
MX
f998948623 merge changes 2023-07-12 21:23:49 +03:00
MX
c4b04a06bb Merge branch 'ofw-dev' into dev 2023-07-12 21:19:16 +03:00
Nikolay Minaylov
92c0baa461 [FL-3383, FL-3413] Archive and file browser fixes (#2862)
* File browser: flickering and reload fixes
* The same for archive browser
2023-07-12 20:35:11 +04:00
あく
a4b4802897 Revert "[FL-3420] Storage: directory sort (#2850)" (#2868)
This reverts commit 136114890f.
2023-07-12 21:02:52 +10:00
Sergey Gavrilov
dcb49c540f [FL-3422] Loader: exit animation fix (#2860)
Co-authored-by: あく <alleteam@gmail.com>
2023-07-12 13:49:17 +04:00
Skorpionm
25ec09c7eb SubGhz: fix check connect cc1101_ext (#2857)
* SubGhz: fix check connect cc1101_ext
* SubGhz: fix syntax
* SubGhz: enable interface pin pullups
* SubGhz: fix syntax
* SubGhz: fix CLI check connect CC1101_ext
* SubGhz: fix CLI display of the selected device

Co-authored-by: あく <alleteam@gmail.com>
2023-07-12 13:41:46 +04:00
AloneLiberty
bf15d3ce74 NFC: Improved MFC emulation on some readers (#2825)
* NFC: Improved MFC emulation on some readers
* NFC: Improved emulation on some readers (part 2): Some Android devices don't like this
* NFC: Improved emulation on some readers (part 3): I knew that during the emulation timings are critical, but one log breaks all...
* NFC: Improved emulation on some readers (part 4): Add fixes to Detect reader and refactor code
* NFC: Improved emulation on some readers (part 5)
* NFC: Improved emulation on some readers (part 6): GUI doesn't update without delay
* NFC: Improved emulation on some readers (part 7): Reworked emulation flow, some bug fixes and improvements


Co-authored-by: あく <alleteam@gmail.com>
Co-authored-by: gornekich <n.gorbadey@gmail.com>
2023-07-12 13:14:11 +04:00
あく
b1e13d44b8 Dolphin: add new animation (#2865) 2023-07-12 12:28:51 +04:00
Max Andreev
a319a6fdf2 Update toolchain to v23 (#2824)
Co-authored-by: あく <alleteam@gmail.com>
2023-07-11 19:36:15 +04:00
Nikita Vostokov
b7d2fe769c Decode only supported Oregon 3 sensor (#2829)
Co-authored-by: wosk <nikita.vostokov@auriga.com>
Co-authored-by: あく <alleteam@gmail.com>
2023-07-11 18:26:18 +04:00
MX
4a2cae23ca Merge branch 'ofw-dev' into dev 2023-07-11 15:49:01 +03:00
MX
4ccfd5ba63 add app in readme 2023-07-11 14:56:05 +03:00
MX
8ab3308553 fbt format for subbrute 2023-07-11 14:54:30 +03:00
MX
b41ffd887d Fix naming, run fbt format 2023-07-11 14:53:54 +03:00
MMX
44baa84cf6 Merge pull request #541 from CodyTolene/camera-suite
Add Camera Suite GPIO application for the ESP32-CAM module.
2023-07-11 14:52:14 +03:00
Astra
8bccfd6fd8 [FL-3363] More descriptive error messages for the log command (#2835)
* More descriptive error messages for the log command
* Log level description improvements
* Log help changes

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2023-07-11 15:41:16 +04:00
MX
bc0722fe25 upd nfc maker / badusb fixes
by @Willy-JL
2023-07-11 13:40:46 +03:00
MX
9d98724dcb Merge branch 'ofw-dev' into dev 2023-07-11 13:31:59 +03:00
MMX
14fc960246 Infrared: RCA protocol support (#2823)
* RCA protocol support
* Add unit test

Co-authored-by: あく <alleteam@gmail.com>
2023-07-11 12:39:07 +04:00
Sergey Gavrilov
136114890f [FL-3420] Storage: directory sort (#2850)
* Storage: sort_data holder in file structure
* Storage: sort directory if it possible
* make pvs happy
* Storage: fail sorting if there is no more space for realloc
* Storage: case insensitive sorting.

Co-authored-by: あく <alleteam@gmail.com>
2023-07-11 11:29:45 +04:00
Cody Tolene
978fecf242 Add Camera Suite GPIO application for the ESP32-CAM module. 2023-07-11 00:06:55 -05:00
MX
e7439272e6 Update mifare nested 2023-07-11 03:46:12 +03:00
MX
5a6c168b68 ext module fix 2023-07-11 00:09:10 +03:00
MMX
640fd92d3b Merge pull request #539 from DarkFlippers/fix_subrem
SubRem app: UPD txrx
2023-07-10 23:52:37 +03:00
gid9798
73737fb94a SubRem app: UPD txrx 2023-07-10 23:50:56 +03:00
MX
342c7dc5b5 upd subbrute 2023-07-10 23:31:38 +03:00
MMX
8e0029586b Merge pull request #536 from gid9798/cc1101_ext_protoview
ProtoView: cc1101 ext
2023-07-10 23:29:27 +03:00
MX
9a7d5189d8 Merge branch 'dev' into cc1101_ext_protoview 2023-07-10 23:29:06 +03:00
MMX
88391c8392 Merge pull request #535 from gid9798/cc1101_ext_pocsag
POCSAG Pager: cc1101 ext
2023-07-10 23:26:41 +03:00
MX
1e8a58c224 Merge branch 'dev' into cc1101_ext_pocsag 2023-07-10 23:17:46 +03:00
MMX
f91a73159f Merge pull request #534 from gid9798/cc1101_ext
Cc1101 ext
2023-07-10 23:16:30 +03:00
MX
5897b8278b api 2023-07-10 22:46:57 +03:00
MX
9f9664f6ca Merge branch 'dev' into cc1101_ext 2023-07-10 22:44:17 +03:00
MMX
171fd947e9 Merge pull request #537 from DarkFlippers/external_main
Fix merge external main
2023-07-10 22:43:31 +03:00
gid9798
0e1a54141e Fix SubGhz Apps & LF RFID 2023-07-10 19:59:25 +03:00
MX
76ddb5de76 Merge branch 'dev' into cc1101_ext 2023-07-10 17:23:30 +03:00
MX
5398fb806e move last apps into microsd 2023-07-10 17:21:49 +03:00
MX
dab2e6e39c remove debug pack for now, fw should fit in debug 2023-07-10 17:10:43 +03:00
MX
5fa0706d70 Merge branch 'dev' into cc1101_ext 2023-07-10 17:04:53 +03:00
MX
bb7ffd6ff5 Merge branch 'ofw-dev' into dev 2023-07-10 16:55:28 +03:00
MX
9c6d0e7f21 fbt format 2023-07-10 16:52:58 +03:00
MX
b451fa91de Update wifi marauder app 2023-07-10 16:52:12 +03:00
MX
e56b970eb4 update mifare nested 2023-07-10 16:48:18 +03:00
Sergey Gavrilov
9b2d80d6b7 [FL-3400] External menu apps (#2849)
* FBT, applications: add MENUEXTERNAL app type
* FBT, uFBT: build MENUEXTERNAL as EXTERNAL app
* Loader menu: show external menu apps
* LFRFID: move to sd card
* FBT: always build External Applications list
* Archive: look for external apps path
* Infrared: move to sd card
* Apps: add "start" apps
* iButton: move to sd card
* BadUSB: move to sd card
* External apps: update icons
* GPIO: move to sd card
* Loader: look for external apps path
* U2F: move to sd
* SubGHz: move to sd
* Apps: "on_start" metapackage
* NFC: move to sd
* Sync f7 and f18

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2023-07-10 12:03:41 +04:00
minchogaydarov
4736fa876d Add Hitachi RAK-50PEB universal ac remote (#2826)
Co-authored-by: あく <alleteam@gmail.com>
2023-07-10 11:04:53 +04:00
Astra
0195f8bf00 [FL-3350] Device Info update (#2840)
* Update F18 version info
* Certification info for F18

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2023-07-10 10:48:00 +04:00
Dusan Hlavaty
b148e396d7 feat(infrared): add TCL TV remote (#2853)
Adds a TCL TV remote to the universal remotes list. Tested with TCL 55C815 television
2023-07-10 10:22:30 +04:00
gid9798
64732d25fc Merge remote-tracking branch 'priv_dark/cc1101_ext' into cc1101_ext_protoview 2023-07-08 17:20:38 +03:00
gid9798
3fad9a2437 Merge branch 'cc1101_ext' into cc1101_ext_pocsag 2023-07-08 17:14:57 +03:00
gid9798
9494cc01a9 Merge remote-tracking branch 'UFW/dev' into cc1101_ext 2023-07-07 15:45:59 +03:00
gid9798
dd2cad0c20 External radio driver in frequency analyzer & test carrier (#5)
* SubGhz App: add support ext_cc1101 in freq analyzer
* SubGhz App: add support ext_cc1101 in test_carrier
* SubGhz app: Deleted the temporary menu
2023-07-06 16:50:25 +03:00
gid9798
b1850fd700 Weather station: new external radio driver (#3)
* Weather station: new external radio driver
2023-07-06 16:23:48 +03:00
gid9798
cb08b84197 Spectrum analyzer: new ext radio driver (#2)
* Sub Analyzer app: UPD to new driver
* Sub Analyzer: fix working on start
2023-07-06 16:23:14 +03:00
gid9798
2be6e330eb Protoview: new ext_cc1101 driver 2023-07-06 10:19:58 +03:00
gid9798
d208b69f42 subghz_playlist app: Upd external module init 2023-07-03 14:26:47 +03:00
gid9798
90ed11e5e1 subrem_configurator app: Upd TXRX 2023-07-03 14:16:43 +03:00
gid9798
2ef07a7a6c SubGhz: add some consts and fix unit tests 2023-07-03 14:02:57 +03:00
gid9798
01d7beef4e SubGhz: furi_hal_subghz remove preset load function by name 2023-07-03 13:36:26 +03:00
gid9798
0d6e6c4d85 SubGhz: fix split h and c 2023-07-03 12:48:47 +03:00
gid9798
2fb57529a0 SubGhz: fiz module seletion, furi_assert(device). drivers targets 2023-07-03 12:35:27 +03:00
gid9798
c1f056cf93 Merge remote-tracking branch 'UFW/dev' into cc1101_ext 2023-07-03 11:15:32 +03:00
gid9798
91ab2fd984 Pocsaq pager App: new radio driver 2023-06-21 14:00:25 +03:00
gid9798
1e76c2d840 SubRem Apps: update 2023-06-21 11:24:16 +03:00
gid9798
7bd0273fd5 SubGhz app: deleted extra check 2023-06-20 14:41:59 +03:00
gid9798
6e26de3763 SubGhz app: fix is_tx_allowed and freq check 2023-06-20 14:28:03 +03:00
gid9798
e2e9e53b6a Sub playlist app: new external and some fixes 2023-06-20 12:38:50 +03:00
gid9798
f9472effe3 Now really block transmission at dangerous freq 2023-06-20 11:02:14 +03:00
gid9798
a519a242d6 SubRem Config internal module by default 2023-06-19 13:37:08 +03:00
gid9798
ab12c8c339 SubRem configurator update 2023-06-19 13:26:01 +03:00
gid9798
72712d9f07 updated TODO descriptions 2023-06-19 12:51:02 +03:00
gid9798
2817913e63 prt3 2023-06-18 21:09:07 +03:00
gid9798
5eb677aa55 prt2 2023-06-18 20:25:40 +03:00
gid9798
3000b8fd0d prt1 2023-06-18 20:25:16 +03:00
gid9798
a191631c32 DIR_NAME and Drivers 2023-06-18 16:44:45 +03:00
2137 changed files with 12609 additions and 157943 deletions

View File

@@ -92,6 +92,13 @@ Min level: 1
Max level: 3
Weight: 4
Name: L1_My_dude_128x64
Min butthurt: 0
Max butthurt: 8
Min level: 1
Max level: 3
Weight: 4
Name: L2_Wake_up_128x64
Min butthurt: 0
Max butthurt: 12
@@ -154,3 +161,10 @@ Max butthurt: 5
Min level: 1
Max level: 3
Weight: 4
Name: L1_Sad_song_128x64
Min butthurt: 8
Max butthurt: 13
Min level: 1
Max level: 3
Weight: 4

View File

@@ -102,8 +102,8 @@ index 0000000..269b544
+ .settings_is_loaded = false};
+
+static const RGBBacklightColor colors[] = {
+ {"Orange", 255, 79, 0},
+ {"Yellow", 255, 170, 0},
+ {"Orange", 255, 60, 0},
+ {"Yellow", 255, 150, 0},
+ {"Spring", 167, 255, 0},
+ {"Lime", 0, 255, 0},
+ {"Aqua", 0, 255, 127},
@@ -114,7 +114,7 @@ index 0000000..269b544
+ {"Magenta", 210, 0, 210},
+ {"Pink", 255, 0, 127},
+ {"Red", 255, 0, 0},
+ {"White", 140, 140, 140},
+ {"White", 150, 150, 110},
+};
+
+uint8_t rgb_backlight_get_color_count(void) {

View File

@@ -15,12 +15,39 @@ steps:
- git submodule foreach git config --local gc.auto 0
- git log -1 --format='%H'
- name: "Build firmware"
- name: "Build clean"
image: hfdj/fztools
pull: never
commands:
- export DIST_SUFFIX=${DRONE_TAG}c
- export WORKFLOW_BRANCH_OR_TAG=release-cfw
- export FORCE_NO_DIRTY=yes
- rm -rf assets/resources/apps/
- rm -rf build/
- rm -rf dist/
- rm -rf .sconsign.dblite
- ./fbt COMPACT=1 DEBUG=0 updater_package
- mkdir artifacts-clean
- mv dist/f7-C/* artifacts-clean/
- ls -laS artifacts-clean
- ls -laS artifacts-clean/f7-update-${DRONE_TAG}c
environment:
FBT_TOOLS_CUSTOM_LINK:
from_secret: fbt_link
- name: "Build default"
image: hfdj/fztools
pull: never
commands:
- export DIST_SUFFIX=${DRONE_TAG}
- export WORKFLOW_BRANCH_OR_TAG=release-cfw
- export FORCE_NO_DIRTY=yes
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-base.tgz
- tar zxvf all-the-apps-base.tgz
- cp -R base_pack_build/artifacts-base/* assets/resources/apps/
- rm -rf base_pack_build
- rm -rf all-the-apps-base.tgz
- rm -f build/f7-firmware-C/toolbox/version.*
- ./fbt COMPACT=1 DEBUG=0 updater_package
- mkdir artifacts-default
- mv dist/f7-C/* artifacts-default/
@@ -34,9 +61,10 @@ steps:
image: hfdj/fztools
pull: never
commands:
- git clone https://github.com/xMasterX/all-the-plugins.git
- cp -R all-the-plugins/apps/* assets/resources/apps/
- rm -rf all-the-plugins
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-extra.tgz
- tar zxvf all-the-apps-extra.tgz
- cp -R extra_pack_build/artifacts-extra/* assets/resources/apps/
- rm -rf extra_pack_build
- export DIST_SUFFIX=${DRONE_TAG}e
- export WORKFLOW_BRANCH_OR_TAG=release-cfw
- export FORCE_NO_DIRTY=yes
@@ -82,6 +110,13 @@ steps:
- export FORCE_NO_DIRTY=yes
- rm -f build/f7-firmware-C/toolbox/version.*
- ./fbt COMPACT=1 DEBUG=0 updater_package
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-base.tgz
- tar zxvf all-the-apps-base.tgz
- cp -R base_pack_build/artifacts-base/* assets/resources/apps/
- rm -rf base_pack_build
- rm -rf all-the-apps-base.tgz
- rm -f build/f7-firmware-C/toolbox/version.*
- ./fbt COMPACT=1 DEBUG=0 updater_package
- mkdir artifacts-ofw-anims
- mv dist/f7-C/* artifacts-ofw-anims/
- ls -laS artifacts-ofw-anims
@@ -89,6 +124,8 @@ steps:
- sed -i 's/(version)/'${DRONE_TAG}'/g' CHANGELOG.md
- echo '# [Install via Web Updater](https://lab.flipper.net/?url=https://unleashedflip.com/fw/${DRONE_TAG}/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')' >> CHANGELOG.md
- echo '' >> CHANGELOG.md
- echo '### [Version with only main apps - Install via Web Updater](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'c.tgz&channel=release-cfw&version='${DRONE_TAG}'c)' >> CHANGELOG.md
- echo '' >> CHANGELOG.md
- echo '### [Version without custom animations - Install via Web Updater](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)' >> CHANGELOG.md
- echo '' >> CHANGELOG.md
- echo '### [Version with RGB patch - only for hardware mod! - Install via Web Updater](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz&channel=release-cfw&version='${DRONE_TAG}'r)' >> CHANGELOG.md
@@ -103,19 +140,23 @@ steps:
commands:
- cp artifacts-extra-apps/flipper-z-f7-update-${DRONE_TAG}e.tgz .
- cp artifacts-rgb-patch/flipper-z-f7-update-${DRONE_TAG}r.tgz .
- cp artifacts-clean/flipper-z-f7-update-${DRONE_TAG}c.tgz .
- cp artifacts-ofw-anims/flipper-z-f7-update-${DRONE_TAG}n.tgz .
- cp artifacts-default/flipper-z-f7-update-${DRONE_TAG}.tgz .
- zip -r artifacts-extra-apps/flipper-z-f7-update-${DRONE_TAG}e.zip artifacts-extra-apps/f7-update-${DRONE_TAG}e
- zip -r artifacts-rgb-patch/flipper-z-f7-update-${DRONE_TAG}r.zip artifacts-rgb-patch/f7-update-${DRONE_TAG}r
- zip -r artifacts-clean/flipper-z-f7-update-${DRONE_TAG}c.zip artifacts-clean/f7-update-${DRONE_TAG}c
- zip -r artifacts-ofw-anims/flipper-z-f7-update-${DRONE_TAG}n.zip artifacts-ofw-anims/f7-update-${DRONE_TAG}n
- zip -r artifacts-default/flipper-z-f7-update-${DRONE_TAG}.zip artifacts-default/f7-update-${DRONE_TAG}
- tar czpf artifacts-default/flipper-z-any-scripts-${DRONE_TAG}.tgz scripts
- rm -rf artifacts-extra-apps/f7-update-${DRONE_TAG}
- rm -rf artifacts-rgb-patch/f7-update-${DRONE_TAG}
- rm -rf artifacts-clean/f7-update-${DRONE_TAG}
- rm -rf artifacts-ofw-anims/f7-update-${DRONE_TAG}
- rm -rf artifacts-default/f7-update-${DRONE_TAG}
- ls -laS artifacts-extra-apps
- ls -laS artifacts-rgb-patch
- ls -laS artifacts-clean
- ls -laS artifacts-ofw-anims
- ls -laS artifacts-default
- mv artifacts-default/ ${DRONE_TAG}
@@ -187,6 +228,21 @@ steps:
from_secret: dep_target_extra
source: flipper-z-f7-update-${DRONE_TAG}r.tgz
- name: "Upload clean version to updates srv"
image: appleboy/drone-scp:linux-amd64
settings:
host:
from_secret: dep_host
username:
from_secret: dep_user
password:
from_secret: dep_passwd
port:
from_secret: dep_port
target:
from_secret: dep_target_extra
source: flipper-z-f7-update-${DRONE_TAG}c.tgz
- name: "Do Github release"
image: ddplugins/github-release
pull: never
@@ -202,6 +258,7 @@ steps:
- artifacts-ofw-anims/*.tgz
- artifacts-extra-apps/*.tgz
- artifacts-rgb-patch/*.tgz
- artifacts-clean/*.tgz
title: ${DRONE_TAG}
note: CHANGELOG.md
checksum:
@@ -243,12 +300,15 @@ steps:
[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)
[-Download latest extra apps pack-](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip)
[-Download latest extra apps pack-](https://github.com/xMasterX/all-the-plugins/releases/latest)
[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/${DRONE_TAG}/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=release-cfw&version=${DRONE_TAG})
[-Version with only main apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-${DRONE_TAG}c.tgz&channel=release-cfw&version=${DRONE_TAG}c)
[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-${DRONE_TAG}n.tgz&channel=release-cfw&version=${DRONE_TAG}n)
@@ -271,7 +331,19 @@ steps:
commands:
- wget "https://raw.githubusercontent.com/fieu/discord.sh/e1dc1a7595efad2cad8f072f0b3531c470f5b7c8/discord.sh"
- chmod +x ./discord.sh
- ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with RGB patch - only for hardware mod! - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz&channel=release-cfw&version='${DRONE_TAG}'r)\n\n[-Version with RGB patch - only for hardware mod! - Direct download-](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz)\n\n[-Version with Extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)'
- ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://github.com/xMasterX/all-the-plugins/releases/latest)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version with only main apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'c.tgz&channel=release-cfw&version='${DRONE_TAG}'c)\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with RGB patch - only for hardware mod! - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz&channel=release-cfw&version='${DRONE_TAG}'r)\n\n[-Version with RGB patch - only for hardware mod! - Direct download-](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz)\n\n[-Version with Extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)'
- name: "Send clean build to telegram"
image: appleboy/drone-telegram
settings:
token:
from_secret: tgtoken
to:
from_secret: tgid
format: markdown
message: "Build with only main apps:"
document:
- flipper-z-f7-update-${DRONE_TAG}c.tgz
- name: "Send extra pack build to telegram"
image: appleboy/drone-telegram
@@ -310,12 +382,40 @@ steps:
- git submodule foreach git config --local gc.auto 0
- git log -1 --format='%H'
- name: "Build dev FW"
- name: "Build dev clean"
image: hfdj/fztools
pull: never
commands:
- export DIST_SUFFIX=${DRONE_BUILD_NUMBER}c
- export WORKFLOW_BRANCH_OR_TAG=dev-cfw
- export FORCE_NO_DIRTY=yes
- rm -rf assets/resources/apps/
- rm -rf build/
- rm -rf dist/
- rm -rf .sconsign.dblite
- ./fbt COMPACT=1 DEBUG=0 updater_package
- mkdir artifacts-clean
- mv dist/f7-C/* artifacts-clean/
- ls -laS artifacts-clean
- ls -laS artifacts-clean/f7-update-${DRONE_BUILD_NUMBER}c
environment:
FBT_TOOLS_CUSTOM_LINK:
from_secret: fbt_link
- name: "Build dev default"
image: hfdj/fztools
pull: never
commands:
- export DIST_SUFFIX=${DRONE_BUILD_NUMBER}
- export WORKFLOW_BRANCH_OR_TAG=dev-cfw
- export FORCE_NO_DIRTY=yes
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-base.tgz
- tar zxvf all-the-apps-base.tgz
- cp -R base_pack_build/artifacts-base/* assets/resources/apps/
- rm -rf base_pack_build
- rm -rf all-the-apps-base.tgz
- rm -f build/f7-firmware-C/toolbox/version.*
- ./fbt COMPACT=1 DEBUG=0 updater_package
- mkdir artifacts-default
- mv dist/f7-C/* artifacts-default/
@@ -329,9 +429,10 @@ steps:
image: hfdj/fztools
pull: never
commands:
- git clone --branch dev https://github.com/xMasterX/all-the-plugins.git
- cp -R all-the-plugins/apps/* assets/resources/apps/
- rm -rf all-the-plugins
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-extra.tgz
- tar zxvf all-the-apps-extra.tgz
- cp -R extra_pack_build/artifacts-extra/* assets/resources/apps/
- rm -rf extra_pack_build
- export DIST_SUFFIX=${DRONE_BUILD_NUMBER}e
- export WORKFLOW_BRANCH_OR_TAG=dev-cfw
- export FORCE_NO_DIRTY=yes
@@ -368,6 +469,7 @@ steps:
commands:
- cp artifacts-extra-apps/flipper-z-f7-update-${DRONE_BUILD_NUMBER}e.tgz .
- cp artifacts-rgb-patch/flipper-z-f7-update-${DRONE_BUILD_NUMBER}r.tgz .
- cp artifacts-clean/flipper-z-f7-update-${DRONE_BUILD_NUMBER}c.tgz .
- cp artifacts-default/flipper-z-f7-update-${DRONE_BUILD_NUMBER}.tgz .
- rm -rf artifacts-default/f7-update-${DRONE_BUILD_NUMBER}
- ls -laS artifacts-default
@@ -440,6 +542,21 @@ steps:
from_secret: dep_target_extra
source: flipper-z-f7-update-${DRONE_BUILD_NUMBER}r.tgz
- name: "Upload clean version to updates srv"
image: appleboy/drone-scp:linux-amd64
settings:
host:
from_secret: dep_host
username:
from_secret: dep_user
password:
from_secret: dep_passwd
port:
from_secret: dep_port
target:
from_secret: dep_target_extra
source: flipper-z-f7-update-${DRONE_BUILD_NUMBER}c.tgz
- name: "Trigger update server reindex"
image: hfdj/fztools
pull: never
@@ -474,6 +591,9 @@ steps:
[-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-${DRONE_BUILD_NUMBER}.tgz&channel=dev-cfw&version=${DRONE_BUILD_NUMBER})
[-Version with only main apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-${DRONE_BUILD_NUMBER}c.tgz&channel=dev-cfw&version=${DRONE_BUILD_NUMBER}c)
[-Version with RGB patch - only for hardware mod! - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-${DRONE_BUILD_NUMBER}r.tgz&channel=dev-cfw&version=${DRONE_BUILD_NUMBER}r)
@@ -494,6 +614,18 @@ steps:
document:
- dev/flipper-z-f7-update-${DRONE_BUILD_NUMBER}.tgz
- name: "Send clean build to telegram"
image: appleboy/drone-telegram
settings:
token:
from_secret: tgtoken
to:
from_secret: tgid_dev
format: markdown
message: "Clean (Main apps only) Build:"
document:
- flipper-z-f7-update-${DRONE_BUILD_NUMBER}c.tgz
- name: "Send extra pack build to telegram"
image: appleboy/drone-telegram
settings:
@@ -515,7 +647,7 @@ steps:
commands:
- wget "https://raw.githubusercontent.com/fieu/discord.sh/e1dc1a7595efad2cad8f072f0b3531c470f5b7c8/discord.sh"
- chmod +x ./discord.sh
- ./discord.sh --text 'Unleashed firmware dev build successful!\n\nBuild - '${DRONE_BUILD_NUMBER}'\n\nCommit - https://github.com/DarkFlippers/unleashed-firmware/commit/'${DRONE_COMMIT_SHA}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[-Version with Extra apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'e.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'e)\n\n[-Version with RGB patch - only for hardware mod! - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'r.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'r)\n\n[-Version with RGB patch - only for hardware mod! - Direct download-](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'r.tgz)\n\n[-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}')'
- ./discord.sh --text 'Unleashed firmware dev build successful!\n\nBuild - '${DRONE_BUILD_NUMBER}'\n\nCommit - https://github.com/DarkFlippers/unleashed-firmware/commit/'${DRONE_COMMIT_SHA}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[-Version with Extra apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'e.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'e)\n\n[-Version with only main apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'c.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'c)\n\n[-Version with RGB patch - only for hardware mod! - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'r.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'r)\n\n[-Version with RGB patch - only for hardware mod! - Direct download-](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'r.tgz)\n\n[-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}')'
trigger:
branch:

2
.github/CODEOWNERS vendored
View File

@@ -2,4 +2,4 @@
* @xMasterX
# Assets
/assets/resources/infrared/ @xMasterX @amec0e
/assets/resources/infrared/assets/ @amec0e @Leptopt1los @xMasterX

1
.github/FUNDING.yml vendored
View File

@@ -1,3 +1,4 @@
patreon: mmxdev
custom:
[
"https://boosty.to/mmxdev",

1
.gitignore vendored
View File

@@ -51,6 +51,7 @@ null.d
/artifacts-ofw-anims
/artifacts-rgb-patch
/artifacts-extra-apps
/artifacts-clean
# SCons build dir
/build

11
.gitmodules vendored
View File

@@ -10,6 +10,7 @@
[submodule "assets/protobuf"]
path = assets/protobuf
url = https://github.com/flipperdevices/flipperzero-protobuf.git
shallow = false
[submodule "lib/libusb_stm32"]
path = lib/libusb_stm32
url = https://github.com/flipperdevices/libusb_stm32.git
@@ -25,12 +26,6 @@
[submodule "lib/cxxheaderparser"]
path = lib/cxxheaderparser
url = https://github.com/robotpy/cxxheaderparser.git
[submodule "applications/external/dap_link/lib/free-dap"]
path = applications/external/dap_link/lib/free-dap
url = https://github.com/ataradov/free-dap.git
[submodule "applications/external/subbrute"]
path = applications/external/subbrute
url = https://github.com/DarkFlippers/flipperzero-subbrute.git
[submodule "lib/heatshrink"]
path = lib/heatshrink
url = https://github.com/flipperdevices/heatshrink.git
@@ -43,3 +38,7 @@
[submodule "lib/stm32wb_copro"]
path = lib/stm32wb_copro
url = https://github.com/flipperdevices/stm32wb_copro.git
[submodule "subghz_remote"]
path = applications/main/subghz_remote
url = https://github.com/DarkFlippers/SubGHz_Remote.git
branch = ufw_main_app

View File

@@ -1 +1 @@
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -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/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/* -e applications/external/dap_link/lib/free-dap
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -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/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/*

9
.vscode/.gitignore vendored
View File

@@ -1,4 +1,5 @@
./c_cpp_properties.json
./launch.json
./settings.json
./tasks.json
/c_cpp_properties.json
/extensions.json
/launch.json
/settings.json
/tasks.json

19
.vscode/example/clangd/extensions.json vendored Normal file
View File

@@ -0,0 +1,19 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"ms-python.black-formatter",
"llvm-vs-code-extensions.vscode-clangd",
"amiralizadeh9480.cpp-helper",
"marus25.cortex-debug",
"zxh404.vscode-proto3",
"augustocdias.tasks-shell-input"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [
"twxs.cmake",
"ms-vscode.cpptools",
"ms-vscode.cmake-tools"
]
}

View File

@@ -13,6 +13,7 @@
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [
"llvm-vs-code-extensions.vscode-clangd",
"twxs.cmake",
"ms-vscode.cmake-tools"
]

View File

@@ -21,5 +21,10 @@
"SConscript": "python",
"SConstruct": "python",
"*.fam": "python",
}
}
},
"clangd.arguments": [
// We might be able to tighten this a bit more to only include the correct toolchain.
"--query-driver=**",
"--compile-commands-dir=${workspaceFolder}/build/latest"
]
}

View File

@@ -4,40 +4,40 @@
"version": "2.0.0",
"tasks": [
{
"label": "[Release] Build",
"label": "[Release] Build Firmware",
"group": "build",
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0"
},
{
"label": "[Debug] Build",
"label": "[Debug] Build Firmware",
"group": "build",
"type": "shell",
"command": "./fbt FIRMWARE_APP_SET=debug_pack"
"command": "./fbt"
},
{
"label": "[Release] Flash (ST-Link)",
"label": "[FBT] Format",
"group": "build",
"type": "shell",
"command": "./fbt format"
},
{
"label": "[FBT] Clear",
"group": "build",
"type": "shell",
"command": "./fbt -c"
},
{
"label": "[Release] Flash (SWD)",
"group": "build",
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash"
},
{
"label": "[Debug] Flash (ST-Link)",
"label": "[Debug] Flash (SWD)",
"group": "build",
"type": "shell",
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash"
},
{
"label": "[Release] Flash (blackmagic)",
"group": "build",
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_blackmagic"
},
{
"label": "[Debug] Flash (blackmagic)",
"group": "build",
"type": "shell",
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash_blackmagic"
"command": "./fbt FORCE=1 flash"
},
{
"label": "[Release] Flash (JLink)",
@@ -49,7 +49,7 @@
"label": "[Debug] Flash (JLink)",
"group": "build",
"type": "shell",
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 jflash"
"command": "./fbt FORCE=1 jflash"
},
{
"label": "[Release] Build update bundle",
@@ -61,7 +61,7 @@
"label": "[Debug] Build update bundle",
"group": "build",
"type": "shell",
"command": "./fbt FIRMWARE_APP_SET=debug_pack updater_package"
"command": "./fbt updater_package"
},
{
"label": "[Release] Build updater",
@@ -73,13 +73,13 @@
"label": "[Debug] Build updater",
"group": "build",
"type": "shell",
"command": "./fbt FIRMWARE_APP_SET=debug_pack updater_all"
"command": "./fbt updater_all"
},
{
"label": "[Debug] Flash (USB, w/o resources)",
"group": "build",
"type": "shell",
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash_usb"
"command": "./fbt FORCE=1 flash_usb"
},
{
"label": "[Release] Flash (USB, w/o resources)",
@@ -97,7 +97,7 @@
"label": "[Debug] Flash (USB, with resources)",
"group": "build",
"type": "shell",
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash_usb_full"
"command": "./fbt FORCE=1 flash_usb_full"
},
{
"label": "[Release] Flash (USB, with resources)",
@@ -123,17 +123,29 @@
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0 fap_dist"
},
{
"label": "[Debug] Build App",
"group": "build",
"type": "shell",
"command": "./fbt build APPSRC=${relativeFileDirname}"
},
{
"label": "[Release] Build App",
"group": "build",
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0 build APPSRC=${relativeFileDirname}"
},
{
"label": "[Debug] Launch App on Flipper",
"group": "build",
"type": "shell",
"command": "./fbt launch_app APPSRC=${relativeFileDirname}"
"command": "./fbt launch APPSRC=${relativeFileDirname}"
},
{
"label": "[Release] Launch App on Flipper",
"group": "build",
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0 launch_app APPSRC=${relativeFileDirname}"
"command": "./fbt COMPACT=1 DEBUG=0 launch APPSRC=${relativeFileDirname}"
},
{
"label": "[Debug] Launch App on Flipper with Serial Console",

View File

@@ -1,45 +1,41 @@
## New changes
* !!! **Warning! After installing, Desktop settings (Favoutite apps, PIN Code, AutoLock time..) will be resetted to default due to settings changes, Please set your PIN code, Favourite apps again in Settings->Desktop** !!!
* If you have copied any apps manually into `apps` folder - remove `apps` folder or that specific apps you copied on your microSD before installing this release to avoid issues due to OFW API version update! If you using regular builds or extra pack builds (e) without your manually added apps, all included apps will be installed automatically, no extra actions needed!
-----
* SubGHz: **Keeloq: Centurion Nova read and emulate support (+ add manually)**
* SubGHz: FAAC SLH - UI Fixes, Fix sending signals with no seed
* SubGHz: Code cleanup, proper handling of protocols ignore options (by @gid9798 | PR #516)
* SubGHz: Various UI fixes (by @wosk | PR #527)
* NFC: Fixed issue #532 (Mifare classic user dict - delete removes more than selected key)
* Infrared: Updated universal remote assets (by @amec0e | PR #529)
* Plugins: **Use correct categories (folders) for all plugins (extra pack too)**
* Plugins: Various fixes for uFBT (by @hedger)
* Plugins: Added **NFC Maker** plugin (make tags with URLs, Wifi and other things) [(by Willy-JL)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/external/nfc_maker)
* Plugins: Added JetPack Joyride [(by timstrasser)](https://github.com/timstrasser)
* Plugins: Moved Barcode Generator [(by Kingal1337)](https://github.com/Kingal1337/flipper-barcode-generator) from extra pack into base fw, old barcode generator was removed
* Plugins: Updated ESP32: WiFi Marauder companion plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-wifi-marauder)
* Plugins: Updated i2c Tools [(by NaejEL)](https://github.com/NaejEL/flipperzero-i2ctools)
* Settings: Change LED and volume settings by 5% steps (by @cokyrain)
* BLE: BadBT fixes and furi_hal_bt cleanup (by @Willy-JL)
* WIP OFW PR 2825: **NFC: Improved MFC emulation on some readers (by AloneLiberty)**
* OFW PR 2829: Decode only supported Oregon 3 sensor (by @wosk)
* OFW PR: Update OFW PR 2782
* OFW: SubGhz: add "SubGhz test" external application and the ability to work "SubGhz" as an external application
* OFW: API: explicitly add math.h
* OFW: NFC: Mf Ultralight emulation optimization
* OFW: Furi_Power: fix furi_hal_power_enable_otg
* OFW: FuriHal: allow nulling null isr
* OFW: FuriHal, Infrared, Protobuf: various fixes and improvements
* OFW: Picopass fix ice
* OFW: Desktop settings: show icon and name for external applications
* OFW: Furi,FuriHal: various improvements
* OFW: Debug apps: speaker, uart_echo with baudrate
* OFW: Add Mitsubishi MSZ-AP25VGK universal ac remote
* OFW: Fix roll-over in file browser and archive
* OFW: Fix fr-FR-mac keylayout
* OFW: NFC/RFID detector app
* OFW: Fast FAP Loader
* OFW: LF-RFID debug: make it work
* OFW: Fix M*LIB usage
* OFW: fix: make `dialog_file_browser_set_basic_options` initialize all fields
* OFW: Scroll acceleration
* OFW: Loader refaptoring: second encounter
* **Apple BLE Spam app** (by @Willy-JL | Plus research from ECTO-1A, xMasterX and techryptic) -> (app can be found in builds ` `, `e`, `n`, `r`)
* SubGHz: **FAAC SLH - Programming mode** (by @xMasterX & @Eng1n33r (full research and PoC by @Skorpionm)| PR #585) -> [How to use](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
* SubGHz: FAAC SLH -> Add manually new options
* SubGHz: Fix 0xFFFF counter value being skipped
* SubGHz: Fix path reset on save name scene exit
* SubGHz: Various fixes
* SubGHz Remote: Fix Sub-GHz Remote folder name (by @OperKH | PR #583)
* SubGHz Remote: submodule (by @gid9798 | PR #592)
* Infrared: Updated universal assets (by @amec0e | PR #594)
* Infrared: Remake custom universal remotes to use new design (New icons by @Svaarich)
* UI: Keyboard ok to toggle select all in cursor mode (by @Willy-JL)
* CI/CD: Fixed regular builds having `c` in version name in the device info while not being actual `c` build
* Docs: New FAAC SLH instructions
* Docs: Readme & Changelog fixes (by @gid9798 | PR #586)
* OFW: iButton: Return to the file selection if file is corrupted
* OFW: Account for the "-" in line carry-over
* OFW: github: workflow improvements
* OFW: Storage: force mount
* OFW: Add File Naming setting for more detailed naming -> **Breaking API change, API 35.x -> API 36.x** - **Update your apps!**
* OFW: Disconnect from BLE on protobuf error
* OFW: Add support for Mifare Classic 4k SAK 0x38 ATQA 0x02, 0x04, 0x08
* OFW: Undo some TODO
* OFW: Check the filetype of the update manifest
* OFW: StorageListRequest: size filter
* OFW: SubGhz: heap overflow text error
* OFW: nfc: add rfal wrong state error handling
* OFW: Rfid: fix crash on broken key launch from archive (fix was already done in UL in similar way)
* OFW: AC OFF button
* OFW: New IR universal remote graphics
* OFW: Intelligent probing with warnings for fwflash.py
* OFW: FuriHal: explicitly pull display pins at early init stage, move PUPD config to early stage
* OFW: Fix display last symbol in multiline text
* OFW: Properly reset the NFC device data
* OFW: fbt: various improvements and bug fixes
* OFW: Littlefs updated to v2.7.0
* OFW: loader: restored support for debug apps
* OFW: Removed explicit dependency on scons for external scripting
----
@@ -48,17 +44,20 @@
[-> Download qFlipper (official link)](https://flipperzero.one/update)
## Please support development of the project
* **Boosty** (patreon alternative): https://boosty.to/mmxdev
* cloudtips (only RU payments accepted): https://pay.cloudtips.ru/p/7b3e9d65
* YooMoney (only RU payments accepted): https://yoomoney.ru/fundraise/XA49mgQLPA0.221209
* USDT(TRC20): `TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`
* BCH: `qquxfyzntuqufy2dx0hrfr4sndp0tucvky4sw8qyu3`
* ETH/BSC/ERC20-Tokens: `darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)
* BTC: `bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`
* DOGE: `D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`
* LTC: `ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`
* XMR (Monero): `41xUz92suUu1u5Mu4qkrcs52gtfpu9rnZRdBpCJ244KRHf6xXSvVFevdf2cnjS7RAeYr5hn9MsEfxKoFDRSctFjG5fv1Mhn`
* TON: `EQCOqcnYkvzOZUV_9bPE_8oTbOrOF03MnF-VcJyjisTZmpGf`
|Service|Remark|Link/Wallet|
|-|-|-|
|**Patreon**||https://patreon.com/mmxdev|
|**Boosty**|patreon alternative|https://boosty.to/mmxdev|
|cloudtips|only RU payments accepted|https://pay.cloudtips.ru/p/7b3e9d65|
|YooMoney|only RU payments accepted|https://yoomoney.ru/fundraise/XA49mgQLPA0.221209|
|USDT|(TRC20)|`TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`|
|BCH||`qquxfyzntuqufy2dx0hrfr4sndp0tucvky4sw8qyu3`|
|ETH|(BSC/ERC20-Tokens)|`darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)|
|BTC||`bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`|
|DOGE||`D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`|
|LTC||`ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`|
|XMR|(Monero)| `41xUz92suUu1u5Mu4qkrcs52gtfpu9rnZRdBpCJ244KRHf6xXSvVFevdf2cnjS7RAeYr5hn9MsEfxKoFDRSctFjG5fv1Mhn`|
|TON||`EQCOqcnYkvzOZUV_9bPE_8oTbOrOF03MnF-VcJyjisTZmpGf`|
#### Thanks to our sponsors:
callmezimbra, Quen0n, MERRON, grvpvl (lvpvrg), art_col, ThurstonWaffles, Moneron, UterGrooll, LUCFER, Northpirate, zloepuzo, T.Rat, Alexey B., ionelife, ...
@@ -67,15 +66,21 @@ and all other great people who supported our project and me (xMasterX), thanks t
## **Recommended update option - Web Updater**
### What `n`, `r`, `e` means? What I need to download if I don't want to use Web updater?
What build I should download and what this name means - `flipper-z-f7-update-(version)(n / r / e).tgz` ? <br>
### What `n`, `r`, `e`, ` `, `c` means? What I need to download if I don't want to use Web updater?
What build I should download and what this name means - `flipper-z-f7-update-(version)(n / r / e / c).tgz` ? <br>
`flipper-z` = for Flipper Zero device<br>
`f7` = Hardware version - same for all flipper zero devices<br>
`update` = Update package, contains updater, all assets (plugins, IR libs, etc.), and firmware itself<br>
`(version)` = Firmware version<br>
`n` = this build comes without our custom animations (we have only 3 of them), only official flipper animations<br>
`e` = build has 🎲 [extra apps pack](https://github.com/xMasterX/all-the-plugins) preinstalled<br>
`r` = RGB patch (+ extra apps) for flippers with rgb backlight mod (this is hardware mod!) (Works only on modded flippers!) (do not install on non modded device!)
| Designation | 3 Custom Animation | [Base Apps](https://github.com/xMasterX/all-the-plugins#default-pack) | [Extra Apps](https://github.com/xMasterX/all-the-plugins#extra-pack) | ⚠RGB mode* |
|-----|:---:|:---:|:---:|:---:|
| ` ` | ✅ | ✅ | | |
| `c` | ✅ | | | |
| `n` | | ✅ | | |
| `e` | ✅ | ✅ | ✅ | |
| `r` | ✅ | ✅ | ✅ | ✅ |
This is [hardware mod](https://github.com/quen0n/flipperzero-firmware-rgb#readme), works only on modded flippers! do not install on non modded device!
Firmware Self-update package (update from microSD) - `flipper-z-f7-update-(version).tgz` for mobile app / qFlipper / web<br>
Archive of `scripts` folder (contains scripts for FW/plugins development) - `flipper-z-any-scripts-(version).tgz`<br>

276
ReadMe.md
View File

@@ -3,6 +3,20 @@
<img src="https://user-images.githubusercontent.com/10697207/186202043-26947e28-b1cc-459a-8f20-ffcc7fc0c71c.png" align="center" alt="fzCUSTOM" border="0">
</a>
</h3>
<div align="center" id="badges">
<a href="https://discord.unleashedflip.com">
<img src="https://img.shields.io/discord/937479784148115456?style=flat-square&logo=discord&label=Discord&color=%237289DA&link=https%3A%2F%2Fdiscord.unleashedflip.com%2F" alt="Discord server"/>
</a>
<a href="https://t.me/flipperzero_unofficial">
<img src="https://img.shields.io/endpoint?label=EN%20Channel&style=flat-square&url=https%3A%2F%2Fmogyo.ro%2Fquart-apis%2Ftgmembercount%3Fchat_id%3Dflipperzero_unofficial" alt="EN TG channel"/>
</a>
<a href="https://t.me/flipperzero_unofficial_ru">
<img src="https://img.shields.io/endpoint?label=RU%20Channel&style=flat-square&url=https%3A%2F%2Fmogyo.ro%2Fquart-apis%2Ftgmembercount%3Fchat_id%3Dflipperzero_unofficial_ru" alt="RU TG channel"/>
</a>
<a href="https://t.me/flipperzero_unofficial_ua">
<img src="https://img.shields.io/endpoint?label=UA%20Channel&style=flat-square&url=https%3A%2F%2Fmogyo.ro%2Fquart-apis%2Ftgmembercount%3Fchat_id%3Dflipperzero_unofficial_ua" alt="UA TG channel"/>
</a>
</div>
### Welcome to the Flipper Zero Unleashed Firmware repo!
@@ -16,13 +30,7 @@
##### This software is for experimental purposes only and is not meant for any illegal activity/purposes. <br> We do not condone illegal activity and strongly encourage keeping transmissions to legal/valid uses allowed by law. <br> Also, this software is made without any support from Flipper Devices and is in no way related to the official devs.
<br>
Our Discord Community:
<br>
<a href="https://discord.unleashedflip.com"><img src="https://discordapp.com/api/guilds/937479784148115456/widget.png?style=banner4" alt="Unofficial Discord Community" target="_blank"></a>
<br>
<br>
<br>
## Dev builds (unstable)
@@ -32,45 +40,59 @@ Our Discord Community:
- https://t.me/unleashed_fw
# What's changed
* Sub-GHz regional TX restrictions removed
* Sub-GHz frequency range can be extended in settings file (Warning: It can damage Flipper's hardware)
* Many rolling code protocols now have the ability to save & send captured signals
* FAAC SLH (Spa) & BFT Mitto (keeloq secure with seed) manual creation
* Sub-GHz static code brute-force plugin
* LFRFID Fuzzer plugin
* Custom community plugins and games added + all known working apps can be downloaded in extra pack in every release
* Extra Sub-GHz frequencies + extra Mifare Classic keys
* Picopass/iClass plugin included in releases
* Recompiled IR TV Universal Remote for ALL buttons
* Universal remote for Projectors, Fans, A/Cs and Audio(soundbars, etc.)
* Customizable Flipper name **Update! Now can be changed in Settings->Desktop** (by @xMasterX and @Willy-JL)
* Text Input UI element -> Cursor feature (by @Willy-JL)
- **BadBT** plugin (BT version of BadKB) [(by Willy-JL, ClaraCrazy, XFW contributors)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/main/bad_kb) - (See in Applications->Tools) - (aka BadUSB via Bluetooth)
- BadUSB -> Keyboard layouts [(by rien > dummy-decoy)](https://github.com/dummy-decoy/flipperzero-firmware/tree/dummy_decoy/bad_usb_keyboard_layout)
- Sub-GHz -> External CC1101 module support - [(by quen0n)](https://github.com/DarkFlippers/unleashed-firmware/pull/307)
- Sub-GHz -> `Add manually` menu extended with new protocols
- Sub-GHz -> New frequency analyzer - [(by ClusterM)](https://github.com/DarkFlippers/unleashed-firmware/pull/43)
- Sub-GHz -> Save last used frequency [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
- Sub-GHz -> Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
- Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79)
- Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107)
* Sub-GHz -> Short press OK in frequency analyzer to save detected frequency for usage in Read modes
* Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu and automatically use selected frequency
* SubGHz -> New option to use timestamps + protocol name when you saving file, instead of random name - Enable in `Radio Settings -> Time in names = ON`
* SubGHz Bruteforcer plugin -> Time delay (between signals) setting (hold Up in main screen(says Up to Save)) + configure repeats in protocols list by pressing right button on selected protocol
* SubGHz -> Read mode UI improvements (scrolling text, + shows time when signal was received) (by @wosk)
* Sub-GHz -> External CC1101 module support (Hardware SPI used)
* SubGHz -> **Hold right in received signal list to delete selected signal**
* SubGHz -> **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S / Somfy Telis / Security+ 2.0 / CAME Atomo** - now you can use arrow buttons to send signal with different button code
* SubGHz -> BFT Mitto / Somfy Telis / Nice Flor S / CAME Atomo, etc.. manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis)
* SubGHz -> Debug mode counter increase settings (+1 -> +5, +10, default: +1)
* SubGHz -> Debug PIN output settings for protocol development
* Infrared -> `RCA` Protocol
* Infrared -> Debug TX PIN output settings
* Other small fixes and changes throughout
* See other changes in readme below
- **Sub-GHz** *lib & hal*
- Regional TX restrictions removed
- Extra Sub-GHz frequencies
- Frequency range can be extended in settings file (Warning: It can damage Flipper's hardware)
- Many rolling code [protocols](https://github.com/DarkFlippers/unleashed-firmware#current-modified-and-new-sub-ghz-protocols-list) now have the ability to save & send captured signals
- FAAC SLH (Spa) & BFT Mitto (keeloq secure with seed) manual creation
- External CC1101 module support [(by quen0n)](https://github.com/DarkFlippers/unleashed-firmware/pull/307)
- **Sub-GHz** *Main App*
- Save last used frequency [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
- New frequency analyzer [(by ClusterM)](https://github.com/DarkFlippers/unleashed-firmware/pull/43)
- Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
- Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79)
- New option to use timestamps + protocol name when you saving file, instead of random name - Enable in `Radio Settings -> Time in names = ON`
- Read mode UI improvements (shows time when signal was received) (by @wosk)
- External CC1101 module support (Hardware SPI used)
- **Hold right in received signal list to delete selected signal**
- **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S / Somfy Telis / Security+ 2.0 / CAME Atomo** - now you can use arrow buttons to send signal with different button code
- `Add manually` menu extended with new protocols
- FAAC SLH, BFT Mitto / Somfy Telis / Nice Flor S / CAME Atomo, etc.. manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis)
- Debug mode counter increase settings (+1 -> +5, +10, default: +1)
- Debug PIN output settings for protocol development
- **Sub-GHz apps** *by unleashed team*
- Sub-GHz Bruteforce - static code brute-force plugin |
- Time delay (between signals) setting (hold Up in main screen(says Up to Save)) + configure repeats in protocols list by pressing right button on selected protocol
- Load your own file and select bytes you want to bruteforce or use preconfigured options in protocols list
- Sub-GHz Remote - remote control for 5 sub-ghz files | bind one file for each button
- use the built-in constructor or make config file by following this [instruction](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)
- **Infrared**
- Recompiled IR TV Universal Remote for ALL buttons
- Universal remotes for Projectors, Fans, A/Cs and Audio(soundbars, etc.) -> Also always updated and verified by our team
- Infrared -> `RCA` Protocol
- Infrared -> Debug TX PIN output settings
- **NFC/RFID/iButton**
* LFRFID/iButton Fuzzer plugins
* Extra Mifare Classic keys
* `Add manually` -> Mifare Classic with custom UID
* Picopass/iClass plugin (now with emulation support!) included in releases
- **Quality of life & other features**
- Customizable Flipper name **Update! Now can be changed in Settings->Desktop** (by @xMasterX and @Willy-JL)
- Text Input UI element -> Cursor feature (by @Willy-JL)
- Byte Input Mini editor -> **Press UP** multiple times until the nibble editor appears
- Clock on Desktop -> `Settings -> Desktop -> Show Clock`
- Battery percentage display with different styles `Settings -> Desktop -> Battery View`
- More games in Dummy Mode -> click or hold any of arrow buttons
- Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107)
- **BadBT** plugin (BT version of BadKB) [(by Willy-JL, ClaraCrazy, XFW contributors)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/main/bad_kb) - (See in Applications->Tools) - (aka BadUSB via Bluetooth)
- BadUSB -> Keyboard layouts [(by rien > dummy-decoy)](https://github.com/dummy-decoy/flipperzero-firmware/tree/dummy_decoy/bad_usb_keyboard_layout)
- Custom community plugins and games added + all known working apps can be downloaded in extra pack in every release
- Other small fixes and changes throughout
- See other changes in readme below
Also check the changelog in releases for latest updates!
Also check the [changelog in releases](https://github.com/DarkFlippers/unleashed-firmware/releases) for latest updates!
### Current modified and new Sub-GHz protocols list:
Thanks to Official team (to their SubGHz Developer, Skorp) for implementing decoders for these protocols in OFW.
@@ -98,8 +120,8 @@ Encoders or sending made by @xMasterX:
Encoders or sending made by @Eng1n33r(first implementation in Q2 2022) & @xMasterX (current version):
- CAME Atomo -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- Nice Flor S -> How to create new remote - [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- FAAC SLH (Spa) [External seed calculation required (For info contact me in Discord: @mmx7)]
- Keeloq: BFT Mitto -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- FAAC SLH (Spa) -> Update!!! Check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- Keeloq: BFT Mitto -> Update! Check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- Star Line
- Security+ v1 & v2 (encoders was made in OFW)
@@ -114,143 +136,109 @@ Encoders made by @assasinfil & @xMasterX:
The majority of this project is developed and maintained by me, @xMasterX.
I'm unemployed, and the only income I receive is from your donations.
Our team is small and the guys are working on this project as much as they can solely based on the enthusiasm they have for this project and the community.
- @assasinfil - SubGHz
- @gid9798 - SubGHz, Plugins, many other things
- @assasinfil - SubGHz protocols
- @Svaarich - UI design and animations
- @Amec0e - Infrared assets
- @amec0e & @Leptopt1los - Infrared assets
- Community moderators in Telegram, Discord, and Reddit
- And of course our GitHub community. Your PRs are a very important part of this firmware and open-source development.
The amount of work done on this project is huge and we need your support, no matter how large or small. Even if you just say, "Thank you Unleashed firmware developers!" somewhere. Doing so will help us continue our work and will help drive us to make the firmware better every time.
Also, regarding our releases, every build has and always will be free and open-source. There will be no paywall releases or closed-source apps within the firmware. As long as I am working on this project it will never happen.
You can support us by using links or addresses below:
* **Boosty** (patreon alternative): https://boosty.to/mmxdev
* cloudtips (only RU payments accepted): https://pay.cloudtips.ru/p/7b3e9d65
* YooMoney (only RU payments accepted): https://yoomoney.ru/fundraise/XA49mgQLPA0.221209
* USDT(TRC20): `TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`
* BCH: `qquxfyzntuqufy2dx0hrfr4sndp0tucvky4sw8qyu3`
* ETH/BSC/ERC20-Tokens: `darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)
* BTC: `bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`
* DOGE: `D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`
* LTC: `ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`
* XMR (Monero): `41xUz92suUu1u5Mu4qkrcs52gtfpu9rnZRdBpCJ244KRHf6xXSvVFevdf2cnjS7RAeYr5hn9MsEfxKoFDRSctFjG5fv1Mhn`
* TON: `EQCOqcnYkvzOZUV_9bPE_8oTbOrOF03MnF-VcJyjisTZmpGf`
|Service|Remark|Link/Wallet|
|-|-|-|
|**Patreon**||https://patreon.com/mmxdev|
|**Boosty**|patreon alternative|https://boosty.to/mmxdev|
|cloudtips|only RU payments accepted|https://pay.cloudtips.ru/p/7b3e9d65|
|YooMoney|only RU payments accepted|https://yoomoney.ru/fundraise/XA49mgQLPA0.221209|
|USDT|(TRC20)|`TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs`|
|BCH||`qquxfyzntuqufy2dx0hrfr4sndp0tucvky4sw8qyu3`|
|ETH|(BSC/ERC20-Tokens)|`darkflippers.eth` (or `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a`)|
|BTC||`bc1q0np836jk9jwr4dd7p6qv66d04vamtqkxrecck9`|
|DOGE||`D6R6gYgBn5LwTNmPyvAQR6bZ9EtGgFCpvv`|
|LTC||`ltc1q3ex4ejkl0xpx3znwrmth4lyuadr5qgv8tmq8z9`|
|XMR|(Monero)| `41xUz92suUu1u5Mu4qkrcs52gtfpu9rnZRdBpCJ244KRHf6xXSvVFevdf2cnjS7RAeYr5hn9MsEfxKoFDRSctFjG5fv1Mhn`|
|TON||`EQCOqcnYkvzOZUV_9bPE_8oTbOrOF03MnF-VcJyjisTZmpGf`|
### Community apps included:
## Community apps included
- **RFID Fuzzer** [(by @gid9798)](https://github.com/DarkFlippers/unleashed-firmware/pull/507) (original by Ganapati & xMasterX)
- **iButton Fuzzer** [(by @gid9798)](https://github.com/DarkFlippers/unleashed-firmware/pull/507) (original by xMasterX)
- **Sub-GHz bruteforcer** [(by @derskythe & xMasterX)](https://github.com/derskythe/flipperzero-subbrute) [(original by Ganapati & xMasterX)](https://github.com/DarkFlippers/unleashed-firmware/pull/57)
- **Sub-GHz playlist** [(by darmiel)](https://github.com/DarkFlippers/unleashed-firmware/pull/62)
- 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)
- MultiConverter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff)
- WAV Player [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player) - Fixed and improved by [LTVA1](https://github.com/LTVA1/wav_player) -> Also outputs audio on `PA6` - `3(A6)` pin
- Barcode Generator [(by Kingal1337)](https://github.com/Kingal1337/flipper-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-wifi-marauder) - Saving .pcap on flipper microSD [by tcpassos](https://github.com/tcpassos/flipperzero-firmware-with-wifi-marauder-companion) -> Only with custom marauder build (It is necessary to uncomment "#define WRITE_PACKETS_SERIAL" in configs.h (in marauder fw) and compile the firmware for the wifi board.) Or download precompiled build -> [Download esp32_marauder_ver_flipper_sd_serial.bin](https://github.com/justcallmekoko/ESP32Marauder/releases/latest)
- NRF24: Sniffer & MouseJacker (with changes) [(by mothball187)](https://github.com/mothball187/flipperzero-nrf24/tree/main/mousejacker)
- Simple Clock (timer by GMMan) [(original by CompaqDisc)](https://gist.github.com/CompaqDisc/4e329c501bd03c1e801849b81f48ea61)
- **Sub-GHz Remote** [(by @gid9798)](https://github.com/gid9798)
- 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)
- Metronome [(by panki27)](https://github.com/panki27/Metronome)
- DTMF Dolphin [(by litui)](https://github.com/litui/dtmf_dolphin)
- **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator)
- GPS [(by ezod)](https://github.com/ezod/flipperzero-gps) works with module `NMEA 0183` via UART (13TX, 14RX, GND pins on Flipper)
- i2c Tools [(by NaejEL)](https://github.com/NaejEL/flipperzero-i2ctools) - C0 -> SCL / C1 -> SDA / GND -> GND | 3v3 logic levels only!
- HC-SR04 Distance sensor - Ported and modified by @xMasterX [(original by Sanqui)](https://github.com/Sanqui/flipperzero-firmware/tree/hc_sr04) - How to connect -> (5V -> VCC) / (GND -> GND) / (13|TX -> Trig) / (14|RX -> Echo)
- Morse Code [(by wh00hw)](https://github.com/wh00hw/MorseCodeFAP)
- **Unitemp - Temperature sensors reader** (DHT11/22, DS18B20, BMP280, HTU21x and more) [(by quen0n)](https://github.com/quen0n/unitemp-flipperzero)
- BH1750 - Lightmeter [(by oleksiikutuzov)](https://github.com/oleksiikutuzov/flipperzero-lightmeter)
- HEX Viewer [(by QtRoS)](https://github.com/QtRoS/flipper-zero-hex-viewer)
- POCSAG Pager [(by xMasterX & Shmuma)](https://github.com/xMasterX/flipper-pager)
- Text Viewer [(by kowalski7cc & kyhwana)](https://github.com/kowalski7cc/flipper-zero-text-viewer/tree/refactor-text-app)
- **UART Terminal** [(by cool4uma)](https://github.com/cool4uma/UART_Terminal/tree/main)
- **ProtoView** [(by antirez)](https://github.com/antirez/protoview)
- **SWD Probe** [(by g3gg0)](https://github.com/g3gg0/flipper-swd_probe)
- IR Scope [(by kallanreed)](https://github.com/DarkFlippers/unleashed-firmware/pull/407)
- **BadBT** plugin (BT version of BadKB) [(by Willy-JL, ClaraCrazy, XFW contributors)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/main/bad_kb) (See in Applications->Tools) - (aka BadUSB via Bluetooth)
- **Mifare Nested** [(by AloneLiberty)](https://github.com/AloneLiberty/FlipperNested) - Works with PC and python app `FlipperNested`
- **NFC Maker** plugin (make tags with URLs, Wifi and other things) [(by Willy-JL)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/external/nfc_maker)
### [🎲 Download Extra plugins for Unleashed](https://github.com/xMasterX/all-the-plugins/releases/latest)
### [List of Extra pack](https://github.com/xMasterX/all-the-plugins/tree/dev#extra-pack) | [List of Base *(Deafult)* pack](https://github.com/xMasterX/all-the-plugins/tree/dev#default-pack)
Games:
- DOOM (fixed) [(by p4nic4ttack)](https://github.com/p4nic4ttack/doom-flipper-zero/)
- Zombiez [(Reworked By DevMilanIan)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/240) [(Original By Dooskington)](https://github.com/Dooskington/flipperzero-zombiez)
- Flappy Bird [(by DroomOne)](https://github.com/DroomOne/flipperzero-firmware/tree/dev/applications/flappy_bird)
- Arkanoid (refactored by xMasterX) [(by gotnull)](https://github.com/gotnull/flipperzero-firmware-wPlugins)
- Tic Tac Toe (refactored by xMasterX) [(by gotnull)](https://github.com/gotnull/flipperzero-firmware-wPlugins)
- Tetris (with fixes) [(by jeffplang)](https://github.com/jeffplang/flipperzero-firmware/tree/tetris_game/applications/tetris_game)
- Minesweeper [(by panki27)](https://github.com/panki27/minesweeper)
- Heap Defence (aka Stack Attack) - Ported to latest firmware by @xMasterX - [(original by wquinoa & Vedmein)](https://github.com/Vedmein/flipperzero-firmware/tree/hd/svisto-perdelki)
- Game15 [(by x27)](https://github.com/x27/flipperzero-game15)
- Solitaire [(by teeebor)](https://github.com/teeebor/flipper_games)
- BlackJack [(by teeebor)](https://github.com/teeebor/flipper_games)
- 2048 game [(by eugene-kirzhanov)](https://github.com/eugene-kirzhanov/flipper-zero-2048-game)
- Bomberduck [(by leo-need-more-coffee)](https://github.com/leo-need-more-coffee/flipperzero-bomberduck)
- JetPack Joyride [(by timstrasser)](https://github.com/timstrasser)
See full list and sources here: [xMasterX/all-the-plugin](https://github.com/xMasterX/all-the-plugins/tree/dev)
### Official Flipper Zero Apps Catalog [web version](https://lab.flipper.net/apps) or mobile app
# Instructions
## [- How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)
## First lock official docs [docs.flipper.net](https://docs.flipper.net/)
## [How to install](/documentation/HowToInstall.md) - [versions info](/CHANGELOG.md#what-n-r-e--c-means-what-i-need-to-download-if-i-dont-want-to-use-web-updater): `n`,` `,`e`...
## Firmware & Development
## [- How to build firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToBuild.md)
### - **[How to build](/documentation/HowToBuild.md#how-to-build-by-yourself) | [Project-structure](#project-structure)**
## [- How to connect external CC1101 module](https://github.com/quen0n/flipperzero-ext-cc1101)
### - **CLion IDE** - How to setup workspace for flipper firmware development [by Savely Krasovsky](https://krasovs.ky/2022/11/01/flipper-zero-clion.html)
## [- BadUSB: how to add new keyboard layouts](https://github.com/dummy-decoy/flipperzero_badusb_kl)
### - **"Hello world!"** - plugin tutorial [English<sub> by DroomOne</sub> ](https://github.com/DroomOne/Flipper-Plugin-Tutorial) | [Russian<sub> by Pavel Yakovlev</sub>](https://yakovlev.me/hello-flipper-zero/)
## [- How to change Flipper name](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/CustomFlipperName.md)
### - [How to write your own app](https://flipper.atmanos.com/docs/overview/intro). Docs by atmanos **⚠outdated API**
## [- How to use Mifare Nested plugin to recover keys](https://github.com/AloneLiberty/FlipperNested#how-to-use-it)
## Firmware & main Apps feature
## [- How to make captures to add them into Universal IR remotes](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/InfraredCaptures.md)
### - System: [How to change Flipper name](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/CustomFlipperName.md)
### **Sub-GHz**
### - BadUSB: [How to add new keyboard layouts](https://github.com/dummy-decoy/flipperzero_badusb_kl)
## [- Transmission is blocked? - How to extend Sub-GHz frequency range](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md)
### - Infrared: [How to make captures to add them into Universal IR remotes](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/InfraredCaptures.md)
## [- How to add extra Sub-GHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md)
## **Sub-GHz**
## [- How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis, Aprimatic, AN-Motors, etc..)](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
### - External Radio: [How to connect CC1101 module](https://github.com/quen0n/flipperzero-ext-cc1101)
## [- Configure Sub-GHz Remote App](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)
### - Transmission is blocked? [How to extend Sub-GHz frequency range](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md)
### **Plugins**
### - [How to add extra Sub-GHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md)
## [- 🎲 Download Extra plugins for Unleashed](https://github.com/xMasterX/all-the-plugins)
### - [How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis, Aprimatic, AN-Motors, etc..)](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
## [- TOTP (Authenticator) config description](https://github.com/akopachov/flipper-zero_authenticator/blob/master/docs/conf-file_description.md)
### - [~~Configure Sub-GHz Remote App~~](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md) Not recomeded, please use embedded configurator
## [- Barcode Generator](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/BarcodeGenerator.md)
## **Plugins**
## [- Multi Converter](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/MultiConverter.md)
### - TOTP (Authenticator): [config description](https://github.com/akopachov/flipper-zero_authenticator/blob/master/docs/conf-file_description.md)
## [- WAV Player sample files & how to convert](https://github.com/UberGuidoZ/Flipper/tree/main/Wav_Player#readme)
### - Mifare Nested plugin: [How to recover keys](https://github.com/AloneLiberty/FlipperNested#how-to-use-it)
## [- Sub-GHz playlist generator script](https://github.com/darmiel/flipper-scripts/blob/main/playlist/playlist_creator_by_chunk.py)
### - Barcode Generator: [How to use](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/BarcodeGenerator.md)
### **Plugins that works with external hardware**
### - Multi Converter: [How to use](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/MultiConverter.md)
## [- How to use: Unitemp - Temperature sensors reader](https://github.com/quen0n/unitemp-flipperzero#readme)
### - WAV Player: [sample files & how to convert](https://github.com/UberGuidoZ/Flipper/tree/main/Wav_Player#readme)
## [- How to use: [NMEA] GPS](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/applications/external/gps_nmea_uart/README.md)
### - Sub-GHz playlist: [generator script](https://github.com/darmiel/flipper-scripts/blob/main/playlist/playlist_creator_by_chunk.py)
## [- How to use: i2c Tools](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/applications/external/flipper_i2ctools/README.md)
## **Plugins that works with external hardware** [GPIO]
## [- How to use: [NRF24] plugins](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/NRF24.md)
### - Unitemp - Temperature sensors reader: [How to use & supported sensors](https://github.com/quen0n/unitemp-flipperzero#readme)
## [- How to use: [WiFi] Scanner](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module#readme)
### - [NMEA] GPS: [How to use](https://github.com/xMasterX/all-the-plugins/blob/dev/base_pack/gps_nmea_uart/README.md)
## [- How to use: [ESP8266] Deauther](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module#readme)
### - i2c Tools [How to use](https://github.com/xMasterX/all-the-plugins/blob/dev/base_pack/flipper_i2ctools/README.md)
## [- How to use: [ESP32] WiFi Marauder](https://github.com/UberGuidoZ/Flipper/tree/main/Wifi_DevBoard)
### - [NRF24] plugins: [How to use](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/NRF24.md)
## [- [WiFi] Scanner - Web Flasher for module firmware](https://sequoiasan.github.io/FlipperZero-WiFi-Scanner_Module/)
## [- [ESP8266] Deauther - Web Flasher for module firmware](https://sequoiasan.github.io/FlipperZero-Wifi-ESP8266-Deauther-Module/)
### - [WiFi] Scanner: [How to use](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module#readme) | [Web Flasher](https://sequoiasan.github.io/FlipperZero-WiFi-Scanner_Module/)
## [- Windows: How to Upload .bin to ESP32/ESP8266](https://github.com/SequoiaSan/Guide-How-To-Upload-bin-to-ESP8266-ESP32)
### - [ESP8266] Deauther: [How to use](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module#readme) | [Web Flasher](https://sequoiasan.github.io/FlipperZero-Wifi-ESP8266-Deauther-Module/)
## [- How to use: [GPIO] SentrySafe plugin](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SentrySafe.md)
### - [ESP32] WiFi Marauder: [How to use](https://github.com/UberGuidoZ/Flipper/tree/main/Wifi_DevBoard)<sub> docs by UberGuidoZ</sub> | [Marauder repo](https://github.com/justcallmekoko/ESP32Marauder)
### - [ESP32-CAM] Camera Suite: [How to use](https://github.com/CodyTolene/Flipper-Zero-Camera-Suite)
### - How to Upload `.bin` to ESP32/ESP8266: [Windows](https://github.com/SequoiaSan/Guide-How-To-Upload-bin-to-ESP8266-ESP32) | [FAP "ESP flasher"](https://github.com/0xchocolate/flipperzero-esp-flasher)
### - [GPIO] SentrySafe plugin: [How to use](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SentrySafe.md)
<br>
<br>
@@ -264,13 +252,7 @@ Games:
# Links
* Unofficial Discord: [discord.unleashedflip.com](https://discord.unleashedflip.com)
* Hello world - plugin tutorial (English): [https://github.com/DroomOne/Flipper-Plugin-Tutorial](https://github.com/DroomOne/Flipper-Plugin-Tutorial)
* Hello world - plugin tutorial (in Russian): [https://yakovlev.me/hello-flipper-zero/](https://yakovlev.me/hello-flipper-zero/)
* CLion IDE - How to setup workspace for flipper firmware development: [https://krasovs.ky/2022/11/01/flipper-zero-clion.html](https://krasovs.ky/2022/11/01/flipper-zero-clion.html)
* Docs by atmanos / How to write your own app (outdated API): [https://flipper.atmanos.com/docs/overview/intro](https://flipper.atmanos.com/docs/overview/intro)
* Official Docs: [http://docs.flipperzero.one](http://docs.flipperzero.one)
* Official Docs: [docs.flipper.net](https://docs.flipper.net/)
* Official Forum: [forum.flipperzero.one](https://forum.flipperzero.one/)
# Project structure

View File

@@ -45,6 +45,7 @@ distenv = coreenv.Clone(
],
ENV=os.environ,
UPDATE_BUNDLE_DIR="dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}",
VSCODE_LANG_SERVER=ARGUMENTS.get("LANG_SERVER", "cpptools"),
)
firmware_env = distenv.AddFwProject(
@@ -184,27 +185,15 @@ copro_dist = distenv.CoproBuilder(
distenv.AlwaysBuild(copro_dist)
distenv.Alias("copro_dist", copro_dist)
firmware_flash = distenv.AddOpenOCDFlashTarget(firmware_env)
firmware_flash = distenv.AddFwFlashTarget(firmware_env)
distenv.Alias("flash", firmware_flash)
# To be implemented in fwflash.py
firmware_jflash = distenv.AddJFlashTarget(firmware_env)
distenv.Alias("jflash", firmware_jflash)
firmware_bm_flash = distenv.PhonyTarget(
"flash_blackmagic",
"$GDB $GDBOPTS $SOURCES $GDBFLASH",
source=firmware_env["FW_ELF"],
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
GDBREMOTE="${BLACKMAGIC_ADDR}",
GDBFLASH=[
"-ex",
"load",
"-ex",
"quit",
],
)
gdb_backtrace_all_threads = distenv.PhonyTarget(
distenv.PhonyTarget(
"gdb_trace_all",
"$GDB $GDBOPTS $SOURCES $GDBFLASH",
source=firmware_env["FW_ELF"],
@@ -327,6 +316,9 @@ distenv.PhonyTarget(
"cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py -p ${FLIP_PORT}"
)
# Update WiFi devboard firmware
distenv.PhonyTarget("devboard_flash", "${PYTHON3} ${FBT_SCRIPT_DIR}/wifi_board.py")
# Find blackmagic probe
distenv.PhonyTarget(
@@ -345,7 +337,14 @@ distenv.PhonyTarget(
)
# Prepare vscode environment
vscode_dist = distenv.Install("#.vscode", distenv.Glob("#.vscode/example/*"))
VSCODE_LANG_SERVER = cmd_environment["LANG_SERVER"]
vscode_dist = distenv.Install(
"#.vscode",
[
distenv.Glob("#.vscode/example/*.json"),
distenv.Glob(f"#.vscode/example/{VSCODE_LANG_SERVER}/*.json"),
],
)
distenv.Precious(vscode_dist)
distenv.NoClean(vscode_dist)
distenv.Alias("vscode_dist", vscode_dist)

View File

@@ -35,21 +35,6 @@ Applications for main Flipper menu.
- `u2f` - U2F Application
## External
External applications deployed to SD Card
- `clock` - Clock application
- `dap_link` - DAP Link OnChip debugger
- `hid_app` - USB/BT Remote controller
- `music_player` - Music player app (demo)
- `nfc_magic` - NFC MFC Magic card application
- `picopass` - Picopass reader / writer
- `signal_generator` - Signal generator app: PWM and clock generator
- `snake_game` - Snake game application
- `spi_mem_manager` - SPI Memory reader / flasher
- `weather_station` - SubGHz weather station
## services
Background services providing system APIs to applications.

View File

@@ -174,7 +174,7 @@ bool WIEGAND::DoWiegandConversion() {
return false;
}
// TODO: Handle validation failure case!
// TODO FL-3490: Handle validation failure case!
} else if(4 == _bitCount) {
// 4-bit Wiegand codes have no data integrity check so we just
// read the LOW nibble.

View File

@@ -12,6 +12,7 @@ struct SubGhzTestCarrier {
View* view;
FuriTimer* timer;
SubGhzTestCarrierCallback callback;
// const SubGhzDevice* radio_device;
void* context;
};
@@ -84,6 +85,7 @@ void subghz_test_carrier_draw(Canvas* canvas, SubGhzTestCarrierModel* model) {
bool subghz_test_carrier_input(InputEvent* event, void* context) {
furi_assert(context);
SubGhzTestCarrier* subghz_test_carrier = context;
// const SubGhzDevice* radio_device = subghz_test_carrier->radio_device;
if(event->key == InputKeyBack || event->type != InputTypeShort) {
return false;
@@ -94,6 +96,7 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
SubGhzTestCarrierModel * model,
{
furi_hal_subghz_idle();
// subghz_devices_idle(radio_device);
if(event->key == InputKeyLeft) {
if(model->frequency > 0) model->frequency--;
@@ -114,10 +117,18 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
model->real_frequency =
furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
furi_hal_subghz_set_path(model->path);
// model->real_frequency = subghz_devices_set_frequency(
// radio_device, subghz_frequencies_testing[model->frequency]);
if(model->status == SubGhzTestCarrierModelStatusRx) {
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
furi_hal_subghz_rx();
// furi_hal_gpio_init(
// subghz_devices_get_data_gpio(radio_device),
// GpioModeInput,
// GpioPullNo,
// GpioSpeedLow);
// subghz_devices_set_rx(radio_device);
} else {
furi_hal_gpio_init(
&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
@@ -127,6 +138,15 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
subghz_test_carrier->callback(
SubGhzTestCarrierEventOnlyRx, subghz_test_carrier->context);
}
// if(!subghz_devices_set_tx(radio_device)) {
// furi_hal_gpio_init(
// subghz_devices_get_data_gpio(radio_device),
// GpioModeInput,
// GpioPullNo,
// GpioSpeedLow);
// subghz_test_carrier->callback(
// SubGhzTestCarrierEventOnlyRx, subghz_test_carrier->context);
// }
}
},
true);
@@ -137,12 +157,20 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
void subghz_test_carrier_enter(void* context) {
furi_assert(context);
SubGhzTestCarrier* subghz_test_carrier = context;
// furi_assert(subghz_test_carrier->radio_device);
// const SubGhzDevice* radio_device = subghz_test_carrier->radio_device;
furi_hal_subghz_reset();
furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs);
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
// subghz_devices_reset(radio_device);
// subghz_devices_load_preset(radio_device, FuriHalSubGhzPresetOok650Async, NULL);
// furi_hal_gpio_init(
// subghz_devices_get_data_gpio(radio_device), GpioModeInput, GpioPullNo, GpioSpeedLow);
with_view_model(
subghz_test_carrier->view,
SubGhzTestCarrierModel * model,
@@ -150,6 +178,8 @@ void subghz_test_carrier_enter(void* context) {
model->frequency = subghz_frequencies_433_92_testing; // 433
model->real_frequency =
furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
// model->real_frequency = subghz_devices_set_frequency(
// radio_device, subghz_frequencies_testing[model->frequency]);
model->path = FuriHalSubGhzPathIsolate; // isolate
model->rssi = 0.0f;
model->status = SubGhzTestCarrierModelStatusRx;
@@ -157,6 +187,7 @@ void subghz_test_carrier_enter(void* context) {
true);
furi_hal_subghz_rx();
// subghz_devices_set_rx(radio_device);
furi_timer_start(subghz_test_carrier->timer, furi_kernel_get_tick_frequency() / 4);
}
@@ -169,6 +200,7 @@ void subghz_test_carrier_exit(void* context) {
// Reinitialize IC to default state
furi_hal_subghz_sleep();
// subghz_devices_sleep(subghz_test_carrier->radio_device);
}
void subghz_test_carrier_rssi_timer_callback(void* context) {
@@ -181,6 +213,7 @@ void subghz_test_carrier_rssi_timer_callback(void* context) {
{
if(model->status == SubGhzTestCarrierModelStatusRx) {
model->rssi = furi_hal_subghz_get_rssi();
// model->rssi = subghz_devices_get_rssi(subghz_test_carrier->radio_device);
}
},
false);
@@ -216,3 +249,10 @@ View* subghz_test_carrier_get_view(SubGhzTestCarrier* subghz_test_carrier) {
furi_assert(subghz_test_carrier);
return subghz_test_carrier->view;
}
// void subghz_test_carrier_set_radio(
// SubGhzTestCarrier* subghz_test_carrier,
// const SubGhzDevice* radio_device) {
// furi_assert(subghz_test_carrier);
// subghz_test_carrier->radio_device = radio_device;
// }

View File

@@ -1,6 +1,7 @@
#pragma once
#include <gui/view.h>
// #include <lib/subghz/devices/devices.h>
typedef enum {
SubGhzTestCarrierEventOnlyRx,
@@ -20,3 +21,7 @@ SubGhzTestCarrier* subghz_test_carrier_alloc();
void subghz_test_carrier_free(SubGhzTestCarrier* subghz_test_carrier);
View* subghz_test_carrier_get_view(SubGhzTestCarrier* subghz_test_carrier);
// void subghz_test_carrier_set_radio(
// SubGhzTestCarrier* subghz_test_carrier,
// const SubGhzDevice* radio_device);

View File

@@ -56,7 +56,6 @@ static void subghz_test_packet_rx_callback(bool level, uint32_t duration, void*
subghz_decoder_princeton_for_testing_parse(instance->decoder, level, duration);
}
//todo
static void subghz_test_packet_rx_pt_callback(SubGhzDecoderPrinceton* parser, void* context) {
UNUSED(parser);
furi_assert(context);

View File

@@ -3,6 +3,7 @@ App(
apptype=FlipperAppType.STARTUP,
entry_point="unit_tests_on_system_start",
cdefines=["APP_UNIT_TESTS"],
requires=["system_settings"],
provides=["delay_test"],
order=100,
)

View File

@@ -26,7 +26,6 @@ void test_furi_memmgr() {
mu_assert_int_eq(66, ((uint8_t*)ptr)[i]);
}
// TODO: fix realloc to copy only old size, and write testcase that leftover of reallocated memory is zero-initialized
free(ptr);
// allocate and zero-initialize array (calloc)

View File

@@ -69,7 +69,7 @@ MU_TEST(mu_test_furi_string_mem) {
mu_check(string != NULL);
mu_check(!furi_string_empty(string));
// TODO: how to test furi_string_reserve?
// TODO FL-3493: how to test furi_string_reserve?
// test furi_string_reset
furi_string_reset(string);

View File

@@ -0,0 +1,602 @@
#include <stdio.h>
#include <furi.h>
#include <furi_hal.h>
#include "../minunit.h"
static const uint8_t key_ctr_1[32] = {
0x77, 0x6B, 0xEF, 0xF2, 0x85, 0x1D, 0xB0, 0x6F, 0x4C, 0x8A, 0x05, 0x42, 0xC8, 0x69, 0x6F, 0x6C,
0x6A, 0x81, 0xAF, 0x1E, 0xEC, 0x96, 0xB4, 0xD3, 0x7F, 0xC1, 0xD6, 0x89, 0xE6, 0xC1, 0xC1, 0x04,
};
static const uint8_t iv_ctr_1[16] = {
0x00,
0x00,
0x00,
0x60,
0xDB,
0x56,
0x72,
0xC9,
0x7A,
0xA8,
0xF0,
0xB2,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_1[16] = {
0x53,
0x69,
0x6E,
0x67,
0x6C,
0x65,
0x20,
0x62,
0x6C,
0x6F,
0x63,
0x6B,
0x20,
0x6D,
0x73,
0x67,
};
static const uint8_t tv_ctr_ct_1[16] = {
0x14,
0x5A,
0xD0,
0x1D,
0xBF,
0x82,
0x4E,
0xC7,
0x56,
0x08,
0x63,
0xDC,
0x71,
0xE3,
0xE0,
0xC0,
};
static const uint8_t key_ctr_2[32] = {
0x77, 0x6B, 0xEF, 0xF2, 0x85, 0x1D, 0xB0, 0x6F, 0x4C, 0x8A, 0x05, 0x42, 0xC8, 0x69, 0x6F, 0x6C,
0x6A, 0x81, 0xAF, 0x1E, 0xEC, 0x96, 0xB4, 0xD3, 0x7F, 0xC1, 0xD6, 0x89, 0xE6, 0xC1, 0xC1, 0x04,
};
static const uint8_t iv_ctr_2[16] = {
0x00,
0x00,
0x00,
0x60,
0xDB,
0x56,
0x72,
0xC9,
0x7A,
0xA8,
0xF0,
0xB2,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_2[0] = {};
//static const uint8_t tv_ctr_ct_2[0] = {};
static const uint8_t key_ctr_3[32] = {
0xF6, 0xD6, 0x6D, 0x6B, 0xD5, 0x2D, 0x59, 0xBB, 0x07, 0x96, 0x36, 0x58, 0x79, 0xEF, 0xF8, 0x86,
0xC6, 0x6D, 0xD5, 0x1A, 0x5B, 0x6A, 0x99, 0x74, 0x4B, 0x50, 0x59, 0x0C, 0x87, 0xA2, 0x38, 0x84,
};
static const uint8_t iv_ctr_3[16] = {
0x00,
0xFA,
0xAC,
0x24,
0xC1,
0x58,
0x5E,
0xF1,
0x5A,
0x43,
0xD8,
0x75,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_3[32] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
};
static const uint8_t tv_ctr_ct_3[32] = {
0xF0, 0x5E, 0x23, 0x1B, 0x38, 0x94, 0x61, 0x2C, 0x49, 0xEE, 0x00, 0x0B, 0x80, 0x4E, 0xB2, 0xA9,
0xB8, 0x30, 0x6B, 0x50, 0x8F, 0x83, 0x9D, 0x6A, 0x55, 0x30, 0x83, 0x1D, 0x93, 0x44, 0xAF, 0x1C,
};
static const uint8_t key_ctr_4[32] = {
0xFF, 0x7A, 0x61, 0x7C, 0xE6, 0x91, 0x48, 0xE4, 0xF1, 0x72, 0x6E, 0x2F, 0x43, 0x58, 0x1D, 0xE2,
0xAA, 0x62, 0xD9, 0xF8, 0x05, 0x53, 0x2E, 0xDF, 0xF1, 0xEE, 0xD6, 0x87, 0xFB, 0x54, 0x15, 0x3D,
};
static const uint8_t iv_ctr_4[16] = {
0x00,
0x1C,
0xC5,
0xB7,
0x51,
0xA5,
0x1D,
0x70,
0xA1,
0xC1,
0x11,
0x48,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_4[36] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23,
};
static const uint8_t tv_ctr_ct_4[36] = {
0xEB, 0x6C, 0x52, 0x82, 0x1D, 0x0B, 0xBB, 0xF7, 0xCE, 0x75, 0x94, 0x46,
0x2A, 0xCA, 0x4F, 0xAA, 0xB4, 0x07, 0xDF, 0x86, 0x65, 0x69, 0xFD, 0x07,
0xF4, 0x8C, 0xC0, 0xB5, 0x83, 0xD6, 0x07, 0x1F, 0x1E, 0xC0, 0xE6, 0xB8,
};
static const uint8_t key_ctr_5[32] = {
0xFF, 0x7A, 0x61, 0x7C, 0xE6, 0x91, 0x48, 0xE4, 0xF1, 0x72, 0x6E, 0x2F, 0x43, 0x58, 0x1D, 0xE2,
0xAA, 0x62, 0xD9, 0xF8, 0x05, 0x53, 0x2E, 0xDF, 0xF1, 0xEE, 0xD6, 0x87, 0xFB, 0x54, 0x15, 0x3D,
};
static const uint8_t iv_ctr_5[16] = {
0x00,
0x1C,
0xC5,
0xB7,
0x51,
0xA5,
0x1D,
0x70,
0xA1,
0xC1,
0x11,
0x48,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_5[0] = {};
//static const uint8_t tv_ctr_ct_5[0] = {};
static const uint8_t key_gcm_1[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const uint8_t iv_gcm_1[16] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t pt_gcm_1[0] = {};
//static const uint8_t tv_gcm_ct_1[0] = {};
static const uint8_t aad_gcm_1[0] = {};
static const uint8_t tv_gcm_tag_1[16] = {
0x53,
0x0F,
0x8A,
0xFB,
0xC7,
0x45,
0x36,
0xB9,
0xA9,
0x63,
0xB4,
0xF1,
0xC4,
0xCB,
0x73,
0x8B,
};
static const uint8_t key_gcm_2[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const uint8_t iv_gcm_2[16] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t pt_gcm_2[16] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t tv_gcm_ct_2[16] = {
0xCE,
0xA7,
0x40,
0x3D,
0x4D,
0x60,
0x6B,
0x6E,
0x07,
0x4E,
0xC5,
0xD3,
0xBA,
0xF3,
0x9D,
0x18,
};
static const uint8_t aad_gcm_2[0] = {};
static const uint8_t tv_gcm_tag_2[16] = {
0xD0,
0xD1,
0xC8,
0xA7,
0x99,
0x99,
0x6B,
0xF0,
0x26,
0x5B,
0x98,
0xB5,
0xD4,
0x8A,
0xB9,
0x19,
};
static const uint8_t key_gcm_3[32] = {
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
};
static const uint8_t iv_gcm_3[16] = {
0xCA,
0xFE,
0xBA,
0xBE,
0xFA,
0xCE,
0xDB,
0xAD,
0xDE,
0xCA,
0xF8,
0x88,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t pt_gcm_3[64] = {
0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x06, 0xE5, 0xA5, 0x59, 0x09, 0xC5, 0xAF, 0xF5, 0x26, 0x9A,
0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA, 0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31, 0x8A, 0x72,
0x1C, 0x3C, 0x0C, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2F, 0xCF, 0x0E, 0x24, 0x49, 0xA6, 0xB5, 0x25,
0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0x0D, 0xE6, 0x57, 0xBA, 0x63, 0x7B, 0x39, 0x1A, 0xAF, 0xD2, 0x55,
};
static const uint8_t tv_gcm_ct_3[64] = {
0x52, 0x2D, 0xC1, 0xF0, 0x99, 0x56, 0x7D, 0x07, 0xF4, 0x7F, 0x37, 0xA3, 0x2A, 0x84, 0x42, 0x7D,
0x64, 0x3A, 0x8C, 0xDC, 0xBF, 0xE5, 0xC0, 0xC9, 0x75, 0x98, 0xA2, 0xBD, 0x25, 0x55, 0xD1, 0xAA,
0x8C, 0xB0, 0x8E, 0x48, 0x59, 0x0D, 0xBB, 0x3D, 0xA7, 0xB0, 0x8B, 0x10, 0x56, 0x82, 0x88, 0x38,
0xC5, 0xF6, 0x1E, 0x63, 0x93, 0xBA, 0x7A, 0x0A, 0xBC, 0xC9, 0xF6, 0x62, 0x89, 0x80, 0x15, 0xAD,
};
static const uint8_t aad_gcm_3[0] = {};
static const uint8_t tv_gcm_tag_3[16] = {
0xB0,
0x94,
0xDA,
0xC5,
0xD9,
0x34,
0x71,
0xBD,
0xEC,
0x1A,
0x50,
0x22,
0x70,
0xE3,
0xCC,
0x6C,
};
static const uint8_t key_gcm_4[32] = {
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
};
static const uint8_t iv_gcm_4[16] = {
0xCA,
0xFE,
0xBA,
0xBE,
0xFA,
0xCE,
0xDB,
0xAD,
0xDE,
0xCA,
0xF8,
0x88,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t pt_gcm_4[60] = {
0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x06, 0xE5, 0xA5, 0x59, 0x09, 0xC5, 0xAF, 0xF5, 0x26,
0x9A, 0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA, 0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31,
0x8A, 0x72, 0x1C, 0x3C, 0x0C, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2F, 0xCF, 0x0E, 0x24, 0x49,
0xA6, 0xB5, 0x25, 0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0x0D, 0xE6, 0x57, 0xBA, 0x63, 0x7B, 0x39,
};
static const uint8_t tv_gcm_ct_4[60] = {
0x52, 0x2D, 0xC1, 0xF0, 0x99, 0x56, 0x7D, 0x07, 0xF4, 0x7F, 0x37, 0xA3, 0x2A, 0x84, 0x42,
0x7D, 0x64, 0x3A, 0x8C, 0xDC, 0xBF, 0xE5, 0xC0, 0xC9, 0x75, 0x98, 0xA2, 0xBD, 0x25, 0x55,
0xD1, 0xAA, 0x8C, 0xB0, 0x8E, 0x48, 0x59, 0x0D, 0xBB, 0x3D, 0xA7, 0xB0, 0x8B, 0x10, 0x56,
0x82, 0x88, 0x38, 0xC5, 0xF6, 0x1E, 0x63, 0x93, 0xBA, 0x7A, 0x0A, 0xBC, 0xC9, 0xF6, 0x62,
};
static const uint8_t aad_gcm_4[20] = {
0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED,
0xFA, 0xCE, 0xDE, 0xAD, 0xBE, 0xEF, 0xAB, 0xAD, 0xDA, 0xD2,
};
static const uint8_t tv_gcm_tag_4[16] = {
0x76,
0xFC,
0x6E,
0xCE,
0x0F,
0x4E,
0x17,
0x68,
0xCD,
0xDF,
0x88,
0x53,
0xBB,
0x2D,
0x55,
0x1B,
};
static void furi_hal_crypto_ctr_setup() {
}
static void furi_hal_crypto_ctr_teardown() {
}
static void furi_hal_crypto_gcm_setup() {
}
static void furi_hal_crypto_gcm_teardown() {
}
MU_TEST(furi_hal_crypto_ctr_1) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_1)];
ret = furi_hal_crypto_ctr(key_ctr_1, iv_ctr_1, pt_ctr_1, ct, sizeof(pt_ctr_1));
mu_assert(ret, "CTR 1 failed");
mu_assert_mem_eq(tv_ctr_ct_1, ct, sizeof(pt_ctr_1));
}
MU_TEST(furi_hal_crypto_ctr_2) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_2)];
ret = furi_hal_crypto_ctr(key_ctr_2, iv_ctr_2, pt_ctr_2, ct, sizeof(pt_ctr_2));
mu_assert(ret, "CTR 2 failed");
//mu_assert_mem_eq(tv_ctr_ct_2, ct, sizeof(pt_ctr_2));
}
MU_TEST(furi_hal_crypto_ctr_3) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_3)];
ret = furi_hal_crypto_ctr(key_ctr_3, iv_ctr_3, pt_ctr_3, ct, sizeof(pt_ctr_3));
mu_assert(ret, "CTR 3 failed");
mu_assert_mem_eq(tv_ctr_ct_3, ct, sizeof(pt_ctr_3));
}
MU_TEST(furi_hal_crypto_ctr_4) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_4)];
ret = furi_hal_crypto_ctr(key_ctr_4, iv_ctr_4, pt_ctr_4, ct, sizeof(pt_ctr_4));
mu_assert(ret, "CTR 4 failed");
mu_assert_mem_eq(tv_ctr_ct_4, ct, sizeof(pt_ctr_4));
}
MU_TEST(furi_hal_crypto_ctr_5) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_5)];
ret = furi_hal_crypto_ctr(key_ctr_5, iv_ctr_5, pt_ctr_5, ct, sizeof(pt_ctr_5));
mu_assert(ret, "CTR 5 failed");
//mu_assert_mem_eq(tv_ctr_ct_5, ct, sizeof(pt_ctr_5));
}
MU_TEST(furi_hal_crypto_gcm_1) {
bool ret = false;
uint8_t pt[sizeof(pt_gcm_1)];
uint8_t ct[sizeof(pt_gcm_1)];
uint8_t tag_enc[16];
uint8_t tag_dec[16];
ret = furi_hal_crypto_gcm(
key_gcm_1,
iv_gcm_1,
aad_gcm_1,
sizeof(aad_gcm_1),
pt_gcm_1,
ct,
sizeof(pt_gcm_1),
tag_enc,
false);
mu_assert(ret, "GCM 1 encryption failed");
//mu_assert_mem_eq(tv_gcm_ct_1, ct, sizeof(pt_gcm_1));
mu_assert_mem_eq(tv_gcm_tag_1, tag_enc, 16);
ret = furi_hal_crypto_gcm(
key_gcm_1, iv_gcm_1, aad_gcm_1, sizeof(aad_gcm_1), ct, pt, sizeof(pt_gcm_1), tag_dec, true);
mu_assert(ret, "GCM 1 decryption failed");
//mu_assert_mem_eq(pt_gcm_1, pt, sizeof(pt_gcm_1));
mu_assert_mem_eq(tv_gcm_tag_1, tag_dec, 16);
}
MU_TEST(furi_hal_crypto_gcm_2) {
bool ret = false;
uint8_t pt[sizeof(pt_gcm_2)];
uint8_t ct[sizeof(pt_gcm_2)];
uint8_t tag_enc[16];
uint8_t tag_dec[16];
ret = furi_hal_crypto_gcm(
key_gcm_2,
iv_gcm_2,
aad_gcm_2,
sizeof(aad_gcm_2),
pt_gcm_2,
ct,
sizeof(pt_gcm_2),
tag_enc,
false);
mu_assert(ret, "GCM 2 encryption failed");
mu_assert_mem_eq(tv_gcm_ct_2, ct, sizeof(pt_gcm_2));
mu_assert_mem_eq(tv_gcm_tag_2, tag_enc, 16);
ret = furi_hal_crypto_gcm(
key_gcm_2, iv_gcm_2, aad_gcm_2, sizeof(aad_gcm_2), ct, pt, sizeof(pt_gcm_2), tag_dec, true);
mu_assert(ret, "GCM 2 decryption failed");
mu_assert_mem_eq(pt_gcm_2, pt, sizeof(pt_gcm_2));
mu_assert_mem_eq(tv_gcm_tag_2, tag_dec, 16);
}
MU_TEST(furi_hal_crypto_gcm_3) {
bool ret = false;
uint8_t pt[sizeof(pt_gcm_3)];
uint8_t ct[sizeof(pt_gcm_3)];
uint8_t tag_enc[16];
uint8_t tag_dec[16];
ret = furi_hal_crypto_gcm(
key_gcm_3,
iv_gcm_3,
aad_gcm_3,
sizeof(aad_gcm_3),
pt_gcm_3,
ct,
sizeof(pt_gcm_3),
tag_enc,
false);
mu_assert(ret, "GCM 3 encryption failed");
mu_assert_mem_eq(tv_gcm_ct_3, ct, sizeof(pt_gcm_3));
mu_assert_mem_eq(tv_gcm_tag_3, tag_enc, 16);
ret = furi_hal_crypto_gcm(
key_gcm_3, iv_gcm_3, aad_gcm_3, sizeof(aad_gcm_3), ct, pt, sizeof(pt_gcm_3), tag_dec, true);
mu_assert(ret, "GCM 3 decryption failed");
mu_assert_mem_eq(pt_gcm_3, pt, sizeof(pt_gcm_3));
mu_assert_mem_eq(tv_gcm_tag_3, tag_dec, 16);
}
MU_TEST(furi_hal_crypto_gcm_4) {
bool ret = false;
uint8_t pt[sizeof(pt_gcm_4)];
uint8_t ct[sizeof(pt_gcm_4)];
uint8_t tag_enc[16];
uint8_t tag_dec[16];
ret = furi_hal_crypto_gcm(
key_gcm_4,
iv_gcm_4,
aad_gcm_4,
sizeof(aad_gcm_4),
pt_gcm_4,
ct,
sizeof(pt_gcm_4),
tag_enc,
false);
mu_assert(ret, "GCM 4 encryption failed");
mu_assert_mem_eq(tv_gcm_ct_4, ct, sizeof(pt_gcm_4));
mu_assert_mem_eq(tv_gcm_tag_4, tag_enc, 16);
ret = furi_hal_crypto_gcm(
key_gcm_4, iv_gcm_4, aad_gcm_4, sizeof(aad_gcm_4), ct, pt, sizeof(pt_gcm_4), tag_dec, true);
mu_assert(ret, "GCM 4 decryption failed");
mu_assert_mem_eq(pt_gcm_4, pt, sizeof(pt_gcm_4));
mu_assert_mem_eq(tv_gcm_tag_4, tag_dec, 16);
}
MU_TEST_SUITE(furi_hal_crypto_ctr_test) {
MU_SUITE_CONFIGURE(&furi_hal_crypto_ctr_setup, &furi_hal_crypto_ctr_teardown);
MU_RUN_TEST(furi_hal_crypto_ctr_1);
MU_RUN_TEST(furi_hal_crypto_ctr_2);
MU_RUN_TEST(furi_hal_crypto_ctr_3);
MU_RUN_TEST(furi_hal_crypto_ctr_4);
MU_RUN_TEST(furi_hal_crypto_ctr_5);
}
MU_TEST_SUITE(furi_hal_crypto_gcm_test) {
MU_SUITE_CONFIGURE(&furi_hal_crypto_gcm_setup, &furi_hal_crypto_gcm_teardown);
MU_RUN_TEST(furi_hal_crypto_gcm_1);
MU_RUN_TEST(furi_hal_crypto_gcm_2);
MU_RUN_TEST(furi_hal_crypto_gcm_3);
MU_RUN_TEST(furi_hal_crypto_gcm_4);
}
int run_minunit_test_furi_hal_crypto() {
MU_RUN_SUITE(furi_hal_crypto_ctr_test);
MU_RUN_SUITE(furi_hal_crypto_gcm_test);
return MU_EXIT_CODE;
}

View File

@@ -311,7 +311,7 @@ MU_TEST(test_bit_lib_test_parity) {
}
MU_TEST(test_bit_lib_remove_bit_every_nth) {
// TODO: more tests
// TODO FL-3494: more tests
uint8_t data_i[1] = {0b00001111};
uint8_t data_o[1] = {0b00011111};
size_t length;

View File

@@ -13,7 +13,7 @@
#include <pb.h>
#include <pb_encode.h>
#include <m-list.h>
#include <lib/toolbox/md5.h>
#include <lib/toolbox/md5_calc.h>
#include <lib/toolbox/path.h>
#include <cli/cli.h>
#include <loader/loader.h>
@@ -67,7 +67,6 @@ static RpcSessionContext rpc_session[TEST_RPC_SESSIONS];
} while(0)
static void output_bytes_callback(void* ctx, uint8_t* got_bytes, size_t got_size);
static void clean_directory(Storage* fs_api, const char* clean_dir);
static void
test_rpc_add_empty_to_list(MsgList_t msg_list, PB_CommandStatus status, uint32_t command_id);
static void test_rpc_encode_and_feed(MsgList_t msg_list, uint8_t session);
@@ -149,11 +148,41 @@ static void test_rpc_teardown_second_session(void) {
rpc_session[1].session = NULL;
}
static void test_rpc_storage_clean_directory(Storage* fs_api, const char* clean_dir) {
furi_check(fs_api);
furi_check(clean_dir);
storage_simply_remove_recursive(fs_api, clean_dir);
FS_Error error = storage_common_mkdir(fs_api, clean_dir);
furi_check(error == FSE_OK);
}
static void test_rpc_storage_create_file(Storage* fs_api, const char* path, size_t size) {
File* file = storage_file_alloc(fs_api);
bool success = false;
do {
if(!storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) break;
if(!storage_file_seek(file, size, true)) break;
success = true;
} while(false);
storage_file_close(file);
storage_file_free(file);
furi_check(success);
}
static void test_rpc_storage_setup(void) {
test_rpc_setup();
Storage* fs_api = furi_record_open(RECORD_STORAGE);
clean_directory(fs_api, TEST_DIR_NAME);
test_rpc_storage_clean_directory(fs_api, TEST_DIR_NAME);
test_rpc_storage_create_file(fs_api, TEST_DIR_NAME "/file100", 100);
test_rpc_storage_create_file(fs_api, TEST_DIR_NAME "/file250", 250);
test_rpc_storage_create_file(fs_api, TEST_DIR_NAME "/file500", 200);
test_rpc_storage_create_file(fs_api, TEST_DIR_NAME "/file1000", 1000);
test_rpc_storage_create_file(fs_api, TEST_DIR_NAME "/file2500", 2500);
test_rpc_storage_create_file(fs_api, TEST_DIR_NAME "/file5000", 5000);
furi_record_close(RECORD_STORAGE);
}
@@ -161,7 +190,7 @@ static void test_rpc_storage_teardown(void) {
test_rpc_teardown();
Storage* fs_api = furi_record_open(RECORD_STORAGE);
clean_directory(fs_api, TEST_DIR_NAME);
test_rpc_storage_clean_directory(fs_api, TEST_DIR_NAME);
furi_record_close(RECORD_STORAGE);
}
@@ -179,36 +208,6 @@ static void test_rpc_session_terminated_callback(void* context) {
xSemaphoreGive(callbacks_context->terminate_semaphore);
}
static void clean_directory(Storage* fs_api, const char* clean_dir) {
furi_check(fs_api);
furi_check(clean_dir);
File* dir = storage_file_alloc(fs_api);
if(storage_dir_open(dir, clean_dir)) {
FileInfo fileinfo;
char* name = malloc(MAX_NAME_LENGTH + 1);
while(storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH)) {
size_t size = strlen(clean_dir) + strlen(name) + 1 + 1;
char* fullname = malloc(size);
snprintf(fullname, size, "%s/%s", clean_dir, name);
if(file_info_is_dir(&fileinfo)) {
clean_directory(fs_api, fullname);
}
FS_Error error = storage_common_remove(fs_api, fullname);
furi_check(error == FSE_OK);
free(fullname);
}
free(name);
} else {
FS_Error error = storage_common_mkdir(fs_api, clean_dir);
(void)error;
furi_check(error == FSE_OK);
}
storage_dir_close(dir);
storage_file_free(dir);
}
static void test_rpc_print_message_list(MsgList_t msg_list) {
#if DEBUG_PRINT
MsgList_reverse(msg_list);
@@ -282,6 +281,27 @@ static void test_rpc_add_ping_to_list(MsgList_t msg_list, bool request, uint32_t
response->which_content = (request == PING_REQUEST) ? PB_Main_system_ping_request_tag :
PB_Main_system_ping_response_tag;
}
static void test_rpc_fill_basic_message(PB_Main* message, uint16_t tag, uint32_t command_id) {
message->command_id = command_id;
message->command_status = PB_CommandStatus_OK;
message->cb_content.funcs.encode = NULL;
message->which_content = tag;
message->has_next = false;
}
static void test_rpc_create_storage_list_request(
PB_Main* message,
const char* path,
bool include_md5,
uint32_t command_id,
uint32_t filter_max_size) {
furi_check(message);
furi_check(path);
test_rpc_fill_basic_message(message, PB_Main_storage_list_request_tag, command_id);
message->content.storage_list_request.path = strdup(path);
message->content.storage_list_request.include_md5 = include_md5;
message->content.storage_list_request.filter_max_size = filter_max_size;
}
static void test_rpc_create_simple_message(
PB_Main* message,
@@ -294,11 +314,7 @@ static void test_rpc_create_simple_message(
if(str) {
str_copy = strdup(str);
}
message->command_id = command_id;
message->command_status = PB_CommandStatus_OK;
message->cb_content.funcs.encode = NULL;
message->which_content = tag;
message->has_next = false;
test_rpc_fill_basic_message(message, tag, command_id);
switch(tag) {
case PB_Main_storage_info_request_tag:
message->content.storage_info_request.path = str_copy;
@@ -306,9 +322,6 @@ static void test_rpc_create_simple_message(
case PB_Main_storage_stat_request_tag:
message->content.storage_stat_request.path = str_copy;
break;
case PB_Main_storage_list_request_tag:
message->content.storage_list_request.path = str_copy;
break;
case PB_Main_storage_mkdir_request_tag:
message->content.storage_mkdir_request.path = str_copy;
break;
@@ -419,6 +432,7 @@ static void
}
mu_check(result_msg_file->size == expected_msg_file->size);
mu_check(result_msg_file->type == expected_msg_file->type);
mu_assert_string_eq(expected_msg_file->md5sum, result_msg_file->md5sum);
if(result_msg_file->data && result_msg_file->type != PB_Storage_File_FileType_DIR) {
mu_check(!result_msg_file->data == !expected_msg_file->data); // Zlo: WTF???
@@ -430,10 +444,10 @@ static void
}
static void test_rpc_compare_messages(PB_Main* result, PB_Main* expected) {
mu_check(result->command_id == expected->command_id);
mu_check(result->command_status == expected->command_status);
mu_check(result->has_next == expected->has_next);
mu_check(result->which_content == expected->which_content);
mu_assert_int_eq(expected->command_id, result->command_id);
mu_assert_int_eq(expected->command_status, result->command_status);
mu_assert_int_eq(expected->has_next, result->has_next);
mu_assert_int_eq(expected->which_content, result->which_content);
if(result->command_status != PB_CommandStatus_OK) {
mu_check(result->which_content == PB_Main_empty_tag);
}
@@ -570,13 +584,36 @@ static void
message->content.storage_list_response.file[2].name = str;
}
static bool test_rpc_system_storage_list_filter(
const FileInfo* fileinfo,
const char* name,
size_t filter_max_size) {
bool result = false;
do {
if(!path_contains_only_ascii(name)) break;
if(filter_max_size) {
if(fileinfo->size > filter_max_size) break;
}
result = true;
} while(false);
return result;
}
static void test_rpc_storage_list_create_expected_list(
MsgList_t msg_list,
const char* path,
uint32_t command_id) {
uint32_t command_id,
bool append_md5,
size_t filter_max_size) {
Storage* fs_api = furi_record_open(RECORD_STORAGE);
File* dir = storage_file_alloc(fs_api);
FuriString* md5 = furi_string_alloc();
FuriString* md5_path = furi_string_alloc();
File* file = storage_file_alloc(fs_api);
PB_Main response = {
.command_id = command_id,
.has_next = false,
@@ -607,13 +644,24 @@ static void test_rpc_storage_list_create_expected_list(
i = 0;
}
if(path_contains_only_ascii(name)) {
if(test_rpc_system_storage_list_filter(&fileinfo, name, filter_max_size)) {
list->file[i].type = file_info_is_dir(&fileinfo) ? PB_Storage_File_FileType_DIR :
PB_Storage_File_FileType_FILE;
list->file[i].size = fileinfo.size;
list->file[i].data = NULL;
/* memory free inside rpc_encode_and_send() -> pb_release() */
list->file[i].name = name;
if(append_md5 && !file_info_is_dir(&fileinfo)) {
furi_string_printf(md5_path, "%s/%s", path, name);
if(md5_string_calc_file(file, furi_string_get_cstr(md5_path), md5, NULL)) {
char* md5sum = list->file[i].md5sum;
size_t md5sum_size = sizeof(list->file[i].md5sum);
snprintf(md5sum, md5sum_size, "%s", furi_string_get_cstr(md5));
}
}
++i;
}
} else {
@@ -626,6 +674,10 @@ static void test_rpc_storage_list_create_expected_list(
response.has_next = false;
MsgList_push_back(msg_list, response);
furi_string_free(md5);
furi_string_free(md5_path);
storage_file_free(file);
storage_dir_close(dir);
storage_file_free(dir);
@@ -675,16 +727,21 @@ static void test_rpc_free_msg_list(MsgList_t msg_list) {
MsgList_clear(msg_list);
}
static void test_rpc_storage_list_run(const char* path, uint32_t command_id) {
static void test_rpc_storage_list_run(
const char* path,
uint32_t command_id,
bool md5,
size_t filter_max_size) {
PB_Main request;
MsgList_t expected_msg_list;
MsgList_init(expected_msg_list);
test_rpc_create_simple_message(&request, PB_Main_storage_list_request_tag, path, command_id);
test_rpc_create_storage_list_request(&request, path, md5, command_id, filter_max_size);
if(!strcmp(path, "/")) {
test_rpc_storage_list_create_expected_list_root(expected_msg_list, command_id);
} else {
test_rpc_storage_list_create_expected_list(expected_msg_list, path, command_id);
test_rpc_storage_list_create_expected_list(
expected_msg_list, path, command_id, md5, filter_max_size);
}
test_rpc_encode_and_feed_one(&request, 0);
test_rpc_decode_and_compare(expected_msg_list, 0);
@@ -694,15 +751,32 @@ static void test_rpc_storage_list_run(const char* path, uint32_t command_id) {
}
MU_TEST(test_storage_list) {
test_rpc_storage_list_run("/", ++command_id);
test_rpc_storage_list_run(EXT_PATH("nfc"), ++command_id);
test_rpc_storage_list_run("/", ++command_id, false, 0);
test_rpc_storage_list_run(EXT_PATH("nfc"), ++command_id, false, 0);
test_rpc_storage_list_run(STORAGE_INT_PATH_PREFIX, ++command_id, false, 0);
test_rpc_storage_list_run(STORAGE_EXT_PATH_PREFIX, ++command_id, false, 0);
test_rpc_storage_list_run(EXT_PATH("infrared"), ++command_id, false, 0);
test_rpc_storage_list_run(EXT_PATH("ibutton"), ++command_id, false, 0);
test_rpc_storage_list_run(EXT_PATH("lfrfid"), ++command_id, false, 0);
test_rpc_storage_list_run("error_path", ++command_id, false, 0);
}
test_rpc_storage_list_run(STORAGE_INT_PATH_PREFIX, ++command_id);
test_rpc_storage_list_run(STORAGE_EXT_PATH_PREFIX, ++command_id);
test_rpc_storage_list_run(EXT_PATH("infrared"), ++command_id);
test_rpc_storage_list_run(EXT_PATH("ibutton"), ++command_id);
test_rpc_storage_list_run(EXT_PATH("lfrfid"), ++command_id);
test_rpc_storage_list_run("error_path", ++command_id);
MU_TEST(test_storage_list_md5) {
test_rpc_storage_list_run("/", ++command_id, true, 0);
test_rpc_storage_list_run(EXT_PATH("nfc"), ++command_id, true, 0);
test_rpc_storage_list_run(STORAGE_INT_PATH_PREFIX, ++command_id, true, 0);
test_rpc_storage_list_run(STORAGE_EXT_PATH_PREFIX, ++command_id, true, 0);
test_rpc_storage_list_run(EXT_PATH("infrared"), ++command_id, true, 0);
test_rpc_storage_list_run(EXT_PATH("ibutton"), ++command_id, true, 0);
test_rpc_storage_list_run(EXT_PATH("lfrfid"), ++command_id, true, 0);
test_rpc_storage_list_run("error_path", ++command_id, true, 0);
}
MU_TEST(test_storage_list_size) {
test_rpc_storage_list_run(TEST_DIR_NAME, ++command_id, false, 0);
test_rpc_storage_list_run(TEST_DIR_NAME, ++command_id, false, 1);
test_rpc_storage_list_run(TEST_DIR_NAME, ++command_id, false, 1000);
test_rpc_storage_list_run(TEST_DIR_NAME, ++command_id, false, 2500);
}
static void
@@ -1229,33 +1303,15 @@ MU_TEST(test_storage_mkdir) {
static void test_storage_calculate_md5sum(const char* path, char* md5sum, size_t md5sum_size) {
Storage* api = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(api);
FuriString* md5 = furi_string_alloc();
if(storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING)) {
const uint16_t once_read_size = 512;
const uint8_t hash_size = MD5SUM_SIZE;
uint8_t* data = malloc(once_read_size);
uint8_t* hash = malloc(sizeof(uint8_t) * hash_size);
md5_context* md5_ctx = malloc(sizeof(md5_context));
md5_starts(md5_ctx);
while(true) {
uint16_t read_size = storage_file_read(file, data, once_read_size);
if(read_size == 0) break;
md5_update(md5_ctx, data, read_size);
}
md5_finish(md5_ctx, hash);
free(md5_ctx);
for(uint8_t i = 0; i < hash_size; i++) {
md5sum += snprintf(md5sum, md5sum_size, "%02x", hash[i]);
}
free(hash);
free(data);
if(md5_string_calc_file(file, path, md5, NULL)) {
snprintf(md5sum, md5sum_size, "%s", furi_string_get_cstr(md5));
} else {
furi_check(0);
}
furi_string_free(md5);
storage_file_close(file);
storage_file_free(file);
@@ -1433,6 +1489,8 @@ MU_TEST_SUITE(test_rpc_storage) {
MU_RUN_TEST(test_storage_info);
MU_RUN_TEST(test_storage_stat);
MU_RUN_TEST(test_storage_list);
MU_RUN_TEST(test_storage_list_md5);
MU_RUN_TEST(test_storage_list_size);
MU_RUN_TEST(test_storage_read);
MU_RUN_TEST(test_storage_write_read);
MU_RUN_TEST(test_storage_write);

View File

@@ -582,6 +582,49 @@ MU_TEST(test_storage_common_migrate) {
furi_record_close(RECORD_STORAGE);
}
#define MD5_HASH_SIZE (16)
#include <lib/toolbox/md5_calc.h>
MU_TEST(test_md5_calc) {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
const char* path = UNIT_TESTS_PATH("storage/md5.txt");
const char* md5_cstr = "2a456fa43e75088fdde41c93159d62a2";
const uint8_t md5[MD5_HASH_SIZE] = {
0x2a,
0x45,
0x6f,
0xa4,
0x3e,
0x75,
0x08,
0x8f,
0xdd,
0xe4,
0x1c,
0x93,
0x15,
0x9d,
0x62,
0xa2,
};
uint8_t md5_output[MD5_HASH_SIZE];
FuriString* md5_output_str = furi_string_alloc();
memset(md5_output, 0, MD5_HASH_SIZE);
mu_check(md5_calc_file(file, path, md5_output, NULL));
mu_check(md5_string_calc_file(file, path, md5_output_str, NULL));
mu_assert_mem_eq(md5, md5_output, MD5_HASH_SIZE);
mu_assert_string_eq(md5_cstr, furi_string_get_cstr(md5_output_str));
storage_file_free(file);
furi_string_free(md5_output_str);
furi_record_close(RECORD_STORAGE);
}
MU_TEST_SUITE(test_data_path) {
MU_RUN_TEST(test_storage_data_path);
MU_RUN_TEST(test_storage_data_path_apps);
@@ -591,11 +634,16 @@ MU_TEST_SUITE(test_storage_common) {
MU_RUN_TEST(test_storage_common_migrate);
}
MU_TEST_SUITE(test_md5_calc_suite) {
MU_RUN_TEST(test_md5_calc);
}
int run_minunit_test_storage() {
MU_RUN_SUITE(storage_file);
MU_RUN_SUITE(storage_dir);
MU_RUN_SUITE(storage_rename);
MU_RUN_SUITE(test_data_path);
MU_RUN_SUITE(test_storage_common);
MU_RUN_SUITE(test_md5_calc_suite);
return MU_EXIT_CODE;
}

View File

@@ -7,8 +7,10 @@
#include <lib/subghz/subghz_file_encoder_worker.h>
#include <lib/subghz/protocols/protocol_items.h>
#include <flipper_format/flipper_format_i.h>
#include <lib/subghz/devices/devices.h>
#include <lib/subghz/devices/cc1101_configs.h>
#define TAG "SubGhz TEST"
#define TAG "SubGhzTest"
#define KEYSTORE_DIR_NAME EXT_PATH("subghz/assets/keeloq_mfcodes")
#define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo")
#define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s")
@@ -40,8 +42,6 @@ static void subghz_test_rx_callback(
static void subghz_test_init(void) {
environment_handler = subghz_environment_alloc();
subghz_environment_set_came_atomo_rainbow_table_file_name(
environment_handler, CAME_ATOMO_DIR_NAME);
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
environment_handler, NICE_FLOR_S_DIR_NAME);
subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
@@ -49,12 +49,15 @@ static void subghz_test_init(void) {
subghz_environment_set_protocol_registry(
environment_handler, (void*)&subghz_protocol_registry);
subghz_devices_init();
receiver_handler = subghz_receiver_alloc_init(environment_handler);
subghz_receiver_set_filter(receiver_handler, SubGhzProtocolFlag_Decodable);
subghz_receiver_set_rx_callback(receiver_handler, subghz_test_rx_callback, NULL);
}
static void subghz_test_deinit(void) {
subghz_devices_deinit();
subghz_receiver_free(receiver_handler);
subghz_environment_free(environment_handler);
}
@@ -68,7 +71,7 @@ static bool subghz_decoder_test(const char* path, const char* name_decoder) {
if(decoder) {
file_worker_encoder_handler = subghz_file_encoder_worker_alloc();
if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path)) {
if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path, NULL)) {
// the worker needs a file in order to open and read part of the file
furi_delay_ms(100);
@@ -108,7 +111,7 @@ static bool subghz_decode_random_test(const char* path) {
uint32_t test_start = furi_get_tick();
file_worker_encoder_handler = subghz_file_encoder_worker_alloc();
if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path)) {
if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path, NULL)) {
// the worker needs a file in order to open and read part of the file
furi_delay_ms(100);
@@ -318,14 +321,19 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) {
SubGhzHalAsyncTxTest test = {0};
test.type = type;
furi_hal_subghz_reset();
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs);
furi_hal_subghz_set_frequency_and_path(433920000);
if(!furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test)) {
return false;
}
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(30000000);
while(!furi_hal_subghz_is_async_tx_complete()) {
if(furi_hal_cortex_timer_is_expired(timer)) {
return false;
}
furi_delay_ms(10);
}
furi_hal_subghz_stop_async_tx();

View File

@@ -10,6 +10,7 @@
int run_minunit_test_furi();
int run_minunit_test_furi_hal();
int run_minunit_test_furi_hal_crypto();
int run_minunit_test_furi_string();
int run_minunit_test_infrared();
int run_minunit_test_rpc();
@@ -39,6 +40,7 @@ typedef struct {
const UnitTest unit_tests[] = {
{.name = "furi", .entry = run_minunit_test_furi},
{.name = "furi_hal", .entry = run_minunit_test_furi_hal},
{.name = "furi_hal_crypto", .entry = run_minunit_test_furi_hal_crypto},
{.name = "furi_string", .entry = run_minunit_test_furi_string},
{.name = "storage", .entry = run_minunit_test_storage},
{.name = "stream", .entry = run_minunit_test_stream},
@@ -88,7 +90,7 @@ void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
Loader* loader = furi_record_open(RECORD_LOADER);
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
// TODO: lock device while test running
// TODO FL-3491: lock device while test running
if(loader_is_locked(loader)) {
printf("RPC: stop all applications to run tests\r\n");
notification_message(notification, &sequence_blink_magenta_100);

View File

@@ -7,6 +7,5 @@ App(
requires=["gui"],
stack_size=1 * 1024,
order=60,
fap_icon="../../external/mousejacker/mouse_10px.png",
fap_category="Debug",
)

View File

@@ -1,6 +1,6 @@
# Placeholder
App(
appid="external_apps",
name="External apps bundle",
appid="drivers",
name="Drivers device",
apptype=FlipperAppType.METAPACKAGE,
)

View File

@@ -0,0 +1,9 @@
App(
appid="radio_device_cc1101_ext",
apptype=FlipperAppType.PLUGIN,
targets=["f7"],
entry_point="subghz_device_cc1101_ext_ep",
requires=["subghz"],
sdk_headers=["cc1101_ext/cc1101_ext_interconnect.h"],
fap_libs=["hwdrivers"],
)

View File

@@ -0,0 +1,850 @@
#include "cc1101_ext.h"
#include <lib/subghz/devices/cc1101_configs.h>
#include <furi_hal_version.h>
#include <furi_hal_rtc.h>
#include <furi_hal_spi.h>
#include <furi_hal_interrupt.h>
#include <furi_hal_resources.h>
#include <furi_hal_bus.h>
#include <stm32wbxx_ll_dma.h>
#include <furi_hal_cortex.h>
#include <furi.h>
#include <cc1101.h>
#include <stdio.h>
#define TAG "SubGhzDeviceCc1101Ext"
#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO &gpio_ext_pb2
#define SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO &gpio_ext_pc3
#define SUBGHZ_DEVICE_CC1101_EXT_FORCE_DANGEROUS_RANGE false
#define SUBGHZ_DEVICE_CC1101_CONFIG_VER 1
/* DMA Channels definition */
#define SUBGHZ_DEVICE_CC1101_EXT_DMA DMA2
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL LL_DMA_CHANNEL_3
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL LL_DMA_CHANNEL_4
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL LL_DMA_CHANNEL_5
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ FuriHalInterruptIdDma2Ch3
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF \
SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF \
SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF \
SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL
/** Low level buffer dimensions and guard times */
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL (256)
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF \
(SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL / 2)
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME 999 << 1
/** SubGhz state */
typedef enum {
SubGhzDeviceCC1101ExtStateInit, /**< Init pending */
SubGhzDeviceCC1101ExtStateIdle, /**< Idle, energy save mode */
SubGhzDeviceCC1101ExtStateAsyncRx, /**< Async RX started */
SubGhzDeviceCC1101ExtStateAsyncTx, /**< Async TX started, DMA and timer is on */
SubGhzDeviceCC1101ExtStateAsyncTxEnd, /**< Async TX complete, cleanup needed */
} SubGhzDeviceCC1101ExtState;
/** SubGhz regulation, receive transmission on the current frequency for the
* region */
typedef enum {
SubGhzDeviceCC1101ExtRegulationOnlyRx, /**only Rx*/
SubGhzDeviceCC1101ExtRegulationTxRx, /**TxRx*/
} SubGhzDeviceCC1101ExtRegulation;
typedef struct {
uint32_t* buffer;
LevelDuration carry_ld;
SubGhzDeviceCC1101ExtCallback callback;
void* callback_context;
uint32_t gpio_tx_buff[2];
uint32_t debug_gpio_buff[2];
} SubGhzDeviceCC1101ExtAsyncTx;
typedef struct {
uint32_t capture_delta_duration;
SubGhzDeviceCC1101ExtCaptureCallback capture_callback;
void* capture_callback_context;
} SubGhzDeviceCC1101ExtAsyncRx;
typedef struct {
volatile SubGhzDeviceCC1101ExtState state;
volatile SubGhzDeviceCC1101ExtRegulation regulation;
const GpioPin* async_mirror_pin;
FuriHalSpiBusHandle* spi_bus_handle;
const GpioPin* g0_pin;
SubGhzDeviceCC1101ExtAsyncTx async_tx;
SubGhzDeviceCC1101ExtAsyncRx async_rx;
bool power_amp;
bool extended_range;
} SubGhzDeviceCC1101Ext;
static SubGhzDeviceCC1101Ext* subghz_device_cc1101_ext = NULL;
static bool subghz_device_cc1101_ext_check_init() {
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateInit);
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle;
bool ret = false;
CC1101Status cc1101_status = {0};
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(100 * 1000);
do {
// Reset
furi_hal_gpio_init(
subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(
subghz_device_cc1101_ext->spi_bus_handle->miso,
GpioModeInput,
GpioPullUp,
GpioSpeedLow);
cc1101_status = cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
if(cc1101_status.CHIP_RDYn != 0) {
//timeout or error
break;
}
cc1101_status = cc1101_write_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance);
if(cc1101_status.CHIP_RDYn != 0) {
//timeout or error
break;
}
// Prepare GD0 for power on self test
furi_hal_gpio_init(
subghz_device_cc1101_ext->g0_pin, GpioModeInput, GpioPullUp, GpioSpeedLow);
// GD0 low
cc1101_status = cc1101_write_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW);
if(cc1101_status.CHIP_RDYn != 0) {
//timeout or error
break;
}
while(furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin) != false) {
if(furi_hal_cortex_timer_is_expired(timer)) {
//timeout
break;
}
}
if(furi_hal_cortex_timer_is_expired(timer)) {
//timeout
break;
}
// GD0 high
furi_hal_gpio_init(
subghz_device_cc1101_ext->g0_pin, GpioModeInput, GpioPullDown, GpioSpeedLow);
cc1101_status = cc1101_write_reg(
subghz_device_cc1101_ext->spi_bus_handle,
CC1101_IOCFG0,
CC1101IocfgHW | CC1101_IOCFG_INV);
if(cc1101_status.CHIP_RDYn != 0) {
//timeout or error
break;
}
while(furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin) != true) {
if(furi_hal_cortex_timer_is_expired(timer)) {
//timeout
break;
}
}
if(furi_hal_cortex_timer_is_expired(timer)) {
//timeout
break;
}
// Reset GD0 to floating state
cc1101_status = cc1101_write_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance);
if(cc1101_status.CHIP_RDYn != 0) {
//timeout or error
break;
}
furi_hal_gpio_init(
subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
// Go to sleep
cc1101_status = cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle);
if(cc1101_status.CHIP_RDYn != 0) {
//timeout or error
break;
}
ret = true;
} while(false);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
if(ret) {
FURI_LOG_I(TAG, "Init OK");
} else {
FURI_LOG_E(TAG, "Init failed");
furi_hal_gpio_init(
subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
}
return ret;
}
bool subghz_device_cc1101_ext_alloc(SubGhzDeviceConf* conf) {
furi_assert(subghz_device_cc1101_ext == NULL);
subghz_device_cc1101_ext = malloc(sizeof(SubGhzDeviceCC1101Ext));
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateInit;
subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationTxRx;
subghz_device_cc1101_ext->async_mirror_pin = NULL;
subghz_device_cc1101_ext->spi_bus_handle = &furi_hal_spi_bus_handle_external;
subghz_device_cc1101_ext->g0_pin = SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO;
subghz_device_cc1101_ext->power_amp = false;
subghz_device_cc1101_ext->extended_range = false;
if(conf) {
if(conf->ver == SUBGHZ_DEVICE_CC1101_CONFIG_VER) {
subghz_device_cc1101_ext->power_amp = conf->power_amp;
subghz_device_cc1101_ext->extended_range = conf->extended_range;
} else {
FURI_LOG_E(TAG, "Config version mismatch");
}
}
subghz_device_cc1101_ext->async_rx.capture_delta_duration = 0;
furi_hal_spi_bus_handle_init(subghz_device_cc1101_ext->spi_bus_handle);
if(subghz_device_cc1101_ext->power_amp) {
furi_hal_gpio_init_simple(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, GpioModeOutputPushPull);
}
return subghz_device_cc1101_ext_check_init();
}
void subghz_device_cc1101_ext_free() {
furi_assert(subghz_device_cc1101_ext != NULL);
furi_hal_spi_bus_handle_deinit(subghz_device_cc1101_ext->spi_bus_handle);
if(subghz_device_cc1101_ext->power_amp) {
furi_hal_gpio_init_simple(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, GpioModeAnalog);
}
free(subghz_device_cc1101_ext);
subghz_device_cc1101_ext = NULL;
}
void subghz_device_cc1101_ext_set_async_mirror_pin(const GpioPin* pin) {
subghz_device_cc1101_ext->async_mirror_pin = pin;
}
const GpioPin* subghz_device_cc1101_ext_get_data_gpio() {
return subghz_device_cc1101_ext->g0_pin;
}
bool subghz_device_cc1101_ext_is_connect() {
bool ret = false;
if(subghz_device_cc1101_ext == NULL) { // not initialized
ret = subghz_device_cc1101_ext_alloc(NULL);
subghz_device_cc1101_ext_free();
} else { // initialized
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
uint8_t partnumber = cc1101_get_partnumber(subghz_device_cc1101_ext->spi_bus_handle);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
ret = (partnumber != 0) && (partnumber != 0xFF);
}
return ret;
}
void subghz_device_cc1101_ext_sleep() {
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle);
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_write_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance);
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
}
void subghz_device_cc1101_ext_dump_state() {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
printf(
"[subghz_device_cc1101_ext] cc1101 chip %d, version %d\r\n",
cc1101_get_partnumber(subghz_device_cc1101_ext->spi_bus_handle),
cc1101_get_version(subghz_device_cc1101_ext->spi_bus_handle));
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
}
void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data) {
//load config
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
uint32_t i = 0;
uint8_t pa[8] = {0};
while(preset_data[i]) {
cc1101_write_reg(
subghz_device_cc1101_ext->spi_bus_handle, preset_data[i], preset_data[i + 1]);
i += 2;
}
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
//load pa table
memcpy(&pa[0], &preset_data[i + 2], 8);
subghz_device_cc1101_ext_load_patable(pa);
//show debug
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
i = 0;
FURI_LOG_D(TAG, "Loading custom preset");
while(preset_data[i]) {
FURI_LOG_D(TAG, "Reg[%lu]: %02X=%02X", i, preset_data[i], preset_data[i + 1]);
i += 2;
}
for(uint8_t y = i; y < i + 10; y++) {
FURI_LOG_D(TAG, "PA[%u]: %02X", y, preset_data[y]);
}
}
}
void subghz_device_cc1101_ext_load_registers(const uint8_t* data) {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
uint32_t i = 0;
while(data[i]) {
cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, data[i], data[i + 1]);
i += 2;
}
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
}
void subghz_device_cc1101_ext_load_patable(const uint8_t data[8]) {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_set_pa_table(subghz_device_cc1101_ext->spi_bus_handle, data);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
}
void subghz_device_cc1101_ext_write_packet(const uint8_t* data, uint8_t size) {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_flush_tx(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_FIFO, size);
cc1101_write_fifo(subghz_device_cc1101_ext->spi_bus_handle, data, size);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
}
void subghz_device_cc1101_ext_flush_rx() {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_flush_rx(subghz_device_cc1101_ext->spi_bus_handle);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
}
void subghz_device_cc1101_ext_flush_tx() {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_flush_tx(subghz_device_cc1101_ext->spi_bus_handle);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
}
bool subghz_device_cc1101_ext_rx_pipe_not_empty() {
CC1101RxBytes status[1];
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_read_reg(
subghz_device_cc1101_ext->spi_bus_handle,
(CC1101_STATUS_RXBYTES) | CC1101_BURST,
(uint8_t*)status);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
// TODO: Find reason why RXFIFO_OVERFLOW doesnt work correctly
if(status->NUM_RXBYTES > 0) {
return true;
} else {
return false;
}
}
bool subghz_device_cc1101_ext_is_rx_data_crc_valid() {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
uint8_t data[1];
cc1101_read_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_STATUS_LQI | CC1101_BURST, data);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
if(((data[0] >> 7) & 0x01)) {
return true;
} else {
return false;
}
}
void subghz_device_cc1101_ext_read_packet(uint8_t* data, uint8_t* size) {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_read_fifo(subghz_device_cc1101_ext->spi_bus_handle, data, size);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
}
void subghz_device_cc1101_ext_shutdown() {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
// Reset and shutdown
cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
}
void subghz_device_cc1101_ext_reset() {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_write_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
}
void subghz_device_cc1101_ext_idle() {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
if(subghz_device_cc1101_ext->power_amp) {
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 0);
}
}
void subghz_device_cc1101_ext_rx() {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_switch_to_rx(subghz_device_cc1101_ext->spi_bus_handle);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
if(subghz_device_cc1101_ext->power_amp) {
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 0);
}
}
bool subghz_device_cc1101_ext_tx() {
if(subghz_device_cc1101_ext->regulation != SubGhzDeviceCC1101ExtRegulationTxRx) return false;
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_switch_to_tx(subghz_device_cc1101_ext->spi_bus_handle);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
if(subghz_device_cc1101_ext->power_amp) {
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 1);
}
return true;
}
float subghz_device_cc1101_ext_get_rssi() {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
int32_t rssi_dec = cc1101_get_rssi(subghz_device_cc1101_ext->spi_bus_handle);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
float rssi = rssi_dec;
if(rssi_dec >= 128) {
rssi = ((rssi - 256.0f) / 2.0f) - 74.0f;
} else {
rssi = (rssi / 2.0f) - 74.0f;
}
return rssi;
}
uint8_t subghz_device_cc1101_ext_get_lqi() {
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
uint8_t data[1];
cc1101_read_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_STATUS_LQI | CC1101_BURST, data);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
return data[0] & 0x7F;
}
bool subghz_device_cc1101_ext_is_frequency_valid(uint32_t value) {
if(!(value >= 281000000 && value <= 361000000) &&
!(value >= 378000000 && value <= 481000000) &&
!(value >= 749000000 && value <= 962000000)) {
return false;
}
return true;
}
bool subghz_device_cc1101_ext_is_tx_allowed(uint32_t value) {
if(!(SUBGHZ_DEVICE_CC1101_EXT_FORCE_DANGEROUS_RANGE ||
subghz_device_cc1101_ext->extended_range) &&
!(value >= 299999755 && value <= 350000335) && // was increased from 348 to 350
!(value >= 386999938 && value <= 467750000) && // was increased from 464 to 467.75
!(value >= 778999847 && value <= 928000000)) {
FURI_LOG_I(TAG, "Frequency blocked - outside default range");
return false;
} else if(
(SUBGHZ_DEVICE_CC1101_EXT_FORCE_DANGEROUS_RANGE ||
subghz_device_cc1101_ext->extended_range) &&
!subghz_device_cc1101_ext_is_frequency_valid(value)) {
FURI_LOG_I(TAG, "Frequency blocked - outside dangerous range");
return false;
}
return true;
}
uint32_t subghz_device_cc1101_ext_set_frequency(uint32_t value) {
if(subghz_device_cc1101_ext_is_tx_allowed(value)) {
subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationTxRx;
} else {
subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationTxRx;
}
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
uint32_t real_frequency =
cc1101_set_frequency(subghz_device_cc1101_ext->spi_bus_handle, value);
cc1101_calibrate(subghz_device_cc1101_ext->spi_bus_handle);
while(true) {
CC1101Status status = cc1101_get_status(subghz_device_cc1101_ext->spi_bus_handle);
if(status.STATE == CC1101StateIDLE) break;
}
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
return real_frequency;
}
static bool subghz_device_cc1101_ext_start_debug() {
bool ret = false;
if(subghz_device_cc1101_ext->async_mirror_pin != NULL) {
furi_hal_gpio_init(
subghz_device_cc1101_ext->async_mirror_pin,
GpioModeOutputPushPull,
GpioPullNo,
GpioSpeedVeryHigh);
ret = true;
}
return ret;
}
static bool subghz_device_cc1101_ext_stop_debug() {
bool ret = false;
if(subghz_device_cc1101_ext->async_mirror_pin != NULL) {
furi_hal_gpio_init(
subghz_device_cc1101_ext->async_mirror_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
ret = true;
}
return ret;
}
static void subghz_device_cc1101_ext_capture_ISR() {
if(!furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin)) {
if(subghz_device_cc1101_ext->async_rx.capture_callback) {
if(subghz_device_cc1101_ext->async_mirror_pin != NULL)
furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false);
subghz_device_cc1101_ext->async_rx.capture_callback(
true,
LL_TIM_GetCounter(TIM17) << 1,
(void*)subghz_device_cc1101_ext->async_rx.capture_callback_context);
}
} else {
if(subghz_device_cc1101_ext->async_rx.capture_callback) {
if(subghz_device_cc1101_ext->async_mirror_pin != NULL)
furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, true);
subghz_device_cc1101_ext->async_rx.capture_callback(
false,
LL_TIM_GetCounter(TIM17) << 1,
(void*)subghz_device_cc1101_ext->async_rx.capture_callback_context);
}
}
LL_TIM_SetCounter(TIM17, 4); //8>>1
}
void subghz_device_cc1101_ext_start_async_rx(
SubGhzDeviceCC1101ExtCaptureCallback callback,
void* context) {
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle);
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncRx;
subghz_device_cc1101_ext->async_rx.capture_callback = callback;
subghz_device_cc1101_ext->async_rx.capture_callback_context = context;
furi_hal_bus_enable(FuriHalBusTIM17);
// Configure TIM
//Set the timer resolution to 2 us
LL_TIM_SetPrescaler(TIM17, (64 << 1) - 1);
LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP);
LL_TIM_SetAutoReload(TIM17, 0xFFFF);
LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1);
// Timer: advanced
LL_TIM_SetClockSource(TIM17, LL_TIM_CLOCKSOURCE_INTERNAL);
LL_TIM_DisableARRPreload(TIM17);
LL_TIM_DisableDMAReq_TRIG(TIM17);
LL_TIM_DisableIT_TRIG(TIM17);
furi_hal_gpio_init(
subghz_device_cc1101_ext->g0_pin, GpioModeInterruptRiseFall, GpioPullUp, GpioSpeedVeryHigh);
furi_hal_gpio_remove_int_callback(subghz_device_cc1101_ext->g0_pin);
furi_hal_gpio_add_int_callback(
subghz_device_cc1101_ext->g0_pin,
subghz_device_cc1101_ext_capture_ISR,
subghz_device_cc1101_ext->async_rx.capture_callback);
// Start timer
LL_TIM_SetCounter(TIM17, 0);
LL_TIM_EnableCounter(TIM17);
// Start debug
subghz_device_cc1101_ext_start_debug();
// Switch to RX
subghz_device_cc1101_ext_rx();
//Clear the variable after the end of the session
subghz_device_cc1101_ext->async_rx.capture_delta_duration = 0;
}
void subghz_device_cc1101_ext_stop_async_rx() {
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncRx);
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle;
// Shutdown radio
subghz_device_cc1101_ext_idle();
FURI_CRITICAL_ENTER();
furi_hal_bus_disable(FuriHalBusTIM17);
// Stop debug
subghz_device_cc1101_ext_stop_debug();
FURI_CRITICAL_EXIT();
furi_hal_gpio_remove_int_callback(subghz_device_cc1101_ext->g0_pin);
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
}
static void subghz_device_cc1101_ext_async_tx_refill(uint32_t* buffer, size_t samples) {
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx);
while(samples > 0) {
bool is_odd = samples % 2;
LevelDuration ld;
if(level_duration_is_reset(subghz_device_cc1101_ext->async_tx.carry_ld)) {
ld = subghz_device_cc1101_ext->async_tx.callback(
subghz_device_cc1101_ext->async_tx.callback_context);
} else {
ld = subghz_device_cc1101_ext->async_tx.carry_ld;
subghz_device_cc1101_ext->async_tx.carry_ld = level_duration_reset();
}
if(level_duration_is_wait(ld)) {
*buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
buffer++;
samples--;
} else if(level_duration_is_reset(ld)) {
*buffer = 0;
buffer++;
samples--;
LL_DMA_DisableIT_HT(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
LL_DMA_DisableIT_TC(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
LL_TIM_EnableIT_UPDATE(TIM17);
break;
} else {
bool level = level_duration_get_level(ld);
// Inject guard time if level is incorrect
if(is_odd != level) {
*buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
buffer++;
samples--;
// Special case: prevent buffer overflow if sample is last
if(samples == 0) {
subghz_device_cc1101_ext->async_tx.carry_ld = ld;
break;
}
}
uint32_t duration = level_duration_get_duration(ld);
furi_assert(duration > 0);
*buffer = duration >> 1;
buffer++;
samples--;
}
}
}
static void subghz_device_cc1101_ext_async_tx_dma_isr() {
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx);
#if SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL == LL_DMA_CHANNEL_3
if(LL_DMA_IsActiveFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) {
LL_DMA_ClearFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA);
subghz_device_cc1101_ext_async_tx_refill(
subghz_device_cc1101_ext->async_tx.buffer,
SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF);
}
if(LL_DMA_IsActiveFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) {
LL_DMA_ClearFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA);
subghz_device_cc1101_ext_async_tx_refill(
subghz_device_cc1101_ext->async_tx.buffer +
SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF,
SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF);
}
#else
#error Update this code. Would you kindly?
#endif
}
static void subghz_device_cc1101_ext_async_tx_timer_isr() {
if(LL_TIM_IsActiveFlag_UPDATE(TIM17)) {
if(LL_TIM_GetAutoReload(TIM17) == 0) {
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
if(subghz_device_cc1101_ext->async_mirror_pin != NULL)
furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false);
LL_TIM_DisableCounter(TIM17);
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTxEnd;
}
LL_TIM_ClearFlag_UPDATE(TIM17);
}
}
bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callback, void* context) {
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle);
furi_assert(callback);
//If transmission is prohibited by regional settings
if(subghz_device_cc1101_ext->regulation != SubGhzDeviceCC1101ExtRegulationTxRx) return false;
subghz_device_cc1101_ext->async_tx.callback = callback;
subghz_device_cc1101_ext->async_tx.callback_context = context;
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTx;
subghz_device_cc1101_ext->async_tx.buffer =
malloc(SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t));
//Signal generation with mem-to-mem DMA
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
furi_hal_gpio_init(
subghz_device_cc1101_ext->g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
// Configure DMA update timer
LL_DMA_SetMemoryAddress(
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t)subghz_device_cc1101_ext->async_tx.buffer);
LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t) & (TIM17->ARR));
LL_DMA_ConfigTransfer(
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF,
LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD |
LL_DMA_MODE_NORMAL);
LL_DMA_SetDataLength(
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL);
LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, LL_DMAMUX_REQ_TIM17_UP);
LL_DMA_EnableIT_TC(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
LL_DMA_EnableIT_HT(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
LL_DMA_EnableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
furi_hal_interrupt_set_isr(
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ, subghz_device_cc1101_ext_async_tx_dma_isr, NULL);
furi_hal_bus_enable(FuriHalBusTIM17);
// Configure TIM
// Set the timer resolution to 2 us
LL_TIM_SetPrescaler(TIM17, (64 << 1) - 1);
LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP);
LL_TIM_SetAutoReload(TIM17, 0xFFFF);
LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1);
LL_TIM_SetClockSource(TIM17, LL_TIM_CLOCKSOURCE_INTERNAL);
LL_TIM_DisableARRPreload(TIM17);
furi_hal_interrupt_set_isr(
FuriHalInterruptIdTim1TrgComTim17, subghz_device_cc1101_ext_async_tx_timer_isr, NULL);
subghz_device_cc1101_ext_async_tx_refill(
subghz_device_cc1101_ext->async_tx.buffer, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL);
// Configure tx gpio dma
const GpioPin* gpio = subghz_device_cc1101_ext->g0_pin;
subghz_device_cc1101_ext->async_tx.gpio_tx_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER;
subghz_device_cc1101_ext->async_tx.gpio_tx_buff[1] = gpio->pin;
LL_DMA_SetMemoryAddress(
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF,
(uint32_t)subghz_device_cc1101_ext->async_tx.gpio_tx_buff);
LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, (uint32_t) & (gpio->port->BSRR));
LL_DMA_ConfigTransfer(
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF,
LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD |
LL_DMA_PRIORITY_HIGH);
LL_DMA_SetDataLength(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, 2);
LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, LL_DMAMUX_REQ_TIM17_UP);
LL_DMA_EnableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF);
// Start debug
if(subghz_device_cc1101_ext_start_debug()) {
gpio = subghz_device_cc1101_ext->async_mirror_pin;
subghz_device_cc1101_ext->async_tx.debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER;
subghz_device_cc1101_ext->async_tx.debug_gpio_buff[1] = gpio->pin;
LL_DMA_SetMemoryAddress(
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF,
(uint32_t)subghz_device_cc1101_ext->async_tx.debug_gpio_buff);
LL_DMA_SetPeriphAddress(
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, (uint32_t) & (gpio->port->BSRR));
LL_DMA_ConfigTransfer(
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF,
LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD |
LL_DMA_PRIORITY_LOW);
LL_DMA_SetDataLength(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, 2);
LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, LL_DMAMUX_REQ_TIM17_UP);
LL_DMA_EnableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF);
}
// Start counter
LL_TIM_EnableDMAReq_UPDATE(TIM17);
LL_TIM_GenerateEvent_UPDATE(TIM17);
subghz_device_cc1101_ext_tx();
LL_TIM_SetCounter(TIM17, 0);
LL_TIM_EnableCounter(TIM17);
return true;
}
bool subghz_device_cc1101_ext_is_async_tx_complete() {
return subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd;
}
void subghz_device_cc1101_ext_stop_async_tx() {
furi_assert(
subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx ||
subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd);
// Shutdown radio
subghz_device_cc1101_ext_idle();
// Deinitialize Timer
FURI_CRITICAL_ENTER();
furi_hal_bus_disable(FuriHalBusTIM17);
furi_hal_interrupt_set_isr(FuriHalInterruptIdTim1TrgComTim17, NULL, NULL);
// Deinitialize DMA
LL_DMA_DeInit(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF);
furi_hal_interrupt_set_isr(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ, NULL, NULL);
// Deinitialize GPIO
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
// Stop debug
if(subghz_device_cc1101_ext_stop_debug()) {
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF);
}
FURI_CRITICAL_EXIT();
free(subghz_device_cc1101_ext->async_tx.buffer);
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle;
}

View File

@@ -0,0 +1,207 @@
/**
* @file furi_hal_subghz.h
* SubGhz HAL API
*/
#pragma once
#include <lib/subghz/devices/preset.h>
#include <lib/subghz/devices/types.h>
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <toolbox/level_duration.h>
#include <furi_hal_gpio.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Mirror RX/TX async modulation signal to specified pin
*
* @warning Configures pin to output mode. Make sure it is not connected
* directly to power or ground.
*
* @param[in] pin pointer to the gpio pin structure or NULL to disable
*/
void subghz_device_cc1101_ext_set_async_mirror_pin(const GpioPin* pin);
/** Get data GPIO
*
* @return pointer to the gpio pin structure
*/
const GpioPin* subghz_device_cc1101_ext_get_data_gpio();
/** Initialize device
*
* @return true if success
*/
bool subghz_device_cc1101_ext_alloc(SubGhzDeviceConf* conf);
/** Deinitialize device
*/
void subghz_device_cc1101_ext_free();
/** Check and switch to power save mode Used by internal API-HAL
* initialization routine Can be used to reinitialize device to safe state and
* send it to sleep
*/
bool subghz_device_cc1101_ext_is_connect();
/** Send device to sleep mode
*/
void subghz_device_cc1101_ext_sleep();
/** Dump info to stdout
*/
void subghz_device_cc1101_ext_dump_state();
/** Load custom registers from preset
*
* @param preset_data registers to load
*/
void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data);
/** Load registers
*
* @param data Registers data
*/
void subghz_device_cc1101_ext_load_registers(const uint8_t* data);
/** Load PATABLE
*
* @param data 8 uint8_t values
*/
void subghz_device_cc1101_ext_load_patable(const uint8_t data[8]);
/** Write packet to FIFO
*
* @param data bytes array
* @param size size
*/
void subghz_device_cc1101_ext_write_packet(const uint8_t* data, uint8_t size);
/** Check if receive pipe is not empty
*
* @return true if not empty
*/
bool subghz_device_cc1101_ext_rx_pipe_not_empty();
/** Check if received data crc is valid
*
* @return true if valid
*/
bool subghz_device_cc1101_ext_is_rx_data_crc_valid();
/** Read packet from FIFO
*
* @param data pointer
* @param size size
*/
void subghz_device_cc1101_ext_read_packet(uint8_t* data, uint8_t* size);
/** Flush rx FIFO buffer
*/
void subghz_device_cc1101_ext_flush_rx();
/** Flush tx FIFO buffer
*/
void subghz_device_cc1101_ext_flush_tx();
/** Shutdown Issue SPWD command
* @warning registers content will be lost
*/
void subghz_device_cc1101_ext_shutdown();
/** Reset Issue reset command
* @warning registers content will be lost
*/
void subghz_device_cc1101_ext_reset();
/** Switch to Idle
*/
void subghz_device_cc1101_ext_idle();
/** Switch to Receive
*/
void subghz_device_cc1101_ext_rx();
/** Switch to Transmit
*
* @return true if the transfer is allowed by belonging to the region
*/
bool subghz_device_cc1101_ext_tx();
/** Get RSSI value in dBm
*
* @return RSSI value
*/
float subghz_device_cc1101_ext_get_rssi();
/** Get LQI
*
* @return LQI value
*/
uint8_t subghz_device_cc1101_ext_get_lqi();
/** Check if frequency is in valid range
*
* @param value frequency in Hz
*
* @return true if frequency is valid, otherwise false
*/
bool subghz_device_cc1101_ext_is_frequency_valid(uint32_t value);
/** Set frequency
*
* @param value frequency in Hz
*
* @return real frequency in Hz
*/
uint32_t subghz_device_cc1101_ext_set_frequency(uint32_t value);
/* High Level API */
/** Signal Timings Capture callback */
typedef void (*SubGhzDeviceCC1101ExtCaptureCallback)(bool level, uint32_t duration, void* context);
/** Enable signal timings capture Initializes GPIO and TIM2 for timings capture
*
* @param callback SubGhzDeviceCC1101ExtCaptureCallback
* @param context callback context
*/
void subghz_device_cc1101_ext_start_async_rx(
SubGhzDeviceCC1101ExtCaptureCallback callback,
void* context);
/** Disable signal timings capture Resets GPIO and TIM2
*/
void subghz_device_cc1101_ext_stop_async_rx();
/** Async TX callback type
* @param context callback context
* @return LevelDuration
*/
typedef LevelDuration (*SubGhzDeviceCC1101ExtCallback)(void* context);
/** Start async TX Initializes GPIO, TIM2 and DMA1 for signal output
*
* @param callback SubGhzDeviceCC1101ExtCallback
* @param context callback context
*
* @return true if the transfer is allowed by belonging to the region
*/
bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callback, void* context);
/** Wait for async transmission to complete
*
* @return true if TX complete
*/
bool subghz_device_cc1101_ext_is_async_tx_complete();
/** Stop async transmission and cleanup resources Resets GPIO, TIM2, and DMA1
*/
void subghz_device_cc1101_ext_stop_async_tx();
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,110 @@
#include "cc1101_ext_interconnect.h"
#include "cc1101_ext.h"
#include <lib/subghz/devices/cc1101_configs.h>
#define TAG "SubGhzDeviceCc1101Ext"
static bool subghz_device_cc1101_ext_interconnect_is_frequency_valid(uint32_t frequency) {
bool ret = subghz_device_cc1101_ext_is_frequency_valid(frequency);
if(!ret) {
furi_crash("SubGhz: Incorrect frequency.");
}
return ret;
}
static uint32_t subghz_device_cc1101_ext_interconnect_set_frequency(uint32_t frequency) {
subghz_device_cc1101_ext_interconnect_is_frequency_valid(frequency);
return subghz_device_cc1101_ext_set_frequency(frequency);
}
static bool subghz_device_cc1101_ext_interconnect_start_async_tx(void* callback, void* context) {
return subghz_device_cc1101_ext_start_async_tx(
(SubGhzDeviceCC1101ExtCallback)callback, context);
}
static void subghz_device_cc1101_ext_interconnect_start_async_rx(void* callback, void* context) {
subghz_device_cc1101_ext_start_async_rx(
(SubGhzDeviceCC1101ExtCaptureCallback)callback, context);
}
static void subghz_device_cc1101_ext_interconnect_load_preset(
FuriHalSubGhzPreset preset,
uint8_t* preset_data) {
switch(preset) {
case FuriHalSubGhzPresetOok650Async:
subghz_device_cc1101_ext_load_custom_preset(
subghz_device_cc1101_preset_ook_650khz_async_regs);
break;
case FuriHalSubGhzPresetOok270Async:
subghz_device_cc1101_ext_load_custom_preset(
subghz_device_cc1101_preset_ook_270khz_async_regs);
break;
case FuriHalSubGhzPreset2FSKDev238Async:
subghz_device_cc1101_ext_load_custom_preset(
subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs);
break;
case FuriHalSubGhzPreset2FSKDev476Async:
subghz_device_cc1101_ext_load_custom_preset(
subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs);
break;
case FuriHalSubGhzPresetMSK99_97KbAsync:
subghz_device_cc1101_ext_load_custom_preset(
subghz_device_cc1101_preset_msk_99_97kb_async_regs);
break;
case FuriHalSubGhzPresetGFSK9_99KbAsync:
subghz_device_cc1101_ext_load_custom_preset(
subghz_device_cc1101_preset_gfsk_9_99kb_async_regs);
break;
default:
subghz_device_cc1101_ext_load_custom_preset(preset_data);
}
}
const SubGhzDeviceInterconnect subghz_device_cc1101_ext_interconnect = {
.begin = subghz_device_cc1101_ext_alloc,
.end = subghz_device_cc1101_ext_free,
.is_connect = subghz_device_cc1101_ext_is_connect,
.reset = subghz_device_cc1101_ext_reset,
.sleep = subghz_device_cc1101_ext_sleep,
.idle = subghz_device_cc1101_ext_idle,
.load_preset = subghz_device_cc1101_ext_interconnect_load_preset,
.set_frequency = subghz_device_cc1101_ext_interconnect_set_frequency,
.is_frequency_valid = subghz_device_cc1101_ext_is_frequency_valid,
.set_async_mirror_pin = subghz_device_cc1101_ext_set_async_mirror_pin,
.get_data_gpio = subghz_device_cc1101_ext_get_data_gpio,
.set_tx = subghz_device_cc1101_ext_tx,
.flush_tx = subghz_device_cc1101_ext_flush_tx,
.start_async_tx = subghz_device_cc1101_ext_interconnect_start_async_tx,
.is_async_complete_tx = subghz_device_cc1101_ext_is_async_tx_complete,
.stop_async_tx = subghz_device_cc1101_ext_stop_async_tx,
.set_rx = subghz_device_cc1101_ext_rx,
.flush_rx = subghz_device_cc1101_ext_flush_rx,
.start_async_rx = subghz_device_cc1101_ext_interconnect_start_async_rx,
.stop_async_rx = subghz_device_cc1101_ext_stop_async_rx,
.get_rssi = subghz_device_cc1101_ext_get_rssi,
.get_lqi = subghz_device_cc1101_ext_get_lqi,
.rx_pipe_not_empty = subghz_device_cc1101_ext_rx_pipe_not_empty,
.is_rx_data_crc_valid = subghz_device_cc1101_ext_is_rx_data_crc_valid,
.read_packet = subghz_device_cc1101_ext_read_packet,
.write_packet = subghz_device_cc1101_ext_write_packet,
};
const SubGhzDevice subghz_device_cc1101_ext = {
.name = SUBGHZ_DEVICE_CC1101_EXT_NAME,
.interconnect = &subghz_device_cc1101_ext_interconnect,
};
static const FlipperAppPluginDescriptor subghz_device_cc1101_ext_descriptor = {
.appid = SUBGHZ_RADIO_DEVICE_PLUGIN_APP_ID,
.ep_api_version = SUBGHZ_RADIO_DEVICE_PLUGIN_API_VERSION,
.entry_point = &subghz_device_cc1101_ext,
};
const FlipperAppPluginDescriptor* subghz_device_cc1101_ext_ep() {
return &subghz_device_cc1101_ext_descriptor;
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include <lib/subghz/devices/types.h>
#define SUBGHZ_DEVICE_CC1101_EXT_NAME "cc1101_ext"
typedef struct SubGhzDeviceCC1101Ext SubGhzDeviceCC1101Ext;
const FlipperAppPluginDescriptor* subghz_device_cc1101_ext_ep();

View File

@@ -4,7 +4,7 @@
#include <toolbox/stream/file_stream.h>
// Define log tag
#define TAG "example_apps_assets"
#define TAG "ExampleAppsAssets"
static void example_apps_data_print_file_content(Storage* storage, const char* path) {
Stream* stream = file_stream_alloc(storage);

View File

@@ -2,7 +2,7 @@
#include <storage/storage.h>
// Define log tag
#define TAG "example_apps_data"
#define TAG "ExampleAppsData"
// Application entry point
int32_t example_apps_data_main(void* p) {

View File

@@ -11,7 +11,7 @@
#include <loader/firmware_api/firmware_api.h>
#include <storage/storage.h>
#define TAG "example_plugins"
#define TAG "ExamplePlugins"
int32_t example_plugins_app(void* p) {
UNUSED(p);

View File

@@ -11,7 +11,7 @@
#include <furi.h>
#define TAG "example_plugins"
#define TAG "ExamplePlugins"
int32_t example_plugins_multi_app(void* p) {
UNUSED(p);

View File

@@ -8,7 +8,7 @@
#include <loader/firmware_api/firmware_api.h>
#define TAG "example_advanced_plugins"
#define TAG "ExampleAdvancedPlugins"
int32_t example_advanced_plugins_app(void* p) {
UNUSED(p);

View File

@@ -18,7 +18,7 @@ Before launching the application, connect the sensor to Flipper's external GPIO
In order to launch this demo, follow the steps below:
1. Make sure your Flipper has an SD card installed.
2. Connect your Flipper to the computer via a USB cable.
3. Run `./fbt launch_app APPSRC=example_thermo` in your terminal emulator of choice.
3. Run `./fbt launch APPSRC=example_thermo` in your terminal emulator of choice.
## Changing the data pin
It is possible to use other GPIO pin as a 1-Wire data pin. In order to change it, set the `THERMO_GPIO_PIN` macro to any of the options listed below:

View File

@@ -1,14 +0,0 @@
App(
appid="arkanoid",
name="Arkanoid",
apptype=FlipperAppType.EXTERNAL,
entry_point="arkanoid_game_app",
requires=["gui"],
stack_size=1 * 1024,
order=30,
fap_icon="arkanoid_10px.png",
fap_category="Games",
fap_author="@xMasterX & @gotnull",
fap_version="1.0",
fap_description="Arkanoid Game",
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,479 +0,0 @@
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
#include <stdlib.h>
#include <gui/view.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <dolphin/dolphin.h>
#define TAG "Arkanoid"
#define FLIPPER_LCD_WIDTH 128
#define FLIPPER_LCD_HEIGHT 64
#define MAX_SPEED 3
typedef enum { EventTypeTick, EventTypeKey } EventType;
typedef struct {
//Brick Bounds used in collision detection
int leftBrick;
int rightBrick;
int topBrick;
int bottomBrick;
bool isHit[4][13]; //Array of if bricks are hit or not
} BrickState;
typedef struct {
int dx; //Initial movement of ball
int dy; //Initial movement of ball
int xb; //Balls starting possition
int yb; //Balls starting possition
bool released; //If the ball has been released by the player
//Ball Bounds used in collision detection
int leftBall;
int rightBall;
int topBall;
int bottomBall;
} BallState;
typedef struct {
FuriMutex* mutex;
BallState ball_state;
BrickState brick_state;
NotificationApp* notify;
unsigned int COLUMNS; //Columns of bricks
unsigned int ROWS; //Rows of bricks
bool initialDraw; //If the inital draw has happened
int xPaddle; //X position of paddle
char text[16]; //General string buffer
bool bounced; //Used to fix double bounce glitch
int lives; //Amount of lives
int level; //Current level
unsigned int score; //Score for the game
unsigned int brickCount; //Amount of bricks hit
int tick; //Tick counter
bool gameStarted; // Did the game start?
int speed; // Ball speed
} ArkanoidState;
typedef struct {
EventType type;
InputEvent input;
} GameEvent;
static const NotificationSequence sequence_short_sound = {
&message_note_c5,
&message_delay_50,
&message_sound_off,
NULL,
};
// generate number in range [min,max)
int rand_range(int min, int max) {
return min + rand() % (max - min);
}
void move_ball(Canvas* canvas, ArkanoidState* st) {
st->tick++;
int current_speed = abs(st->speed - 1 - MAX_SPEED);
if(st->tick % current_speed != 0 && st->tick % (current_speed + 1) != 0) {
return;
}
if(st->ball_state.released) {
//Move ball
if(abs(st->ball_state.dx) == 2) {
st->ball_state.xb += st->ball_state.dx / 2;
// 2x speed is really 1.5 speed
if((st->tick / current_speed) % 2 == 0) st->ball_state.xb += st->ball_state.dx / 2;
} else {
st->ball_state.xb += st->ball_state.dx;
}
st->ball_state.yb = st->ball_state.yb + st->ball_state.dy;
//Set bounds
st->ball_state.leftBall = st->ball_state.xb;
st->ball_state.rightBall = st->ball_state.xb + 2;
st->ball_state.topBall = st->ball_state.yb;
st->ball_state.bottomBall = st->ball_state.yb + 2;
//Bounce off top edge
if(st->ball_state.yb <= 0) {
st->ball_state.yb = 2;
st->ball_state.dy = -st->ball_state.dy;
}
//Lose a life if bottom edge hit
if(st->ball_state.yb >= FLIPPER_LCD_HEIGHT) {
canvas_draw_frame(canvas, st->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
st->xPaddle = 54;
st->ball_state.yb = 60;
st->ball_state.released = false;
st->lives--;
st->gameStarted = false;
if(rand_range(0, 2) == 0) {
st->ball_state.dx = 1;
} else {
st->ball_state.dx = -1;
}
}
//Bounce off left side
if(st->ball_state.xb <= 0) {
st->ball_state.xb = 2;
st->ball_state.dx = -st->ball_state.dx;
}
//Bounce off right side
if(st->ball_state.xb >= FLIPPER_LCD_WIDTH - 2) {
st->ball_state.xb = FLIPPER_LCD_WIDTH - 4;
st->ball_state.dx = -st->ball_state.dx;
// arduboy.tunes.tone(523, 250);
}
//Bounce off paddle
if(st->ball_state.xb + 1 >= st->xPaddle && st->ball_state.xb <= st->xPaddle + 12 &&
st->ball_state.yb + 2 >= FLIPPER_LCD_HEIGHT - 1 &&
st->ball_state.yb <= FLIPPER_LCD_HEIGHT) {
st->ball_state.dy = -st->ball_state.dy;
st->ball_state.dx =
((st->ball_state.xb - (st->xPaddle + 6)) / 3); //Applies spin on the ball
// prevent straight bounce, but not prevent roguuemaster from stealing
if(st->ball_state.dx == 0) {
st->ball_state.dx = (rand_range(0, 2) == 1) ? 1 : -1;
}
}
//Bounce off Bricks
for(unsigned int row = 0; row < st->ROWS; row++) {
for(unsigned int column = 0; column < st->COLUMNS; column++) {
if(!st->brick_state.isHit[row][column]) {
//Sets Brick bounds
st->brick_state.leftBrick = 10 * column;
st->brick_state.rightBrick = 10 * column + 10;
st->brick_state.topBrick = 6 * row + 1;
st->brick_state.bottomBrick = 6 * row + 7;
//If A collison has occured
if(st->ball_state.topBall <= st->brick_state.bottomBrick &&
st->ball_state.bottomBall >= st->brick_state.topBrick &&
st->ball_state.leftBall <= st->brick_state.rightBrick &&
st->ball_state.rightBall >= st->brick_state.leftBrick) {
st->score += st->level;
// Blink led when we hit some brick
notification_message(st->notify, &sequence_short_sound);
//notification_message(st->notify, &sequence_blink_white_100);
st->brickCount++;
st->brick_state.isHit[row][column] = true;
canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4);
//Vertical collision
if(st->ball_state.bottomBall > st->brick_state.bottomBrick ||
st->ball_state.topBall < st->brick_state.topBrick) {
//Only bounce once each ball move
if(!st->bounced) {
st->ball_state.dy = -st->ball_state.dy;
st->ball_state.yb += st->ball_state.dy;
st->bounced = true;
}
}
//Hoizontal collision
if(st->ball_state.leftBall < st->brick_state.leftBrick ||
st->ball_state.rightBall > st->brick_state.rightBrick) {
//Only bounce once brick each ball move
if(!st->bounced) {
st->ball_state.dx = -st->ball_state.dx;
st->ball_state.xb += st->ball_state.dx;
st->bounced = true;
}
}
}
}
}
}
//Reset Bounce
st->bounced = false;
} else {
//Ball follows paddle
st->ball_state.xb = st->xPaddle + 5;
}
}
void draw_lives(Canvas* canvas, ArkanoidState* arkanoid_state) {
if(arkanoid_state->lives == 3) {
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 11);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 11);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 12);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 12);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 15);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 15);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 16);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 16);
} else if(arkanoid_state->lives == 2) {
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 11);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 11);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 12);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 12);
} else {
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8);
}
}
void draw_score(Canvas* canvas, ArkanoidState* arkanoid_state) {
snprintf(arkanoid_state->text, sizeof(arkanoid_state->text), "%u", arkanoid_state->score);
canvas_draw_str_aligned(
canvas,
FLIPPER_LCD_WIDTH - 2,
FLIPPER_LCD_HEIGHT - 6,
AlignRight,
AlignBottom,
arkanoid_state->text);
}
void draw_ball(Canvas* canvas, ArkanoidState* ast) {
canvas_draw_dot(canvas, ast->ball_state.xb, ast->ball_state.yb);
canvas_draw_dot(canvas, ast->ball_state.xb + 1, ast->ball_state.yb);
canvas_draw_dot(canvas, ast->ball_state.xb, ast->ball_state.yb + 1);
canvas_draw_dot(canvas, ast->ball_state.xb + 1, ast->ball_state.yb + 1);
move_ball(canvas, ast);
}
void draw_paddle(Canvas* canvas, ArkanoidState* arkanoid_state) {
canvas_draw_frame(canvas, arkanoid_state->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
}
void reset_level(Canvas* canvas, ArkanoidState* arkanoid_state) {
//Undraw paddle
canvas_draw_frame(canvas, arkanoid_state->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
//Undraw ball
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb, arkanoid_state->ball_state.yb);
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb + 1, arkanoid_state->ball_state.yb);
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb, arkanoid_state->ball_state.yb + 1);
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb + 1, arkanoid_state->ball_state.yb + 1);
//Alter various variables to reset the game
arkanoid_state->xPaddle = 54;
arkanoid_state->ball_state.yb = 60;
arkanoid_state->brickCount = 0;
arkanoid_state->ball_state.released = false;
arkanoid_state->gameStarted = false;
// Reset all brick hit states
for(unsigned int row = 0; row < arkanoid_state->ROWS; row++) {
for(unsigned int column = 0; column < arkanoid_state->COLUMNS; column++) {
arkanoid_state->brick_state.isHit[row][column] = false;
}
}
}
static void arkanoid_state_init(ArkanoidState* arkanoid_state) {
// Init notification
arkanoid_state->notify = furi_record_open(RECORD_NOTIFICATION);
// Set the initial game state
arkanoid_state->COLUMNS = 13;
arkanoid_state->ROWS = 4;
arkanoid_state->ball_state.dx = -1;
arkanoid_state->ball_state.dy = -1;
arkanoid_state->speed = 2;
arkanoid_state->bounced = false;
arkanoid_state->lives = 3;
arkanoid_state->level = 1;
arkanoid_state->score = 0;
arkanoid_state->COLUMNS = 13;
arkanoid_state->COLUMNS = 13;
// Reset initial state
arkanoid_state->initialDraw = false;
arkanoid_state->gameStarted = false;
}
static void arkanoid_draw_callback(Canvas* const canvas, void* ctx) {
furi_assert(ctx);
ArkanoidState* arkanoid_state = ctx;
furi_mutex_acquire(arkanoid_state->mutex, FuriWaitForever);
//Initial level draw
if(!arkanoid_state->initialDraw) {
arkanoid_state->initialDraw = true;
// Set default font for text
canvas_set_font(canvas, FontSecondary);
//Draws the new level
reset_level(canvas, arkanoid_state);
}
//Draws new bricks and resets their values
for(unsigned int row = 0; row < arkanoid_state->ROWS; row++) {
for(unsigned int column = 0; column < arkanoid_state->COLUMNS; column++) {
if(!arkanoid_state->brick_state.isHit[row][column]) {
canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4);
}
}
}
if(arkanoid_state->lives > 0) {
draw_paddle(canvas, arkanoid_state);
draw_ball(canvas, arkanoid_state);
draw_score(canvas, arkanoid_state);
draw_lives(canvas, arkanoid_state);
if(arkanoid_state->brickCount == arkanoid_state->ROWS * arkanoid_state->COLUMNS) {
arkanoid_state->level++;
reset_level(canvas, arkanoid_state);
}
} else {
reset_level(canvas, arkanoid_state);
arkanoid_state->initialDraw = false;
arkanoid_state->lives = 3;
arkanoid_state->score = 0;
}
furi_mutex_release(arkanoid_state->mutex);
}
static void arkanoid_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
GameEvent event = {.type = EventTypeKey, .input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
static void arkanoid_update_timer_callback(FuriMessageQueue* event_queue) {
furi_assert(event_queue);
GameEvent event = {.type = EventTypeTick};
furi_message_queue_put(event_queue, &event, 0);
}
int32_t arkanoid_game_app(void* p) {
UNUSED(p);
int32_t return_code = 0;
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent));
ArkanoidState* arkanoid_state = malloc(sizeof(ArkanoidState));
arkanoid_state_init(arkanoid_state);
arkanoid_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!arkanoid_state->mutex) {
FURI_LOG_E(TAG, "Cannot create mutex\r\n");
return_code = 255;
goto free_and_exit;
}
// Set system callbacks
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, arkanoid_draw_callback, arkanoid_state);
view_port_input_callback_set(view_port, arkanoid_input_callback, event_queue);
FuriTimer* timer =
furi_timer_alloc(arkanoid_update_timer_callback, FuriTimerTypePeriodic, event_queue);
furi_timer_start(timer, furi_kernel_get_tick_frequency() / 22);
// Open GUI and register view_port
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
// Call dolphin deed on game start
dolphin_deed(DolphinDeedPluginGameStart);
GameEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
furi_mutex_acquire(arkanoid_state->mutex, FuriWaitForever);
if(event_status == FuriStatusOk) {
// Key events
if(event.type == EventTypeKey) {
if(event.input.type == InputTypePress || event.input.type == InputTypeLong ||
event.input.type == InputTypeRepeat) {
switch(event.input.key) {
case InputKeyBack:
processing = false;
break;
case InputKeyRight:
if(arkanoid_state->xPaddle < FLIPPER_LCD_WIDTH - 12) {
arkanoid_state->xPaddle += 8;
}
break;
case InputKeyLeft:
if(arkanoid_state->xPaddle > 0) {
arkanoid_state->xPaddle -= 8;
}
break;
case InputKeyUp:
if(arkanoid_state->speed < MAX_SPEED) {
arkanoid_state->speed++;
}
break;
case InputKeyDown:
if(arkanoid_state->speed > 1) {
arkanoid_state->speed--;
}
break;
case InputKeyOk:
if(arkanoid_state->gameStarted == false) {
//Release ball if FIRE pressed
arkanoid_state->ball_state.released = true;
//Apply random direction to ball on release
if(rand_range(0, 2) == 0) {
arkanoid_state->ball_state.dx = 1;
} else {
arkanoid_state->ball_state.dx = -1;
}
//Makes sure the ball heads upwards
arkanoid_state->ball_state.dy = -1;
//start the game flag
arkanoid_state->gameStarted = true;
}
break;
default:
break;
}
}
}
}
view_port_update(view_port);
furi_mutex_release(arkanoid_state->mutex);
}
furi_timer_free(timer);
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close(RECORD_GUI);
furi_record_close(RECORD_NOTIFICATION);
view_port_free(view_port);
furi_mutex_free(arkanoid_state->mutex);
free_and_exit:
free(arkanoid_state);
furi_message_queue_free(event_queue);
return return_code;
}

View File

@@ -1,17 +0,0 @@
App(
appid="avr_isp",
name="AVR Flasher",
apptype=FlipperAppType.EXTERNAL,
entry_point="avr_isp_app",
requires=["gui"],
stack_size=4 * 1024,
order=20,
fap_icon="avr_app_icon_10x10.png",
fap_category="GPIO",
fap_icon_assets="images",
fap_private_libs=[
Lib(
name="driver",
),
],
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -1,179 +0,0 @@
#include "avr_isp_app_i.h"
static bool avr_isp_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
AvrIspApp* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}
static bool avr_isp_app_back_event_callback(void* context) {
furi_assert(context);
AvrIspApp* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}
static void avr_isp_app_tick_event_callback(void* context) {
furi_assert(context);
AvrIspApp* app = context;
scene_manager_handle_tick_event(app->scene_manager);
}
AvrIspApp* avr_isp_app_alloc() {
AvrIspApp* app = malloc(sizeof(AvrIspApp));
app->file_path = furi_string_alloc();
furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
app->error = AvrIspErrorNoError;
// GUI
app->gui = furi_record_open(RECORD_GUI);
// View Dispatcher
app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&avr_isp_scene_handlers, app);
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_custom_event_callback(
app->view_dispatcher, avr_isp_app_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher, avr_isp_app_back_event_callback);
view_dispatcher_set_tick_event_callback(
app->view_dispatcher, avr_isp_app_tick_event_callback, 100);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
// Open Notification record
app->notifications = furi_record_open(RECORD_NOTIFICATION);
// SubMenu
app->submenu = submenu_alloc();
view_dispatcher_add_view(
app->view_dispatcher, AvrIspViewSubmenu, submenu_get_view(app->submenu));
// Widget
app->widget = widget_alloc();
view_dispatcher_add_view(app->view_dispatcher, AvrIspViewWidget, widget_get_view(app->widget));
// Text Input
app->text_input = text_input_alloc();
view_dispatcher_add_view(
app->view_dispatcher, AvrIspViewTextInput, text_input_get_view(app->text_input));
// Popup
app->popup = popup_alloc();
view_dispatcher_add_view(app->view_dispatcher, AvrIspViewPopup, popup_get_view(app->popup));
//Dialog
app->dialogs = furi_record_open(RECORD_DIALOGS);
// Programmer view
app->avr_isp_programmer_view = avr_isp_programmer_view_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
AvrIspViewProgrammer,
avr_isp_programmer_view_get_view(app->avr_isp_programmer_view));
// Reader view
app->avr_isp_reader_view = avr_isp_reader_view_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
AvrIspViewReader,
avr_isp_reader_view_get_view(app->avr_isp_reader_view));
// Writer view
app->avr_isp_writer_view = avr_isp_writer_view_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
AvrIspViewWriter,
avr_isp_writer_view_get_view(app->avr_isp_writer_view));
// Chip detect view
app->avr_isp_chip_detect_view = avr_isp_chip_detect_view_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
AvrIspViewChipDetect,
avr_isp_chip_detect_view_get_view(app->avr_isp_chip_detect_view));
// Enable 5v power, multiple attempts to avoid issues with power chip protection false triggering
uint8_t attempts = 0;
while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
furi_hal_power_enable_otg();
furi_delay_ms(10);
}
scene_manager_next_scene(app->scene_manager, AvrIspSceneStart);
return app;
} //-V773
void avr_isp_app_free(AvrIspApp* app) {
furi_assert(app);
// Disable 5v power
if(furi_hal_power_is_otg_enabled()) {
furi_hal_power_disable_otg();
}
// Submenu
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewSubmenu);
submenu_free(app->submenu);
// Widget
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewWidget);
widget_free(app->widget);
// TextInput
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewTextInput);
text_input_free(app->text_input);
// Popup
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewPopup);
popup_free(app->popup);
//Dialog
furi_record_close(RECORD_DIALOGS);
// Programmer view
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewProgrammer);
avr_isp_programmer_view_free(app->avr_isp_programmer_view);
// Reader view
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewReader);
avr_isp_reader_view_free(app->avr_isp_reader_view);
// Writer view
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewWriter);
avr_isp_writer_view_free(app->avr_isp_writer_view);
// Chip detect view
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewChipDetect);
avr_isp_chip_detect_view_free(app->avr_isp_chip_detect_view);
// View dispatcher
view_dispatcher_free(app->view_dispatcher);
scene_manager_free(app->scene_manager);
// Notifications
furi_record_close(RECORD_NOTIFICATION);
app->notifications = NULL;
// Close records
furi_record_close(RECORD_GUI);
// Path strings
furi_string_free(app->file_path);
free(app);
}
int32_t avr_isp_app(void* p) {
UNUSED(p);
AvrIspApp* avr_isp_app = avr_isp_app_alloc();
view_dispatcher_run(avr_isp_app->view_dispatcher);
avr_isp_app_free(avr_isp_app);
return 0;
}

View File

@@ -1,31 +0,0 @@
#include "avr_isp_app_i.h"
#include <lib/toolbox/path.h>
#include <flipper_format/flipper_format_i.h>
#define TAG "AvrIsp"
bool avr_isp_load_from_file(AvrIspApp* app) {
furi_assert(app);
FuriString* file_path = furi_string_alloc();
FuriString* file_name = furi_string_alloc();
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(
&browser_options, AVR_ISP_APP_EXTENSION, &I_avr_app_icon_10x10);
browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
// Input events and views are managed by file_select
bool res = dialog_file_browser_show(app->dialogs, file_path, app->file_path, &browser_options);
if(res) {
path_extract_dirname(furi_string_get_cstr(file_path), app->file_path);
path_extract_filename(file_path, file_name, true);
strncpy(app->file_name_tmp, furi_string_get_cstr(file_name), AVR_ISP_MAX_LEN_NAME);
}
furi_string_free(file_name);
furi_string_free(file_path);
return res;
}

View File

@@ -1,44 +0,0 @@
#pragma once
#include "helpers/avr_isp_types.h"
#include <avr_isp_icons.h>
#include "scenes/avr_isp_scene.h"
#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <gui/modules/submenu.h>
#include <gui/modules/widget.h>
#include <notification/notification_messages.h>
#include <gui/modules/text_input.h>
#include <dialogs/dialogs.h>
#include <storage/storage.h>
#include <gui/modules/popup.h>
#include "views/avr_isp_view_programmer.h"
#include "views/avr_isp_view_reader.h"
#include "views/avr_isp_view_writer.h"
#include "views/avr_isp_view_chip_detect.h"
#define AVR_ISP_MAX_LEN_NAME 64
typedef struct {
Gui* gui;
ViewDispatcher* view_dispatcher;
SceneManager* scene_manager;
NotificationApp* notifications;
DialogsApp* dialogs;
Popup* popup;
Submenu* submenu;
Widget* widget;
TextInput* text_input;
FuriString* file_path;
char file_name_tmp[AVR_ISP_MAX_LEN_NAME];
AvrIspProgrammerView* avr_isp_programmer_view;
AvrIspReaderView* avr_isp_reader_view;
AvrIspWriterView* avr_isp_writer_view;
AvrIspChipDetectView* avr_isp_chip_detect_view;
AvrIspError error;
} AvrIspApp;
bool avr_isp_load_from_file(AvrIspApp* app);

View File

@@ -1,496 +0,0 @@
#include "avr_isp.h"
#include "../lib/driver/avr_isp_prog_cmd.h"
#include "../lib/driver/avr_isp_spi_sw.h"
#include <furi.h>
#define AVR_ISP_PROG_TX_RX_BUF_SIZE 320
#define TAG "AvrIsp"
struct AvrIsp {
AvrIspSpiSw* spi;
bool pmode;
AvrIspCallback callback;
void* context;
};
AvrIsp* avr_isp_alloc(void) {
AvrIsp* instance = malloc(sizeof(AvrIsp));
return instance;
}
void avr_isp_free(AvrIsp* instance) {
furi_assert(instance);
if(instance->spi) avr_isp_end_pmode(instance);
free(instance);
}
void avr_isp_set_tx_callback(AvrIsp* instance, AvrIspCallback callback, void* context) {
furi_assert(instance);
furi_assert(context);
instance->callback = callback;
instance->context = context;
}
uint8_t avr_isp_spi_transaction(
AvrIsp* instance,
uint8_t cmd,
uint8_t addr_hi,
uint8_t addr_lo,
uint8_t data) {
furi_assert(instance);
avr_isp_spi_sw_txrx(instance->spi, cmd);
avr_isp_spi_sw_txrx(instance->spi, addr_hi);
avr_isp_spi_sw_txrx(instance->spi, addr_lo);
return avr_isp_spi_sw_txrx(instance->spi, data);
}
static bool avr_isp_set_pmode(AvrIsp* instance, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
furi_assert(instance);
uint8_t res = 0;
avr_isp_spi_sw_txrx(instance->spi, a);
avr_isp_spi_sw_txrx(instance->spi, b);
res = avr_isp_spi_sw_txrx(instance->spi, c);
avr_isp_spi_sw_txrx(instance->spi, d);
return res == 0x53;
}
void avr_isp_end_pmode(AvrIsp* instance) {
furi_assert(instance);
if(instance->pmode) {
avr_isp_spi_sw_res_set(instance->spi, true);
// We're about to take the target out of reset
// so configure SPI pins as input
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
instance->spi = NULL;
}
instance->pmode = false;
}
static bool avr_isp_start_pmode(AvrIsp* instance, AvrIspSpiSwSpeed spi_speed) {
furi_assert(instance);
// Reset target before driving PIN_SCK or PIN_MOSI
// SPI.begin() will configure SS as output,
// so SPI master mode is selected.
// We have defined RESET as pin 10,
// which for many arduino's is not the SS pin.
// So we have to configure RESET as output here,
// (reset_target() first sets the correct level)
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
instance->spi = avr_isp_spi_sw_init(spi_speed);
avr_isp_spi_sw_res_set(instance->spi, false);
// See avr datasheets, chapter "SERIAL_PRG Programming Algorithm":
// Pulse RESET after PIN_SCK is low:
avr_isp_spi_sw_sck_set(instance->spi, false);
// discharge PIN_SCK, value arbitrally chosen
furi_delay_ms(20);
avr_isp_spi_sw_res_set(instance->spi, true);
// Pulse must be minimum 2 target CPU speed cycles
// so 100 usec is ok for CPU speeds above 20KHz
furi_delay_ms(1);
avr_isp_spi_sw_res_set(instance->spi, false);
// Send the enable programming command:
// datasheet: must be > 20 msec
furi_delay_ms(50);
if(avr_isp_set_pmode(instance, AVR_ISP_SET_PMODE)) {
instance->pmode = true;
return true;
}
return false;
}
bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance) {
furi_assert(instance);
AvrIspSpiSwSpeed spi_speed[] = {
AvrIspSpiSwSpeed1Mhz,
AvrIspSpiSwSpeed400Khz,
AvrIspSpiSwSpeed250Khz,
AvrIspSpiSwSpeed125Khz,
AvrIspSpiSwSpeed60Khz,
AvrIspSpiSwSpeed40Khz,
AvrIspSpiSwSpeed20Khz,
AvrIspSpiSwSpeed10Khz,
AvrIspSpiSwSpeed5Khz,
AvrIspSpiSwSpeed1Khz,
};
for(uint8_t i = 0; i < COUNT_OF(spi_speed); i++) {
if(avr_isp_start_pmode(instance, spi_speed[i])) {
AvrIspSignature sig = avr_isp_read_signature(instance);
AvrIspSignature sig_examination = avr_isp_read_signature(instance); //-V656
uint8_t y = 0;
while(y < 8) {
if(memcmp((uint8_t*)&sig, (uint8_t*)&sig_examination, sizeof(AvrIspSignature)) !=
0)
break;
sig_examination = avr_isp_read_signature(instance);
y++;
}
if(y == 8) {
if(spi_speed[i] > AvrIspSpiSwSpeed1Mhz) {
if(i < (COUNT_OF(spi_speed) - 1)) {
avr_isp_end_pmode(instance);
i++;
return avr_isp_start_pmode(instance, spi_speed[i]);
}
}
return true;
}
}
}
if(instance->spi) {
avr_isp_spi_sw_free(instance->spi);
instance->spi = NULL;
}
return false;
}
static void avr_isp_commit(AvrIsp* instance, uint16_t addr, uint8_t data) {
furi_assert(instance);
avr_isp_spi_transaction(instance, AVR_ISP_COMMIT(addr));
/* polling flash */
if(data == 0xFF) {
furi_delay_ms(5);
} else {
/* polling flash */
uint32_t starttime = furi_get_tick();
while((furi_get_tick() - starttime) < 30) {
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) {
break;
};
}
}
}
static uint16_t avr_isp_current_page(AvrIsp* instance, uint32_t addr, uint16_t page_size) {
furi_assert(instance);
uint16_t page = 0;
switch(page_size) {
case 32:
page = addr & 0xFFFFFFF0;
break;
case 64:
page = addr & 0xFFFFFFE0;
break;
case 128:
page = addr & 0xFFFFFFC0;
break;
case 256:
page = addr & 0xFFFFFF80;
break;
default:
page = addr;
break;
}
return page;
}
static bool avr_isp_flash_write_pages(
AvrIsp* instance,
uint16_t addr,
uint16_t page_size,
uint8_t* data,
uint32_t data_size) {
furi_assert(instance);
size_t x = 0;
uint16_t page = avr_isp_current_page(instance, addr, page_size);
while(x < data_size) {
if(page != avr_isp_current_page(instance, addr, page_size)) {
avr_isp_commit(instance, page, data[x - 1]);
page = avr_isp_current_page(instance, addr, page_size);
}
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FLASH_LO(addr, data[x++]));
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FLASH_HI(addr, data[x++]));
addr++;
}
avr_isp_commit(instance, page, data[x - 1]);
return true;
}
bool avr_isp_erase_chip(AvrIsp* instance) {
furi_assert(instance);
bool ret = false;
if(!instance->pmode) avr_isp_auto_set_spi_speed_start_pmode(instance);
if(instance->pmode) {
avr_isp_spi_transaction(instance, AVR_ISP_ERASE_CHIP);
furi_delay_ms(100);
avr_isp_end_pmode(instance);
ret = true;
}
return ret;
}
static bool
avr_isp_eeprom_write(AvrIsp* instance, uint16_t addr, uint8_t* data, uint32_t data_size) {
furi_assert(instance);
for(uint16_t i = 0; i < data_size; i++) {
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_EEPROM(addr, data[i]));
furi_delay_ms(10);
addr++;
}
return true;
}
bool avr_isp_write_page(
AvrIsp* instance,
uint32_t mem_type,
uint32_t mem_size,
uint16_t addr,
uint16_t page_size,
uint8_t* data,
uint32_t data_size) {
furi_assert(instance);
bool ret = false;
switch(mem_type) {
case STK_SET_FLASH_TYPE:
if((addr + data_size / 2) <= mem_size) {
ret = avr_isp_flash_write_pages(instance, addr, page_size, data, data_size);
}
break;
case STK_SET_EEPROM_TYPE:
if((addr + data_size) <= mem_size) {
ret = avr_isp_eeprom_write(instance, addr, data, data_size);
}
break;
default:
furi_crash(TAG " Incorrect mem type.");
break;
}
return ret;
}
static bool avr_isp_flash_read_page(
AvrIsp* instance,
uint16_t addr,
uint16_t page_size,
uint8_t* data,
uint32_t data_size) {
furi_assert(instance);
if(page_size > data_size) return false;
for(uint16_t i = 0; i < page_size; i += 2) {
data[i] = avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_LO(addr));
data[i + 1] = avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr));
addr++;
}
return true;
}
static bool avr_isp_eeprom_read_page(
AvrIsp* instance,
uint16_t addr,
uint16_t page_size,
uint8_t* data,
uint32_t data_size) {
furi_assert(instance);
if(page_size > data_size) return false;
for(uint16_t i = 0; i < page_size; i++) {
data[i] = avr_isp_spi_transaction(instance, AVR_ISP_READ_EEPROM(addr));
addr++;
}
return true;
}
bool avr_isp_read_page(
AvrIsp* instance,
uint32_t mem_type,
uint16_t addr,
uint16_t page_size,
uint8_t* data,
uint32_t data_size) {
furi_assert(instance);
bool res = false;
if(mem_type == STK_SET_FLASH_TYPE)
res = avr_isp_flash_read_page(instance, addr, page_size, data, data_size);
if(mem_type == STK_SET_EEPROM_TYPE)
res = avr_isp_eeprom_read_page(instance, addr, page_size, data, data_size);
return res;
}
AvrIspSignature avr_isp_read_signature(AvrIsp* instance) {
furi_assert(instance);
AvrIspSignature signature;
signature.vendor = avr_isp_spi_transaction(instance, AVR_ISP_READ_VENDOR);
signature.part_family = avr_isp_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY);
signature.part_number = avr_isp_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER);
return signature;
}
uint8_t avr_isp_read_lock_byte(AvrIsp* instance) {
furi_assert(instance);
uint8_t data = 0;
uint32_t starttime = furi_get_tick();
while((furi_get_tick() - starttime) < 300) {
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE);
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == data) {
break;
};
data = 0x00;
}
return data;
}
bool avr_isp_write_lock_byte(AvrIsp* instance, uint8_t lock) {
furi_assert(instance);
bool ret = false;
if(avr_isp_read_lock_byte(instance) == lock) {
ret = true;
} else {
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_LOCK_BYTE(lock));
/* polling lock byte */
uint32_t starttime = furi_get_tick();
while((furi_get_tick() - starttime) < 30) {
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == lock) {
ret = true;
break;
};
}
}
return ret;
}
uint8_t avr_isp_read_fuse_low(AvrIsp* instance) {
furi_assert(instance);
uint8_t data = 0;
uint32_t starttime = furi_get_tick();
while((furi_get_tick() - starttime) < 300) {
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW);
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == data) {
break;
};
data = 0x00;
}
return data;
}
bool avr_isp_write_fuse_low(AvrIsp* instance, uint8_t lfuse) {
furi_assert(instance);
bool ret = false;
if(avr_isp_read_fuse_low(instance) == lfuse) {
ret = true;
} else {
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_LOW(lfuse));
/* polling fuse */
uint32_t starttime = furi_get_tick();
while((furi_get_tick() - starttime) < 30) {
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == lfuse) {
ret = true;
break;
};
}
}
return ret;
}
uint8_t avr_isp_read_fuse_high(AvrIsp* instance) {
furi_assert(instance);
uint8_t data = 0;
uint32_t starttime = furi_get_tick();
while((furi_get_tick() - starttime) < 300) {
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH);
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == data) {
break;
};
data = 0x00;
}
return data;
}
bool avr_isp_write_fuse_high(AvrIsp* instance, uint8_t hfuse) {
furi_assert(instance);
bool ret = false;
if(avr_isp_read_fuse_high(instance) == hfuse) {
ret = true;
} else {
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_HIGH(hfuse));
/* polling fuse */
uint32_t starttime = furi_get_tick();
while((furi_get_tick() - starttime) < 30) {
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == hfuse) {
ret = true;
break;
};
}
}
return ret;
}
uint8_t avr_isp_read_fuse_extended(AvrIsp* instance) {
furi_assert(instance);
uint8_t data = 0;
uint32_t starttime = furi_get_tick();
while((furi_get_tick() - starttime) < 300) {
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED);
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == data) {
break;
};
data = 0x00;
}
return data;
}
bool avr_isp_write_fuse_extended(AvrIsp* instance, uint8_t efuse) {
furi_assert(instance);
bool ret = false;
if(avr_isp_read_fuse_extended(instance) == efuse) {
ret = true;
} else {
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_EXTENDED(efuse));
/* polling fuse */
uint32_t starttime = furi_get_tick();
while((furi_get_tick() - starttime) < 30) {
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == efuse) {
ret = true;
break;
};
}
}
return ret;
}
void avr_isp_write_extended_addr(AvrIsp* instance, uint8_t extended_addr) {
furi_assert(instance);
avr_isp_spi_transaction(instance, AVR_ISP_EXTENDED_ADDR(extended_addr));
furi_delay_ms(10);
}

View File

@@ -1,70 +0,0 @@
#pragma once
#include <furi_hal.h>
typedef struct AvrIsp AvrIsp;
typedef void (*AvrIspCallback)(void* context);
struct AvrIspSignature {
uint8_t vendor;
uint8_t part_family;
uint8_t part_number;
};
typedef struct AvrIspSignature AvrIspSignature;
AvrIsp* avr_isp_alloc(void);
void avr_isp_free(AvrIsp* instance);
void avr_isp_set_tx_callback(AvrIsp* instance, AvrIspCallback callback, void* context);
bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance);
AvrIspSignature avr_isp_read_signature(AvrIsp* instance);
void avr_isp_end_pmode(AvrIsp* instance);
bool avr_isp_erase_chip(AvrIsp* instance);
uint8_t avr_isp_spi_transaction(
AvrIsp* instance,
uint8_t cmd,
uint8_t addr_hi,
uint8_t addr_lo,
uint8_t data);
bool avr_isp_read_page(
AvrIsp* instance,
uint32_t memtype,
uint16_t addr,
uint16_t page_size,
uint8_t* data,
uint32_t data_size);
bool avr_isp_write_page(
AvrIsp* instance,
uint32_t mem_type,
uint32_t mem_size,
uint16_t addr,
uint16_t page_size,
uint8_t* data,
uint32_t data_size);
uint8_t avr_isp_read_lock_byte(AvrIsp* instance);
bool avr_isp_write_lock_byte(AvrIsp* instance, uint8_t lock);
uint8_t avr_isp_read_fuse_low(AvrIsp* instance);
bool avr_isp_write_fuse_low(AvrIsp* instance, uint8_t lfuse);
uint8_t avr_isp_read_fuse_high(AvrIsp* instance);
bool avr_isp_write_fuse_high(AvrIsp* instance, uint8_t hfuse);
uint8_t avr_isp_read_fuse_extended(AvrIsp* instance);
bool avr_isp_write_fuse_extended(AvrIsp* instance, uint8_t efuse);
void avr_isp_write_extended_addr(AvrIsp* instance, uint8_t extended_addr);

View File

@@ -1,23 +0,0 @@
#pragma once
typedef enum {
//SubmenuIndex
SubmenuIndexAvrIspProgrammer = 10,
SubmenuIndexAvrIspReader,
SubmenuIndexAvrIspWriter,
SubmenuIndexAvrIsWiring,
SubmenuIndexAvrIspAbout,
//AvrIspCustomEvent
AvrIspCustomEventSceneChipDetectOk = 100,
AvrIspCustomEventSceneReadingOk,
AvrIspCustomEventSceneWritingOk,
AvrIspCustomEventSceneErrorVerification,
AvrIspCustomEventSceneErrorReading,
AvrIspCustomEventSceneErrorWriting,
AvrIspCustomEventSceneErrorWritingFuse,
AvrIspCustomEventSceneInputName,
AvrIspCustomEventSceneSuccess,
AvrIspCustomEventSceneExit,
AvrIspCustomEventSceneExitStartMenu,
} AvrIspCustomEvent;

View File

@@ -1,32 +0,0 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#define AVR_ISP_VERSION_APP "0.1"
#define AVR_ISP_DEVELOPED "SkorP"
#define AVR_ISP_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
#define AVR_ISP_APP_FILE_VERSION 1
#define AVR_ISP_APP_FILE_TYPE "Flipper Dump AVR"
#define AVR_ISP_APP_EXTENSION ".avr"
typedef enum {
//AvrIspViewVariableItemList,
AvrIspViewSubmenu,
AvrIspViewProgrammer,
AvrIspViewReader,
AvrIspViewWriter,
AvrIspViewWidget,
AvrIspViewPopup,
AvrIspViewTextInput,
AvrIspViewChipDetect,
} AvrIspView;
typedef enum {
AvrIspErrorNoError,
AvrIspErrorReading,
AvrIspErrorWriting,
AvrIspErrorVerification,
AvrIspErrorWritingFuse,
} AvrIspError;

View File

@@ -1,266 +0,0 @@
#include "avr_isp_worker.h"
#include <furi_hal_pwm.h>
#include "../lib/driver/avr_isp_prog.h"
#include "../lib/driver/avr_isp_prog_cmd.h"
#include "../lib/driver/avr_isp_chip_arr.h"
#include <furi.h>
#define TAG "AvrIspWorker"
typedef enum {
AvrIspWorkerEvtStop = (1 << 0),
AvrIspWorkerEvtRx = (1 << 1),
AvrIspWorkerEvtTxCoplete = (1 << 2),
AvrIspWorkerEvtTx = (1 << 3),
AvrIspWorkerEvtState = (1 << 4),
//AvrIspWorkerEvtCfg = (1 << 5),
} AvrIspWorkerEvt;
struct AvrIspWorker {
FuriThread* thread;
volatile bool worker_running;
uint8_t connect_usb;
AvrIspWorkerCallback callback;
void* context;
};
#define AVR_ISP_WORKER_PROG_ALL_EVENTS (AvrIspWorkerEvtStop)
#define AVR_ISP_WORKER_ALL_EVENTS \
(AvrIspWorkerEvtTx | AvrIspWorkerEvtTxCoplete | AvrIspWorkerEvtRx | AvrIspWorkerEvtStop | \
AvrIspWorkerEvtState)
//########################/* VCP CDC */#############################################
#include "usb_cdc.h"
#include <cli/cli_vcp.h>
#include <cli/cli.h>
#include <furi_hal_usb_cdc.h>
#define AVR_ISP_VCP_CDC_CH 1
#define AVR_ISP_VCP_CDC_PKT_LEN CDC_DATA_SZ
#define AVR_ISP_VCP_UART_RX_BUF_SIZE (AVR_ISP_VCP_CDC_PKT_LEN * 5)
static void vcp_on_cdc_tx_complete(void* context);
static void vcp_on_cdc_rx(void* context);
static void vcp_state_callback(void* context, uint8_t state);
static void vcp_on_cdc_control_line(void* context, uint8_t state);
static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config);
static const CdcCallbacks cdc_cb = {
vcp_on_cdc_tx_complete,
vcp_on_cdc_rx,
vcp_state_callback,
vcp_on_cdc_control_line,
vcp_on_line_config,
};
/* VCP callbacks */
static void vcp_on_cdc_tx_complete(void* context) {
furi_assert(context);
AvrIspWorker* instance = context;
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTxCoplete);
}
static void vcp_on_cdc_rx(void* context) {
furi_assert(context);
AvrIspWorker* instance = context;
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
}
static void vcp_state_callback(void* context, uint8_t state) {
UNUSED(context);
AvrIspWorker* instance = context;
instance->connect_usb = state;
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtState);
}
static void vcp_on_cdc_control_line(void* context, uint8_t state) {
UNUSED(context);
UNUSED(state);
}
static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config) {
UNUSED(context);
UNUSED(config);
}
static void avr_isp_worker_vcp_cdc_init(void* context) {
furi_hal_usb_unlock();
Cli* cli = furi_record_open(RECORD_CLI);
//close cli
cli_session_close(cli);
//disable callbacks VCP_CDC=0
furi_hal_cdc_set_callbacks(0, NULL, NULL);
//set 2 cdc
furi_check(furi_hal_usb_set_config(&usb_cdc_dual, NULL) == true);
//open cli VCP_CDC=0
cli_session_open(cli, &cli_vcp);
furi_record_close(RECORD_CLI);
furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, (CdcCallbacks*)&cdc_cb, context);
}
static void avr_isp_worker_vcp_cdc_deinit(void) {
//disable callbacks AVR_ISP_VCP_CDC_CH
furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, NULL, NULL);
Cli* cli = furi_record_open(RECORD_CLI);
//close cli
cli_session_close(cli);
furi_hal_usb_unlock();
//set 1 cdc
furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true);
//open cli VCP_CDC=0
cli_session_open(cli, &cli_vcp);
furi_record_close(RECORD_CLI);
}
//#################################################################################
static int32_t avr_isp_worker_prog_thread(void* context) {
AvrIspProg* prog = context;
FURI_LOG_D(TAG, "AvrIspProgWorker Start");
while(1) {
if(furi_thread_flags_get() & AvrIspWorkerEvtStop) break;
avr_isp_prog_avrisp(prog);
}
FURI_LOG_D(TAG, "AvrIspProgWorker Stop");
return 0;
}
static void avr_isp_worker_prog_tx_data(void* context) {
furi_assert(context);
AvrIspWorker* instance = context;
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTx);
}
/** Worker thread
*
* @param context
* @return exit code
*/
static int32_t avr_isp_worker_thread(void* context) {
AvrIspWorker* instance = context;
avr_isp_worker_vcp_cdc_init(instance);
/* start PWM on &gpio_ext_pa4 */
furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
AvrIspProg* prog = avr_isp_prog_init();
avr_isp_prog_set_tx_callback(prog, avr_isp_worker_prog_tx_data, instance);
uint8_t buf[AVR_ISP_VCP_UART_RX_BUF_SIZE];
size_t len = 0;
FuriThread* prog_thread =
furi_thread_alloc_ex("AvrIspProgWorker", 1024, avr_isp_worker_prog_thread, prog);
furi_thread_start(prog_thread);
FURI_LOG_D(TAG, "Start");
while(instance->worker_running) {
uint32_t events =
furi_thread_flags_wait(AVR_ISP_WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever);
if(events & AvrIspWorkerEvtRx) {
if(avr_isp_prog_spaces_rx(prog) >= AVR_ISP_VCP_CDC_PKT_LEN) {
len = furi_hal_cdc_receive(AVR_ISP_VCP_CDC_CH, buf, AVR_ISP_VCP_CDC_PKT_LEN);
// for(uint8_t i = 0; i < len; i++) {
// FURI_LOG_I(TAG, "--> %X", buf[i]);
// }
avr_isp_prog_rx(prog, buf, len);
} else {
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
}
}
if((events & AvrIspWorkerEvtTxCoplete) || (events & AvrIspWorkerEvtTx)) {
len = avr_isp_prog_tx(prog, buf, AVR_ISP_VCP_CDC_PKT_LEN);
// for(uint8_t i = 0; i < len; i++) {
// FURI_LOG_I(TAG, "<-- %X", buf[i]);
// }
if(len > 0) furi_hal_cdc_send(AVR_ISP_VCP_CDC_CH, buf, len);
}
if(events & AvrIspWorkerEvtStop) {
break;
}
if(events & AvrIspWorkerEvtState) {
if(instance->callback)
instance->callback(instance->context, (bool)instance->connect_usb);
}
}
FURI_LOG_D(TAG, "Stop");
furi_thread_flags_set(furi_thread_get_id(prog_thread), AvrIspWorkerEvtStop);
avr_isp_prog_exit(prog);
furi_delay_ms(10);
furi_thread_join(prog_thread);
furi_thread_free(prog_thread);
avr_isp_prog_free(prog);
furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
avr_isp_worker_vcp_cdc_deinit();
return 0;
}
AvrIspWorker* avr_isp_worker_alloc(void* context) {
furi_assert(context);
UNUSED(context);
AvrIspWorker* instance = malloc(sizeof(AvrIspWorker));
instance->thread = furi_thread_alloc_ex("AvrIspWorker", 2048, avr_isp_worker_thread, instance);
return instance;
}
void avr_isp_worker_free(AvrIspWorker* instance) {
furi_assert(instance);
furi_check(!instance->worker_running);
furi_thread_free(instance->thread);
free(instance);
}
void avr_isp_worker_set_callback(
AvrIspWorker* instance,
AvrIspWorkerCallback callback,
void* context) {
furi_assert(instance);
instance->callback = callback;
instance->context = context;
}
void avr_isp_worker_start(AvrIspWorker* instance) {
furi_assert(instance);
furi_assert(!instance->worker_running);
instance->worker_running = true;
furi_thread_start(instance->thread);
}
void avr_isp_worker_stop(AvrIspWorker* instance) {
furi_assert(instance);
furi_assert(instance->worker_running);
instance->worker_running = false;
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtStop);
furi_thread_join(instance->thread);
}
bool avr_isp_worker_is_running(AvrIspWorker* instance) {
furi_assert(instance);
return instance->worker_running;
}

View File

@@ -1,49 +0,0 @@
#pragma once
#include <furi_hal.h>
typedef struct AvrIspWorker AvrIspWorker;
typedef void (*AvrIspWorkerCallback)(void* context, bool connect_usb);
/** Allocate AvrIspWorker
*
* @param context AvrIsp* context
* @return AvrIspWorker*
*/
AvrIspWorker* avr_isp_worker_alloc(void* context);
/** Free AvrIspWorker
*
* @param instance AvrIspWorker instance
*/
void avr_isp_worker_free(AvrIspWorker* instance);
/** Callback AvrIspWorker
*
* @param instance AvrIspWorker instance
* @param callback AvrIspWorkerOverrunCallback callback
* @param context
*/
void avr_isp_worker_set_callback(
AvrIspWorker* instance,
AvrIspWorkerCallback callback,
void* context);
/** Start AvrIspWorker
*
* @param instance AvrIspWorker instance
*/
void avr_isp_worker_start(AvrIspWorker* instance);
/** Stop AvrIspWorker
*
* @param instance AvrIspWorker instance
*/
void avr_isp_worker_stop(AvrIspWorker* instance);
/** Check if worker is running
* @param instance AvrIspWorker instance
* @return bool - true if running
*/
bool avr_isp_worker_is_running(AvrIspWorker* instance);

File diff suppressed because it is too large Load Diff

View File

@@ -1,99 +0,0 @@
#pragma once
#include <furi_hal.h>
typedef struct AvrIspWorkerRW AvrIspWorkerRW;
typedef void (*AvrIspWorkerRWCallback)(
void* context,
const char* name,
bool detect_chip,
uint32_t flash_size);
typedef enum {
AvrIspWorkerRWStatusILDE = 0,
AvrIspWorkerRWStatusEndReading = 1,
AvrIspWorkerRWStatusEndVerification = 2,
AvrIspWorkerRWStatusEndWriting = 3,
AvrIspWorkerRWStatusEndWritingFuse = 4,
AvrIspWorkerRWStatusErrorReading = (-1),
AvrIspWorkerRWStatusErrorVerification = (-2),
AvrIspWorkerRWStatusErrorWriting = (-3),
AvrIspWorkerRWStatusErrorWritingFuse = (-4),
AvrIspWorkerRWStatusReserved = 0x7FFFFFFF, ///< Prevents enum down-size compiler optimization.
} AvrIspWorkerRWStatus;
typedef void (*AvrIspWorkerRWStatusCallback)(void* context, AvrIspWorkerRWStatus status);
AvrIspWorkerRW* avr_isp_worker_rw_alloc(void* context);
void avr_isp_worker_rw_free(AvrIspWorkerRW* instance);
void avr_isp_worker_rw_start(AvrIspWorkerRW* instance);
void avr_isp_worker_rw_stop(AvrIspWorkerRW* instance);
bool avr_isp_worker_rw_is_running(AvrIspWorkerRW* instance);
void avr_isp_worker_rw_set_callback(
AvrIspWorkerRW* instance,
AvrIspWorkerRWCallback callback,
void* context);
void avr_isp_worker_rw_set_callback_status(
AvrIspWorkerRW* instance,
AvrIspWorkerRWStatusCallback callback_status,
void* context_status);
bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance);
float avr_isp_worker_rw_get_progress_flash(AvrIspWorkerRW* instance);
float avr_isp_worker_rw_get_progress_eeprom(AvrIspWorkerRW* instance);
bool avr_isp_worker_rw_read_dump(
AvrIspWorkerRW* instance,
const char* file_path,
const char* file_name);
void avr_isp_worker_rw_read_dump_start(
AvrIspWorkerRW* instance,
const char* file_path,
const char* file_name);
bool avr_isp_worker_rw_verification(
AvrIspWorkerRW* instance,
const char* file_path,
const char* file_name);
void avr_isp_worker_rw_verification_start(
AvrIspWorkerRW* instance,
const char* file_path,
const char* file_name);
bool avr_isp_worker_rw_check_hex(
AvrIspWorkerRW* instance,
const char* file_path,
const char* file_name);
bool avr_isp_worker_rw_write_dump(
AvrIspWorkerRW* instance,
const char* file_path,
const char* file_name);
void avr_isp_worker_rw_write_dump_start(
AvrIspWorkerRW* instance,
const char* file_path,
const char* file_name);
bool avr_isp_worker_rw_write_fuse(
AvrIspWorkerRW* instance,
const char* file_path,
const char* file_name);
void avr_isp_worker_rw_write_fuse_start(
AvrIspWorkerRW* instance,
const char* file_path,
const char* file_name);

View File

@@ -1,321 +0,0 @@
#include "flipper_i32hex_file.h"
#include <string.h>
#include <storage/storage.h>
#include <toolbox/stream/stream.h>
#include <toolbox/stream/file_stream.h>
#include <toolbox/hex.h>
//https://en.wikipedia.org/wiki/Intel_HEX
#define TAG "FlipperI32HexFile"
#define COUNT_BYTE_PAYLOAD 32 //how much payload will be used
#define I32HEX_TYPE_DATA 0x00
#define I32HEX_TYPE_END_OF_FILE 0x01
#define I32HEX_TYPE_EXT_LINEAR_ADDR 0x04
#define I32HEX_TYPE_START_LINEAR_ADDR 0x05
struct FlipperI32HexFile {
uint32_t addr;
uint32_t addr_last;
Storage* storage;
Stream* stream;
FuriString* str_data;
FlipperI32HexFileStatus file_open;
};
FlipperI32HexFile* flipper_i32hex_file_open_write(const char* name, uint32_t start_addr) {
furi_assert(name);
FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
instance->addr = start_addr;
instance->addr_last = 0;
instance->storage = furi_record_open(RECORD_STORAGE);
instance->stream = file_stream_alloc(instance->storage);
if(file_stream_open(instance->stream, name, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
instance->file_open = FlipperI32HexFileStatusOpenFileWrite;
FURI_LOG_D(TAG, "Open write file %s", name);
} else {
FURI_LOG_E(TAG, "Failed to open file %s", name);
instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
}
instance->str_data = furi_string_alloc(instance->storage);
return instance;
}
FlipperI32HexFile* flipper_i32hex_file_open_read(const char* name) {
furi_assert(name);
FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
instance->addr = 0;
instance->addr_last = 0;
instance->storage = furi_record_open(RECORD_STORAGE);
instance->stream = file_stream_alloc(instance->storage);
if(file_stream_open(instance->stream, name, FSAM_READ, FSOM_OPEN_EXISTING)) {
instance->file_open = FlipperI32HexFileStatusOpenFileRead;
FURI_LOG_D(TAG, "Open read file %s", name);
} else {
FURI_LOG_E(TAG, "Failed to open file %s", name);
instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
}
instance->str_data = furi_string_alloc(instance->storage);
return instance;
}
void flipper_i32hex_file_close(FlipperI32HexFile* instance) {
furi_assert(instance);
furi_string_free(instance->str_data);
file_stream_close(instance->stream);
stream_free(instance->stream);
furi_record_close(RECORD_STORAGE);
}
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_data(
FlipperI32HexFile* instance,
uint8_t* data,
uint32_t data_size) {
furi_assert(instance);
furi_assert(data);
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
ret.status = FlipperI32HexFileStatusErrorFileWrite;
}
uint8_t count_byte = 0;
uint32_t ind = 0;
uint8_t crc = 0;
furi_string_reset(instance->str_data);
if((instance->addr_last & 0xFF0000) < (instance->addr & 0xFF0000)) {
crc = 0x02 + 0x04 + ((instance->addr >> 24) & 0xFF) + ((instance->addr >> 16) & 0xFF);
crc = 0x01 + ~crc;
//I32HEX_TYPE_EXT_LINEAR_ADDR
furi_string_cat_printf(
instance->str_data, ":02000004%04lX%02X\r\n", (instance->addr >> 16), crc);
instance->addr_last = instance->addr;
}
while(ind < data_size) {
if((ind + COUNT_BYTE_PAYLOAD) > data_size) {
count_byte = data_size - ind;
} else {
count_byte = COUNT_BYTE_PAYLOAD;
}
//I32HEX_TYPE_DATA
furi_string_cat_printf(
instance->str_data, ":%02X%04lX00", count_byte, (instance->addr & 0xFFFF));
crc = count_byte + ((instance->addr >> 8) & 0xFF) + (instance->addr & 0xFF);
for(uint32_t i = 0; i < count_byte; i++) {
furi_string_cat_printf(instance->str_data, "%02X", *data);
crc += *data++;
}
crc = 0x01 + ~crc;
furi_string_cat_printf(instance->str_data, "%02X\r\n", crc);
ind += count_byte;
instance->addr += count_byte;
}
if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
return ret;
}
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_end_line(FlipperI32HexFile* instance) {
furi_assert(instance);
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
ret.status = FlipperI32HexFileStatusErrorFileWrite;
}
furi_string_reset(instance->str_data);
//I32HEX_TYPE_END_OF_FILE
furi_string_cat_printf(instance->str_data, ":00000001FF\r\n");
if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
return ret;
}
void flipper_i32hex_file_bin_to_i32hex_set_addr(FlipperI32HexFile* instance, uint32_t addr) {
furi_assert(instance);
instance->addr = addr;
}
const char* flipper_i32hex_file_get_string(FlipperI32HexFile* instance) {
furi_assert(instance);
return furi_string_get_cstr(instance->str_data);
}
static FlipperI32HexFileRet flipper_i32hex_file_parse_line(
FlipperI32HexFile* instance,
const char* str,
uint8_t* data,
uint32_t data_size) {
furi_assert(instance);
furi_assert(data);
char* str1;
uint32_t data_wrire_ind = 0;
uint32_t data_len = 0;
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusErrorData, .data_size = 0};
//Search for start of data I32HEX
str1 = strstr(str, ":");
do {
if(str1 == NULL) {
ret.status = FlipperI32HexFileStatusErrorData;
break;
}
str1++;
if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
ret.status = FlipperI32HexFileStatusErrorData;
break;
}
str1++;
if(++data_wrire_ind > data_size) {
ret.status = FlipperI32HexFileStatusErrorOverflow;
break;
}
data_len = 5 + data[0]; // +5 bytes per header and crc
while(data_len > data_wrire_ind) {
str1++;
if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
ret.status = FlipperI32HexFileStatusErrorData;
break;
}
str1++;
if(++data_wrire_ind > data_size) {
ret.status = FlipperI32HexFileStatusErrorOverflow;
break;
}
}
ret.status = FlipperI32HexFileStatusOK;
ret.data_size = data_wrire_ind;
} while(0);
return ret;
}
static bool flipper_i32hex_file_check_data(uint8_t* data, uint32_t data_size) {
furi_assert(data);
uint8_t crc = 0;
uint32_t data_read_ind = 0;
if(data[0] > data_size) return false;
while(data_read_ind < data_size - 1) {
crc += data[data_read_ind++];
}
return data[data_size - 1] == ((1 + ~crc) & 0xFF);
}
static FlipperI32HexFileRet flipper_i32hex_file_parse(
FlipperI32HexFile* instance,
const char* str,
uint8_t* data,
uint32_t data_size) {
furi_assert(instance);
furi_assert(data);
FlipperI32HexFileRet ret = flipper_i32hex_file_parse_line(instance, str, data, data_size);
if((ret.status == FlipperI32HexFileStatusOK) && (ret.data_size > 4)) {
switch(data[3]) {
case I32HEX_TYPE_DATA:
if(flipper_i32hex_file_check_data(data, ret.data_size)) {
ret.data_size -= 5;
memcpy(data, data + 4, ret.data_size);
ret.status = FlipperI32HexFileStatusData;
} else {
ret.status = FlipperI32HexFileStatusErrorCrc;
ret.data_size = 0;
}
break;
case I32HEX_TYPE_END_OF_FILE:
if(flipper_i32hex_file_check_data(data, ret.data_size)) {
ret.status = FlipperI32HexFileStatusEofFile;
ret.data_size = 0;
} else {
ret.status = FlipperI32HexFileStatusErrorCrc;
ret.data_size = 0;
}
break;
case I32HEX_TYPE_EXT_LINEAR_ADDR:
if(flipper_i32hex_file_check_data(data, ret.data_size)) {
data[0] = data[4];
data[1] = data[5];
data[3] = 0;
data[4] = 0;
ret.status = FlipperI32HexFileStatusUdateAddr;
ret.data_size = 4;
} else {
ret.status = FlipperI32HexFileStatusErrorCrc;
ret.data_size = 0;
}
break;
case I32HEX_TYPE_START_LINEAR_ADDR:
ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
ret.data_size = 0;
break;
default:
ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
ret.data_size = 0;
break;
}
} else {
ret.status = FlipperI32HexFileStatusErrorData;
ret.data_size = 0;
}
return ret;
}
bool flipper_i32hex_file_check(FlipperI32HexFile* instance) {
furi_assert(instance);
uint32_t data_size = 280;
uint8_t data[280] = {0};
bool ret = true;
if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
FURI_LOG_E(TAG, "File is not open");
ret = false;
} else {
stream_rewind(instance->stream);
while(stream_read_line(instance->stream, instance->str_data)) {
FlipperI32HexFileRet parse_ret = flipper_i32hex_file_parse(
instance, furi_string_get_cstr(instance->str_data), data, data_size);
if(parse_ret.status < 0) {
ret = false;
}
}
stream_rewind(instance->stream);
}
return ret;
}
FlipperI32HexFileRet flipper_i32hex_file_i32hex_to_bin_get_data(
FlipperI32HexFile* instance,
uint8_t* data,
uint32_t data_size) {
furi_assert(instance);
furi_assert(data);
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
ret.status = FlipperI32HexFileStatusErrorFileRead;
} else {
stream_read_line(instance->stream, instance->str_data);
ret = flipper_i32hex_file_parse(
instance, furi_string_get_cstr(instance->str_data), data, data_size);
}
return ret;
}

View File

@@ -1,55 +0,0 @@
#pragma once
#include <furi_hal.h>
typedef struct FlipperI32HexFile FlipperI32HexFile;
typedef enum {
FlipperI32HexFileStatusOK = 0,
FlipperI32HexFileStatusData = 2,
FlipperI32HexFileStatusUdateAddr = 3,
FlipperI32HexFileStatusEofFile = 4,
FlipperI32HexFileStatusOpenFileWrite = 5,
FlipperI32HexFileStatusOpenFileRead = 6,
// Errors
FlipperI32HexFileStatusErrorCrc = (-1),
FlipperI32HexFileStatusErrorOverflow = (-2),
FlipperI32HexFileStatusErrorData = (-3),
FlipperI32HexFileStatusErrorUnsupportedCommand = (-4),
FlipperI32HexFileStatusErrorNoOpenFile = (-5),
FlipperI32HexFileStatusErrorFileWrite = (-6),
FlipperI32HexFileStatusErrorFileRead = (-7),
FlipperI32HexFileStatusReserved =
0x7FFFFFFF, ///< Prevents enum down-size compiler optimization.
} FlipperI32HexFileStatus;
typedef struct {
FlipperI32HexFileStatus status;
uint32_t data_size;
} FlipperI32HexFileRet;
FlipperI32HexFile* flipper_i32hex_file_open_write(const char* name, uint32_t start_addr);
FlipperI32HexFile* flipper_i32hex_file_open_read(const char* name);
void flipper_i32hex_file_close(FlipperI32HexFile* instance);
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_data(
FlipperI32HexFile* instance,
uint8_t* data,
uint32_t data_size);
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_end_line(FlipperI32HexFile* instance);
const char* flipper_i32hex_file_get_string(FlipperI32HexFile* instance);
void flipper_i32hex_file_bin_to_i32hex_set_addr(FlipperI32HexFile* instance, uint32_t addr);
bool flipper_i32hex_file_check(FlipperI32HexFile* instance);
FlipperI32HexFileRet flipper_i32hex_file_i32hex_to_bin_get_data(
FlipperI32HexFile* instance,
uint8_t* data,
uint32_t data_size);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -1,386 +0,0 @@
#include "avr_isp_chip_arr.h"
#include <furi.h>
//https://github.com/avrdudes/avrdude/blob/master/src/avrintel.c
const AvrIspChipArr avr_isp_chip_arr[] = { // Value of -1 typically means unknown
//{mcu_name, mcuid, family, {sig, na, ture}, flstart, flsize, pgsiz, nb, bootsz, eestart, eesize, ep, rambeg, ramsiz, nf, nl, ni}, // Source
{"ATtiny4", 0, F_AVR8L, {0x1E, 0x8F, 0x0A}, 0, 0x00200, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
{"ATtiny5", 1, F_AVR8L, {0x1E, 0x8F, 0x09}, 0, 0x00200, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 11}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
{"ATtiny9", 2, F_AVR8L, {0x1E, 0x90, 0x08}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
{"ATtiny10", 3, F_AVR8L, {0x1E, 0x90, 0x03}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 11}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
{"ATtiny20", 4, F_AVR8L, {0x1E, 0x91, 0x0F}, 0, 0x00800, 0x020, 0, 0, 0, 0, 0, 0x0040, 0x0080, 1, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
{"ATtiny40", 5, F_AVR8L, {0x1E, 0x92, 0x0E}, 0, 0x01000, 0x040, 0, 0, 0, 0, 0, 0x0040, 0x0100, 1, 1, 18}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
{"ATtiny102", 6, F_AVR8L, {0x1E, 0x90, 0x0C}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 16}, // atdf, avrdude, boot size (manual)
{"ATtiny104", 7, F_AVR8L, {0x1E, 0x90, 0x0B}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 16}, // atdf, avrdude, boot size (manual)
{"ATtiny11", 8, F_AVR8, {0x1E, 0x90, 0x04}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 1, 0x0060, 0x0020, 1, 1, 5}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny12", 9, F_AVR8, {0x1E, 0x90, 0x05}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 2, 0x0060, 0x0020, 1, 1, 6}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny13", 10, F_AVR8, {0x1E, 0x90, 0x07}, 0, 0x00400, 0x020, 0, 0, 0, 0x0040, 4, 0x0060, 0x0040, 2, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny13A", 11, F_AVR8, {0x1E, 0x90, 0x07}, 0, 0x00400, 0x020, 0, 0, 0, 0x0040, 4, 0x0060, 0x0040, 2, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny15", 12, F_AVR8, {0x1E, 0x90, 0x06}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 2, 0x0060, 0x0020, 1, 1, 9}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny22", 13, F_AVR8, {0x1E, 0x91, 0x06}, 0, 0x00800, -1, 0, 0, -1, -1, -1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, boot size (manual)
{"ATtiny24", 14, F_AVR8, {0x1E, 0x91, 0x0B}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny24A", 15, F_AVR8, {0x1E, 0x91, 0x0B}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny25", 16, F_AVR8, {0x1E, 0x91, 0x08}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny26", 17, F_AVR8, {0x1E, 0x91, 0x09}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 2, 1, 12}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny28", 18, F_AVR8, {0x1E, 0x91, 0x07}, 0, 0x00800, 0x002, 0, 0, 0, 0, 0, 0x0060, 0x0020, 1, 1, 6}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny43U", 19, F_AVR8, {0x1E, 0x92, 0x0C}, 0, 0x01000, 0x040, 0, 0, 0, 0x0040, 4, 0x0060, 0x0100, 3, 1, 16}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny44", 20, F_AVR8, {0x1E, 0x92, 0x07}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny44A", 21, F_AVR8, {0x1E, 0x92, 0x07}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny45", 22, F_AVR8, {0x1E, 0x92, 0x06}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny48", 23, F_AVR8, {0x1E, 0x92, 0x09}, 0, 0x01000, 0x040, 0, 0, 0, 0x0040, 4, 0x0100, 0x0100, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny84", 24, F_AVR8, {0x1E, 0x93, 0x0C}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny84A", 25, F_AVR8, {0x1E, 0x93, 0x0C}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny85", 26, F_AVR8, {0x1E, 0x93, 0x0B}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny87", 27, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny88", 28, F_AVR8, {0x1E, 0x93, 0x11}, 0, 0x02000, 0x040, 0, 0, 0, 0x0040, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny167", 29, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny261", 30, F_AVR8, {0x1E, 0x91, 0x0C}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny261A", 31, F_AVR8, {0x1E, 0x91, 0x0C}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny441", 32, F_AVR8, {0x1E, 0x92, 0x15}, 0, 0x01000, 0x010, 0, 0, 0, 0x0100, 4, 0x0100, 0x0100, 3, 1, 30}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny461", 33, F_AVR8, {0x1E, 0x92, 0x08}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny461A", 34, F_AVR8, {0x1E, 0x92, 0x08}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny828", 35, F_AVR8, {0x1E, 0x93, 0x14}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny828R", 36, F_AVR8, {0x1E, 0x93, 0x14}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // avrdude, from ATtiny828
{"ATtiny841", 37, F_AVR8, {0x1E, 0x93, 0x15}, 0, 0x02000, 0x010, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 30}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny861", 38, F_AVR8, {0x1E, 0x93, 0x0D}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny861A", 39, F_AVR8, {0x1E, 0x93, 0x0D}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny1634", 40, F_AVR8, {0x1E, 0x94, 0x12}, 0, 0x04000, 0x020, 0, 0, 0, 0x0100, 4, 0x0100, 0x0400, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny1634R", 41, F_AVR8, {0x1E, 0x94, 0x12}, 0, 0x04000, 0x020, 0, 0, 0, 0x0100, 4, 0x0100, 0x0400, 3, 1, 28}, // avrdude, from ATtiny1634
{"ATtiny2313", 42, F_AVR8, {0x1E, 0x91, 0x0A}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny2313A", 43, F_AVR8, {0x1E, 0x91, 0x0A}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny4313", 44, F_AVR8, {0x1E, 0x92, 0x0D}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega8", 45, F_AVR8, {0x1E, 0x93, 0x07}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega8A", 46, F_AVR8, {0x1E, 0x93, 0x07}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega8HVA", 47, F_AVR8, {0x1E, 0x93, 0x10}, 0, 0x02000, 0x080, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 1, 1, 21}, // atdf, avr-gcc 12.2.0
{"ATmega8U2", 48, F_AVR8, {0x1E, 0x93, 0x89}, 0, 0x02000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega16", 49, F_AVR8, {0x1E, 0x94, 0x03}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega16A", 50, F_AVR8, {0x1E, 0x94, 0x03}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega16HVA", 51, F_AVR8, {0x1E, 0x94, 0x0C}, 0, 0x04000, 0x080, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 1, 1, 21}, // atdf, avr-gcc 12.2.0
{"ATmega16HVB", 52, F_AVR8, {0x1E, 0x94, 0x0D}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 2, 1, 29}, // atdf, avr-gcc 12.2.0
{"ATmega16HVBrevB", 53, F_AVR8, {0x1E, 0x94, 0x0D}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 2, 1, 29}, // atdf, avr-gcc 12.2.0
{"ATmega16M1", 54, F_AVR8, {0x1E, 0x94, 0x84}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0
{"ATmega16HVA2", 55, F_AVR8, {0x1E, 0x94, 0x0E}, 0, 0x04000, 0x080, -1, -1, -1, -1, -1, 0x0100, 0x0400, 2, 1, 22}, // avr-gcc 12.2.0
{"ATmega16U2", 56, F_AVR8, {0x1E, 0x94, 0x89}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega16U4", 57, F_AVR8, {0x1E, 0x94, 0x88}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0500, 3, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega32", 58, F_AVR8, {0x1E, 0x95, 0x02}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0060, 0x0800, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega32A", 59, F_AVR8, {0x1E, 0x95, 0x02}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0060, 0x0800, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega32HVB", 60, F_AVR8, {0x1E, 0x95, 0x10}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 2, 1, 29}, // atdf, avr-gcc 12.2.0
{"ATmega32HVBrevB", 61, F_AVR8, {0x1E, 0x95, 0x10}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 2, 1, 29}, // atdf, avr-gcc 12.2.0
{"ATmega32C1", 62, F_AVR8, {0x1E, 0x95, 0x86}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0
{"ATmega32M1", 63, F_AVR8, {0x1E, 0x95, 0x84}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega32U2", 64, F_AVR8, {0x1E, 0x95, 0x8A}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0400, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega32U4", 65, F_AVR8, {0x1E, 0x95, 0x87}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0a00, 3, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega32U6", 66, F_AVR8, {0x1E, 0x95, 0x88}, 0, 0x08000, 0x080, 4, 0x0200, -1, -1, -1, 0x0100, 0x0a00, 3, 1, 38}, // avr-gcc 12.2.0, boot size (manual)
{"ATmega48", 67, F_AVR8, {0x1E, 0x92, 0x05}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega48A", 68, F_AVR8, {0x1E, 0x92, 0x05}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega48P", 69, F_AVR8, {0x1E, 0x92, 0x0A}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega48PA", 70, F_AVR8, {0x1E, 0x92, 0x0A}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega48PB", 71, F_AVR8, {0x1E, 0x92, 0x10}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 27}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega64", 72, F_AVR8, {0x1E, 0x96, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega64A", 73, F_AVR8, {0x1E, 0x96, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega64HVE", 74, F_AVR8, {0x1E, 0x96, 0x10}, 0, 0x10000, 0x080, 4, 0x0400, -1, -1, -1, 0x0100, 0x1000, 2, 1, 25}, // avr-gcc 12.2.0, boot size (manual)
{"ATmega64C1", 75, F_AVR8, {0x1E, 0x96, 0x86}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0
{"ATmega64M1", 76, F_AVR8, {0x1E, 0x96, 0x84}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega64HVE2", 77, F_AVR8, {0x1E, 0x96, 0x10}, 0, 0x10000, 0x080, 4, 0x0400, 0, 0x0400, 4, 0x0100, 0x1000, 2, 1, 25}, // atdf, avr-gcc 12.2.0
{"ATmega64RFR2", 78, F_AVR8, {0x1E, 0xA6, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0200, 0x2000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega88", 79, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega88A", 80, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega88P", 81, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega88PA", 82, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega88PB", 83, F_AVR8, {0x1E, 0x93, 0x16}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 27}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega103", 84, F_AVR8, {0x1E, 0x97, 0x01}, 0, 0x20000, 0x100, 0, 0, 0, 0x1000, 1, 0x0060, 0x0fa0, 1, 1, 24}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"ATmega128", 85, F_AVR8, {0x1E, 0x97, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega128A", 86, F_AVR8, {0x1E, 0x97, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega128RFA1", 87, F_AVR8, {0x1E, 0xA7, 0x01}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 72}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega128RFR2", 88, F_AVR8, {0x1E, 0xA7, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega161", 89, F_AVR8, {0x1E, 0x94, 0x01}, 0, 0x04000, 0x080, 1, 0x0400, 0, 0x0200, 1, 0x0060, 0x0400, 1, 1, 21}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"ATmega162", 90, F_AVR8, {0x1E, 0x94, 0x04}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega163", 91, F_AVR8, {0x1E, 0x94, 0x02}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 1, 0x0060, 0x0400, 2, 1, 18}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"ATmega164A", 92, F_AVR8, {0x1E, 0x94, 0x0F}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega164P", 93, F_AVR8, {0x1E, 0x94, 0x0A}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega164PA", 94, F_AVR8, {0x1E, 0x94, 0x0A}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega165", 95, F_AVR8, {0x1E, 0x94, 0x10}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"ATmega165A", 96, F_AVR8, {0x1E, 0x94, 0x10}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega165P", 97, F_AVR8, {0x1E, 0x94, 0x07}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega165PA", 98, F_AVR8, {0x1E, 0x94, 0x07}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega168", 99, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega168A", 100, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega168P", 101, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega168PA", 102, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega168PB", 103, F_AVR8, {0x1E, 0x94, 0x15}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 27}, // atdf, avr-gcc 7.3.0, avrdude
{"ATmega169", 104, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"ATmega169A", 105, F_AVR8, {0x1E, 0x94, 0x11}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega169P", 106, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega169PA", 107, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega256RFR2", 108, F_AVR8, {0x1E, 0xA8, 0x02}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x2000, 8, 0x0200, 0x8000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega323", 109, F_AVR8, {0x1E, 0x95, 0x01}, 0, 0x08000, 0x080, 4, 0x0200, -1, -1, -1, 0x0060, 0x0800, 2, 1, 21}, // avr-gcc 12.2.0, boot size (manual)
{"ATmega324A", 110, F_AVR8, {0x1E, 0x95, 0x15}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega324P", 111, F_AVR8, {0x1E, 0x95, 0x08}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega324PA", 112, F_AVR8, {0x1E, 0x95, 0x11}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega324PB", 113, F_AVR8, {0x1E, 0x95, 0x17}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 51}, // atdf, avrdude
{"ATmega325", 114, F_AVR8, {0x1E, 0x95, 0x05}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega325A", 115, F_AVR8, {0x1E, 0x95, 0x05}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega325P", 116, F_AVR8, {0x1E, 0x95, 0x0D}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega325PA", 117, F_AVR8, {0x1E, 0x95, 0x0D}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega328", 118, F_AVR8, {0x1E, 0x95, 0x14}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega328P", 119, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega328PB", 120, F_AVR8, {0x1E, 0x95, 0x16}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 45}, // atdf, avr-gcc 7.3.0, avrdude
{"ATmega329", 121, F_AVR8, {0x1E, 0x95, 0x03}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega329A", 122, F_AVR8, {0x1E, 0x95, 0x03}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega329P", 123, F_AVR8, {0x1E, 0x95, 0x0B}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega329PA", 124, F_AVR8, {0x1E, 0x95, 0x0B}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega406", 125, F_AVR8, {0x1E, 0x95, 0x07}, 0, 0x0a000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0800, 2, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega640", 126, F_AVR8, {0x1E, 0x96, 0x08}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega644", 127, F_AVR8, {0x1E, 0x96, 0x09}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega644A", 128, F_AVR8, {0x1E, 0x96, 0x09}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega644P", 129, F_AVR8, {0x1E, 0x96, 0x0A}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega644PA", 130, F_AVR8, {0x1E, 0x96, 0x0A}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega644RFR2", 131, F_AVR8, {0x1E, 0xA6, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0200, 0x2000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega645", 132, F_AVR8, {0x1E, 0x96, 0x05}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega645A", 133, F_AVR8, {0x1E, 0x96, 0x05}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega645P", 134, F_AVR8, {0x1E, 0x96, 0x0D}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega649", 135, F_AVR8, {0x1E, 0x96, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega649A", 136, F_AVR8, {0x1E, 0x96, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega649P", 137, F_AVR8, {0x1E, 0x96, 0x0B}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega1280", 138, F_AVR8, {0x1E, 0x97, 0x03}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega1281", 139, F_AVR8, {0x1E, 0x97, 0x04}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega1284", 140, F_AVR8, {0x1E, 0x97, 0x06}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x4000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega1284P", 141, F_AVR8, {0x1E, 0x97, 0x05}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x4000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega1284RFR2", 142, F_AVR8, {0x1E, 0xA7, 0x03}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega2560", 143, F_AVR8, {0x1E, 0x98, 0x01}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega2561", 144, F_AVR8, {0x1E, 0x98, 0x02}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega2564RFR2", 145, F_AVR8, {0x1E, 0xA8, 0x03}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x2000, 8, 0x0200, 0x8000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega3250", 146, F_AVR8, {0x1E, 0x95, 0x06}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega3250A", 147, F_AVR8, {0x1E, 0x95, 0x06}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega3250P", 148, F_AVR8, {0x1E, 0x95, 0x0E}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega3250PA", 149, F_AVR8, {0x1E, 0x95, 0x0E}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega3290", 150, F_AVR8, {0x1E, 0x95, 0x04}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega3290A", 151, F_AVR8, {0x1E, 0x95, 0x04}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega3290P", 152, F_AVR8, {0x1E, 0x95, 0x0C}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega3290PA", 153, F_AVR8, {0x1E, 0x95, 0x0C}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega6450", 154, F_AVR8, {0x1E, 0x96, 0x06}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega6450A", 155, F_AVR8, {0x1E, 0x96, 0x06}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega6450P", 156, F_AVR8, {0x1E, 0x96, 0x0E}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega6490", 157, F_AVR8, {0x1E, 0x96, 0x04}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega6490A", 158, F_AVR8, {0x1E, 0x96, 0x04}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega6490P", 159, F_AVR8, {0x1E, 0x96, 0x0C}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega8515", 160, F_AVR8, {0x1E, 0x93, 0x06}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0200, 2, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega8535", 161, F_AVR8, {0x1E, 0x93, 0x08}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0200, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
{"AT43USB320", 162, F_AVR8, {0xff, -1, -1}, 0, 0x10000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0200, -1, -1, 0}, // avr-gcc 12.2.0
{"AT43USB355", 163, F_AVR8, {0xff, -1, -1}, 0, 0x06000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0400, -1, -1, 0}, // avr-gcc 12.2.0
{"AT76C711", 164, F_AVR8, {0xff, -1, -1}, 0, 0x04000, -1, -1, -1, -1, -1, -1, 0x0060, 0x07a0, -1, -1, 0}, // avr-gcc 12.2.0
{"AT86RF401", 165, F_AVR8, {0x1E, 0x91, 0x81}, 0, 0x00800, -1, -1, -1, -1, -1, -1, 0x0060, 0x0080, 0, 1, 3}, // avr-gcc 12.2.0
{"AT90PWM1", 166, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0
{"AT90PWM2", 167, F_AVR8, {0x1E, 0x93, 0x81}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"AT90PWM2B", 168, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90PWM3", 169, F_AVR8, {0x1E, 0x93, 0x81}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90PWM3B", 170, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90CAN32", 171, F_AVR8, {0x1E, 0x95, 0x81}, 0, 0x08000, 0x100, 4, 0x0400, 0, 0x0400, 8, 0x0100, 0x0800, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90CAN64", 172, F_AVR8, {0x1E, 0x96, 0x81}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90PWM81", 173, F_AVR8, {0x1E, 0x93, 0x88}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0100, 3, 1, 20}, // atdf, avr-gcc 12.2.0
{"AT90USB82", 174, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90SCR100", 175, F_AVR8, {0x1E, 0x96, 0xC1}, 0, 0x10000, 0x100, 4, 0x0200, -1, -1, -1, 0x0100, 0x1000, 3, 1, 38}, // avr-gcc 12.2.0, boot size (manual)
{"AT90CAN128", 176, F_AVR8, {0x1E, 0x97, 0x81}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90PWM161", 177, F_AVR8, {0x1E, 0x94, 0x8B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 20}, // atdf, avr-gcc 12.2.0
{"AT90USB162", 178, F_AVR8, {0x1E, 0x94, 0x82}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90PWM216", 179, F_AVR8, {0x1E, 0x94, 0x83}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90PWM316", 180, F_AVR8, {0x1E, 0x94, 0x83}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90USB646", 181, F_AVR8, {0x1E, 0x96, 0x82}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90USB647", 182, F_AVR8, {0x1E, 0x96, 0x82}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90S1200", 183, F_AVR8, {0x1E, 0x90, 0x01}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 1, 0x0060, 0x0020, 1, 1, 4}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"AT90USB1286", 184, F_AVR8, {0x1E, 0x97, 0x82}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x2000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90USB1287", 185, F_AVR8, {0x1E, 0x97, 0x82}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x2000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
{"AT90S2313", 186, F_AVR8, {0x1E, 0x91, 0x01}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, 1, 1, 11}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"AT90S2323", 187, F_AVR8, {0x1E, 0x91, 0x02}, 0, 0x00800, -1, 0, 0, -1, -1, -1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, boot size (manual)
{"AT90S2333", 188, F_AVR8, {0x1E, 0x91, 0x05}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, -1, -1, 14}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"AT90S2343", 189, F_AVR8, {0x1E, 0x91, 0x03}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"AT90S4414", 190, F_AVR8, {0x1E, 0x92, 0x01}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0100, 1, 1, 13}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"AT90S4433", 191, F_AVR8, {0x1E, 0x92, 0x03}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0080, 1, 1, 14}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"AT90S4434", 192, F_AVR8, {0x1E, 0x92, 0x02}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0100, 1, 1, 17}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"AT90S8515", 193, F_AVR8, {0x1E, 0x93, 0x01}, 0, 0x02000, 0x001, 0, 0, 0, 0x0200, 1, 0x0060, 0x0200, 1, 1, 13}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"AT90C8534", 194, F_AVR8, {0xff, -1, -1}, 0, 0x02000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0100, -1, -1, 0}, // avr-gcc 12.2.0
{"AT90S8535", 195, F_AVR8, {0x1E, 0x93, 0x03}, 0, 0x02000, 0x001, 0, 0, 0, 0x0200, 1, 0x0060, 0x0200, 1, 1, 17}, // avr-gcc 12.2.0, avrdude, boot size (manual)
{"AT94K", 196, F_AVR8, {0xff, -1, -1}, 0, 0x08000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0fa0, -1, -1, 0}, // avr-gcc 12.2.0
{"ATA5272", 197, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 37}, // atdf, avr-gcc 12.2.0
{"ATA5505", 198, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
{"ATA5700M322", 199, F_AVR8, {0x1E, 0x95, 0x67}, 0x08000, 0x08000, 0x040, 0, 0, 0, 0x0880, 16, 0x0200, 0x0400, 1, 1, 51}, // atdf
{"ATA5702M322", 200, F_AVR8, {0x1E, 0x95, 0x69}, 0x08000, 0x08000, 0x040, 0, 0, 0, 0x0880, 16, 0x0200, 0x0400, 1, 1, 51}, // atdf, avr-gcc 12.2.0
{"ATA5781", 201, F_AVR8, {0x1E, 0x95, 0x64}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
{"ATA5782", 202, F_AVR8, {0x1E, 0x95, 0x65}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 12.2.0
{"ATA5783", 203, F_AVR8, {0x1E, 0x95, 0x66}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
{"ATA5787", 204, F_AVR8, {0x1E, 0x94, 0x6C}, 0x08000, 0x05200, 0x040, 0, 0, 0, 0x0400, 16, 0x0200, 0x0800, 1, 1, 44}, // atdf
{"ATA5790", 205, F_AVR8, {0x1E, 0x94, 0x61}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 30}, // atdf, avr-gcc 12.2.0
{"ATA5790N", 206, F_AVR8, {0x1E, 0x94, 0x62}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 31}, // atdf, avr-gcc 12.2.0
{"ATA5791", 207, F_AVR8, {0x1E, 0x94, 0x62}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 31}, // atdf, avr-gcc 7.3.0
{"ATA5795", 208, F_AVR8, {0x1E, 0x93, 0x61}, 0, 0x02000, 0x040, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 23}, // atdf, avr-gcc 12.2.0
{"ATA5831", 209, F_AVR8, {0x1E, 0x95, 0x61}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 12.2.0
{"ATA5832", 210, F_AVR8, {0x1E, 0x95, 0x62}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
{"ATA5833", 211, F_AVR8, {0x1E, 0x95, 0x63}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
{"ATA5835", 212, F_AVR8, {0x1E, 0x94, 0x6B}, 0x08000, 0x05200, 0x040, 0, 0, 0, 0x0400, 16, 0x0200, 0x0800, 1, 1, 44}, // atdf
{"ATA6285", 213, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0140, 4, 0x0100, 0x0200, 2, 1, 27}, // atdf, avr-gcc 12.2.0
{"ATA6286", 214, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0140, 4, 0x0100, 0x0200, 2, 1, 27}, // atdf, avr-gcc 12.2.0
{"ATA6289", 215, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, -1, -1, -1, 0x0100, 0x0200, 2, 1, 27}, // avr-gcc 12.2.0, boot size (manual)
{"ATA6612C", 216, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0
{"ATA6613C", 217, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0
{"ATA6614Q", 218, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0
{"ATA6616C", 219, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
{"ATA6617C", 220, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
{"ATA8210", 221, F_AVR8, {0x1E, 0x95, 0x65}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 7.3.0
{"ATA8215", 222, F_AVR8, {0x1E, 0x95, 0x64}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
{"ATA8510", 223, F_AVR8, {0x1E, 0x95, 0x61}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 7.3.0
{"ATA8515", 224, F_AVR8, {0x1E, 0x95, 0x63}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
{"ATA664251", 225, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
{"M3000", 226, F_AVR8, {0xff, -1, -1}, 0, 0x10000, -1, -1, -1, -1, -1, -1, 0x1000, 0x1000, -1, -1, 0}, // avr-gcc 12.2.0
{"LGT8F88P", 227, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // avrdude, from ATmega88
{"LGT8F168P", 228, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // avrdude, from ATmega168P
{"LGT8F328P", 229, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // avrdude, from ATmega328P
{"ATxmega8E5", 230, F_XMEGA, {0x1E, 0x93, 0x41}, 0, 0x02800, 0x080, 1, 0x0800, 0, 0x0200, 32, 0x2000, 0x0400, 7, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega16A4", 231, F_XMEGA, {0x1E, 0x94, 0x41}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 94}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega16A4U", 232, F_XMEGA, {0x1E, 0x94, 0x41}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega16C4", 233, F_XMEGA, {0x1E, 0x94, 0x43}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega16D4", 234, F_XMEGA, {0x1E, 0x94, 0x42}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega16E5", 235, F_XMEGA, {0x1E, 0x94, 0x45}, 0, 0x05000, 0x080, 1, 0x1000, 0, 0x0200, 32, 0x2000, 0x0800, 7, 1, 43}, // atdf, avr-gcc 7.3.0, avrdude
{"ATxmega32C3", 236, F_XMEGA, {0x1E, 0x95, 0x49}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0
{"ATxmega32D3", 237, F_XMEGA, {0x1E, 0x95, 0x4A}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 114}, // atdf, avr-gcc 12.2.0
{"ATxmega32A4", 238, F_XMEGA, {0x1E, 0x95, 0x41}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 94}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega32A4U", 239, F_XMEGA, {0x1E, 0x95, 0x41}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega32C4", 240, F_XMEGA, {0x1E, 0x95, 0x44}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega32D4", 241, F_XMEGA, {0x1E, 0x95, 0x42}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega32E5", 242, F_XMEGA, {0x1E, 0x95, 0x4C}, 0, 0x09000, 0x080, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 7, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega64A1", 243, F_XMEGA, {0x1E, 0x96, 0x4E}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 125}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega64A1U", 244, F_XMEGA, {0x1E, 0x96, 0x4E}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega64B1", 245, F_XMEGA, {0x1E, 0x96, 0x52}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 81}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega64A3", 246, F_XMEGA, {0x1E, 0x96, 0x42}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega64A3U", 247, F_XMEGA, {0x1E, 0x96, 0x42}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega64B3", 248, F_XMEGA, {0x1E, 0x96, 0x51}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 54}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega64C3", 249, F_XMEGA, {0x1E, 0x96, 0x49}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega64D3", 250, F_XMEGA, {0x1E, 0x96, 0x4A}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega64A4", 251, F_XMEGA, {0x1E, 0x96, 0x46}, 0, 0x11000, 0x100, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
{"ATxmega64A4U", 252, F_XMEGA, {0x1E, 0x96, 0x46}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega64D4", 253, F_XMEGA, {0x1E, 0x96, 0x47}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega128A1", 254, F_XMEGA, {0x1E, 0x97, 0x4C}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 125}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega128A1revD", 255, F_XMEGA, {0x1E, 0x97, 0x41}, 0, 0x22000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
{"ATxmega128A1U", 256, F_XMEGA, {0x1E, 0x97, 0x4C}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega128B1", 257, F_XMEGA, {0x1E, 0x97, 0x4D}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 81}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega128A3", 258, F_XMEGA, {0x1E, 0x97, 0x42}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega128A3U", 259, F_XMEGA, {0x1E, 0x97, 0x42}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega128B3", 260, F_XMEGA, {0x1E, 0x97, 0x4B}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 54}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega128C3", 261, F_XMEGA, {0x1E, 0x97, 0x52}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega128D3", 262, F_XMEGA, {0x1E, 0x97, 0x48}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega128A4", 263, F_XMEGA, {0x1E, 0x97, 0x46}, 0, 0x22000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
{"ATxmega128A4U", 264, F_XMEGA, {0x1E, 0x97, 0x46}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega128D4", 265, F_XMEGA, {0x1E, 0x97, 0x47}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega192A1", 266, F_XMEGA, {0x1E, 0x97, 0x4E}, 0, 0x32000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
{"ATxmega192A3", 267, F_XMEGA, {0x1E, 0x97, 0x44}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega192A3U", 268, F_XMEGA, {0x1E, 0x97, 0x44}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega192C3", 269, F_XMEGA, {0x1E, 0x97, 0x51}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega192D3", 270, F_XMEGA, {0x1E, 0x97, 0x49}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega256A1", 271, F_XMEGA, {0x1E, 0x98, 0x46}, 0, 0x42000, 0x200, -1, -1, 0, 0x1000, 32, -1, -1, -1, -1, 0}, // avrdude
{"ATxmega256A3", 272, F_XMEGA, {0x1E, 0x98, 0x42}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega256A3B", 273, F_XMEGA, {0x1E, 0x98, 0x43}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega256A3BU", 274, F_XMEGA, {0x1E, 0x98, 0x43}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega256A3U", 275, F_XMEGA, {0x1E, 0x98, 0x42}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega256C3", 276, F_XMEGA, {0x1E, 0x98, 0x46}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega256D3", 277, F_XMEGA, {0x1E, 0x98, 0x44}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega384C3", 278, F_XMEGA, {0x1E, 0x98, 0x45}, 0, 0x62000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x8000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
{"ATxmega384D3", 279, F_XMEGA, {0x1E, 0x98, 0x47}, 0, 0x62000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x8000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny202", 280, F_AVR8X, {0x1E, 0x91, 0x23}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny204", 281, F_AVR8X, {0x1E, 0x91, 0x22}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny212", 282, F_AVR8X, {0x1E, 0x91, 0x21}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny214", 283, F_AVR8X, {0x1E, 0x91, 0x20}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny402", 284, F_AVR8X, {0x1E, 0x92, 0x27}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny404", 285, F_AVR8X, {0x1E, 0x92, 0x26}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny406", 286, F_AVR8X, {0x1E, 0x92, 0x25}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny412", 287, F_AVR8X, {0x1E, 0x92, 0x23}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny414", 288, F_AVR8X, {0x1E, 0x92, 0x22}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny416", 289, F_AVR8X, {0x1E, 0x92, 0x21}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny416auto", 290, F_AVR8X, {0x1E, 0x92, 0x28}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf
{"ATtiny417", 291, F_AVR8X, {0x1E, 0x92, 0x20}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny424", 292, F_AVR8X, {0x1E, 0x92, 0x2C}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
{"ATtiny426", 293, F_AVR8X, {0x1E, 0x92, 0x2B}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
{"ATtiny427", 294, F_AVR8X, {0x1E, 0x92, 0x2A}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
{"ATtiny804", 295, F_AVR8X, {0x1E, 0x93, 0x25}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny806", 296, F_AVR8X, {0x1E, 0x93, 0x24}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny807", 297, F_AVR8X, {0x1E, 0x93, 0x23}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny814", 298, F_AVR8X, {0x1E, 0x93, 0x22}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny816", 299, F_AVR8X, {0x1E, 0x93, 0x21}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny817", 300, F_AVR8X, {0x1E, 0x93, 0x20}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny824", 301, F_AVR8X, {0x1E, 0x93, 0x29}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
{"ATtiny826", 302, F_AVR8X, {0x1E, 0x93, 0x28}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
{"ATtiny827", 303, F_AVR8X, {0x1E, 0x93, 0x27}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
{"ATtiny1604", 304, F_AVR8X, {0x1E, 0x94, 0x25}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny1606", 305, F_AVR8X, {0x1E, 0x94, 0x24}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny1607", 306, F_AVR8X, {0x1E, 0x94, 0x23}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny1614", 307, F_AVR8X, {0x1E, 0x94, 0x22}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny1616", 308, F_AVR8X, {0x1E, 0x94, 0x21}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny1617", 309, F_AVR8X, {0x1E, 0x94, 0x20}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny1624", 310, F_AVR8X, {0x1E, 0x94, 0x2A}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
{"ATtiny1626", 311, F_AVR8X, {0x1E, 0x94, 0x29}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
{"ATtiny1627", 312, F_AVR8X, {0x1E, 0x94, 0x28}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
{"ATtiny3214", 313, F_AVR8X, {0x1E, 0x95, 0x20}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // avr-gcc 12.2.0
{"ATtiny3216", 314, F_AVR8X, {0x1E, 0x95, 0x21}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny3217", 315, F_AVR8X, {0x1E, 0x95, 0x22}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
{"ATtiny3224", 316, F_AVR8X, {0x1E, 0x95, 0x28}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
{"ATtiny3226", 317, F_AVR8X, {0x1E, 0x95, 0x27}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
{"ATtiny3227", 318, F_AVR8X, {0x1E, 0x95, 0x26}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
{"ATmega808", 319, F_AVR8X, {0x1E, 0x93, 0x26}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega809", 320, F_AVR8X, {0x1E, 0x93, 0x2A}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega1608", 321, F_AVR8X, {0x1E, 0x94, 0x27}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega1609", 322, F_AVR8X, {0x1E, 0x94, 0x26}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega3208", 323, F_AVR8X, {0x1E, 0x95, 0x30}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3000, 0x1000, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega3209", 324, F_AVR8X, {0x1E, 0x95, 0x31}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3000, 0x1000, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega4808", 325, F_AVR8X, {0x1E, 0x96, 0x50}, 0, 0x0c000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x2800, 0x1800, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
{"ATmega4809", 326, F_AVR8X, {0x1E, 0x96, 0x51}, 0, 0x0c000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x2800, 0x1800, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
{"AVR8EA28", 327, F_AVR8X, {0x1E, 0x93, 0x2C}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
{"AVR8EA32", 328, F_AVR8X, {0x1E, 0x93, 0x2B}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
{"AVR16DD14", 329, F_AVR8X, {0x1E, 0x94, 0x34}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
{"AVR16DD20", 330, F_AVR8X, {0x1E, 0x94, 0x33}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
{"AVR16DD28", 331, F_AVR8X, {0x1E, 0x94, 0x32}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
{"AVR16EA28", 332, F_AVR8X, {0x1E, 0x94, 0x37}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
{"AVR16DD32", 333, F_AVR8X, {0x1E, 0x94, 0x31}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
{"AVR16EA32", 334, F_AVR8X, {0x1E, 0x94, 0x36}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
{"AVR16EA48", 335, F_AVR8X, {0x1E, 0x94, 0x35}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
{"AVR32DD14", 336, F_AVR8X, {0x1E, 0x95, 0x3B}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
{"AVR32DD20", 337, F_AVR8X, {0x1E, 0x95, 0x3A}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
{"AVR32DA28", 338, F_AVR8X, {0x1E, 0x95, 0x34}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 41}, // atdf, avrdude
{"AVR32DB28", 339, F_AVR8X, {0x1E, 0x95, 0x37}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 42}, // atdf, avrdude
{"AVR32DD28", 340, F_AVR8X, {0x1E, 0x95, 0x39}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
{"AVR32EA28", 341, F_AVR8X, {0x1E, 0x95, 0x3E}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
{"AVR32DA32", 342, F_AVR8X, {0x1E, 0x95, 0x33}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 44}, // atdf, avrdude
{"AVR32DB32", 343, F_AVR8X, {0x1E, 0x95, 0x36}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 44}, // atdf, avrdude
{"AVR32DD32", 344, F_AVR8X, {0x1E, 0x95, 0x38}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
{"AVR32EA32", 345, F_AVR8X, {0x1E, 0x95, 0x3D}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
{"AVR32DA48", 346, F_AVR8X, {0x1E, 0x95, 0x32}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 58}, // atdf, avrdude
{"AVR32DB48", 347, F_AVR8X, {0x1E, 0x95, 0x35}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 61}, // atdf, avrdude
{"AVR32EA48", 348, F_AVR8X, {0x1E, 0x95, 0x3C}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
{"AVR64DD14", 349, F_AVR8X, {0x1E, 0x96, 0x1D}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
{"AVR64DD20", 350, F_AVR8X, {0x1E, 0x96, 0x1C}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
{"AVR64DA28", 351, F_AVR8X, {0x1E, 0x96, 0x15}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 41}, // atdf, avrdude
{"AVR64DB28", 352, F_AVR8X, {0x1E, 0x96, 0x19}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 42}, // atdf, avrdude
{"AVR64DD28", 353, F_AVR8X, {0x1E, 0x96, 0x1B}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
{"AVR64EA28", 354, F_AVR8X, {0x1E, 0x96, 0x20}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 37}, // atdf, avrdude
{"AVR64DA32", 355, F_AVR8X, {0x1E, 0x96, 0x14}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 44}, // atdf, avrdude
{"AVR64DB32", 356, F_AVR8X, {0x1E, 0x96, 0x18}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 44}, // atdf, avrdude
{"AVR64DD32", 357, F_AVR8X, {0x1E, 0x96, 0x1A}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
{"AVR64EA32", 358, F_AVR8X, {0x1E, 0x96, 0x1F}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 37}, // atdf, avrdude
{"AVR64DA48", 359, F_AVR8X, {0x1E, 0x96, 0x13}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 58}, // atdf, avrdude
{"AVR64DB48", 360, F_AVR8X, {0x1E, 0x96, 0x17}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 61}, // atdf, avrdude
{"AVR64EA48", 361, F_AVR8X, {0x1E, 0x96, 0x1E}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 45}, // atdf, avrdude
{"AVR64DA64", 362, F_AVR8X, {0x1E, 0x96, 0x12}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 64}, // atdf, avrdude
{"AVR64DB64", 363, F_AVR8X, {0x1E, 0x96, 0x16}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 65}, // atdf, avrdude
{"AVR128DA28", 364, F_AVR8X, {0x1E, 0x97, 0x0A}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 41}, // atdf, avrdude
{"AVR128DB28", 365, F_AVR8X, {0x1E, 0x97, 0x0E}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 42}, // atdf, avrdude
{"AVR128DA32", 366, F_AVR8X, {0x1E, 0x97, 0x09}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 44}, // atdf, avrdude
{"AVR128DB32", 367, F_AVR8X, {0x1E, 0x97, 0x0D}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 44}, // atdf, avrdude
{"AVR128DA48", 368, F_AVR8X, {0x1E, 0x97, 0x08}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 58}, // atdf, avrdude
{"AVR128DB48", 369, F_AVR8X, {0x1E, 0x97, 0x0C}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 61}, // atdf, avrdude
{"AVR128DA64", 370, F_AVR8X, {0x1E, 0x97, 0x07}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 64}, // atdf, avrdude
{"AVR128DB64", 371, F_AVR8X, {0x1E, 0x97, 0x0B}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 65}, // atdf, avrdude
};
const size_t avr_isp_chip_arr_size = COUNT_OF(avr_isp_chip_arr);

View File

@@ -1,33 +0,0 @@
#pragma once
#include <furi_hal.h>
#define F_AVR8L 1 // TPI programming, ATtiny(4|5|9|10|20|40|102|104)
#define F_AVR8 2 // ISP programming with SPI, "classic" AVRs
#define F_XMEGA 4 // PDI programming, ATxmega family
#define F_AVR8X 8 // UPDI programming, newer 8-bit MCUs
struct AvrIspChipArr { // Value of -1 typically means unknown
const char* name; // Name of part
uint16_t mcuid; // ID of MCU in 0..2039
uint8_t avrarch; // F_AVR8L, F_AVR8, F_XMEGA or F_AVR8X
uint8_t sigs[3]; // Signature bytes
int32_t flashoffset; // Flash offset
int32_t flashsize; // Flash size
int16_t pagesize; // Flash page size
int8_t nboots; // Number of supported boot sectors
int16_t bootsize; // Size of (smallest) boot sector
int32_t eepromoffset; // EEPROM offset
int32_t eepromsize; // EEPROM size
int32_t eeprompagesize; // EEPROM page size
int32_t sramstart; // SRAM offset
int32_t sramsize; // SRAM size
int8_t nfuses; // Number of fuse bytes
int8_t nlocks; // Number of lock bytes
uint8_t ninterrupts; // Number of vectors in interrupt vector table
};
typedef struct AvrIspChipArr AvrIspChipArr;
extern const AvrIspChipArr avr_isp_chip_arr[];
extern const size_t avr_isp_chip_arr_size;

View File

@@ -1,639 +0,0 @@
#include "avr_isp_prog.h"
#include "avr_isp_prog_cmd.h"
#include <furi.h>
#define AVR_ISP_PROG_TX_RX_BUF_SIZE 320
#define TAG "AvrIspProg"
struct AvrIspProgSignature {
uint8_t vendor;
uint8_t part_family;
uint8_t part_number;
};
typedef struct AvrIspProgSignature AvrIspProgSignature;
struct AvrIspProgCfgDevice {
uint8_t devicecode;
uint8_t revision;
uint8_t progtype;
uint8_t parmode;
uint8_t polling;
uint8_t selftimed;
uint8_t lockbytes;
uint8_t fusebytes;
uint8_t flashpoll;
uint16_t eeprompoll;
uint16_t pagesize;
uint16_t eepromsize;
uint32_t flashsize;
};
typedef struct AvrIspProgCfgDevice AvrIspProgCfgDevice;
struct AvrIspProg {
AvrIspSpiSw* spi;
AvrIspProgCfgDevice* cfg;
FuriStreamBuffer* stream_rx;
FuriStreamBuffer* stream_tx;
uint16_t error;
uint16_t addr;
bool pmode;
bool exit;
bool rst_active_high;
uint8_t buff[AVR_ISP_PROG_TX_RX_BUF_SIZE];
AvrIspProgCallback callback;
void* context;
};
static void avr_isp_prog_end_pmode(AvrIspProg* instance);
AvrIspProg* avr_isp_prog_init(void) {
AvrIspProg* instance = malloc(sizeof(AvrIspProg));
instance->cfg = malloc(sizeof(AvrIspProgCfgDevice));
instance->stream_rx =
furi_stream_buffer_alloc(sizeof(int8_t) * AVR_ISP_PROG_TX_RX_BUF_SIZE, sizeof(int8_t));
instance->stream_tx =
furi_stream_buffer_alloc(sizeof(int8_t) * AVR_ISP_PROG_TX_RX_BUF_SIZE, sizeof(int8_t));
instance->rst_active_high = false;
instance->exit = false;
return instance;
}
void avr_isp_prog_free(AvrIspProg* instance) {
furi_assert(instance);
if(instance->spi) avr_isp_prog_end_pmode(instance);
furi_stream_buffer_free(instance->stream_tx);
furi_stream_buffer_free(instance->stream_rx);
free(instance->cfg);
free(instance);
}
size_t avr_isp_prog_spaces_rx(AvrIspProg* instance) {
return furi_stream_buffer_spaces_available(instance->stream_rx);
}
bool avr_isp_prog_rx(AvrIspProg* instance, uint8_t* data, size_t len) {
furi_assert(instance);
furi_assert(data);
furi_assert(len != 0);
size_t ret = furi_stream_buffer_send(instance->stream_rx, data, sizeof(uint8_t) * len, 0);
return ret == sizeof(uint8_t) * len;
}
size_t avr_isp_prog_tx(AvrIspProg* instance, uint8_t* data, size_t max_len) {
furi_assert(instance);
return furi_stream_buffer_receive(instance->stream_tx, data, sizeof(int8_t) * max_len, 0);
}
void avr_isp_prog_exit(AvrIspProg* instance) {
furi_assert(instance);
instance->exit = true;
}
void avr_isp_prog_set_tx_callback(AvrIspProg* instance, AvrIspProgCallback callback, void* context) {
furi_assert(instance);
furi_assert(context);
instance->callback = callback;
instance->context = context;
}
static void avr_isp_prog_tx_ch(AvrIspProg* instance, uint8_t data) {
furi_assert(instance);
furi_stream_buffer_send(instance->stream_tx, &data, sizeof(uint8_t), FuriWaitForever);
}
static uint8_t avr_isp_prog_getch(AvrIspProg* instance) {
furi_assert(instance);
uint8_t data[1] = {0};
while(furi_stream_buffer_receive(instance->stream_rx, &data, sizeof(int8_t), 30) == 0) {
if(instance->exit) break;
};
return data[0];
}
static void avr_isp_prog_fill(AvrIspProg* instance, size_t len) {
furi_assert(instance);
for(size_t x = 0; x < len; x++) {
instance->buff[x] = avr_isp_prog_getch(instance);
}
}
static void avr_isp_prog_reset_target(AvrIspProg* instance, bool reset) {
furi_assert(instance);
avr_isp_spi_sw_res_set(instance->spi, (reset == instance->rst_active_high) ? true : false);
}
static uint8_t avr_isp_prog_spi_transaction(
AvrIspProg* instance,
uint8_t cmd,
uint8_t addr_hi,
uint8_t addr_lo,
uint8_t data) {
furi_assert(instance);
avr_isp_spi_sw_txrx(instance->spi, cmd);
avr_isp_spi_sw_txrx(instance->spi, addr_hi);
avr_isp_spi_sw_txrx(instance->spi, addr_lo);
return avr_isp_spi_sw_txrx(instance->spi, data);
}
static void avr_isp_prog_empty_reply(AvrIspProg* instance) {
furi_assert(instance);
if(avr_isp_prog_getch(instance) == CRC_EOP) {
avr_isp_prog_tx_ch(instance, STK_INSYNC);
avr_isp_prog_tx_ch(instance, STK_OK);
} else {
instance->error++;
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
}
}
static void avr_isp_prog_breply(AvrIspProg* instance, uint8_t data) {
furi_assert(instance);
if(avr_isp_prog_getch(instance) == CRC_EOP) {
avr_isp_prog_tx_ch(instance, STK_INSYNC);
avr_isp_prog_tx_ch(instance, data);
avr_isp_prog_tx_ch(instance, STK_OK);
} else {
instance->error++;
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
}
}
static void avr_isp_prog_get_version(AvrIspProg* instance, uint8_t data) {
furi_assert(instance);
switch(data) {
case STK_HW_VER:
avr_isp_prog_breply(instance, AVR_ISP_HWVER);
break;
case STK_SW_MAJOR:
avr_isp_prog_breply(instance, AVR_ISP_SWMAJ);
break;
case STK_SW_MINOR:
avr_isp_prog_breply(instance, AVR_ISP_SWMIN);
break;
case AVP_ISP_CONNECT_TYPE:
avr_isp_prog_breply(instance, AVP_ISP_SERIAL_CONNECT_TYPE);
break;
default:
avr_isp_prog_breply(instance, AVR_ISP_RESP_0);
}
}
static void avr_isp_prog_set_cfg(AvrIspProg* instance) {
furi_assert(instance);
// call this after reading cfg packet into buff[]
instance->cfg->devicecode = instance->buff[0];
instance->cfg->revision = instance->buff[1];
instance->cfg->progtype = instance->buff[2];
instance->cfg->parmode = instance->buff[3];
instance->cfg->polling = instance->buff[4];
instance->cfg->selftimed = instance->buff[5];
instance->cfg->lockbytes = instance->buff[6];
instance->cfg->fusebytes = instance->buff[7];
instance->cfg->flashpoll = instance->buff[8];
// ignore (instance->buff[9] == instance->buff[8]) //FLASH polling value. Same as <20>flashpoll<6C>
instance->cfg->eeprompoll = instance->buff[10] << 8 | instance->buff[11];
instance->cfg->pagesize = instance->buff[12] << 8 | instance->buff[13];
instance->cfg->eepromsize = instance->buff[14] << 8 | instance->buff[15];
instance->cfg->flashsize = instance->buff[16] << 24 | instance->buff[17] << 16 |
instance->buff[18] << 8 | instance->buff[19];
// avr devices have active low reset, at89sx are active high
instance->rst_active_high = (instance->cfg->devicecode >= 0xe0);
}
static bool
avr_isp_prog_set_pmode(AvrIspProg* instance, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
furi_assert(instance);
uint8_t res = 0;
avr_isp_spi_sw_txrx(instance->spi, a);
avr_isp_spi_sw_txrx(instance->spi, b);
res = avr_isp_spi_sw_txrx(instance->spi, c);
avr_isp_spi_sw_txrx(instance->spi, d);
return res == 0x53;
}
static void avr_isp_prog_end_pmode(AvrIspProg* instance) {
furi_assert(instance);
if(instance->pmode) {
avr_isp_prog_reset_target(instance, false);
// We're about to take the target out of reset
// so configure SPI pins as input
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
instance->spi = NULL;
}
instance->pmode = false;
}
static bool avr_isp_prog_start_pmode(AvrIspProg* instance, AvrIspSpiSwSpeed spi_speed) {
furi_assert(instance);
// Reset target before driving PIN_SCK or PIN_MOSI
// SPI.begin() will configure SS as output,
// so SPI master mode is selected.
// We have defined RESET as pin 10,
// which for many arduino's is not the SS pin.
// So we have to configure RESET as output here,
// (reset_target() first sets the correct level)
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
instance->spi = avr_isp_spi_sw_init(spi_speed);
avr_isp_prog_reset_target(instance, true);
// See avr datasheets, chapter "SERIAL_PRG Programming Algorithm":
// Pulse RESET after PIN_SCK is low:
avr_isp_spi_sw_sck_set(instance->spi, false);
// discharge PIN_SCK, value arbitrally chosen
furi_delay_ms(20);
avr_isp_prog_reset_target(instance, false);
// Pulse must be minimum 2 target CPU speed cycles
// so 100 usec is ok for CPU speeds above 20KHz
furi_delay_ms(1);
avr_isp_prog_reset_target(instance, true);
// Send the enable programming command:
// datasheet: must be > 20 msec
furi_delay_ms(50);
if(avr_isp_prog_set_pmode(instance, AVR_ISP_SET_PMODE)) {
instance->pmode = true;
return true;
}
return false;
}
static AvrIspProgSignature avr_isp_prog_check_signature(AvrIspProg* instance) {
furi_assert(instance);
AvrIspProgSignature signature;
signature.vendor = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_VENDOR);
signature.part_family = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY);
signature.part_number = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER);
return signature;
}
static bool avr_isp_prog_auto_set_spi_speed_start_pmode(AvrIspProg* instance) {
AvrIspSpiSwSpeed spi_speed[] = {
AvrIspSpiSwSpeed1Mhz,
AvrIspSpiSwSpeed400Khz,
AvrIspSpiSwSpeed250Khz,
AvrIspSpiSwSpeed125Khz,
AvrIspSpiSwSpeed60Khz,
AvrIspSpiSwSpeed40Khz,
AvrIspSpiSwSpeed20Khz,
AvrIspSpiSwSpeed10Khz,
AvrIspSpiSwSpeed5Khz,
AvrIspSpiSwSpeed1Khz,
};
for(uint8_t i = 0; i < COUNT_OF(spi_speed); i++) {
if(avr_isp_prog_start_pmode(instance, spi_speed[i])) {
AvrIspProgSignature sig = avr_isp_prog_check_signature(instance);
AvrIspProgSignature sig_examination = avr_isp_prog_check_signature(instance); //-V656
uint8_t y = 0;
while(y < 8) {
if(memcmp(
(uint8_t*)&sig, (uint8_t*)&sig_examination, sizeof(AvrIspProgSignature)) !=
0)
break;
sig_examination = avr_isp_prog_check_signature(instance);
y++;
}
if(y == 8) {
if(spi_speed[i] > AvrIspSpiSwSpeed1Mhz) {
if(i < (COUNT_OF(spi_speed) - 1)) {
avr_isp_prog_end_pmode(instance);
i++;
return avr_isp_prog_start_pmode(instance, spi_speed[i]);
}
}
return true;
}
}
}
if(instance->spi) {
avr_isp_spi_sw_free(instance->spi);
instance->spi = NULL;
}
return false;
}
static void avr_isp_prog_universal(AvrIspProg* instance) {
furi_assert(instance);
uint8_t data;
avr_isp_prog_fill(instance, 4);
data = avr_isp_prog_spi_transaction(
instance, instance->buff[0], instance->buff[1], instance->buff[2], instance->buff[3]);
avr_isp_prog_breply(instance, data);
}
static void avr_isp_prog_commit(AvrIspProg* instance, uint16_t addr, uint8_t data) {
furi_assert(instance);
avr_isp_prog_spi_transaction(instance, AVR_ISP_COMMIT(addr));
/* polling flash */
if(data == 0xFF) {
furi_delay_ms(5);
} else {
/* polling flash */
uint32_t starttime = furi_get_tick();
while((furi_get_tick() - starttime) < 30) {
if(avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) {
break;
};
}
}
}
static uint16_t avr_isp_prog_current_page(AvrIspProg* instance) {
furi_assert(instance);
uint16_t page = 0;
switch(instance->cfg->pagesize) {
case 32:
page = instance->addr & 0xFFFFFFF0;
break;
case 64:
page = instance->addr & 0xFFFFFFE0;
break;
case 128:
page = instance->addr & 0xFFFFFFC0;
break;
case 256:
page = instance->addr & 0xFFFFFF80;
break;
default:
page = instance->addr;
break;
}
return page;
}
static uint8_t avr_isp_prog_write_flash_pages(AvrIspProg* instance, size_t length) {
furi_assert(instance);
size_t x = 0;
uint16_t page = avr_isp_prog_current_page(instance);
while(x < length) {
if(page != avr_isp_prog_current_page(instance)) {
--x;
avr_isp_prog_commit(instance, page, instance->buff[x++]);
page = avr_isp_prog_current_page(instance);
}
avr_isp_prog_spi_transaction(
instance, AVR_ISP_WRITE_FLASH_LO(instance->addr, instance->buff[x++]));
avr_isp_prog_spi_transaction(
instance, AVR_ISP_WRITE_FLASH_HI(instance->addr, instance->buff[x++]));
instance->addr++;
}
avr_isp_prog_commit(instance, page, instance->buff[--x]);
return STK_OK;
}
static void avr_isp_prog_write_flash(AvrIspProg* instance, size_t length) {
furi_assert(instance);
avr_isp_prog_fill(instance, length);
if(avr_isp_prog_getch(instance) == CRC_EOP) {
avr_isp_prog_tx_ch(instance, STK_INSYNC);
avr_isp_prog_tx_ch(instance, avr_isp_prog_write_flash_pages(instance, length));
} else {
instance->error++;
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
}
}
// write (length) bytes, (start) is a byte address
static uint8_t
avr_isp_prog_write_eeprom_chunk(AvrIspProg* instance, uint16_t start, uint16_t length) {
furi_assert(instance);
// this writes byte-by-byte,
// page writing may be faster (4 bytes at a time)
avr_isp_prog_fill(instance, length);
for(uint16_t x = 0; x < length; x++) {
uint16_t addr = start + x;
avr_isp_prog_spi_transaction(instance, AVR_ISP_WRITE_EEPROM(addr, instance->buff[x]));
furi_delay_ms(10);
}
return STK_OK;
}
static uint8_t avr_isp_prog_write_eeprom(AvrIspProg* instance, size_t length) {
furi_assert(instance);
// here is a word address, get the byte address
uint16_t start = instance->addr * 2;
uint16_t remaining = length;
if(length > instance->cfg->eepromsize) {
instance->error++;
return STK_FAILED;
}
while(remaining > AVR_ISP_EECHUNK) {
avr_isp_prog_write_eeprom_chunk(instance, start, AVR_ISP_EECHUNK);
start += AVR_ISP_EECHUNK;
remaining -= AVR_ISP_EECHUNK;
}
avr_isp_prog_write_eeprom_chunk(instance, start, remaining);
return STK_OK;
}
static void avr_isp_prog_program_page(AvrIspProg* instance) {
furi_assert(instance);
uint8_t result = STK_FAILED;
uint16_t length = avr_isp_prog_getch(instance) << 8 | avr_isp_prog_getch(instance);
uint8_t memtype = avr_isp_prog_getch(instance);
// flash memory @addr, (length) bytes
if(memtype == STK_SET_FLASH_TYPE) {
avr_isp_prog_write_flash(instance, length);
return;
}
if(memtype == STK_SET_EEPROM_TYPE) {
result = avr_isp_prog_write_eeprom(instance, length);
if(avr_isp_prog_getch(instance) == CRC_EOP) {
avr_isp_prog_tx_ch(instance, STK_INSYNC);
avr_isp_prog_tx_ch(instance, result);
} else {
instance->error++;
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
}
return;
}
avr_isp_prog_tx_ch(instance, STK_FAILED);
return;
}
static uint8_t avr_isp_prog_flash_read_page(AvrIspProg* instance, uint16_t length) {
furi_assert(instance);
for(uint16_t x = 0; x < length; x += 2) {
avr_isp_prog_tx_ch(
instance,
avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_LO(instance->addr)));
avr_isp_prog_tx_ch(
instance,
avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(instance->addr)));
instance->addr++;
}
return STK_OK;
}
static uint8_t avr_isp_prog_eeprom_read_page(AvrIspProg* instance, uint16_t length) {
furi_assert(instance);
// here again we have a word address
uint16_t start = instance->addr * 2;
for(uint16_t x = 0; x < length; x++) {
uint16_t addr = start + x;
avr_isp_prog_tx_ch(
instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_EEPROM(addr)));
}
return STK_OK;
}
static void avr_isp_prog_read_page(AvrIspProg* instance) {
furi_assert(instance);
uint8_t result = STK_FAILED;
uint16_t length = avr_isp_prog_getch(instance) << 8 | avr_isp_prog_getch(instance);
uint8_t memtype = avr_isp_prog_getch(instance);
if(avr_isp_prog_getch(instance) != CRC_EOP) {
instance->error++;
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
return;
}
avr_isp_prog_tx_ch(instance, STK_INSYNC);
if(memtype == STK_SET_FLASH_TYPE) result = avr_isp_prog_flash_read_page(instance, length);
if(memtype == STK_SET_EEPROM_TYPE) result = avr_isp_prog_eeprom_read_page(instance, length);
avr_isp_prog_tx_ch(instance, result);
}
static void avr_isp_prog_read_signature(AvrIspProg* instance) {
furi_assert(instance);
if(avr_isp_prog_getch(instance) != CRC_EOP) {
instance->error++;
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
return;
}
avr_isp_prog_tx_ch(instance, STK_INSYNC);
avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_VENDOR));
avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY));
avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER));
avr_isp_prog_tx_ch(instance, STK_OK);
}
void avr_isp_prog_avrisp(AvrIspProg* instance) {
furi_assert(instance);
uint8_t ch = avr_isp_prog_getch(instance);
switch(ch) {
case STK_GET_SYNC:
FURI_LOG_D(TAG, "cmd STK_GET_SYNC");
instance->error = 0;
avr_isp_prog_empty_reply(instance);
break;
case STK_GET_SIGN_ON:
FURI_LOG_D(TAG, "cmd STK_GET_SIGN_ON");
if(avr_isp_prog_getch(instance) == CRC_EOP) {
avr_isp_prog_tx_ch(instance, STK_INSYNC);
avr_isp_prog_tx_ch(instance, 'A');
avr_isp_prog_tx_ch(instance, 'V');
avr_isp_prog_tx_ch(instance, 'R');
avr_isp_prog_tx_ch(instance, ' ');
avr_isp_prog_tx_ch(instance, 'I');
avr_isp_prog_tx_ch(instance, 'S');
avr_isp_prog_tx_ch(instance, 'P');
avr_isp_prog_tx_ch(instance, STK_OK);
} else {
instance->error++;
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
}
break;
case STK_GET_PARAMETER:
FURI_LOG_D(TAG, "cmd STK_GET_PARAMETER");
avr_isp_prog_get_version(instance, avr_isp_prog_getch(instance));
break;
case STK_SET_DEVICE:
FURI_LOG_D(TAG, "cmd STK_SET_DEVICE");
avr_isp_prog_fill(instance, 20);
avr_isp_prog_set_cfg(instance);
avr_isp_prog_empty_reply(instance);
break;
case STK_SET_DEVICE_EXT: // ignore for now
FURI_LOG_D(TAG, "cmd STK_SET_DEVICE_EXT");
avr_isp_prog_fill(instance, 5);
avr_isp_prog_empty_reply(instance);
break;
case STK_ENTER_PROGMODE:
FURI_LOG_D(TAG, "cmd STK_ENTER_PROGMODE");
if(!instance->pmode) avr_isp_prog_auto_set_spi_speed_start_pmode(instance);
avr_isp_prog_empty_reply(instance);
break;
case STK_LOAD_ADDRESS:
FURI_LOG_D(TAG, "cmd STK_LOAD_ADDRESS");
instance->addr = avr_isp_prog_getch(instance) | avr_isp_prog_getch(instance) << 8;
avr_isp_prog_empty_reply(instance);
break;
case STK_PROG_FLASH: // ignore for now
FURI_LOG_D(TAG, "cmd STK_PROG_FLASH");
avr_isp_prog_getch(instance);
avr_isp_prog_getch(instance);
avr_isp_prog_empty_reply(instance);
break;
case STK_PROG_DATA: // ignore for now
FURI_LOG_D(TAG, "cmd STK_PROG_DATA");
avr_isp_prog_getch(instance);
avr_isp_prog_empty_reply(instance);
break;
case STK_PROG_PAGE:
FURI_LOG_D(TAG, "cmd STK_PROG_PAGE");
avr_isp_prog_program_page(instance);
break;
case STK_READ_PAGE:
FURI_LOG_D(TAG, "cmd STK_READ_PAGE");
avr_isp_prog_read_page(instance);
break;
case STK_UNIVERSAL:
FURI_LOG_D(TAG, "cmd STK_UNIVERSAL");
avr_isp_prog_universal(instance);
break;
case STK_LEAVE_PROGMODE:
FURI_LOG_D(TAG, "cmd STK_LEAVE_PROGMODE");
instance->error = 0;
if(instance->pmode) avr_isp_prog_end_pmode(instance);
avr_isp_prog_empty_reply(instance);
break;
case STK_READ_SIGN:
FURI_LOG_D(TAG, "cmd STK_READ_SIGN");
avr_isp_prog_read_signature(instance);
break;
// expecting a command, not CRC_EOP
// this is how we can get back in sync
case CRC_EOP:
FURI_LOG_D(TAG, "cmd CRC_EOP");
instance->error++;
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
break;
// anything else we will return STK_UNKNOWN
default:
FURI_LOG_D(TAG, "cmd STK_ERROR_CMD");
instance->error++;
if(avr_isp_prog_getch(instance) == CRC_EOP)
avr_isp_prog_tx_ch(instance, STK_UNKNOWN);
else
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
}
if(instance->callback) {
instance->callback(instance->context);
}
}

View File

@@ -1,16 +0,0 @@
#pragma once
#include "avr_isp_spi_sw.h"
#include <furi_hal.h>
typedef struct AvrIspProg AvrIspProg;
typedef void (*AvrIspProgCallback)(void* context);
AvrIspProg* avr_isp_prog_init(void);
void avr_isp_prog_free(AvrIspProg* instance);
size_t avr_isp_prog_spaces_rx(AvrIspProg* instance) ;
bool avr_isp_prog_rx(AvrIspProg* instance, uint8_t* data, size_t len);
size_t avr_isp_prog_tx(AvrIspProg* instance, uint8_t* data, size_t max_len);
void avr_isp_prog_avrisp(AvrIspProg* instance);
void avr_isp_prog_exit(AvrIspProg* instance);
void avr_isp_prog_set_tx_callback(AvrIspProg* instance, AvrIspProgCallback callback, void* context);

View File

@@ -1,97 +0,0 @@
#pragma once
// http://ww1.microchip.com/downloads/en/appnotes/atmel-0943-in-system-programming_applicationnote_avr910.pdf
// AVR ISP Definitions
#define AVR_ISP_HWVER 0X02
#define AVR_ISP_SWMAJ 0X01
#define AVR_ISP_SWMIN 0X12
#define AVP_ISP_SERIAL_CONNECT_TYPE 0X53
#define AVP_ISP_CONNECT_TYPE 0x93
#define AVR_ISP_RESP_0 0X00
#define AVR_ISP_SET_PMODE 0xAC, 0x53, 0x00, 0x00
#define AVR_ISP_READ_VENDOR 0x30, 0x00, 0x00, 0x00
#define AVR_ISP_READ_PART_FAMILY 0x30, 0x00, 0x01, 0x00
#define AVR_ISP_READ_PART_NUMBER 0x30, 0x00, 0x02, 0x00
#define AVR_ISP_ERASE_CHIP \
0xAC, 0x80, 0x00, 0x00 //Erase Chip, Wait N ms, Release RESET to end the erase.
//The only way to end a Chip Erase cycle is by temporarily releasing the Reset line
#define AVR_ISP_EXTENDED_ADDR(data) 0x4D, 0x00, data, 0x00
#define AVR_ISP_WRITE_FLASH_LO(add, data) 0x40, (add >> 8) & 0xFF, add & 0xFF, data
#define AVR_ISP_WRITE_FLASH_HI(add, data) 0x48, (add >> 8) & 0xFF, add & 0xFF, data
#define AVR_ISP_READ_FLASH_LO(add) 0x20, (add >> 8) & 0xFF, add & 0xFF, 0x00
#define AVR_ISP_READ_FLASH_HI(add) 0x28, (add >> 8) & 0xFF, add & 0xFF, 0x00
#define AVR_ISP_WRITE_EEPROM(add, data) \
0xC0, (add >> 8) & 0xFF, add & 0xFF, data //Send cmd, Wait N ms
#define AVR_ISP_READ_EEPROM(add) 0xA0, (add >> 8) & 0xFF, add & 0xFF, 0xFF
#define AVR_ISP_COMMIT(add) \
0x4C, (add >> 8) & 0xFF, add & 0xFF, 0x00 //Send cmd, polling read last addr page
#define AVR_ISP_OSCCAL(add) 0x38, 0x00, add, 0x00
#define AVR_ISP_WRITE_LOCK_BYTE(data) 0xAC, 0xE0, 0x00, data //Send cmd, Wait N ms
#define AVR_ISP_READ_LOCK_BYTE 0x58, 0x00, 0x00, 0x00
#define AVR_ISP_WRITE_FUSE_LOW(data) 0xAC, 0xA0, 0x00, data //Send cmd, Wait N ms
#define AVR_ISP_READ_FUSE_LOW 0x50, 0x00, 0x00, 0x00
#define AVR_ISP_WRITE_FUSE_HIGH(data) 0xAC, 0xA8, 0x00, data //Send cmd, Wait N ms
#define AVR_ISP_READ_FUSE_HIGH 0x58, 0x08, 0x00, 0x00
#define AVR_ISP_WRITE_FUSE_EXTENDED(data) 0xAC, 0xA4, 0x00, data //Send cmd, Wait N ms (~write)
#define AVR_ISP_READ_FUSE_EXTENDED 0x50, 0x08, 0x00, 0x00
#define AVR_ISP_EECHUNK 0x20
// https://www.microchip.com/content/dam/mchp/documents/OTH/ApplicationNotes/ApplicationNotes/doc2525.pdf
// STK Definitions
#define STK_OK 0x10
#define STK_FAILED 0x11
#define STK_UNKNOWN 0x12
#define STK_INSYNC 0x14
#define STK_NOSYNC 0x15
#define CRC_EOP 0x20
#define STK_GET_SYNC 0x30
#define STK_GET_SIGN_ON 0x31
#define STK_SET_PARAMETER 0x40
#define STK_GET_PARAMETER 0x41
#define STK_SET_DEVICE 0x42
#define STK_SET_DEVICE_EXT 0x45
#define STK_ENTER_PROGMODE 0x50
#define STK_LEAVE_PROGMODE 0x51
#define STK_CHIP_ERASE 0x52
#define STK_CHECK_AUTOINC 0x53
#define STK_LOAD_ADDRESS 0x55
#define STK_UNIVERSAL 0x56
#define STK_UNIVERSAL_MULTI 0x57
#define STK_PROG_FLASH 0x60
#define STK_PROG_DATA 0x61
#define STK_PROG_FUSE 0x62
#define STK_PROG_FUSE_EXT 0x65
#define STK_PROG_LOCK 0x63
#define STK_PROG_PAGE 0x64
#define STK_READ_FLASH 0x70
#define STK_READ_DATA 0x71
#define STK_READ_FUSE 0x72
#define STK_READ_LOCK 0x73
#define STK_READ_PAGE 0x74
#define STK_READ_SIGN 0x75
#define STK_READ_OSCCAL 0x76
#define STK_READ_FUSE_EXT 0x77
#define STK_READ_OSCCAL_EXT 0x78
#define STK_HW_VER 0x80
#define STK_SW_MAJOR 0x81
#define STK_SW_MINOR 0x82
#define STK_LEDS 0x83
#define STK_VTARGET 0x84
#define STK_VADJUST 0x85
#define STK_OSC_PSCALE 0x86
#define STK_OSC_CMATCH 0x87
#define STK_SCK_DURATION 0x89
#define STK_BUFSIZEL 0x90
#define STK_BUFSIZEH 0x91
#define STK_STK500_TOPCARD_DETECT 0x98
#define STK_SET_EEPROM_TYPE 0X45
#define STK_SET_FLASH_TYPE 0X46

View File

@@ -1,71 +0,0 @@
#include "avr_isp_spi_sw.h"
#include <furi.h>
#define AVR_ISP_SPI_SW_MISO &gpio_ext_pa6
#define AVR_ISP_SPI_SW_MOSI &gpio_ext_pa7
#define AVR_ISP_SPI_SW_SCK &gpio_ext_pb3
#define AVR_ISP_RESET &gpio_ext_pb2
struct AvrIspSpiSw {
AvrIspSpiSwSpeed speed_wait_time;
const GpioPin* miso;
const GpioPin* mosi;
const GpioPin* sck;
const GpioPin* res;
};
AvrIspSpiSw* avr_isp_spi_sw_init(AvrIspSpiSwSpeed speed) {
AvrIspSpiSw* instance = malloc(sizeof(AvrIspSpiSw));
instance->speed_wait_time = speed;
instance->miso = AVR_ISP_SPI_SW_MISO;
instance->mosi = AVR_ISP_SPI_SW_MOSI;
instance->sck = AVR_ISP_SPI_SW_SCK;
instance->res = AVR_ISP_RESET;
furi_hal_gpio_init(instance->miso, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
furi_hal_gpio_write(instance->mosi, false);
furi_hal_gpio_init(instance->mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
furi_hal_gpio_write(instance->sck, false);
furi_hal_gpio_init(instance->sck, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
furi_hal_gpio_init(instance->res, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
return instance;
}
void avr_isp_spi_sw_free(AvrIspSpiSw* instance) {
furi_assert(instance);
furi_hal_gpio_init(instance->res, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(instance->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(instance->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(instance->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
free(instance);
}
uint8_t avr_isp_spi_sw_txrx(AvrIspSpiSw* instance, uint8_t data) {
furi_assert(instance);
for(uint8_t i = 0; i < 8; ++i) {
furi_hal_gpio_write(instance->mosi, (data & 0x80) ? true : false);
furi_hal_gpio_write(instance->sck, true);
if(instance->speed_wait_time != AvrIspSpiSwSpeed1Mhz)
furi_delay_us(instance->speed_wait_time - 1);
data = (data << 1) | furi_hal_gpio_read(instance->miso); //-V792
furi_hal_gpio_write(instance->sck, false);
if(instance->speed_wait_time != AvrIspSpiSwSpeed1Mhz)
furi_delay_us(instance->speed_wait_time - 1);
}
return data;
}
void avr_isp_spi_sw_res_set(AvrIspSpiSw* instance, bool state) {
furi_assert(instance);
furi_hal_gpio_write(instance->res, state);
}
void avr_isp_spi_sw_sck_set(AvrIspSpiSw* instance, bool state) {
furi_assert(instance);
furi_hal_gpio_write(instance->sck, state);
}

View File

@@ -1,24 +0,0 @@
#pragma once
#include <furi_hal.h>
typedef enum {
AvrIspSpiSwSpeed1Mhz = 0,
AvrIspSpiSwSpeed400Khz = 1,
AvrIspSpiSwSpeed250Khz = 2,
AvrIspSpiSwSpeed125Khz = 4,
AvrIspSpiSwSpeed60Khz = 8,
AvrIspSpiSwSpeed40Khz = 12,
AvrIspSpiSwSpeed20Khz = 24,
AvrIspSpiSwSpeed10Khz = 48,
AvrIspSpiSwSpeed5Khz = 96,
AvrIspSpiSwSpeed1Khz = 480,
} AvrIspSpiSwSpeed;
typedef struct AvrIspSpiSw AvrIspSpiSw;
AvrIspSpiSw* avr_isp_spi_sw_init(AvrIspSpiSwSpeed speed);
void avr_isp_spi_sw_free(AvrIspSpiSw* instance);
uint8_t avr_isp_spi_sw_txrx(AvrIspSpiSw* instance, uint8_t data);
void avr_isp_spi_sw_res_set(AvrIspSpiSw* instance, bool state);
void avr_isp_spi_sw_sck_set(AvrIspSpiSw* instance, bool state);

View File

@@ -1,30 +0,0 @@
#include "../avr_isp_app_i.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const avr_isp_scene_on_enter_handlers[])(void*) = {
#include "avr_isp_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const avr_isp_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "avr_isp_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const avr_isp_scene_on_exit_handlers[])(void* context) = {
#include "avr_isp_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers avr_isp_scene_handlers = {
.on_enter_handlers = avr_isp_scene_on_enter_handlers,
.on_event_handlers = avr_isp_scene_on_event_handlers,
.on_exit_handlers = avr_isp_scene_on_exit_handlers,
.scene_num = AvrIspSceneNum,
};

View File

@@ -1,29 +0,0 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) AvrIspScene##id,
typedef enum {
#include "avr_isp_scene_config.h"
AvrIspSceneNum,
} AvrIspScene;
#undef ADD_SCENE
extern const SceneManagerHandlers avr_isp_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "avr_isp_scene_config.h"
#undef ADD_SCENE
// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "avr_isp_scene_config.h"
#undef ADD_SCENE
// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "avr_isp_scene_config.h"
#undef ADD_SCENE

View File

@@ -1,99 +0,0 @@
#include "../avr_isp_app_i.h"
#include "../helpers/avr_isp_types.h"
void avr_isp_scene_about_widget_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context);
AvrIspApp* app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
}
void avr_isp_scene_about_on_enter(void* context) {
furi_assert(context);
AvrIspApp* app = context;
FuriString* temp_str = furi_string_alloc();
furi_string_printf(temp_str, "\e#%s\n", "Information");
furi_string_cat_printf(temp_str, "Version: %s\n", AVR_ISP_VERSION_APP);
furi_string_cat_printf(temp_str, "Developed by: %s\n", AVR_ISP_DEVELOPED);
furi_string_cat_printf(temp_str, "Github: %s\n\n", AVR_ISP_GITHUB);
furi_string_cat_printf(temp_str, "\e#%s\n", "Description");
furi_string_cat_printf(
temp_str,
"This application is an AVR in-system programmer based on stk500mk1. It is compatible with AVR-based"
" microcontrollers including Arduino. You can also use it to repair the chip if you accidentally"
" corrupt the bootloader.\n\n");
furi_string_cat_printf(temp_str, "\e#%s\n", "What it can do:");
furi_string_cat_printf(temp_str, "- Create a dump of your chip on an SD card\n");
furi_string_cat_printf(temp_str, "- Flash your chip firmware from the SD card\n");
furi_string_cat_printf(temp_str, "- Act as a wired USB ISP using avrdude software\n\n");
furi_string_cat_printf(temp_str, "\e#%s\n", "Supported chip series:");
furi_string_cat_printf(
temp_str,
"Example command for avrdude flashing: avrdude.exe -p m328p -c stk500v1 -P COMxx -U flash:r:"
"X:\\sketch_sample.hex"
":i\n");
furi_string_cat_printf(
temp_str,
"Where: "
"-p m328p"
" brand of your chip, "
"-P COMxx"
" com port number in the system when "
"ISP Programmer"
" is enabled\n\n");
furi_string_cat_printf(temp_str, "\e#%s\n", "Info");
furi_string_cat_printf(
temp_str,
"ATtinyXXXX\nATmegaXXXX\nAT43Uxxx\nAT76C711\nAT86RF401\nAT90xxxxx\nAT94K\n"
"ATAxxxxx\nATA664251\nM3000\nLGT8F88P\nLGT8F168P\nLGT8F328P\n");
furi_string_cat_printf(
temp_str, "For a more detailed list of supported chips, see AVRDude help\n");
widget_add_text_box_element(
app->widget,
0,
0,
128,
14,
AlignCenter,
AlignBottom,
"\e#\e! \e!\n",
false);
widget_add_text_box_element(
app->widget,
0,
2,
128,
14,
AlignCenter,
AlignBottom,
"\e#\e! ISP Programmer \e!\n",
false);
widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str));
furi_string_free(temp_str);
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWidget);
}
bool avr_isp_scene_about_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void avr_isp_scene_about_on_exit(void* context) {
furi_assert(context);
AvrIspApp* app = context;
// Clear views
widget_reset(app->widget);
}

View File

@@ -1,72 +0,0 @@
#include "../avr_isp_app_i.h"
void avr_isp_scene_chip_detect_callback(AvrIspCustomEvent event, void* context) {
furi_assert(context);
AvrIspApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void avr_isp_scene_chip_detect_on_enter(void* context) {
furi_assert(context);
AvrIspApp* app = context;
switch(app->error) {
case AvrIspErrorReading:
case AvrIspErrorWriting:
case AvrIspErrorWritingFuse:
avr_isp_chip_detect_set_state(
app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateErrorOccured);
break;
case AvrIspErrorVerification:
avr_isp_chip_detect_set_state(
app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateErrorVerification);
break;
default:
avr_isp_chip_detect_set_state(
app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateNoDetect);
break;
}
app->error = AvrIspErrorNoError;
avr_isp_chip_detect_view_set_callback(
app->avr_isp_chip_detect_view, avr_isp_scene_chip_detect_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewChipDetect);
}
bool avr_isp_scene_chip_detect_on_event(void* context, SceneManagerEvent event) {
furi_assert(context);
AvrIspApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case AvrIspCustomEventSceneChipDetectOk:
if(scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
AvrIspViewProgrammer) {
scene_manager_next_scene(app->scene_manager, AvrIspSceneProgrammer);
} else if(
scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
AvrIspViewReader) {
scene_manager_next_scene(app->scene_manager, AvrIspSceneInputName);
} else if(
scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
AvrIspViewWriter) {
scene_manager_next_scene(app->scene_manager, AvrIspSceneLoad);
}
consumed = true;
break;
default:
break;
}
} else if(event.type == SceneManagerEventTypeTick) {
}
return consumed;
}
void avr_isp_scene_chip_detect_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -1,10 +0,0 @@
ADD_SCENE(avr_isp, start, Start)
ADD_SCENE(avr_isp, about, About)
ADD_SCENE(avr_isp, programmer, Programmer)
ADD_SCENE(avr_isp, reader, Reader)
ADD_SCENE(avr_isp, input_name, InputName)
ADD_SCENE(avr_isp, load, Load)
ADD_SCENE(avr_isp, writer, Writer)
ADD_SCENE(avr_isp, wiring, Wiring)
ADD_SCENE(avr_isp, chip_detect, ChipDetect)
ADD_SCENE(avr_isp, success, Success)

View File

@@ -1,89 +0,0 @@
#include "../avr_isp_app_i.h"
#include <gui/modules/validators.h>
#define MAX_TEXT_INPUT_LEN 22
void avr_isp_scene_input_name_text_callback(void* context) {
furi_assert(context);
AvrIspApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, AvrIspCustomEventSceneInputName);
}
void avr_isp_scene_input_name_get_timefilename(FuriString* name) {
FuriHalRtcDateTime datetime = {0};
furi_hal_rtc_get_datetime(&datetime);
furi_string_printf(
name,
"AVR_dump-%.4d%.2d%.2d-%.2d%.2d%.2d",
datetime.year,
datetime.month,
datetime.day,
datetime.hour,
datetime.minute,
datetime.second);
}
void avr_isp_scene_input_name_on_enter(void* context) {
furi_assert(context);
AvrIspApp* app = context;
// Setup view
TextInput* text_input = app->text_input;
bool dev_name_empty = false;
FuriString* file_name = furi_string_alloc();
avr_isp_scene_input_name_get_timefilename(file_name);
furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
//highlighting the entire filename by default
dev_name_empty = true;
strncpy(app->file_name_tmp, furi_string_get_cstr(file_name), AVR_ISP_MAX_LEN_NAME);
text_input_set_header_text(text_input, "Name dump");
text_input_set_result_callback(
text_input,
avr_isp_scene_input_name_text_callback,
app,
app->file_name_tmp,
MAX_TEXT_INPUT_LEN, // buffer size
dev_name_empty);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(STORAGE_APP_DATA_PATH_PREFIX, AVR_ISP_APP_EXTENSION, "");
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
furi_string_free(file_name);
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewTextInput);
}
bool avr_isp_scene_input_name_on_event(void* context, SceneManagerEvent event) {
furi_assert(context);
AvrIspApp* app = context;
if(event.type == SceneManagerEventTypeBack) {
scene_manager_previous_scene(app->scene_manager);
return true;
} else if(event.type == SceneManagerEventTypeCustom) {
if(event.event == AvrIspCustomEventSceneInputName) {
if(strcmp(app->file_name_tmp, "") != 0) {
scene_manager_next_scene(app->scene_manager, AvrIspSceneReader);
} else {
}
}
}
return false;
}
void avr_isp_scene_input_name_on_exit(void* context) {
furi_assert(context);
AvrIspApp* app = context;
// Clear validator
void* validator_context = text_input_get_validator_callback_context(app->text_input);
text_input_set_validator(app->text_input, NULL, NULL);
validator_is_file_free(validator_context);
// Clear view
text_input_reset(app->text_input);
}

View File

@@ -1,22 +0,0 @@
#include "../avr_isp_app_i.h"
void avr_isp_scene_load_on_enter(void* context) {
furi_assert(context);
AvrIspApp* app = context;
if(avr_isp_load_from_file(app)) {
scene_manager_next_scene(app->scene_manager, AvrIspSceneWriter);
} else {
scene_manager_previous_scene(app->scene_manager);
}
}
bool avr_isp_scene_load_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void avr_isp_scene_load_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -1,28 +0,0 @@
#include "../avr_isp_app_i.h"
void avr_isp_scene_programmer_callback(AvrIspCustomEvent event, void* context) {
furi_assert(context);
AvrIspApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void avr_isp_scene_programmer_on_enter(void* context) {
furi_assert(context);
AvrIspApp* app = context;
avr_isp_programmer_view_set_callback(
app->avr_isp_programmer_view, avr_isp_scene_programmer_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewProgrammer);
}
bool avr_isp_scene_programmer_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void avr_isp_scene_programmer_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -1,64 +0,0 @@
#include "../avr_isp_app_i.h"
void avr_isp_scene_reader_callback(AvrIspCustomEvent event, void* context) {
furi_assert(context);
AvrIspApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void avr_isp_scene_reader_on_enter(void* context) {
furi_assert(context);
AvrIspApp* app = context;
avr_isp_reader_set_file_path(
app->avr_isp_reader_view, furi_string_get_cstr(app->file_path), app->file_name_tmp);
avr_isp_reader_view_set_callback(app->avr_isp_reader_view, avr_isp_scene_reader_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewReader);
}
bool avr_isp_scene_reader_on_event(void* context, SceneManagerEvent event) {
furi_assert(context);
AvrIspApp* app = context;
UNUSED(app);
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
//do not handle exit on "Back"
consumed = true;
} else if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case AvrIspCustomEventSceneReadingOk:
scene_manager_next_scene(app->scene_manager, AvrIspSceneSuccess);
consumed = true;
break;
case AvrIspCustomEventSceneExit:
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, AvrIspSceneChipDetect);
consumed = true;
break;
case AvrIspCustomEventSceneErrorVerification:
app->error = AvrIspErrorVerification;
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, AvrIspSceneChipDetect);
consumed = true;
break;
case AvrIspCustomEventSceneErrorReading:
app->error = AvrIspErrorReading;
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, AvrIspSceneChipDetect);
consumed = true;
break;
default:
break;
}
} else if(event.type == SceneManagerEventTypeTick) {
avr_isp_reader_update_progress(app->avr_isp_reader_view);
}
return consumed;
}
void avr_isp_scene_reader_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -1,75 +0,0 @@
#include "../avr_isp_app_i.h"
void avr_isp_scene_start_submenu_callback(void* context, uint32_t index) {
furi_assert(context);
AvrIspApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void avr_isp_scene_start_on_enter(void* context) {
furi_assert(context);
AvrIspApp* app = context;
Submenu* submenu = app->submenu;
submenu_add_item(
submenu, "Dump AVR", SubmenuIndexAvrIspReader, avr_isp_scene_start_submenu_callback, app);
submenu_add_item(
submenu, "Flash AVR", SubmenuIndexAvrIspWriter, avr_isp_scene_start_submenu_callback, app);
submenu_add_item(
submenu,
"ISP Programmer",
SubmenuIndexAvrIspProgrammer,
avr_isp_scene_start_submenu_callback,
app);
submenu_add_item(
submenu, "Wiring", SubmenuIndexAvrIsWiring, avr_isp_scene_start_submenu_callback, app);
submenu_add_item(
submenu, "About", SubmenuIndexAvrIspAbout, avr_isp_scene_start_submenu_callback, app);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(app->scene_manager, AvrIspSceneStart));
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewSubmenu);
}
bool avr_isp_scene_start_on_event(void* context, SceneManagerEvent event) {
furi_assert(context);
AvrIspApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexAvrIspAbout) {
scene_manager_next_scene(app->scene_manager, AvrIspSceneAbout);
consumed = true;
} else if(event.event == SubmenuIndexAvrIspProgrammer) {
scene_manager_set_scene_state(
app->scene_manager, AvrIspSceneChipDetect, AvrIspViewProgrammer);
scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
consumed = true;
} else if(event.event == SubmenuIndexAvrIspReader) {
scene_manager_set_scene_state(
app->scene_manager, AvrIspSceneChipDetect, AvrIspViewReader);
scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
consumed = true;
} else if(event.event == SubmenuIndexAvrIspWriter) {
scene_manager_set_scene_state(
app->scene_manager, AvrIspSceneChipDetect, AvrIspViewWriter);
scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
consumed = true;
} else if(event.event == SubmenuIndexAvrIsWiring) {
scene_manager_next_scene(app->scene_manager, AvrIspSceneWiring);
consumed = true;
}
scene_manager_set_scene_state(app->scene_manager, AvrIspSceneStart, event.event);
}
return consumed;
}
void avr_isp_scene_start_on_exit(void* context) {
furi_assert(context);
AvrIspApp* app = context;
submenu_reset(app->submenu);
}

View File

@@ -1,44 +0,0 @@
#include "../avr_isp_app_i.h"
void avr_isp_scene_success_popup_callback(void* context) {
furi_assert(context);
AvrIspApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, AvrIspCustomEventSceneSuccess);
}
void avr_isp_scene_success_on_enter(void* context) {
furi_assert(context);
AvrIspApp* app = context;
Popup* popup = app->popup;
popup_set_icon(popup, 32, 5, &I_dolphin_nice_96x59);
popup_set_header(popup, "Success!", 8, 22, AlignLeft, AlignBottom);
popup_set_timeout(popup, 1500);
popup_set_context(popup, app);
popup_set_callback(popup, avr_isp_scene_success_popup_callback);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewPopup);
}
bool avr_isp_scene_success_on_event(void* context, SceneManagerEvent event) {
furi_assert(context);
AvrIspApp* app = context;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == AvrIspCustomEventSceneSuccess) {
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, AvrIspSceneStart);
return true;
}
}
return false;
}
void avr_isp_scene_success_on_exit(void* context) {
furi_assert(context);
AvrIspApp* app = context;
Popup* popup = app->popup;
popup_reset(popup);
}

View File

@@ -1,21 +0,0 @@
#include "../avr_isp_app_i.h"
void avr_isp_scene_wiring_on_enter(void* context) {
furi_assert(context);
AvrIspApp* app = context;
widget_add_icon_element(app->widget, 0, 0, &I_avr_wiring);
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWidget);
}
bool avr_isp_scene_wiring_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void avr_isp_scene_wiring_on_exit(void* context) {
furi_assert(context);
AvrIspApp* app = context;
widget_reset(app->widget);
}

View File

@@ -1,69 +0,0 @@
#include "../avr_isp_app_i.h"
void avr_isp_scene_writer_callback(AvrIspCustomEvent event, void* context) {
furi_assert(context);
AvrIspApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void avr_isp_scene_writer_on_enter(void* context) {
furi_assert(context);
AvrIspApp* app = context;
avr_isp_writer_set_file_path(
app->avr_isp_writer_view, furi_string_get_cstr(app->file_path), app->file_name_tmp);
avr_isp_writer_view_set_callback(app->avr_isp_writer_view, avr_isp_scene_writer_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWriter);
}
bool avr_isp_scene_writer_on_event(void* context, SceneManagerEvent event) {
furi_assert(context);
AvrIspApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
//do not handle exit on "Back"
consumed = true;
} else if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case AvrIspCustomEventSceneExitStartMenu:
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, AvrIspSceneStart);
consumed = true;
break;
case AvrIspCustomEventSceneExit:
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, AvrIspSceneChipDetect);
consumed = true;
break;
case AvrIspCustomEventSceneErrorVerification:
app->error = AvrIspErrorVerification;
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, AvrIspSceneChipDetect);
consumed = true;
break;
case AvrIspCustomEventSceneErrorWriting:
app->error = AvrIspErrorWriting;
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, AvrIspSceneChipDetect);
consumed = true;
break;
case AvrIspCustomEventSceneErrorWritingFuse:
app->error = AvrIspErrorWritingFuse;
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, AvrIspSceneChipDetect);
consumed = true;
break;
default:
break;
}
} else if(event.type == SceneManagerEventTypeTick) {
avr_isp_writer_update_progress(app->avr_isp_writer_view);
}
return consumed;
}
void avr_isp_scene_writer_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -1,213 +0,0 @@
#include "avr_isp_view_chip_detect.h"
#include <avr_isp_icons.h>
#include <gui/elements.h>
#include "../helpers/avr_isp_worker_rw.h"
struct AvrIspChipDetectView {
View* view;
AvrIspWorkerRW* avr_isp_worker_rw;
AvrIspChipDetectViewCallback callback;
void* context;
};
typedef struct {
uint16_t idx;
const char* name_chip;
uint32_t flash_size;
AvrIspChipDetectViewState state;
} AvrIspChipDetectViewModel;
void avr_isp_chip_detect_view_set_callback(
AvrIspChipDetectView* instance,
AvrIspChipDetectViewCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
void avr_isp_chip_detect_set_state(AvrIspChipDetectView* instance, AvrIspChipDetectViewState state) {
furi_assert(instance);
with_view_model(
instance->view, AvrIspChipDetectViewModel * model, { model->state = state; }, true);
}
void avr_isp_chip_detect_view_draw(Canvas* canvas, AvrIspChipDetectViewModel* model) {
canvas_clear(canvas);
char str_buf[64] = {0};
canvas_set_font(canvas, FontPrimary);
switch(model->state) {
case AvrIspChipDetectViewStateDetected:
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "AVR chip detected!");
canvas_draw_icon(canvas, 29, 14, &I_chip_long_70x22);
canvas_set_font(canvas, FontSecondary);
snprintf(str_buf, sizeof(str_buf), "%ld Kb", model->flash_size / 1024);
canvas_draw_str_aligned(canvas, 64, 25, AlignCenter, AlignCenter, str_buf);
canvas_draw_str_aligned(canvas, 64, 45, AlignCenter, AlignCenter, model->name_chip);
elements_button_right(canvas, "Next");
break;
case AvrIspChipDetectViewStateErrorOccured:
canvas_draw_str_aligned(
canvas, 64, 5, AlignCenter, AlignCenter, "Error occured, try again!");
canvas_draw_icon(canvas, 29, 14, &I_chip_error_70x22);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas, 64, 45, AlignCenter, AlignCenter, "Check the wiring and retry");
break;
case AvrIspChipDetectViewStateErrorVerification:
canvas_draw_str_aligned(
canvas, 64, 5, AlignCenter, AlignCenter, "Data verification failed");
canvas_draw_icon(canvas, 29, 14, &I_chip_error_70x22);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas, 64, 45, AlignCenter, AlignCenter, "Try to restart the process");
break;
default:
//AvrIspChipDetectViewStateNoDetect
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "AVR chip not found!");
canvas_draw_icon(canvas, 29, 12, &I_chif_not_found_83x37);
break;
}
canvas_set_font(canvas, FontSecondary);
elements_button_left(canvas, "Retry");
}
bool avr_isp_chip_detect_view_input(InputEvent* event, void* context) {
furi_assert(context);
AvrIspChipDetectView* instance = context;
if(event->type == InputTypeShort) {
if(event->key == InputKeyBack) {
return false;
} else if(event->key == InputKeyRight) {
with_view_model(
instance->view,
AvrIspChipDetectViewModel * model,
{
if(model->state == AvrIspChipDetectViewStateDetected) {
if(instance->callback)
instance->callback(
AvrIspCustomEventSceneChipDetectOk, instance->context);
}
},
false);
} else if(event->key == InputKeyLeft) {
bool detect_chip = false;
with_view_model(
instance->view,
AvrIspChipDetectViewModel * model,
{
if(model->state != AvrIspChipDetectViewStateDetecting) {
model->state = AvrIspChipDetectViewStateDetecting;
detect_chip = true;
}
},
false);
if(detect_chip) avr_isp_worker_rw_detect_chip(instance->avr_isp_worker_rw);
}
} else {
return false;
}
return true;
}
static void avr_isp_chip_detect_detect_chip_callback(
void* context,
const char* name,
bool detect_chip,
uint32_t flash_size) {
furi_assert(context);
AvrIspChipDetectView* instance = context;
with_view_model(
instance->view,
AvrIspChipDetectViewModel * model,
{
model->name_chip = name;
model->flash_size = flash_size;
if(detect_chip) {
model->state = AvrIspChipDetectViewStateDetected;
} else {
model->state = AvrIspChipDetectViewStateNoDetect;
}
},
true);
}
void avr_isp_chip_detect_view_enter(void* context) {
furi_assert(context);
AvrIspChipDetectView* instance = context;
bool detect_chip = false;
with_view_model(
instance->view,
AvrIspChipDetectViewModel * model,
{
if(model->state == AvrIspChipDetectViewStateNoDetect ||
model->state == AvrIspChipDetectViewStateDetected) {
detect_chip = true;
}
},
false);
//Start avr_isp_worker_rw
instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
avr_isp_worker_rw_set_callback(
instance->avr_isp_worker_rw, avr_isp_chip_detect_detect_chip_callback, instance);
if(detect_chip) avr_isp_worker_rw_detect_chip(instance->avr_isp_worker_rw);
}
void avr_isp_chip_detect_view_exit(void* context) {
furi_assert(context);
AvrIspChipDetectView* instance = context;
avr_isp_worker_rw_set_callback(instance->avr_isp_worker_rw, NULL, NULL);
avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
}
AvrIspChipDetectView* avr_isp_chip_detect_view_alloc() {
AvrIspChipDetectView* instance = malloc(sizeof(AvrIspChipDetectView));
// View allocation and configuration
instance->view = view_alloc();
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspChipDetectViewModel));
view_set_context(instance->view, instance);
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_chip_detect_view_draw);
view_set_input_callback(instance->view, avr_isp_chip_detect_view_input);
view_set_enter_callback(instance->view, avr_isp_chip_detect_view_enter);
view_set_exit_callback(instance->view, avr_isp_chip_detect_view_exit);
with_view_model(
instance->view,
AvrIspChipDetectViewModel * model,
{ model->state = AvrIspChipDetectViewStateNoDetect; },
false);
return instance;
}
void avr_isp_chip_detect_view_free(AvrIspChipDetectView* instance) {
furi_assert(instance);
view_free(instance->view);
free(instance);
}
View* avr_isp_chip_detect_view_get_view(AvrIspChipDetectView* instance) {
furi_assert(instance);
return instance->view;
}

View File

@@ -1,32 +0,0 @@
#pragma once
#include <gui/view.h>
#include "../helpers/avr_isp_types.h"
#include "../helpers/avr_isp_event.h"
typedef struct AvrIspChipDetectView AvrIspChipDetectView;
typedef void (*AvrIspChipDetectViewCallback)(AvrIspCustomEvent event, void* context);
typedef enum {
AvrIspChipDetectViewStateNoDetect,
AvrIspChipDetectViewStateDetecting,
AvrIspChipDetectViewStateDetected,
AvrIspChipDetectViewStateErrorOccured,
AvrIspChipDetectViewStateErrorVerification,
} AvrIspChipDetectViewState;
void avr_isp_chip_detect_view_set_callback(
AvrIspChipDetectView* instance,
AvrIspChipDetectViewCallback callback,
void* context);
void avr_isp_chip_detect_set_state(AvrIspChipDetectView* instance, AvrIspChipDetectViewState state);
AvrIspChipDetectView* avr_isp_chip_detect_view_alloc();
void avr_isp_chip_detect_view_free(AvrIspChipDetectView* instance);
View* avr_isp_chip_detect_view_get_view(AvrIspChipDetectView* instance);
void avr_isp_chip_detect_view_exit(void* context);

View File

@@ -1,134 +0,0 @@
#include "avr_isp_view_programmer.h"
#include <avr_isp_icons.h>
#include "../helpers/avr_isp_worker.h"
#include <gui/elements.h>
struct AvrIspProgrammerView {
View* view;
AvrIspWorker* worker;
AvrIspProgrammerViewCallback callback;
void* context;
};
typedef struct {
AvrIspProgrammerViewStatus status;
} AvrIspProgrammerViewModel;
void avr_isp_programmer_view_set_callback(
AvrIspProgrammerView* instance,
AvrIspProgrammerViewCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
void avr_isp_programmer_view_draw(Canvas* canvas, AvrIspProgrammerViewModel* model) {
canvas_clear(canvas);
if(model->status == AvrIspProgrammerViewStatusUSBConnect) {
canvas_set_font(canvas, FontPrimary);
canvas_draw_icon(canvas, 0, 0, &I_isp_active_128x53);
elements_multiline_text(canvas, 45, 10, "ISP mode active");
} else {
canvas_set_font(canvas, FontSecondary);
canvas_draw_icon(canvas, 51, 6, &I_link_waiting_77x56);
elements_multiline_text(canvas, 0, 25, "Waiting for\nsoftware\nconnection");
}
}
bool avr_isp_programmer_view_input(InputEvent* event, void* context) {
furi_assert(context);
UNUSED(context);
if(event->key == InputKeyBack || event->type != InputTypeShort) {
return false;
}
return true;
}
static void avr_isp_programmer_usb_connect_callback(void* context, bool status_connect) {
furi_assert(context);
AvrIspProgrammerView* instance = context;
with_view_model(
instance->view,
AvrIspProgrammerViewModel * model,
{
if(status_connect) {
model->status = AvrIspProgrammerViewStatusUSBConnect;
} else {
model->status = AvrIspProgrammerViewStatusNoUSBConnect;
}
},
true);
}
void avr_isp_programmer_view_enter(void* context) {
furi_assert(context);
AvrIspProgrammerView* instance = context;
with_view_model(
instance->view,
AvrIspProgrammerViewModel * model,
{ model->status = AvrIspProgrammerViewStatusNoUSBConnect; },
true);
//Start worker
instance->worker = avr_isp_worker_alloc(instance->context);
avr_isp_worker_set_callback(
instance->worker, avr_isp_programmer_usb_connect_callback, instance);
avr_isp_worker_start(instance->worker);
}
void avr_isp_programmer_view_exit(void* context) {
furi_assert(context);
AvrIspProgrammerView* instance = context;
//Stop worker
if(avr_isp_worker_is_running(instance->worker)) {
avr_isp_worker_stop(instance->worker);
}
avr_isp_worker_set_callback(instance->worker, NULL, NULL);
avr_isp_worker_free(instance->worker);
}
AvrIspProgrammerView* avr_isp_programmer_view_alloc() {
AvrIspProgrammerView* instance = malloc(sizeof(AvrIspProgrammerView));
// View allocation and configuration
instance->view = view_alloc();
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspProgrammerViewModel));
view_set_context(instance->view, instance);
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_programmer_view_draw);
view_set_input_callback(instance->view, avr_isp_programmer_view_input);
view_set_enter_callback(instance->view, avr_isp_programmer_view_enter);
view_set_exit_callback(instance->view, avr_isp_programmer_view_exit);
with_view_model(
instance->view,
AvrIspProgrammerViewModel * model,
{ model->status = AvrIspProgrammerViewStatusNoUSBConnect; },
false);
return instance;
}
void avr_isp_programmer_view_free(AvrIspProgrammerView* instance) {
furi_assert(instance);
view_free(instance->view);
free(instance);
}
View* avr_isp_programmer_view_get_view(AvrIspProgrammerView* instance) {
furi_assert(instance);
return instance->view;
}

View File

@@ -1,27 +0,0 @@
#pragma once
#include <gui/view.h>
#include "../helpers/avr_isp_types.h"
#include "../helpers/avr_isp_event.h"
typedef struct AvrIspProgrammerView AvrIspProgrammerView;
typedef void (*AvrIspProgrammerViewCallback)(AvrIspCustomEvent event, void* context);
typedef enum {
AvrIspProgrammerViewStatusNoUSBConnect,
AvrIspProgrammerViewStatusUSBConnect,
} AvrIspProgrammerViewStatus;
void avr_isp_programmer_view_set_callback(
AvrIspProgrammerView* instance,
AvrIspProgrammerViewCallback callback,
void* context);
AvrIspProgrammerView* avr_isp_programmer_view_alloc();
void avr_isp_programmer_view_free(AvrIspProgrammerView* instance);
View* avr_isp_programmer_view_get_view(AvrIspProgrammerView* instance);
void avr_isp_programmer_view_exit(void* context);

View File

@@ -1,215 +0,0 @@
#include "avr_isp_view_reader.h"
#include <gui/elements.h>
#include "../helpers/avr_isp_worker_rw.h"
struct AvrIspReaderView {
View* view;
AvrIspWorkerRW* avr_isp_worker_rw;
const char* file_path;
const char* file_name;
AvrIspReaderViewCallback callback;
void* context;
};
typedef struct {
AvrIspReaderViewStatus status;
float progress_flash;
float progress_eeprom;
} AvrIspReaderViewModel;
void avr_isp_reader_update_progress(AvrIspReaderView* instance) {
with_view_model(
instance->view,
AvrIspReaderViewModel * model,
{
model->progress_flash =
avr_isp_worker_rw_get_progress_flash(instance->avr_isp_worker_rw);
model->progress_eeprom =
avr_isp_worker_rw_get_progress_eeprom(instance->avr_isp_worker_rw);
},
true);
}
void avr_isp_reader_view_set_callback(
AvrIspReaderView* instance,
AvrIspReaderViewCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
void avr_isp_reader_set_file_path(
AvrIspReaderView* instance,
const char* file_path,
const char* file_name) {
furi_assert(instance);
instance->file_path = file_path;
instance->file_name = file_name;
}
void avr_isp_reader_view_draw(Canvas* canvas, AvrIspReaderViewModel* model) {
canvas_clear(canvas);
char str_buf[64] = {0};
canvas_set_font(canvas, FontPrimary);
switch(model->status) {
case AvrIspReaderViewStatusIDLE:
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Press start to dump");
canvas_set_font(canvas, FontSecondary);
elements_button_center(canvas, "Start");
break;
case AvrIspReaderViewStatusReading:
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Reading dump");
break;
case AvrIspReaderViewStatusVerification:
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifyng dump");
break;
default:
break;
}
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 0, 27, "Flash");
snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_flash * 100));
elements_progress_bar_with_text(canvas, 44, 17, 84, model->progress_flash, str_buf);
canvas_draw_str(canvas, 0, 43, "EEPROM");
snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_eeprom * 100));
elements_progress_bar_with_text(canvas, 44, 34, 84, model->progress_eeprom, str_buf);
}
bool avr_isp_reader_view_input(InputEvent* event, void* context) {
furi_assert(context);
AvrIspReaderView* instance = context;
bool ret = true;
if(event->key == InputKeyBack && event->type == InputTypeShort) {
with_view_model(
instance->view,
AvrIspReaderViewModel * model,
{
if(model->status == AvrIspReaderViewStatusIDLE) {
if(instance->callback)
instance->callback(AvrIspCustomEventSceneExit, instance->context);
ret = false;
}
},
false);
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
with_view_model(
instance->view,
AvrIspReaderViewModel * model,
{
if(model->status == AvrIspReaderViewStatusIDLE) {
model->status = AvrIspReaderViewStatusReading;
avr_isp_worker_rw_read_dump_start(
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
}
},
false);
}
return ret;
}
static void avr_isp_reader_callback_status(void* context, AvrIspWorkerRWStatus status) {
furi_assert(context);
AvrIspReaderView* instance = context;
with_view_model(
instance->view,
AvrIspReaderViewModel * model,
{
switch(status) {
case AvrIspWorkerRWStatusEndReading:
model->status = AvrIspReaderViewStatusVerification;
avr_isp_worker_rw_verification_start(
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
model->status = AvrIspReaderViewStatusVerification;
break;
case AvrIspWorkerRWStatusEndVerification:
if(instance->callback)
instance->callback(AvrIspCustomEventSceneReadingOk, instance->context);
break;
case AvrIspWorkerRWStatusErrorVerification:
if(instance->callback)
instance->callback(AvrIspCustomEventSceneErrorVerification, instance->context);
break;
default:
//AvrIspWorkerRWStatusErrorReading;
if(instance->callback)
instance->callback(AvrIspCustomEventSceneErrorReading, instance->context);
break;
}
},
true);
}
void avr_isp_reader_view_enter(void* context) {
furi_assert(context);
AvrIspReaderView* instance = context;
with_view_model(
instance->view,
AvrIspReaderViewModel * model,
{
model->status = AvrIspReaderViewStatusIDLE;
model->progress_flash = 0.0f;
model->progress_eeprom = 0.0f;
},
true);
//Start avr_isp_worker_rw
instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
avr_isp_worker_rw_set_callback_status(
instance->avr_isp_worker_rw, avr_isp_reader_callback_status, instance);
avr_isp_worker_rw_start(instance->avr_isp_worker_rw);
}
void avr_isp_reader_view_exit(void* context) {
furi_assert(context);
AvrIspReaderView* instance = context;
//Stop avr_isp_worker_rw
if(avr_isp_worker_rw_is_running(instance->avr_isp_worker_rw)) {
avr_isp_worker_rw_stop(instance->avr_isp_worker_rw);
}
avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
}
AvrIspReaderView* avr_isp_reader_view_alloc() {
AvrIspReaderView* instance = malloc(sizeof(AvrIspReaderView));
// View allocation and configuration
instance->view = view_alloc();
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspReaderViewModel));
view_set_context(instance->view, instance);
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_reader_view_draw);
view_set_input_callback(instance->view, avr_isp_reader_view_input);
view_set_enter_callback(instance->view, avr_isp_reader_view_enter);
view_set_exit_callback(instance->view, avr_isp_reader_view_exit);
return instance;
}
void avr_isp_reader_view_free(AvrIspReaderView* instance) {
furi_assert(instance);
view_free(instance->view);
free(instance);
}
View* avr_isp_reader_view_get_view(AvrIspReaderView* instance) {
furi_assert(instance);
return instance->view;
}

View File

@@ -1,35 +0,0 @@
#pragma once
#include <gui/view.h>
#include "../helpers/avr_isp_types.h"
#include "../helpers/avr_isp_event.h"
typedef struct AvrIspReaderView AvrIspReaderView;
typedef void (*AvrIspReaderViewCallback)(AvrIspCustomEvent event, void* context);
typedef enum {
AvrIspReaderViewStatusIDLE,
AvrIspReaderViewStatusReading,
AvrIspReaderViewStatusVerification,
} AvrIspReaderViewStatus;
void avr_isp_reader_update_progress(AvrIspReaderView* instance);
void avr_isp_reader_set_file_path(
AvrIspReaderView* instance,
const char* file_path,
const char* file_name);
void avr_isp_reader_view_set_callback(
AvrIspReaderView* instance,
AvrIspReaderViewCallback callback,
void* context);
AvrIspReaderView* avr_isp_reader_view_alloc();
void avr_isp_reader_view_free(AvrIspReaderView* instance);
View* avr_isp_reader_view_get_view(AvrIspReaderView* instance);
void avr_isp_reader_view_exit(void* context);

View File

@@ -1,268 +0,0 @@
#include "avr_isp_view_writer.h"
#include <gui/elements.h>
#include "../helpers/avr_isp_worker_rw.h"
#include <float_tools.h>
struct AvrIspWriterView {
View* view;
AvrIspWorkerRW* avr_isp_worker_rw;
const char* file_path;
const char* file_name;
AvrIspWriterViewCallback callback;
void* context;
};
typedef struct {
AvrIspWriterViewStatus status;
float progress_flash;
float progress_eeprom;
} AvrIspWriterViewModel;
void avr_isp_writer_update_progress(AvrIspWriterView* instance) {
with_view_model(
instance->view,
AvrIspWriterViewModel * model,
{
model->progress_flash =
avr_isp_worker_rw_get_progress_flash(instance->avr_isp_worker_rw);
model->progress_eeprom =
avr_isp_worker_rw_get_progress_eeprom(instance->avr_isp_worker_rw);
},
true);
}
void avr_isp_writer_view_set_callback(
AvrIspWriterView* instance,
AvrIspWriterViewCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
void avr_isp_writer_set_file_path(
AvrIspWriterView* instance,
const char* file_path,
const char* file_name) {
furi_assert(instance);
instance->file_path = file_path;
instance->file_name = file_name;
}
void avr_isp_writer_view_draw(Canvas* canvas, AvrIspWriterViewModel* model) {
canvas_clear(canvas);
char str_flash[32] = {0};
char str_eeprom[32] = {0};
canvas_set_font(canvas, FontPrimary);
switch(model->status) {
case AvrIspWriterViewStatusIDLE:
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Press start to write");
canvas_set_font(canvas, FontSecondary);
elements_button_center(canvas, "Start");
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
break;
case AvrIspWriterViewStatusWriting:
if(float_is_equal(model->progress_flash, 0.f)) {
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifying firmware");
snprintf(str_flash, sizeof(str_flash), "***");
snprintf(str_eeprom, sizeof(str_eeprom), "***");
} else {
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Writing dump");
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
snprintf(
str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
}
break;
case AvrIspWriterViewStatusVerification:
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifying dump");
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
break;
case AvrIspWriterViewStatusWritingFuse:
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Writing fuse");
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
break;
case AvrIspWriterViewStatusWritingFuseOk:
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Done!");
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
canvas_set_font(canvas, FontSecondary);
elements_button_center(canvas, "Reflash");
elements_button_right(canvas, "Exit");
break;
default:
break;
}
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 0, 27, "Flash");
// snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_flash * 100));
elements_progress_bar_with_text(canvas, 44, 17, 84, model->progress_flash, str_flash);
canvas_draw_str(canvas, 0, 43, "EEPROM");
// snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_eeprom * 100));
elements_progress_bar_with_text(canvas, 44, 34, 84, model->progress_eeprom, str_eeprom);
}
bool avr_isp_writer_view_input(InputEvent* event, void* context) {
furi_assert(context);
AvrIspWriterView* instance = context;
bool ret = true;
if(event->key == InputKeyBack && event->type == InputTypeShort) {
with_view_model(
instance->view,
AvrIspWriterViewModel * model,
{
if((model->status == AvrIspWriterViewStatusIDLE) ||
(model->status == AvrIspWriterViewStatusWritingFuseOk)) {
if(instance->callback)
instance->callback(AvrIspCustomEventSceneExit, instance->context);
ret = false;
}
},
false);
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
with_view_model(
instance->view,
AvrIspWriterViewModel * model,
{
if((model->status == AvrIspWriterViewStatusIDLE) ||
(model->status == AvrIspWriterViewStatusWritingFuseOk)) {
model->status = AvrIspWriterViewStatusWriting;
avr_isp_worker_rw_write_dump_start(
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
}
},
false);
} else if(event->key == InputKeyRight && event->type == InputTypeShort) {
with_view_model(
instance->view,
AvrIspWriterViewModel * model,
{
if((model->status == AvrIspWriterViewStatusIDLE) ||
(model->status == AvrIspWriterViewStatusWritingFuseOk)) {
if(instance->callback)
instance->callback(AvrIspCustomEventSceneExitStartMenu, instance->context);
ret = false;
}
},
false);
}
return ret;
}
static void avr_isp_writer_callback_status(void* context, AvrIspWorkerRWStatus status) {
furi_assert(context);
AvrIspWriterView* instance = context;
with_view_model(
instance->view,
AvrIspWriterViewModel * model,
{
switch(status) {
case AvrIspWorkerRWStatusEndWriting:
model->status = AvrIspWriterViewStatusVerification;
avr_isp_worker_rw_verification_start(
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
model->status = AvrIspWriterViewStatusVerification;
break;
case AvrIspWorkerRWStatusErrorVerification:
if(instance->callback)
instance->callback(AvrIspCustomEventSceneErrorVerification, instance->context);
break;
case AvrIspWorkerRWStatusEndVerification:
avr_isp_worker_rw_write_fuse_start(
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
model->status = AvrIspWriterViewStatusWritingFuse;
break;
case AvrIspWorkerRWStatusErrorWritingFuse:
if(instance->callback)
instance->callback(AvrIspCustomEventSceneErrorWritingFuse, instance->context);
break;
case AvrIspWorkerRWStatusEndWritingFuse:
model->status = AvrIspWriterViewStatusWritingFuseOk;
break;
default:
//AvrIspWorkerRWStatusErrorWriting;
if(instance->callback)
instance->callback(AvrIspCustomEventSceneErrorWriting, instance->context);
break;
}
},
true);
}
void avr_isp_writer_view_enter(void* context) {
furi_assert(context);
AvrIspWriterView* instance = context;
with_view_model(
instance->view,
AvrIspWriterViewModel * model,
{
model->status = AvrIspWriterViewStatusIDLE;
model->progress_flash = 0.0f;
model->progress_eeprom = 0.0f;
},
true);
//Start avr_isp_worker_rw
instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
avr_isp_worker_rw_set_callback_status(
instance->avr_isp_worker_rw, avr_isp_writer_callback_status, instance);
avr_isp_worker_rw_start(instance->avr_isp_worker_rw);
}
void avr_isp_writer_view_exit(void* context) {
furi_assert(context);
AvrIspWriterView* instance = context;
//Stop avr_isp_worker_rw
if(avr_isp_worker_rw_is_running(instance->avr_isp_worker_rw)) {
avr_isp_worker_rw_stop(instance->avr_isp_worker_rw);
}
avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
}
AvrIspWriterView* avr_isp_writer_view_alloc() {
AvrIspWriterView* instance = malloc(sizeof(AvrIspWriterView));
// View allocation and configuration
instance->view = view_alloc();
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspWriterViewModel));
view_set_context(instance->view, instance);
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_writer_view_draw);
view_set_input_callback(instance->view, avr_isp_writer_view_input);
view_set_enter_callback(instance->view, avr_isp_writer_view_enter);
view_set_exit_callback(instance->view, avr_isp_writer_view_exit);
return instance;
}
void avr_isp_writer_view_free(AvrIspWriterView* instance) {
furi_assert(instance);
view_free(instance->view);
free(instance);
}
View* avr_isp_writer_view_get_view(AvrIspWriterView* instance) {
furi_assert(instance);
return instance->view;
}

View File

@@ -1,37 +0,0 @@
#pragma once
#include <gui/view.h>
#include "../helpers/avr_isp_types.h"
#include "../helpers/avr_isp_event.h"
typedef struct AvrIspWriterView AvrIspWriterView;
typedef void (*AvrIspWriterViewCallback)(AvrIspCustomEvent event, void* context);
typedef enum {
AvrIspWriterViewStatusIDLE,
AvrIspWriterViewStatusWriting,
AvrIspWriterViewStatusVerification,
AvrIspWriterViewStatusWritingFuse,
AvrIspWriterViewStatusWritingFuseOk,
} AvrIspWriterViewStatus;
void avr_isp_writer_update_progress(AvrIspWriterView* instance);
void avr_isp_writer_set_file_path(
AvrIspWriterView* instance,
const char* file_path,
const char* file_name);
void avr_isp_writer_view_set_callback(
AvrIspWriterView* instance,
AvrIspWriterViewCallback callback,
void* context);
AvrIspWriterView* avr_isp_writer_view_alloc();
void avr_isp_writer_view_free(AvrIspWriterView* instance);
View* avr_isp_writer_view_get_view(AvrIspWriterView* instance);
void avr_isp_writer_view_exit(void* context);

View File

@@ -1,16 +0,0 @@
App(
appid="bad_bt",
name="Bad BT",
apptype=FlipperAppType.EXTERNAL,
entry_point="bad_bt_app",
requires=[
"gui",
"dialogs",
],
stack_size=2 * 1024,
order=70,
fap_libs=["assets"],
fap_category="Bluetooth",
fap_icon="images/badbt_10px.png",
fap_icon_assets="images",
)

Some files were not shown because too many files have changed in this diff Show More