From a8db46124e44c3e360899871f011853ba119bc24 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 20 Sep 2022 04:09:14 +0300 Subject: [PATCH 01/30] update docs & changelog --- CHANGELOG.md | 18 +++++++----------- ReadMe.md | 3 +-- documentation/HowToInstall.md | 17 +++++++++++++++++ 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65247313c..589729286 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,15 @@ ### New changes -* PR: Added 868.95 MHz into subghz user config (PR 71 by TasyDevilsky) -* Lower framerate in custom anim to save a bit of battery charge -* Removed unused icon from OFW PR 1533, fixed unirf icon name, updated api symbols (version is 3.0) -* OFW: NFC user dict list, delete, and de-duplication. (OFW PR 1533) -* OFW: Add new russian transport card parsers (OFW PR 1503) -* OFW: SubGhz: Oregon v2.1 decoder (OFR PR 1678) -* OFW: Show error popup when NFC chip is not init/disconnected (OFW PR 1722) +* PR: Allow running apps from Archive app (also allows adding them to Favourites) (PR 72 by RogueMaster) (new icon by @Svaarich) -#### **DFU files no longer included in releases to avoid issues with wrong manual installation of assets - use web updater or microSD update package** +#### **DFU files no longer included in releases to avoid issues with wrong manual installation of assets - use .tgz file with qFlipper, or install automatically via web updater or use microSD update package** [- How to install](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md) -**Note: To avoid issues prefer installing using web updater or by self update package, all needed assets will be installed** +[- Download qFlipper 1.2.0-rc1 (allows .tgz installation) (official link)](https://update.flipperzero.one/builds/qFlipper/1.2.0-rc1/) -Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip` or `.tgz` for iOS mobile app +**Note: To avoid issues with .dfu, prefer installing using .tgz with qFlipper, web updater or by self update package, all needed assets will be installed** -DFU for update using qFlipper is no longer included in releases to avoid issues with assets - Use Web Updater or self-update package! +Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip` or download `.tgz` for iOS mobile app / qFlipper + +Update using qFlipper (1.2.0-rc1) is now possible with `.tgz` update package! Also you can use Web Updater or self-update package. diff --git a/ReadMe.md b/ReadMe.md index f3eaba888..ffb1cacf6 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -49,7 +49,7 @@ See changelog in releases for latest updates! - Keeloq [Not ALL systems supported yet!] - Nice Flor S - Security+ v1 & v2 -- Star Line +- Star Line (saving only) ## Support us so we can buy equipment and develop new features * ETH/BSC/ERC20-Tokens: `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a` @@ -87,7 +87,6 @@ Games: - BadUSB -> Keyboard layouts [(by rien > dummy-decoy)](https://github.com/dummy-decoy/flipperzero-firmware/tree/dummy_decoy/bad_usb_keyboard_layout) - SubGHz -> New frequency analyzer - [(by ClusterM)](https://github.com/ClusterM) - SubGHz -> Detect RAW feature - [(by perspecdev)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/152) -- SubGHz -> Save last used config settings - [(by derskythe)](https://github.com/Eng1n33r/flipperzero-firmware/pull/67) # Instructions ## [- How to install firmware](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md) diff --git a/documentation/HowToInstall.md b/documentation/HowToInstall.md index 4991d69a0..bce86a572 100644 --- a/documentation/HowToInstall.md +++ b/documentation/HowToInstall.md @@ -40,6 +40,23 @@ after that on web updater page - press `Connect` button - And if all flashed successfully - you will have all needed assets pre installed - Done +
+
+ +## With qFlipper (1.2.0-rc1) + +- Download qFlipper that allows `.tgz` installation [Download qFlipper 1.2.0-rc1 (official link)](https://update.flipperzero.one/builds/qFlipper/1.2.0-rc1/) +- Be sure you updated to latest official release before(only if installing for the first time), and verify that microSD card is installed +- Open latest release page - [Releases](https://github.com/Eng1n33r/flipperzero-firmware/releases/latest) +- Download `flipper-z-f7-update-(version).tgz` +- Launch qFlipper +- Connect your device and select `Install from file` +- Select `flipper-z-f7-update-(version).tgz` that you downloaded +- Update will start +- And wait, if all flashed successfully - you will have all needed assets pre installed +- Done + +

From b2c118f26785d5aa0dcf92161b932f0fc794ebd8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 20 Sep 2022 05:52:13 +0300 Subject: [PATCH 02/30] fix null pointer dereference in archive -> Info and fix long path display --- applications/main/archive/scenes/archive_scene_info.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/applications/main/archive/scenes/archive_scene_info.c b/applications/main/archive/scenes/archive_scene_info.c index b6fae4bca..08c403b4b 100644 --- a/applications/main/archive/scenes/archive_scene_info.c +++ b/applications/main/archive/scenes/archive_scene_info.c @@ -37,7 +37,11 @@ void archive_scene_info_on_enter(void* context) { // Directory path path_extract_dirname(string_get_cstr(current->path), dirname); - string_replace_str(dirname, STORAGE_ANY_PATH_PREFIX, ""); + if(strcmp(string_get_cstr(dirname), "/any") == 0) { + string_replace_str(dirname, STORAGE_ANY_PATH_PREFIX, "/"); + } else { + string_replace_str(dirname, STORAGE_ANY_PATH_PREFIX, ""); + } // File size FileInfo fileinfo; @@ -60,7 +64,7 @@ void archive_scene_info_on_enter(void* context) { string_get_cstr(dirname)); } widget_add_text_box_element( - instance->widget, 0, 25, 128, 25, AlignLeft, AlignCenter, file_info_message, false); + instance->widget, 0, 25, 128, 25, AlignLeft, AlignCenter, file_info_message, true); // This one to return and cursor select this file path_extract_filename_no_ext(string_get_cstr(current->path), filename); From 066da4080bf5950ece9cb71cbe6f2c75ad0992be Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Tue, 20 Sep 2022 08:09:37 +0300 Subject: [PATCH 03/30] [FL-2792] AC Universal Remote (#1725) * Add Universal AC Remote scene * Implement AC gui * Basic working implemetation * Another Universal AC Remote implementation * Update icons * Adjust button positions * Revert old ButtonPanel class * Update resource manifest * [FL-2627] Flipper applications: SDK, build and debug system (#1387) * Update api definitions * Add UniversalRemotes documentation * Use more Flipper-friendly signal names Co-authored-by: SG --- .../infrared/scenes/infrared_scene_config.h | 1 + .../scenes/infrared_scene_universal.c | 14 ++- .../scenes/infrared_scene_universal_ac.c | 109 ++++++++++++++++++ assets/icons/Infrared/CoolHi_25x27.png | Bin 0 -> 3680 bytes assets/icons/Infrared/CoolHi_hvr_25x27.png | Bin 0 -> 3669 bytes assets/icons/Infrared/CoolLo_25x27.png | Bin 0 -> 3676 bytes assets/icons/Infrared/CoolLo_hvr_25x27.png | Bin 0 -> 3657 bytes assets/icons/Infrared/Dehumidify_25x27.png | Bin 0 -> 3665 bytes .../icons/Infrared/Dehumidify_hvr_25x27.png | Bin 0 -> 3652 bytes assets/icons/Infrared/HeatHi_25x27.png | Bin 0 -> 3676 bytes assets/icons/Infrared/HeatHi_hvr_25x27.png | Bin 0 -> 3661 bytes assets/icons/Infrared/HeatLo_25x27.png | Bin 0 -> 3670 bytes assets/icons/Infrared/HeatLo_hvr_25x27.png | Bin 0 -> 3655 bytes assets/icons/Infrared/Off_25x27.png | Bin 0 -> 9530 bytes assets/icons/Infrared/Off_hvr_25x27.png | Bin 0 -> 8460 bytes assets/resources/infrared/assets/ac.ir | 38 ++++++ documentation/UniversalRemotes.md | 36 ++++++ firmware/targets/f7/api_symbols.csv | 14 ++- 18 files changed, 207 insertions(+), 5 deletions(-) create mode 100644 applications/main/infrared/scenes/infrared_scene_universal_ac.c create mode 100644 assets/icons/Infrared/CoolHi_25x27.png create mode 100644 assets/icons/Infrared/CoolHi_hvr_25x27.png create mode 100644 assets/icons/Infrared/CoolLo_25x27.png create mode 100644 assets/icons/Infrared/CoolLo_hvr_25x27.png create mode 100644 assets/icons/Infrared/Dehumidify_25x27.png create mode 100644 assets/icons/Infrared/Dehumidify_hvr_25x27.png create mode 100644 assets/icons/Infrared/HeatHi_25x27.png create mode 100644 assets/icons/Infrared/HeatHi_hvr_25x27.png create mode 100644 assets/icons/Infrared/HeatLo_25x27.png create mode 100644 assets/icons/Infrared/HeatLo_hvr_25x27.png create mode 100644 assets/icons/Infrared/Off_25x27.png create mode 100644 assets/icons/Infrared/Off_hvr_25x27.png create mode 100644 assets/resources/infrared/assets/ac.ir create mode 100644 documentation/UniversalRemotes.md diff --git a/applications/main/infrared/scenes/infrared_scene_config.h b/applications/main/infrared/scenes/infrared_scene_config.h index 26a92056d..22125fb79 100644 --- a/applications/main/infrared/scenes/infrared_scene_config.h +++ b/applications/main/infrared/scenes/infrared_scene_config.h @@ -15,6 +15,7 @@ ADD_SCENE(infrared, remote, Remote) ADD_SCENE(infrared, remote_list, RemoteList) ADD_SCENE(infrared, universal, Universal) ADD_SCENE(infrared, universal_tv, UniversalTV) +ADD_SCENE(infrared, universal_ac, UniversalAC) ADD_SCENE(infrared, debug, Debug) ADD_SCENE(infrared, error_databases, ErrorDatabases) ADD_SCENE(infrared, rpc, Rpc) diff --git a/applications/main/infrared/scenes/infrared_scene_universal.c b/applications/main/infrared/scenes/infrared_scene_universal.c index cc6568834..2bd7082c4 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal.c +++ b/applications/main/infrared/scenes/infrared_scene_universal.c @@ -2,8 +2,8 @@ typedef enum { SubmenuIndexUniversalTV, + SubmenuIndexUniversalAC, SubmenuIndexUniversalAudio, - SubmenuIndexUniversalAirConditioner, } SubmenuIndex; static void infrared_scene_universal_submenu_callback(void* context, uint32_t index) { @@ -21,6 +21,12 @@ void infrared_scene_universal_on_enter(void* context) { SubmenuIndexUniversalTV, infrared_scene_universal_submenu_callback, context); + submenu_add_item( + submenu, + "Air Conditioners", + SubmenuIndexUniversalAC, + infrared_scene_universal_submenu_callback, + context); submenu_set_selected_item(submenu, 0); view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewSubmenu); @@ -35,12 +41,12 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexUniversalTV) { scene_manager_next_scene(scene_manager, InfraredSceneUniversalTV); consumed = true; + } else if(event.event == SubmenuIndexUniversalAC) { + scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC); + consumed = true; } else if(event.event == SubmenuIndexUniversalAudio) { //TODO Implement Audio universal remote consumed = true; - } else if(event.event == SubmenuIndexUniversalAirConditioner) { - //TODO Implement A/C universal remote - consumed = true; } } diff --git a/applications/main/infrared/scenes/infrared_scene_universal_ac.c b/applications/main/infrared/scenes/infrared_scene_universal_ac.c new file mode 100644 index 000000000..58f067735 --- /dev/null +++ b/applications/main/infrared/scenes/infrared_scene_universal_ac.c @@ -0,0 +1,109 @@ +#include "../infrared_i.h" + +#include "common/infrared_scene_universal_common.h" + +void infrared_scene_universal_ac_on_enter(void* context) { + infrared_scene_universal_common_on_enter(context); + + Infrared* infrared = context; + ButtonPanel* button_panel = infrared->button_panel; + InfraredBruteForce* brute_force = infrared->brute_force; + + infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/ac.ir")); + + button_panel_reserve(button_panel, 2, 3); + uint32_t i = 0; + button_panel_add_item( + button_panel, + i, + 0, + 0, + 3, + 22, + &I_Off_25x27, + &I_Off_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Off"); + button_panel_add_item( + button_panel, + i, + 1, + 0, + 36, + 22, + &I_Dehumidify_25x27, + &I_Dehumidify_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Dh"); + button_panel_add_item( + button_panel, + i, + 0, + 1, + 3, + 59, + &I_CoolHi_25x27, + &I_CoolHi_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Cool_hi"); + button_panel_add_item( + button_panel, + i, + 1, + 1, + 36, + 59, + &I_HeatHi_25x27, + &I_HeatHi_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Heat_hi"); + button_panel_add_item( + button_panel, + i, + 0, + 2, + 3, + 91, + &I_CoolLo_25x27, + &I_CoolLo_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Cool_lo"); + button_panel_add_item( + button_panel, + i, + 1, + 2, + 36, + 91, + &I_HeatLo_25x27, + &I_HeatLo_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Heat_lo"); + + button_panel_add_label(button_panel, 6, 10, FontPrimary, "AC remote"); + + view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); + + infrared_show_loading_popup(infrared, true); + bool success = infrared_brute_force_calculate_messages(brute_force); + infrared_show_loading_popup(infrared, false); + + if(!success) { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneErrorDatabases); + } +} + +bool infrared_scene_universal_ac_on_event(void* context, SceneManagerEvent event) { + return infrared_scene_universal_common_on_event(context, event); +} + +void infrared_scene_universal_ac_on_exit(void* context) { + infrared_scene_universal_common_on_exit(context); +} diff --git a/assets/icons/Infrared/CoolHi_25x27.png b/assets/icons/Infrared/CoolHi_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..cea29a5b9e764c88ae56f305368568d04e544876 GIT binary patch literal 3680 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 literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/CoolHi_hvr_25x27.png b/assets/icons/Infrared/CoolHi_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..692ac7b8be718dfe02b460c9ce9a710857feb562 GIT binary patch literal 3669 zcmaJ@c{r4N`+r3CEm@Lu#t;%SW-MbSW0@KI7Dh%|j4{TfS&XT%M3!vTAt`GkD%n-k zNGMw-SqZ7M=OqdzCr4dUaMhK(ApTBdLhWX9 z?5)HLFIGQ<-wJ$FxBRJdxbRkuiksARgWfvZuJWHDy%j`y)`Ev+9WAQsW$ z8caY|w8~E{cwJopScx<>JpgVHc>)N8^ht;U4Nf@?`g;;KWximtjtWGb7ieIonmC9? z$paQ)$(TEUg|$EwH&fFc$P)s5I!M0bz#%=rN9)|DJ|K#_k`*ohcwbdh5XegfKs(8a zI3VC4P}Y6;f)zl}2ju-7T9CjyJwV^i)87`jR}D0D$x2iLqLP5VYhv7fKqwsWX;)Vd z0nTRu^49a7rr!=!$WH0-E0tAgTBCuqiuM-O3lj14gzVMsvQs)BZ%o`q%(j3ug=Q(k zqYY)=FT4bRyi^5#whQYaUD6d@UB<~g=@WWio(gY*eSOC_Cc8_S769;p9oe&?3$5B6 zbx=5pwsCXctWdyliM-Rx7yT<`EFJ=R(}SK1%&pp3Duzr`zIeYqT$D)ZG=|dH@#eREZEb1MeMxq@TU};wQ7mYHPt?Fi=A%` zK}UYvRW2wQmwjmgUI0$QT-pC@U+<>h$1&YiL9;O<;ND3yf$&tlqGKe%?+#kB1a`y6 zWdNA3Wi-Cl78Q&Ni2cyb*_<<9x5?WFMEToY2?BuQI1LE?MU{D*C;;H{qIK?Bsw_6{ z(rpml)3|-OQDV)<_&i3Vr3oX85%-JQ!}8f*7K71_@4Tm~;{$zdp=#LR8W5kxl!i2U zJd#E;WquGva~rkmqQ!(P+eLR0)dmvTJj;brUS~wrUVF7UEz)#J!fb1V@7NJKG}A9u31CgJK9V!Sk+7THv%IhX(r{9koC&w|xRvcT zQk0M1VU%(NQ=ZRryX%@zwA1i(HnKBT(axcu{N}a3-2qAg%hbD{*^hUOT-)oM@yfHe zW7_6(#%IArj-*t)LTpuL9M^V^YL>q)|1&5q43*xRmo_fL%1wSpu_%2gq{YJpOv@u#DWS~Tx>4xBxs zQ=7T2T6+;)Qk;*(8rU0nR=F))^*0w8&kS0*&UO}?(k{$ch`cZ=Kezwmew90hjx{jy z(ZG`QjC4Y&ZK-Ri&DVP4ikU+0oqDTUuhnR2%QkzhqgpnUl&QkwWo8MJF_B zsRB|GSfG+$i{m_{7tUtpJ~&Pe^4XvO0u_pq$j$fz!C|t6UBnVeYY6uTWcI`5K zW)#FQRfV<a9A`|lidJm}cg`Lgq7=bJ2}95n1Ld@5%u=WWhdwa<}|Bf7jI-XpSI<;0OY zUbDP9dfXADR{_D}$gwKxa&Gy)H?`%pg*yssoYS03bKg*!?|tJv=M`5g- z@gj&6UnNTQvx?@~wEDD&#}U7;qeY|=2Bb?>kElilKVZqD4x>i1yROfgM?70hpN3Kh z-Ll>9490moJNCCwx$ZfAHWVdFO>pc&;>9F~m<~vW86-!gb)>z1!k)bpbnHV|?-Dns zDyM0tXz1>&@ho*VVfe;N!yEf^y$ph1HMe8myH56)OWe4oA2?PP>4J5MraYWdhmxSF zp5<@vRTpqdmWgvpX5Y|2b z)II@X z+v+%lUHK!m&L~vlnL&Z>WX*Z4;>&f8QjQ}zs9eSDGawoqjjD&mUP-+igeg&TO5;(! zP(Jye=_n(|Rc<_^U#y1iy(aQJu-O*UpZ+wem+LK^UXt-CLz*r%F!(@f?C^t` zrSDcl(2P#)q1sp;w&vDT(?@mW!slI`2hH)f@r(E$c;ngLk%z>$EA*aOmGHXnhJW-A zdDktkn>~LrWAJv(-(240~v9aa7QmDZ*m%__Fi1ht-MwOxp zJ&DPl&$iBS&tCQR^?vN~(yZsrm(j2_o1x!it{a+qh1xIRpHl~?WBSr4^WB%Y*SHap zkUxighHmo0r$}96CuJCOk7d~(daX7uP93Z}*mZRN5qrLJXmY3LBhT!+s1vj=>@TJp zX?-qjwbyI2D{77g*35?0KMeO@o>s|4bd4<5hkjGseAAzcM32-jgfW(%Eia8JjzqGw z*1I}t2RK@@<#jG~Cl)PcEC;Y73H|2Y8^iDBhR>aB;N&gz4BIRV$HjJUq%Nh%V7I4a zrF6tg#edB;F+(ChnzPoY*9x)Se%+e6N*gyfIx3VDp^+>7U*C51WcK7|%x9!MrJXHU z|I+YP`R-6_Q|sO*&qEAg#}^N;&NOm{IjVEF#$;S3&VtTqZwCB%f64t-;cA+4TH2otv^h*6@l%}@Mm*~EHYr}$M7YC>}W&^*^Nx}3k`ZsHU$7dZ7QC?COA2w zNDLZ;xa9*0p)vVr05CNVVG>D!WH!i`Org@z;JMnTU=Y<04fZs0(syEF$pKW`Fc#T8 z%o$G#3nU@^z~*Kk(-0J&fJSB$K_RqL^k7s78vGY8iof47L&2cGT-bqV@P9-RoDPAo z3>F!LfWY)f`uh4H1QJ5_Bf@pC?2*&`zU{RnjBoYbLheP3TJ-&xta44Nk4AG+ptN&!ck%LJr zDw9oR&_P>_L|?{fHX6(q`=2am%ztRFDJ2zg=mxf4qa) zZsh;d`(KHJ@u5sI)Qud>IL#vQd*`pd6^e<%vdBa>gN0`>PW>$8p#TP(5gfo^g5U-a z7)aZRNTSlWEc^e0I60y0=)r6vokX_7p}~9-2$kxGva~WWF+x~d!%a-AU@$A3r6mGk zf<$1D1~`nhHP+xK7RMl+rjhCFpIE=2SQCByUt+fgg2v=W#*tanGh{z&7J~-*D{B<> z*IIDDUjH=l2WV^i&+zgO|BOGG&YyV}f4HZ9lv?pW z4B@~3XD(8zX6(LTDSlJ literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/CoolLo_25x27.png b/assets/icons/Infrared/CoolLo_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..23288e44f158d4034bebfd6a2a9005514b132a9d GIT binary patch literal 3676 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 literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/CoolLo_hvr_25x27.png b/assets/icons/Infrared/CoolLo_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..ae5316e4d49992b01a39a4298e36cac1fd365388 GIT binary patch literal 3657 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 P_yK!sCtMlE=iI*m`3F!x literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Dehumidify_25x27.png b/assets/icons/Infrared/Dehumidify_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..dca77ae410bcc2196a693023640372da1b1912ea GIT binary patch literal 3665 zcmaJ@c{o&k`#&Q4mMlqX3?VUN#@0;6GBcL3hLN#U24hSbGse_dN|x+Jl0Bl5T}3G& zYbeaw>( zj7L8N42(HKveFdofE+HswcXuq8aSl}xGG)!)CYuQZKMZr0M57NBsg*s0nmO@G#2nW z36yl5jx_=Z>VUYXc{2hSR0Gs;4xXmKH%#Y7-Jk1gA74!=gu>5+ns9A=Y<#zBk$0%;7T-0u(N75`Kc5Ti{FLnjH{;x@2rA;! zHe$Z<*o^Bd@H}t~`qr`6M|*cXrY2N3IrS#AfXCwZWs-9g2=T<-@&$miSOp0FZH0a-F92Y3LRB6c%B(gVP_5@a z)UbE7LExvW_BFIZb0b<5&F>L%h~avyBn+(_+3{Fb#TEMAKvuKf#w#+3E(~e3e<6&b zi~Jz+W;ZC;gz|A2w(;&K$_+uqM)L)ANJ|s?$q7}yB=`0w;1a>&mV=K^mvC0cthskR zVR4Ct8rAb@bFt7M;$cHmf(5~9(6j(_NI`SoFrN+|=QW!~C2&%K`BTN0`@T0HaD&65 z2&Ss?17ZpLp`t<2m}VUXu^0?osp{q)+>;0RUa?-|ULRZedDX&9P1A$&NpFTdyvunI zw^c#M+ahMNW}0R+W@KjMmYw;t+zfmlY}idH+rB+-COs=Ut2xU}N`o8P-_NieE6By~ z(@Jncm*!U5KC+1_*spmp1JMyKi8IeDy_ei~&`Zi|o$}~2^X0y=w!cn*-ISqC1aSv-{Pi<54}tLwnNrp={`q|@vPDwQgiB@*BA zCz~ZJCd;Tm@r6YXi^hut>{smD@d<@z?XHv=+iTcO7xKMNDYh@lI`!2~#*SQgvLLF6 zTtLI?KL~c*is5!_vS_l#Jg~`ma&Ee&1tj1uUE!}P=Pgtmc`;P0S@B87(B(@i)oEL@ z)p4kz!dwJK!%V}W!gl4hr#{bgn(xLPrWN0ua(?PcaO}AF(y^&yG7mK^s$e7+@1m5{ z6hg6Su}!hb*IMneh5W3CwMNyBo1wynt!7FtN+#rl&b?W4c0+b!`TY5kmMG*}8KlTN zPbRk-%c}FqUrft>bv7j1f|frXP&@bI&=u$wevA4ef6YXYz+EAzz&#?^c|iBImM=|L z7TP-Urw!&zlL01=m`qHayp~wiqkF&K_=d5_bxMoNw8AvCh1zmoky}wt(cJQj%bd&nkU8<()ydyUwX&e{1qoL^KDXXMbULlg* zq{z=-mo+UW)h1nedF93yibp7FNVr(mNjBK;DMK828abZPd1q1o%InpXc_^9CCE7Kp zFJCkGDE;vG zc^<21owy{W_f3y+cUo^+S7#hP?s)EG-ankVU{klWd~ z8j&wq2oY07rWja6Tb;Q5FGEq40?F$~m-n-d#`6a>$~Kb0&>roc=s}E&%3-TzQx(g= zTYn_hXay*|*2q(xt-7XEc(cYr$YLxLnJt-d2}FgXkhQSzTZuP)(M58WNtNU;@zjg6~ zLuy%Ytzw|1cj(!Mw_y#>IK00K*z?auT=_csVd0E50qQvMjQArmOGZy3Cbmp`L@HI{ z>Y(zd|Ex?D?QLE9=>2UHhELC;Oi;}?%|H4_oNLy% z^xnK0vFEV2?Dy;^ZQ?d7*7eI`ism;`HmPSyt*E{Wt(?7_TRif@l^?3!_sjO8@U{s9 z$G@5gw;p-5owdYL6Vev4zj3E!N}i4ln3-San^-?AgdDzfJ*Z@or|-xmS+XqjJUU}J z!#L9}W7FBq`K9$cy`F(D?fk zxmOu9=iWJSUWB&vQj|H_YqS$Lce3VWr_1sS=5qPS?0$zA4jGS-=cr$pUv#&V`m9^4 z?^I`$Rk?UqEe6&;3-Vl_m&w-Y99yjo_)~Icpg$Xd8mnCiq^-YRUz?B|3uY*7b+%Uz zv6L1|YpiR|tr{#C4q?Wk`t_Z+M+cWiub!`G<*f9Knyhn2gm-Nxt|f?I_9mn!v_}d> ze$76ihd@l}Gq&b`=3}}%x)igew(o7Xmq|%NgE#uWe(3B;>&Z=BPED$#Ue4S4QvX%@ z(MU^U%i&jV{54=_S5I#)G_XclvP<_TM672ngRUy?czu7eX4jp+nIxT*w8O=jw(@gH z>vq`gA12d?z_g=zGFe0h2{81axsgCPDv?aGB@sOWeBY3C0f1APf+sKumKI2N8Wlp^ z^?~?P>1;Fr=<55^iSFJcCdiFMrud-1OVxE?5XA!pcF?j^x1?i8UKG+6AZ{gG?}Dv3!1`BN|W_#ypK;JrPe;fb`x8vh-R zeL{h~m`pkn3T3fa5S9jn#vnss2m}JE4u`_wYHSZRzW^U5(O=ESPyQDJmgMKopwO8V znh$7~k?2Od$V7qJV*ir`mHrQ{kKf;wV%H4nPozU(5cS=xemPoN{%=<*^&f9PrY-5e zdjDTyKYRe41hpmk(JnIF*}e0W-wj1aVi+VMlg7Z)XcvAJ@{|{iN%Qlf(Lrzx2n?ib zNpz?9>{^cf1+lb5;(Yv=L?3q&4vPY_Ngx!82NI(J(=w_4!F zzvcTI>+yRn>c7Q8*vc?(mJ^^;3K!l7ALqbLsXqJCdK%kp zdt|Xj@v@XygOqJUQYlnx{yXS+`)2KpZ(V!`CPk%{amz>g4sUm84vNn7?MK(dLR|I; Y0_*BPx59$cJUb46GqS>#p?%qL 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 Tfe|}@hk%WR1FiydCgT49&LB(v literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/HeatHi_25x27.png b/assets/icons/Infrared/HeatHi_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..a1724f995562587ec54740789f37729d567e0f88 GIT binary patch literal 3676 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 literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/HeatHi_hvr_25x27.png b/assets/icons/Infrared/HeatHi_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..b92108d68de2ab09bed6b451e36396881e5611ea GIT binary patch literal 3661 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 T-|@M}j{(?QJ7Y`Hry~9hE1FGt literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/HeatLo_25x27.png b/assets/icons/Infrared/HeatLo_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..af2e59d4940aefa657c280acb8073800408dabba GIT binary patch literal 3670 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 O0dr$(Y#G`u;{O0;Ay2me literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Off_25x27.png b/assets/icons/Infrared/Off_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..c15100606ac9b2c46fec8d5ed290d72345fb22e2 GIT binary patch literal 9530 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 T&A>rCE`gSso@%+Wb;y4K-_9ky literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Off_hvr_25x27.png b/assets/icons/Infrared/Off_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..d5e5e6f45d78e070d06e033bd529d0067de94301 GIT binary patch literal 8460 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 literal 0 HcmV?d00001 diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir new file mode 100644 index 000000000..b1075b2f3 --- /dev/null +++ b/assets/resources/infrared/assets/ac.ir @@ -0,0 +1,38 @@ +Filetype: IR library file +Version: 1 +# +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 502 3436 510 475 509 476 508 477 507 477 507 479 505 480 504 480 504 490 504 481 502 482 501 483 563 420 511 474 510 475 509 476 508 485 561 423 508 476 508 477 507 478 506 479 505 480 504 481 503 517 508 476 508 478 506 479 505 479 505 481 503 483 521 1456 501 498 507 479 505 480 504 481 503 482 501 483 563 421 562 422 509 499 506 479 505 480 504 481 503 482 502 484 510 1451 506 479 505 1542 562 1396 509 471 502 476 508 469 504 3425 511 +# +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 507 3430 506 479 505 480 504 481 503 481 503 483 501 485 509 1453 504 1465 503 482 502 483 511 473 500 485 509 476 508 477 507 478 506 487 507 477 507 478 506 479 505 480 504 482 502 483 501 484 500 523 503 482 502 484 500 485 509 476 508 476 508 478 506 1456 501 501 504 482 502 483 501 484 500 485 509 476 508 477 507 1455 502 509 506 479 505 1457 500 485 509 476 508 1454 503 482 502 483 501 568 499 1459 509 1450 507 471 502 474 510 3421 505 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 504 3433 503 482 502 484 510 474 510 475 509 476 508 478 506 1456 564 1405 510 475 509 476 508 502 482 477 507 478 506 479 505 480 504 489 505 480 504 481 503 482 502 483 511 473 511 474 510 475 509 509 506 479 505 480 504 481 503 482 512 473 511 474 510 476 508 1469 509 475 509 476 508 477 507 478 506 479 505 480 504 481 503 505 510 475 509 502 482 503 481 504 480 505 478 507 477 1459 509 560 507 1451 506 473 511 493 480 1450 507 3422 503 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 525 3615 530 506 561 474 562 474 562 473 563 473 531 505 562 1502 528 1542 562 474 562 474 530 505 531 504 532 504 532 504 616 419 533 510 589 447 526 509 527 509 527 509 527 508 528 508 528 507 529 542 525 510 526 509 527 509 527 509 527 508 528 508 528 1535 527 524 533 503 533 503 533 502 534 502 534 502 534 501 535 501 525 534 533 502 534 502 534 501 535 502 534 1529 533 503 533 503 533 587 533 497 528 501 524 1536 526 501 524 3609 526 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 531 3406 530 455 529 456 528 457 537 447 537 448 535 450 534 1429 528 1442 536 448 536 449 534 451 532 452 532 453 530 454 530 455 529 464 530 454 529 456 528 457 537 448 536 449 535 450 533 451 533 490 535 449 534 450 534 451 533 452 532 453 531 455 529 1433 534 1443 535 449 535 450 534 452 531 453 530 454 530 455 529 456 538 472 532 452 532 454 530 1433 535 1427 530 1432 536 1427 530 1431 537 1511 530 448 536 1422 535 1423 534 1422 535 3395 530 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 506 3430 506 478 506 479 505 480 504 481 503 482 502 484 500 1463 505 1465 503 482 502 483 501 484 500 485 509 476 508 477 507 478 506 486 508 477 507 478 506 479 505 480 504 481 503 482 502 483 500 523 502 482 502 483 501 484 500 485 509 476 508 478 506 1455 502 498 507 478 506 479 505 481 503 482 501 483 500 484 500 485 509 500 505 481 502 482 502 1461 507 1455 502 1459 509 476 508 477 507 563 504 1453 504 1454 503 1454 503 1453 504 3426 499 diff --git a/documentation/UniversalRemotes.md b/documentation/UniversalRemotes.md new file mode 100644 index 000000000..ac98d451f --- /dev/null +++ b/documentation/UniversalRemotes.md @@ -0,0 +1,36 @@ +# Universal Remotes +## Air Conditioners +### Recording signals +Air conditioners differ from most other infrared-controlled devices because their state is tracked by the remote. +The majority of A/C remotes have a small display which shows current mode, temperature and other settings. +When the user presses a button, a whole set of parameters is transmitted to the device, which must be recorded and used as a whole. + +In order to add a particular air conditioner to the universal remote, 6 signals must be recorded: `Off`, `Dh`, `Cool_hi`, `Cool_lo`, `Heat_hi`, `Heat_lo`. +Each signal (except `Off`) is recorded using the following algorithm: + +1. Get the remote and press the **Power Button** so that the display shows that A/C is ON. +2. Set the A/C to the corresponding mode (see table below), while leaving other parameters such as fan speed or vane on **AUTO** (if applicable). +3. Press the **POWER** button to switch the A/C off. +4. Start learning a new remote on Flipper if it's the first button or press `+` to add a new button otherwise. +5. Point the remote to Flipper's IR receiver as directed and press **POWER** button once again. +6. Save the resulting signal under the specified name. +7. Repeat the steps 2-6 for each signal from the table below. + +| Signal | Mode | Temperature | Note | +| :-----: | :--------: | :---------: | ----------------------------------- | +| Dh | Dehumidify | N/A | | +| Cool_hi | Cooling | See note | Lowest temperature in cooling mode | +| Cool_lo | Cooling | 23°C | | +| Heat_hi | Heating | See note | Highest temperature in heating mode | +| Heat_lo | Heating | 23°C | | + +Finally, record the `Off` signal: +1. Make sure the display shows that A/C is ON. +2. Start learning a new signal on Flipper and point the remote towards the IR receiver. +3. Press the **POWER** button so that the remote shows the OFF state. +4. Save the resulting signal under the name `Off`. + +The resulting remote file should now contain 6 signals. Any of them can be omitted, but that will mean that this functionality will not be used. +Test the file against the actual device. Every signal must do what it's supposed to. +If everything checks out, add these signals to the [A/C universal remote file](/assets/resources/infrared/assets/ac.ir) +and open a pull request. diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 331cda812..8dff220ee 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,1.6,, +Version,+,1.7,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2580,8 +2580,14 @@ Variable,+,I_Circles_47x47,const Icon, Variable,+,I_Clock_18x18,const Icon, Variable,+,I_Connect_me_62x31,const Icon, Variable,+,I_Connected_62x31,const Icon, +Variable,+,I_CoolHi_25x27,const Icon, +Variable,+,I_CoolHi_hvr_25x27,const Icon, +Variable,+,I_CoolLo_25x27,const Icon, +Variable,+,I_CoolLo_hvr_25x27,const Icon, Variable,+,I_Cry_dolph_55x52,const Icon, Variable,+,I_DFU_128x50,const Icon, +Variable,+,I_Dehumidify_25x27,const Icon, +Variable,+,I_Dehumidify_hvr_25x27,const Icon, Variable,+,I_Detailed_chip_17x13,const Icon, Variable,+,I_DolphinCommon_56x48,const Icon, Variable,+,I_DolphinMafia_115x62,const Icon, @@ -2605,6 +2611,10 @@ Variable,+,I_FaceNopower_29x14,const Icon, Variable,+,I_FaceNormal_29x14,const Icon, Variable,+,I_GameMode_11x8,const Icon, Variable,+,I_Health_16x16,const Icon, +Variable,+,I_HeatHi_25x27,const Icon, +Variable,+,I_HeatHi_hvr_25x27,const Icon, +Variable,+,I_HeatLo_25x27,const Icon, +Variable,+,I_HeatLo_hvr_25x27,const Icon, Variable,+,I_InfraredArrowDown_4x8,const Icon, Variable,+,I_InfraredArrowUp_4x8,const Icon, Variable,+,I_InfraredLearnShort_128x31,const Icon, @@ -2622,6 +2632,8 @@ Variable,+,I_Mute_25x27,const Icon, Variable,+,I_Mute_hvr_25x27,const Icon, Variable,+,I_NFC_manual_60x50,const Icon, Variable,+,I_Nfc_10px,const Icon, +Variable,+,I_Off_25x27,const Icon, +Variable,+,I_Off_hvr_25x27,const Icon, Variable,+,I_Ok_btn_9x9,const Icon, Variable,+,I_Ok_btn_pressed_13x13,const Icon, Variable,+,I_Percent_10x14,const Icon, From 3360f818a1d10771c2e70616ddedccca37d33a86 Mon Sep 17 00:00:00 2001 From: Max Lapan Date: Tue, 20 Sep 2022 07:29:10 +0200 Subject: [PATCH 04/30] Subghz: Adding checks for get_upload functions (#1704) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adding checks for get_upload functions Almost in every protocol, function which generates upload might fail and return false. But we don't check this result, which might end up sending random memory contents to the air. * Format sources and fix crash on ivalid bit count in chamberlain Co-authored-by: あく --- lib/subghz/protocols/bett.c | 2 +- lib/subghz/protocols/came.c | 2 +- lib/subghz/protocols/chamberlain_code.c | 4 ++-- lib/subghz/protocols/clemsa.c | 2 +- lib/subghz/protocols/doitrand.c | 2 +- lib/subghz/protocols/gate_tx.c | 2 +- lib/subghz/protocols/holtek.c | 2 +- lib/subghz/protocols/honeywell_wdb.c | 2 +- lib/subghz/protocols/hormann.c | 2 +- lib/subghz/protocols/intertechno_v3.c | 2 +- lib/subghz/protocols/keeloq.c | 2 +- lib/subghz/protocols/linear.c | 2 +- lib/subghz/protocols/magellen.c | 2 +- lib/subghz/protocols/megacode.c | 2 +- lib/subghz/protocols/nero_radio.c | 2 +- lib/subghz/protocols/nero_sketch.c | 2 +- lib/subghz/protocols/nice_flo.c | 2 +- lib/subghz/protocols/phoenix_v2.c | 2 +- lib/subghz/protocols/princeton.c | 2 +- 19 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c index 08080dc6c..c80702577 100644 --- a/lib/subghz/protocols/bett.c +++ b/lib/subghz/protocols/bett.c @@ -173,7 +173,7 @@ bool subghz_protocol_encoder_bett_deserialize(void* context, FlipperFormat* flip flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_bett_get_upload(instance); + if(!subghz_protocol_encoder_bett_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index 14c66b7fa..53d3d0788 100644 --- a/lib/subghz/protocols/came.c +++ b/lib/subghz/protocols/came.c @@ -162,7 +162,7 @@ bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flip flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_came_get_upload(instance); + if(!subghz_protocol_encoder_came_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/chamberlain_code.c b/lib/subghz/protocols/chamberlain_code.c index 51f2bcd32..66d230d13 100644 --- a/lib/subghz/protocols/chamberlain_code.c +++ b/lib/subghz/protocols/chamberlain_code.c @@ -155,7 +155,7 @@ static bool break; default: - furi_crash(TAG " unknown protocol."); + FURI_LOG_E(TAG, "Invalid bits count"); return false; break; } @@ -224,7 +224,7 @@ bool subghz_protocol_encoder_chamb_code_deserialize(void* context, FlipperFormat flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_chamb_code_get_upload(instance); + if(!subghz_protocol_encoder_chamb_code_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/clemsa.c b/lib/subghz/protocols/clemsa.c index 357a0b06d..337346934 100644 --- a/lib/subghz/protocols/clemsa.c +++ b/lib/subghz/protocols/clemsa.c @@ -173,7 +173,7 @@ bool subghz_protocol_encoder_clemsa_deserialize(void* context, FlipperFormat* fl flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_clemsa_get_upload(instance); + if(!subghz_protocol_encoder_clemsa_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/doitrand.c b/lib/subghz/protocols/doitrand.c index 9a0a58190..9122c1935 100644 --- a/lib/subghz/protocols/doitrand.c +++ b/lib/subghz/protocols/doitrand.c @@ -154,7 +154,7 @@ bool subghz_protocol_encoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_doitrand_get_upload(instance); + if(!subghz_protocol_encoder_doitrand_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/gate_tx.c b/lib/subghz/protocols/gate_tx.c index d7efb3862..56c224aef 100644 --- a/lib/subghz/protocols/gate_tx.c +++ b/lib/subghz/protocols/gate_tx.c @@ -147,7 +147,7 @@ bool subghz_protocol_encoder_gate_tx_deserialize(void* context, FlipperFormat* f flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_gate_tx_get_upload(instance); + if(!subghz_protocol_encoder_gate_tx_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/holtek.c b/lib/subghz/protocols/holtek.c index 137ba85d3..5cd160633 100644 --- a/lib/subghz/protocols/holtek.c +++ b/lib/subghz/protocols/holtek.c @@ -160,7 +160,7 @@ bool subghz_protocol_encoder_holtek_deserialize(void* context, FlipperFormat* fl flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_holtek_get_upload(instance); + if(!subghz_protocol_encoder_holtek_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/honeywell_wdb.c b/lib/subghz/protocols/honeywell_wdb.c index e1e21426d..451a13f50 100644 --- a/lib/subghz/protocols/honeywell_wdb.c +++ b/lib/subghz/protocols/honeywell_wdb.c @@ -162,7 +162,7 @@ bool subghz_protocol_encoder_honeywell_wdb_deserialize( flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_honeywell_wdb_get_upload(instance); + if(!subghz_protocol_encoder_honeywell_wdb_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/hormann.c b/lib/subghz/protocols/hormann.c index 0197f59e6..d78bc9273 100644 --- a/lib/subghz/protocols/hormann.c +++ b/lib/subghz/protocols/hormann.c @@ -163,7 +163,7 @@ bool subghz_protocol_encoder_hormann_deserialize(void* context, FlipperFormat* f flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_hormann_get_upload(instance); + if(!subghz_protocol_encoder_hormann_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/intertechno_v3.c b/lib/subghz/protocols/intertechno_v3.c index e70bb8c8b..ffe52e875 100644 --- a/lib/subghz/protocols/intertechno_v3.c +++ b/lib/subghz/protocols/intertechno_v3.c @@ -179,7 +179,7 @@ bool subghz_protocol_encoder_intertechno_v3_deserialize( flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_intertechno_v3_get_upload(instance); + if(!subghz_protocol_encoder_intertechno_v3_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 0321a8767..99b3c5fb3 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -280,7 +280,7 @@ bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* fl flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_keeloq_get_upload(instance, instance->generic.btn); + if(!subghz_protocol_encoder_keeloq_get_upload(instance, instance->generic.btn)) break; if(!flipper_format_rewind(flipper_format)) { FURI_LOG_E(TAG, "Rewind error"); diff --git a/lib/subghz/protocols/linear.c b/lib/subghz/protocols/linear.c index 92ba02a8f..8f7aed794 100644 --- a/lib/subghz/protocols/linear.c +++ b/lib/subghz/protocols/linear.c @@ -165,7 +165,7 @@ bool subghz_protocol_encoder_linear_deserialize(void* context, FlipperFormat* fl flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_linear_get_upload(instance); + if(!subghz_protocol_encoder_linear_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/magellen.c b/lib/subghz/protocols/magellen.c index bb0600a74..52ef5a724 100644 --- a/lib/subghz/protocols/magellen.c +++ b/lib/subghz/protocols/magellen.c @@ -168,7 +168,7 @@ bool subghz_protocol_encoder_magellen_deserialize(void* context, FlipperFormat* flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_magellen_get_upload(instance); + if(!subghz_protocol_encoder_magellen_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/megacode.c b/lib/subghz/protocols/megacode.c index 909e72171..1501580d8 100644 --- a/lib/subghz/protocols/megacode.c +++ b/lib/subghz/protocols/megacode.c @@ -193,7 +193,7 @@ bool subghz_protocol_encoder_megacode_deserialize(void* context, FlipperFormat* flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_megacode_get_upload(instance); + if(!subghz_protocol_encoder_megacode_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/nero_radio.c b/lib/subghz/protocols/nero_radio.c index 69326f5a0..b5a7e8c0e 100644 --- a/lib/subghz/protocols/nero_radio.c +++ b/lib/subghz/protocols/nero_radio.c @@ -172,7 +172,7 @@ bool subghz_protocol_encoder_nero_radio_deserialize(void* context, FlipperFormat flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_nero_radio_get_upload(instance); + if(!subghz_protocol_encoder_nero_radio_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/nero_sketch.c b/lib/subghz/protocols/nero_sketch.c index c93b36a53..66ee569c2 100644 --- a/lib/subghz/protocols/nero_sketch.c +++ b/lib/subghz/protocols/nero_sketch.c @@ -166,7 +166,7 @@ bool subghz_protocol_encoder_nero_sketch_deserialize(void* context, FlipperForma flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_nero_sketch_get_upload(instance); + if(!subghz_protocol_encoder_nero_sketch_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/nice_flo.c b/lib/subghz/protocols/nice_flo.c index 07b18e3ea..f07e9efcc 100644 --- a/lib/subghz/protocols/nice_flo.c +++ b/lib/subghz/protocols/nice_flo.c @@ -149,7 +149,7 @@ bool subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_nice_flo_get_upload(instance); + if(!subghz_protocol_encoder_nice_flo_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index 3d2796e44..d680b2e62 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -150,7 +150,7 @@ bool subghz_protocol_encoder_phoenix_v2_deserialize(void* context, FlipperFormat flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_phoenix_v2_get_upload(instance); + if(!subghz_protocol_encoder_phoenix_v2_get_upload(instance)) break; instance->encoder.is_running = true; res = true; diff --git a/lib/subghz/protocols/princeton.c b/lib/subghz/protocols/princeton.c index 2ddfa2cb6..a5b8134d8 100644 --- a/lib/subghz/protocols/princeton.c +++ b/lib/subghz/protocols/princeton.c @@ -167,7 +167,7 @@ bool subghz_protocol_encoder_princeton_deserialize(void* context, FlipperFormat* flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); - subghz_protocol_encoder_princeton_get_upload(instance); + if(!subghz_protocol_encoder_princeton_get_upload(instance)) break; instance->encoder.is_running = true; res = true; From c213ff596a4df9bb0fa49abb42c4b1dfb8e241ac Mon Sep 17 00:00:00 2001 From: Matt Van Zanten Date: Tue, 20 Sep 2022 11:45:16 -0700 Subject: [PATCH 05/30] adding support for HIDProx, updating the UI to switch between protocols --- applications/plugins/flipfrid/README.md | 28 +- applications/plugins/flipfrid/flipfrid.c | 3 + applications/plugins/flipfrid/flipfrid.h | 12 +- .../scene/flipfrid_scene_entrypoint.c | 76 ++++- .../flipfrid/scene/flipfrid_scene_load_file.c | 43 ++- .../scene/flipfrid_scene_run_attack.c | 285 +++++++++++++----- 6 files changed, 348 insertions(+), 99 deletions(-) diff --git a/applications/plugins/flipfrid/README.md b/applications/plugins/flipfrid/README.md index 51ed2fa67..69fdb3e66 100644 --- a/applications/plugins/flipfrid/README.md +++ b/applications/plugins/flipfrid/README.md @@ -1,21 +1,35 @@ # Flipfrid -Basic EM4100 Fuzzer +Basic EM4100 and HIDProx Fuzzer. ## Why Flipfrid is a simple Rfid fuzzer using EM4100 protocol (125khz). Objective is to provide a simple to use fuzzer to test readers by emulating various cards. -EM4100 cards use a 1 byte customer id and 4 bytes card id. +- EM4100 cards use a 1 byte customer id and 4 bytes card id. +- HIDProx cards use a 2 byte customer id and 3 byte card id. ## How -There is 4 modes : -- Default key loop over 16 factory/default keys and emulate each one after one ; -- BF customer id. just an iteration from 0X00 to 0XFF on the first byte ; -- Load Dump file : Load an existing EM4100 dump generated by Flipperzero, select an index and bruteforce from 0X00 to 0XFF; -- Uids list: loop over a text file (one uid per line) +1) Select the Protocol with the left and right arrows +2) Select the Mode with the up and down arrows + +### Info + +There are 2 Protocols: +- EM4100 +- HIDProx + +There are 4 modes: +- Default Values: Try factory/default keys and emulate one after the other. +- BF customer id: An iteration from 0X00 to 0XFF on the first byte. +- Load Dump file: Load an existing dump (.rfid) generated by Flipperzero, select an index and bruteforce from 0X00 to 0XFF; +- Uids list: Iterate over an input text file (one uid per line) and emulate one after the other. + + + TODO : - blank screen on back press +- Add second byte test to `BF customer id` diff --git a/applications/plugins/flipfrid/flipfrid.c b/applications/plugins/flipfrid/flipfrid.c index 1dab3cae1..ba059ff7f 100644 --- a/applications/plugins/flipfrid/flipfrid.c +++ b/applications/plugins/flipfrid/flipfrid.c @@ -64,6 +64,7 @@ FlipFridState* flipfrid_alloc() { flipfrid->is_attacking = false; flipfrid->key_index = 0; flipfrid->menu_index = 0; + flipfrid->menu_proto_index = 0; flipfrid->attack = FlipFridAttackDefaultValues; flipfrid->notify = furi_record_open(RECORD_NOTIFICATION); @@ -73,12 +74,14 @@ FlipFridState* flipfrid_alloc() { flipfrid->data[2] = 0x00; flipfrid->data[3] = 0x00; flipfrid->data[4] = 0x00; + flipfrid->data[5] = 0x00; flipfrid->payload[0] = 0x00; flipfrid->payload[1] = 0x00; flipfrid->payload[2] = 0x00; flipfrid->payload[3] = 0x00; flipfrid->payload[4] = 0x00; + flipfrid->payload[5] = 0x00; //Dialog flipfrid->dialogs = furi_record_open(RECORD_DIALOGS); diff --git a/applications/plugins/flipfrid/flipfrid.h b/applications/plugins/flipfrid/flipfrid.h index 44756f26e..5417817e9 100644 --- a/applications/plugins/flipfrid/flipfrid.h +++ b/applications/plugins/flipfrid/flipfrid.h @@ -28,6 +28,11 @@ typedef enum { FlipFridAttackLoadFileCustomUids, } FlipFridAttacks; +typedef enum { + EM4100, + HIDProx, +} FlipFridProtos; + typedef enum { NoneScene, SceneEntryPoint, @@ -56,13 +61,16 @@ typedef struct { FlipFridScene previous_scene; NotificationApp* notify; u_int8_t menu_index; + u_int8_t menu_proto_index; string_t data_str; - uint8_t data[5]; - uint8_t payload[5]; + uint8_t data[6]; + uint8_t payload[6]; uint8_t attack_step; FlipFridAttacks attack; + FlipFridProtos proto; string_t attack_name; + string_t proto_name; DialogsApp* dialogs; string_t notification_msg; diff --git a/applications/plugins/flipfrid/scene/flipfrid_scene_entrypoint.c b/applications/plugins/flipfrid/scene/flipfrid_scene_entrypoint.c index f30bb8e1d..c71a35903 100644 --- a/applications/plugins/flipfrid/scene/flipfrid_scene_entrypoint.c +++ b/applications/plugins/flipfrid/scene/flipfrid_scene_entrypoint.c @@ -1,8 +1,9 @@ #include "flipfrid_scene_entrypoint.h" string_t menu_items[4]; +string_t menu_proto_items[2]; -void flipfrid_scene_entrypoint_menu_callback(FlipFridState* context, uint32_t index) { +void flipfrid_scene_entrypoint_menu_callback(FlipFridState* context, uint32_t index, uint32_t proto_index) { switch(index) { case FlipFridAttackDefaultValues: context->attack = FlipFridAttackDefaultValues; @@ -27,6 +28,19 @@ void flipfrid_scene_entrypoint_menu_callback(FlipFridState* context, uint32_t in default: break; } + + switch(proto_index) { + case EM4100: + context->proto = EM4100; + string_set_str(context->proto_name, "EM4100"); + break; + case HIDProx: + context->proto = HIDProx; + string_set_str(context->proto_name, "HIDProx"); + break; + default: + break; + } } void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) { @@ -36,6 +50,7 @@ void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) { context->payload[2] = 0x00; context->payload[3] = 0x00; context->payload[4] = 0x00; + context->payload[5] = 0x00; context->menu_index = 0; for(uint32_t i = 0; i < 4; i++) { @@ -46,6 +61,14 @@ void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) { string_set(menu_items[1], "BF Customer ID"); string_set(menu_items[2], "Load File"); string_set(menu_items[3], "Load uids from file"); + + context->menu_proto_index = 0; + for(uint32_t i = 0; i < 2; i++) { + string_init(menu_proto_items[i]); + } + + string_set(menu_proto_items[0], "EM4100"); + string_set(menu_proto_items[1], "HIDProx"); } void flipfrid_scene_entrypoint_on_exit(FlipFridState* context) { @@ -53,6 +76,10 @@ void flipfrid_scene_entrypoint_on_exit(FlipFridState* context) { for(uint32_t i = 0; i < 4; i++) { string_clear(menu_items[i]); } + + for(uint32_t i = 0; i < 2; i++) { + string_clear(menu_proto_items[i]); + } } void flipfrid_scene_entrypoint_on_tick(FlipFridState* context) { @@ -74,10 +101,17 @@ void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* cont } break; case InputKeyLeft: + if(context->menu_proto_index > EM4100) { + context->menu_proto_index--; + } + break; case InputKeyRight: + if(context->menu_proto_index < HIDProx) { + context->menu_proto_index++; + } break; case InputKeyOk: - flipfrid_scene_entrypoint_menu_callback(context, context->menu_index); + flipfrid_scene_entrypoint_menu_callback(context, context->menu_index, context->menu_proto_index); break; case InputKeyBack: context->is_running = false; @@ -91,10 +125,6 @@ void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); - // Title - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignTop, "RFID Fuzzer"); - if(context->menu_index > FlipFridAttackDefaultValues) { canvas_set_font(canvas, FontSecondary); canvas_draw_str_aligned( @@ -120,4 +150,38 @@ void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) { AlignTop, string_get_cstr(menu_items[context->menu_index + 1])); } + + if(context->menu_proto_index > EM4100) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + -12, + AlignCenter, + AlignTop, + string_get_cstr(menu_proto_items[context->menu_proto_index - 1])); + } + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, 34, 4, AlignCenter, AlignTop, "<"); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, 64, 4, AlignCenter, AlignTop, string_get_cstr(menu_proto_items[context->menu_proto_index])); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, 94, 4, AlignCenter, AlignTop, ">"); + + if(context->menu_proto_index < HIDProx) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + -12, + AlignCenter, + AlignTop, + string_get_cstr(menu_proto_items[context->menu_proto_index + 1])); + } } \ No newline at end of file diff --git a/applications/plugins/flipfrid/scene/flipfrid_scene_load_file.c b/applications/plugins/flipfrid/scene/flipfrid_scene_load_file.c index 072185ccf..ded62750a 100644 --- a/applications/plugins/flipfrid/scene/flipfrid_scene_load_file.c +++ b/applications/plugins/flipfrid/scene/flipfrid_scene_load_file.c @@ -36,11 +36,21 @@ bool flipfrid_load(FlipFridState* context, const char* file_path) { break; } else { FURI_LOG_I(TAG, "Key type: %s", string_get_cstr(temp_str)); - if(strcmp(string_get_cstr(temp_str), "EM4100") != 0) { - FURI_LOG_E(TAG, "Unsupported Key type"); - string_reset(context->notification_msg); - string_set_str(context->notification_msg, "Unsupported Key type"); - break; + + if(context->proto == EM4100) { + if(strcmp(string_get_cstr(temp_str), "EM4100") != 0) { + FURI_LOG_E(TAG, "Unsupported Key type"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Unsupported Key type"); + break; + } + } else { + if(strcmp(string_get_cstr(temp_str), "HIDProx") != 0) { + FURI_LOG_E(TAG, "Unsupported Key type"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Unsupported Key type"); + break; + } } } @@ -53,15 +63,24 @@ bool flipfrid_load(FlipFridState* context, const char* file_path) { } else { FURI_LOG_I(TAG, "Key: %s", string_get_cstr(context->data_str)); - // Check data size - if(string_size(context->data_str) != 14) { - FURI_LOG_E(TAG, "Incorrect Key length"); - string_reset(context->notification_msg); - string_set_str(context->notification_msg, "Incorrect Key length"); - break; + if(context->proto == EM4100) { + if(string_size(context->data_str) != 14) { + FURI_LOG_E(TAG, "Incorrect Key length"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Incorrect Key length"); + break; + } + } else { + if(string_size(context->data_str) != 17) { + FURI_LOG_E(TAG, "Incorrect Key length"); + string_reset(context->notification_msg); + string_set_str(context->notification_msg, "Incorrect Key length"); + break; + } } + // String to uint8_t - for(uint8_t i = 0; i < 5; i++) { + for(uint8_t i = 0; i < 6; i++) { char temp_str2[3]; temp_str2[0] = string_get_cstr(context->data_str)[i * 3]; temp_str2[1] = string_get_cstr(context->data_str)[i * 3 + 1]; diff --git a/applications/plugins/flipfrid/scene/flipfrid_scene_run_attack.c b/applications/plugins/flipfrid/scene/flipfrid_scene_run_attack.c index e34cb8986..707ac74f0 100644 --- a/applications/plugins/flipfrid/scene/flipfrid_scene_run_attack.c +++ b/applications/plugins/flipfrid/scene/flipfrid_scene_run_attack.c @@ -3,7 +3,7 @@ uint8_t counter = 0; #define TIME_BETWEEN_CARDS 5 -uint8_t id_list[16][5] = { +uint8_t id_list[17][5] = { {0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF {0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11 @@ -16,17 +16,34 @@ uint8_t id_list[16][5] = { {0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88 {0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99 {0x12, 0x34, 0x56, 0x78, 0x9A}, // Incremental UID + {0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID {0x04, 0xd0, 0x9b, 0x0d, 0x6a}, // From arha {0x34, 0x00, 0x29, 0x3d, 0x9e}, // From arha {0x04, 0xdf, 0x00, 0x00, 0x01}, // From arha {0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha }; +uint8_t id_list_hid[14][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF + {0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11 + {0x22, 0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22 + {0x33, 0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33 + {0x44, 0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44 + {0x55, 0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55 + {0x66, 0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66 + {0x77, 0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77 + {0x88, 0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88 + {0x99, 0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99 + {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}, // Incremental UID + {0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID + {0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha +}; + void flipfrid_scene_run_attack_on_enter(FlipFridState* context) { context->attack_step = 0; context->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); context->worker = lfrfid_worker_alloc(context->dict); - context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100"); } void flipfrid_scene_run_attack_on_exit(FlipFridState* context) { @@ -40,7 +57,7 @@ void flipfrid_scene_run_attack_on_exit(FlipFridState* context) { void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { if(context->is_attacking) { if(1 == counter) { - protocol_dict_set_data(context->dict, context->protocol, context->payload, 5); + protocol_dict_set_data(context->dict, context->protocol, context->payload, 6); lfrfid_worker_free(context->worker); context->worker = lfrfid_worker_alloc(context->dict); lfrfid_worker_start_thread(context->worker); @@ -50,88 +67,198 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { lfrfid_worker_stop_thread(context->worker); switch(context->attack) { case FlipFridAttackDefaultValues: - context->payload[0] = id_list[context->attack_step][0]; - context->payload[1] = id_list[context->attack_step][1]; - context->payload[2] = id_list[context->attack_step][2]; - context->payload[3] = id_list[context->attack_step][3]; - context->payload[4] = id_list[context->attack_step][4]; + if(context->proto == EM4100) { + context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100"); - if(context->attack_step == 15) { - context->attack_step = 0; - counter = 0; - context->is_attacking = false; - notification_message(context->notify, &sequence_blink_stop); - notification_message(context->notify, &sequence_single_vibro); + context->payload[0] = id_list[context->attack_step][0]; + context->payload[1] = id_list[context->attack_step][1]; + context->payload[2] = id_list[context->attack_step][2]; + context->payload[3] = id_list[context->attack_step][3]; + context->payload[4] = id_list[context->attack_step][4]; - } else { - context->attack_step++; - } - break; - - case FlipFridAttackBfCustomerId: - context->payload[0] = context->attack_step; - context->payload[1] = 0x00; - context->payload[2] = 0x00; - context->payload[3] = 0x00; - context->payload[4] = 0x00; - - if(context->attack_step == 255) { - context->attack_step = 0; - counter = 0; - context->is_attacking = false; - notification_message(context->notify, &sequence_blink_stop); - notification_message(context->notify, &sequence_single_vibro); - } else { - context->attack_step++; - } - break; - case FlipFridAttackLoadFile: - context->payload[0] = context->data[0]; - context->payload[1] = context->data[1]; - context->payload[2] = context->data[2]; - context->payload[3] = context->data[3]; - context->payload[4] = context->data[4]; - - context->payload[context->key_index] = context->attack_step; - - if(context->attack_step == 255) { - context->attack_step = 0; - counter = 0; - context->is_attacking = false; - notification_message(context->notify, &sequence_blink_stop); - notification_message(context->notify, &sequence_single_vibro); + if(context->attack_step == 15) { + context->attack_step = 0; + counter = 0; + context->is_attacking = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + } else { + context->attack_step++; + } break; } else { - context->attack_step++; + context->protocol = protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); + + context->payload[0] = id_list_hid[context->attack_step][0]; + context->payload[1] = id_list_hid[context->attack_step][1]; + context->payload[2] = id_list_hid[context->attack_step][2]; + context->payload[3] = id_list_hid[context->attack_step][3]; + context->payload[4] = id_list_hid[context->attack_step][4]; + context->payload[5] = id_list_hid[context->attack_step][5]; + + if(context->attack_step == 15) { + context->attack_step = 0; + counter = 0; + context->is_attacking = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + + } else { + context->attack_step++; + } + break; } - break; - case FlipFridAttackLoadFileCustomUids: - while(true) { - string_reset(context->data_str); - if(!stream_read_line(context->uids_stream, context->data_str)) { + + case FlipFridAttackBfCustomerId: + if(context->proto == EM4100) { + context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100"); + + context->payload[0] = context->attack_step; + context->payload[1] = 0x00; + context->payload[2] = 0x00; + context->payload[3] = 0x00; + context->payload[4] = 0x00; + + if(context->attack_step == 255) { + context->attack_step = 0; + counter = 0; + context->is_attacking = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + } else { + context->attack_step++; + } + break; + } else { + context->protocol = protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); + + context->payload[0] = context->attack_step; + context->payload[1] = 0x00; + context->payload[2] = 0x00; + context->payload[3] = 0x00; + context->payload[4] = 0x00; + context->payload[5] = 0x00; + + if(context->attack_step == 255) { + context->attack_step = 0; + counter = 0; + context->is_attacking = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + } else { + context->attack_step++; + } + break; + } + + case FlipFridAttackLoadFile: + if(context->proto == EM4100) { + context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100"); + + context->payload[0] = context->data[0]; + context->payload[1] = context->data[1]; + context->payload[2] = context->data[2]; + context->payload[3] = context->data[3]; + context->payload[4] = context->data[4]; + + context->payload[context->key_index] = context->attack_step; + + if(context->attack_step == 255) { context->attack_step = 0; counter = 0; context->is_attacking = false; notification_message(context->notify, &sequence_blink_stop); notification_message(context->notify, &sequence_single_vibro); break; - }; - if(string_get_char(context->data_str, 0) == '#') continue; - if(string_size(context->data_str) != 11) continue; + } else { + context->attack_step++; + } + break; + } else { + context->protocol = protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); + + context->payload[0] = context->data[0]; + context->payload[1] = context->data[1]; + context->payload[2] = context->data[2]; + context->payload[3] = context->data[3]; + context->payload[4] = context->data[4]; + context->payload[5] = context->data[5]; + + context->payload[context->key_index] = context->attack_step; + + if(context->attack_step == 255) { + context->attack_step = 0; + counter = 0; + context->is_attacking = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + break; + } else { + context->attack_step++; + } break; } - FURI_LOG_D(TAG, string_get_cstr(context->data_str)); - // string is valid, parse it in context->payload - for(uint8_t i = 0; i < 5; i++) { - char temp_str[3]; - temp_str[0] = string_get_cstr(context->data_str)[i * 2]; - temp_str[1] = string_get_cstr(context->data_str)[i * 2 + 1]; - temp_str[2] = '\0'; - context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16); + case FlipFridAttackLoadFileCustomUids: + if(context->proto == EM4100) { + context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100"); + + while(true) { + string_reset(context->data_str); + if(!stream_read_line(context->uids_stream, context->data_str)) { + context->attack_step = 0; + counter = 0; + context->is_attacking = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + break; + }; + if(string_get_char(context->data_str, 0) == '#') continue; + if(string_size(context->data_str) != 11) continue; + break; + } + FURI_LOG_D(TAG, string_get_cstr(context->data_str)); + + // string is valid, parse it in context->payload + for(uint8_t i = 0; i < 5; i++) { + char temp_str[3]; + temp_str[0] = string_get_cstr(context->data_str)[i * 2]; + temp_str[1] = string_get_cstr(context->data_str)[i * 2 + 1]; + temp_str[2] = '\0'; + context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16); + } + break; + } else { + context->protocol = protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); + + while(true) { + string_reset(context->data_str); + if(!stream_read_line(context->uids_stream, context->data_str)) { + context->attack_step = 0; + counter = 0; + context->is_attacking = false; + notification_message(context->notify, &sequence_blink_stop); + notification_message(context->notify, &sequence_single_vibro); + break; + }; + if(string_get_char(context->data_str, 0) == '#') continue; + if(string_size(context->data_str) != 13) continue; + break; + } + FURI_LOG_D(TAG, string_get_cstr(context->data_str)); + + // string is valid, parse it in context->payload + for(uint8_t i = 0; i < 6; i++) { + char temp_str[3]; + temp_str[0] = string_get_cstr(context->data_str)[i * 2]; + temp_str[1] = string_get_cstr(context->data_str)[i * 2 + 1]; + temp_str[2] = '\0'; + context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16); + } + break; } - break; } + } if(counter > TIME_BETWEEN_CARDS) { @@ -189,9 +316,21 @@ void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context) { canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned( canvas, 64, 8, AlignCenter, AlignTop, string_get_cstr(context->attack_name)); - - char uid[16]; - snprintf( + + char uid[18]; + if(context->protocol == protocol_dict_get_protocol_by_name(context->dict, "HIDProx")) { + snprintf( + uid, + sizeof(uid), + "%02X:%02X:%02X:%02X:%02X:%02X", + context->payload[0], + context->payload[1], + context->payload[2], + context->payload[3], + context->payload[4], + context->payload[5]); + } else { + snprintf( uid, sizeof(uid), "%02X:%02X:%02X:%02X:%02X", @@ -200,6 +339,8 @@ void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context) { context->payload[2], context->payload[3], context->payload[4]); + } + canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignTop, uid); canvas_set_font(canvas, FontSecondary); From 96ad7f3cef86d0d853b01c40311a7757c93b57c8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 20 Sep 2022 23:13:15 +0300 Subject: [PATCH 06/30] fix nfc list crash, fix magellen gui, fix transmitter gui --- .../main/nfc/scenes/nfc_scene_mf_classic_keys_list.c | 5 ++++- applications/main/subghz/views/transmitter.c | 7 +++++-- lib/subghz/protocols/magellen.c | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c index 36f01897e..bc6e5cb57 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c @@ -17,10 +17,13 @@ void nfc_scene_mf_classic_keys_list_on_enter(void* context) { if(dict) { mf_classic_dict_rewind(dict); while(mf_classic_dict_get_next_key_str(dict, temp_key)) { + if(index > 200) { + break; + } char* current_key = (char*)malloc(sizeof(char) * 13); strncpy(current_key, string_get_cstr(temp_key), 12); MfClassicUserKeys_push_back(nfc->mfc_key_strs, current_key); - FURI_LOG_D("ListKeys", "Key %d: %s", index, current_key); + FURI_LOG_T("ListKeys", "Key %d: %s", index, current_key); submenu_add_item( submenu, current_key, diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index be9c0fe09..2055180a6 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -45,7 +45,7 @@ void subghz_view_transmitter_add_data_to_show( } static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str) { - const uint8_t button_height = 13; + const uint8_t button_height = 12; const uint8_t vertical_offset = 3; const uint8_t horizontal_offset = 1; const uint8_t string_width = canvas_string_width(canvas, str); @@ -69,7 +69,10 @@ static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str canvas_invert_color(canvas); canvas_draw_icon( - canvas, x + horizontal_offset, y - button_height + vertical_offset, &I_ButtonCenter_7x7); + canvas, + x + horizontal_offset, + y - button_height + vertical_offset - 1, + &I_ButtonCenter_7x7); canvas_draw_str( canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str); canvas_invert_color(canvas); diff --git a/lib/subghz/protocols/magellen.c b/lib/subghz/protocols/magellen.c index 52ef5a724..6dcc83e56 100644 --- a/lib/subghz/protocols/magellen.c +++ b/lib/subghz/protocols/magellen.c @@ -381,7 +381,7 @@ static void subghz_protocol_magellen_get_event_serialize(uint8_t event, string_t "%s%s%s%s%s%s%s%s", ((event >> 4) & 0x1 ? (event & 0x1 ? " Open" : " Close") : (event & 0x1 ? " Motion" : " Ok")), - ((event >> 1) & 0x1 ? ", Tamper On (Alarm)" : ""), + ((event >> 1) & 0x1 ? ", Tamper On\n(Alarm)" : ""), ((event >> 2) & 0x1 ? ", ?" : ""), ((event >> 3) & 0x1 ? ", Power On" : ""), ((event >> 4) & 0x1 ? ", MT:Wireless_Reed" : ""), From ca02826cfd669f31261448f8d3384cd505976990 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 20 Sep 2022 23:24:34 +0300 Subject: [PATCH 07/30] set time between cards to 6, run fbt format --- .../main/archive/helpers/archive_menu.h | 5 +- .../archive/scenes/archive_scene_browser.c | 2 +- .../scene/flipfrid_scene_entrypoint.c | 21 ++++-- .../flipfrid/scene/flipfrid_scene_load_file.c | 2 +- .../scene/flipfrid_scene_run_attack.c | 69 ++++++++++--------- .../notification_settings_app.c | 15 +--- lib/nfc/helpers/reader_analyzer.c | 6 +- 7 files changed, 61 insertions(+), 59 deletions(-) diff --git a/applications/main/archive/helpers/archive_menu.h b/applications/main/archive/helpers/archive_menu.h index 5df6a1ca2..201333987 100644 --- a/applications/main/archive/helpers/archive_menu.h +++ b/applications/main/archive/helpers/archive_menu.h @@ -42,10 +42,7 @@ ARRAY_DEF( #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" // Using in applications/archive/views/archive_browser_view.c -static void archive_menu_add_item( - ArchiveContextMenuItem_t* obj, - string_t text, - uint32_t event) { +static void archive_menu_add_item(ArchiveContextMenuItem_t* obj, string_t text, uint32_t event) { string_init_move(obj->text, text); obj->event = event; } diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index 23722e30b..552a6557e 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -133,7 +133,7 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { case ArchiveBrowserEventFileMenuRename: if(favorites) { browser->callback(ArchiveBrowserEventEnterFavMove, browser->context); - //} else if((archive_is_known_app(selected->type)) && (selected->is_app == false)) { + //} else if((archive_is_known_app(selected->type)) && (selected->is_app == false)) { } else { // Added ability to rename files and folders archive_show_file_menu(browser, false); diff --git a/applications/plugins/flipfrid/scene/flipfrid_scene_entrypoint.c b/applications/plugins/flipfrid/scene/flipfrid_scene_entrypoint.c index c71a35903..c709572e3 100644 --- a/applications/plugins/flipfrid/scene/flipfrid_scene_entrypoint.c +++ b/applications/plugins/flipfrid/scene/flipfrid_scene_entrypoint.c @@ -3,7 +3,10 @@ string_t menu_items[4]; string_t menu_proto_items[2]; -void flipfrid_scene_entrypoint_menu_callback(FlipFridState* context, uint32_t index, uint32_t proto_index) { +void flipfrid_scene_entrypoint_menu_callback( + FlipFridState* context, + uint32_t index, + uint32_t proto_index) { switch(index) { case FlipFridAttackDefaultValues: context->attack = FlipFridAttackDefaultValues; @@ -111,7 +114,8 @@ void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* cont } break; case InputKeyOk: - flipfrid_scene_entrypoint_menu_callback(context, context->menu_index, context->menu_proto_index); + flipfrid_scene_entrypoint_menu_callback( + context, context->menu_index, context->menu_proto_index); break; case InputKeyBack: context->is_running = false; @@ -163,16 +167,19 @@ void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) { } canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, 34, 4, AlignCenter, AlignTop, "<"); + canvas_draw_str_aligned(canvas, 34, 4, AlignCenter, AlignTop, "<"); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned( - canvas, 64, 4, AlignCenter, AlignTop, string_get_cstr(menu_proto_items[context->menu_proto_index])); + canvas, + 64, + 4, + AlignCenter, + AlignTop, + string_get_cstr(menu_proto_items[context->menu_proto_index])); canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, 94, 4, AlignCenter, AlignTop, ">"); + canvas_draw_str_aligned(canvas, 94, 4, AlignCenter, AlignTop, ">"); if(context->menu_proto_index < HIDProx) { canvas_set_font(canvas, FontSecondary); diff --git a/applications/plugins/flipfrid/scene/flipfrid_scene_load_file.c b/applications/plugins/flipfrid/scene/flipfrid_scene_load_file.c index ded62750a..687a861c9 100644 --- a/applications/plugins/flipfrid/scene/flipfrid_scene_load_file.c +++ b/applications/plugins/flipfrid/scene/flipfrid_scene_load_file.c @@ -36,7 +36,7 @@ bool flipfrid_load(FlipFridState* context, const char* file_path) { break; } else { FURI_LOG_I(TAG, "Key type: %s", string_get_cstr(temp_str)); - + if(context->proto == EM4100) { if(strcmp(string_get_cstr(temp_str), "EM4100") != 0) { FURI_LOG_E(TAG, "Unsupported Key type"); diff --git a/applications/plugins/flipfrid/scene/flipfrid_scene_run_attack.c b/applications/plugins/flipfrid/scene/flipfrid_scene_run_attack.c index 707ac74f0..f7776fb4d 100644 --- a/applications/plugins/flipfrid/scene/flipfrid_scene_run_attack.c +++ b/applications/plugins/flipfrid/scene/flipfrid_scene_run_attack.c @@ -2,7 +2,7 @@ #include uint8_t counter = 0; -#define TIME_BETWEEN_CARDS 5 +#define TIME_BETWEEN_CARDS 6 uint8_t id_list[17][5] = { {0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF @@ -68,7 +68,8 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { switch(context->attack) { case FlipFridAttackDefaultValues: if(context->proto == EM4100) { - context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100"); + context->protocol = + protocol_dict_get_protocol_by_name(context->dict, "EM4100"); context->payload[0] = id_list[context->attack_step][0]; context->payload[1] = id_list[context->attack_step][1]; @@ -87,7 +88,8 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { } break; } else { - context->protocol = protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); + context->protocol = + protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); context->payload[0] = id_list_hid[context->attack_step][0]; context->payload[1] = id_list_hid[context->attack_step][1]; @@ -95,7 +97,7 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { context->payload[3] = id_list_hid[context->attack_step][3]; context->payload[4] = id_list_hid[context->attack_step][4]; context->payload[5] = id_list_hid[context->attack_step][5]; - + if(context->attack_step == 15) { context->attack_step = 0; counter = 0; @@ -111,7 +113,8 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { case FlipFridAttackBfCustomerId: if(context->proto == EM4100) { - context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100"); + context->protocol = + protocol_dict_get_protocol_by_name(context->dict, "EM4100"); context->payload[0] = context->attack_step; context->payload[1] = 0x00; @@ -130,7 +133,8 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { } break; } else { - context->protocol = protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); + context->protocol = + protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); context->payload[0] = context->attack_step; context->payload[1] = 0x00; @@ -150,10 +154,11 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { } break; } - + case FlipFridAttackLoadFile: if(context->proto == EM4100) { - context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100"); + context->protocol = + protocol_dict_get_protocol_by_name(context->dict, "EM4100"); context->payload[0] = context->data[0]; context->payload[1] = context->data[1]; @@ -175,7 +180,8 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { } break; } else { - context->protocol = protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); + context->protocol = + protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); context->payload[0] = context->data[0]; context->payload[1] = context->data[1]; @@ -201,7 +207,8 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { case FlipFridAttackLoadFileCustomUids: if(context->proto == EM4100) { - context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100"); + context->protocol = + protocol_dict_get_protocol_by_name(context->dict, "EM4100"); while(true) { string_reset(context->data_str); @@ -229,7 +236,8 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { } break; } else { - context->protocol = protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); + context->protocol = + protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); while(true) { string_reset(context->data_str); @@ -258,7 +266,6 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { break; } } - } if(counter > TIME_BETWEEN_CARDS) { @@ -316,31 +323,31 @@ void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context) { canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned( canvas, 64, 8, AlignCenter, AlignTop, string_get_cstr(context->attack_name)); - + char uid[18]; if(context->protocol == protocol_dict_get_protocol_by_name(context->dict, "HIDProx")) { snprintf( - uid, - sizeof(uid), - "%02X:%02X:%02X:%02X:%02X:%02X", - context->payload[0], - context->payload[1], - context->payload[2], - context->payload[3], - context->payload[4], - context->payload[5]); + uid, + sizeof(uid), + "%02X:%02X:%02X:%02X:%02X:%02X", + context->payload[0], + context->payload[1], + context->payload[2], + context->payload[3], + context->payload[4], + context->payload[5]); } else { snprintf( - uid, - sizeof(uid), - "%02X:%02X:%02X:%02X:%02X", - context->payload[0], - context->payload[1], - context->payload[2], - context->payload[3], - context->payload[4]); + uid, + sizeof(uid), + "%02X:%02X:%02X:%02X:%02X", + context->payload[0], + context->payload[1], + context->payload[2], + context->payload[3], + context->payload[4]); } - + canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignTop, uid); canvas_set_font(canvas, FontSecondary); diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index bfda689ea..db9a1a01f 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -60,19 +60,8 @@ const char* const delay_text[DELAY_COUNT] = { "10min", "30min", }; -const uint32_t delay_value[DELAY_COUNT] = { - 1000, - 5000, - 10000, - 15000, - 30000, - 60000, - 90000, - 120000, - 300000, - 600000, - 1800000 -}; +const uint32_t delay_value[DELAY_COUNT] = + {1000, 5000, 10000, 15000, 30000, 60000, 90000, 120000, 300000, 600000, 1800000}; #define VIBRO_COUNT 2 const char* const vibro_text[VIBRO_COUNT] = { diff --git a/lib/nfc/helpers/reader_analyzer.c b/lib/nfc/helpers/reader_analyzer.c index 90b917296..3d065d144 100644 --- a/lib/nfc/helpers/reader_analyzer.c +++ b/lib/nfc/helpers/reader_analyzer.c @@ -39,7 +39,8 @@ struct ReaderAnalyzer { NfcDebugPcap* pcap; }; -static FuriHalNfcDevData reader_analyzer_nfc_data[] = { //XXX +static FuriHalNfcDevData reader_analyzer_nfc_data[] = { + //XXX [ReaderAnalyzerNfcDataMfClassic] = {.sak = 0x08, .atqa = {0x44, 0x00}, @@ -101,7 +102,8 @@ int32_t reader_analyzer_thread(void* context) { ReaderAnalyzer* reader_analyzer_alloc() { ReaderAnalyzer* instance = malloc(sizeof(ReaderAnalyzer)); reader_analyzer_nfc_data[ReaderAnalyzerNfcDataMfClassic].cuid = rand(); //XXX - furi_hal_random_fill_buf((uint8_t*) &reader_analyzer_nfc_data[ReaderAnalyzerNfcDataMfClassic].uid, 7); + furi_hal_random_fill_buf( + (uint8_t*)&reader_analyzer_nfc_data[ReaderAnalyzerNfcDataMfClassic].uid, 7); instance->nfc_data = reader_analyzer_nfc_data[ReaderAnalyzerNfcDataMfClassic]; instance->alive = false; instance->stream = From daee9db3667dd2bf3258efd985d9494b628255e3 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Tue, 20 Sep 2022 17:43:59 -0400 Subject: [PATCH 08/30] Clock in menu from fap --- .../desktop/scenes/desktop_scene_main.c | 20 +++--------------- applications/services/loader/loader.c | 21 ++++++++++++++++++- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index f50481906..68f712891 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -86,11 +86,6 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { consumed = true; break; - // case DesktopMainEventOpenGames: - // loader_show_game_menu(); - // consumed = true; - // break; - case DesktopMainEventOpenLockMenu: scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu); consumed = true; @@ -117,12 +112,8 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { break; } case DesktopMainEventOpenClock: { - // loader_start(desktop->loader, FLIPPER_APPS[0].name, NULL); - LoaderStatus status = loader_start( - desktop->loader, "Applications", EXT_PATH("/apps/Main/Clock.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + // it has its own error + LoaderStatus status = loader_start(desktop->loader, "Applications", EXT_PATH("/apps/Main/Clock.fap")); consumed = true; break; } @@ -233,12 +224,7 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { break; } case DesktopMainEventOpenSubRemote: { - loader_start(desktop->loader, FLIPPER_APPS[1].name, NULL); - // LoaderStatus status = loader_start( - // desktop->loader, "Applications", EXT_PATH("/apps/Main/SubGHz_Remote.fap")); - // if(status != LoaderStatusOk) { - // FURI_LOG_E(TAG, "loader_start failed: %d", status); - // } + loader_start(desktop->loader, FLIPPER_APPS[2].name, NULL); consumed = true; break; } diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 649b01476..fbf5cb937 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -1,7 +1,9 @@ #include "applications.h" #include +#include #include "loader/loader.h" #include "loader_i.h" +#include "applications/services/desktop/desktop_i.h" #define TAG "LoaderSrv" @@ -55,6 +57,16 @@ static void loader_submenu_callback(void* context, uint32_t index) { view_dispatcher_switch_to_view(loader_instance->view_dispatcher, view_id); } +static void loader_clock_callback(void* context, uint32_t index) { + UNUSED(index); + Desktop* desktop = desktop_alloc(); + LoaderStatus status = loader_start( + desktop->loader, "Applications", EXT_PATH("/apps/Main/Clock.fap")); + if(status != LoaderStatusOk) { + FURI_LOG_E(TAG, "loader_start failed: %d", status); + } +} + static void loader_cli_print_usage() { printf("Usage:\r\n"); printf("loader \r\n"); @@ -372,7 +384,14 @@ static void loader_free(Loader* instance) { static void loader_build_menu() { FURI_LOG_I(TAG, "Building main menu"); size_t i; - for(i = 0; i < FLIPPER_APPS_COUNT; i++) { + menu_add_item( + loader_instance->primary_menu, + "Clock", + &A_Clock_14, + 0, + loader_clock_callback, + (void*)LoaderMenuViewPlugins); + for(i = 1; i < FLIPPER_APPS_COUNT; i++) { menu_add_item( loader_instance->primary_menu, FLIPPER_APPS[i].name, From f85dc1675d380c15f9d1dbe3d5b84dbfac5ff705 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 21 Sep 2022 01:00:56 +0300 Subject: [PATCH 09/30] update changelog, rm unused var from clock --- .github/CODEOWNERS | 1 + CHANGELOG.md | 7 ++++++- applications/main/clock_app/clock_settings.h | 1 - 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..59ab7a1d8 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @xMasterX \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 589729286..16d072373 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ### New changes -* PR: Allow running apps from Archive app (also allows adding them to Favourites) (PR 72 by RogueMaster) (new icon by @Svaarich) +* PR: RFID Fuzzer - support for HIDProx, update for UI (PR #74 by mvanzanten) (xMasterX -> time between cards set to 6) +* Fix NFC User dict (list) crash, now it displays only first 200 elements for large lists +* Fix SubGHz transmitter GUI button +* Fix SubGHz Magellen protocol GUI +* Fix null pointer dereference crash in Archive -> Info in root folder (+ fix long path names display) +* OFW: SubGHz: Adding checks for get_upload functions #### **DFU files no longer included in releases to avoid issues with wrong manual installation of assets - use .tgz file with qFlipper, or install automatically via web updater or use microSD update package** diff --git a/applications/main/clock_app/clock_settings.h b/applications/main/clock_app/clock_settings.h index d05f986ef..b2970f659 100644 --- a/applications/main/clock_app/clock_settings.h +++ b/applications/main/clock_app/clock_settings.h @@ -33,5 +33,4 @@ typedef enum { typedef struct { TimeFormat time_format; DateFormat date_format; - uint8_t increment_precision; } ClockSettings; \ No newline at end of file From 42c9917a543c96ad49dcd32b3850a61cbbe9dd50 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Tue, 20 Sep 2022 18:01:33 -0400 Subject: [PATCH 10/30] Update ReadMe.md --- ReadMe.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ReadMe.md b/ReadMe.md index 2a2e4ffe6..83bb2d2f5 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -10,11 +10,13 @@ Latest Updates: - Known Issues: `Chess`, `Tanks` & `Chip8` (No Controls) -- Last Synched changes from [Unleashed/xMasterX](https://github.com/Eng1n33r/flipperzero-firmware) in [changelog](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/CHANGELOG.md): `2022-09-19 20:45 GMT` +- Last Synched changes from [Unleashed/xMasterX](https://github.com/Eng1n33r/flipperzero-firmware) in [changelog](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/CHANGELOG.md): `2022-09-20 22:55 GMT` +- Last Synched changes from [OFW](https://github.com/flipperdevices/flipperzero-firmware): `2022-09-20 22:55 GMT` - To avoid Application errors and duplicates, delete /ext/apps before doing the RM firmware update - Archive: FAPs are now launchable from Archive [By RogueMaster], thanks @xMasterX for the suggestion - Updated [Metronome (By panki27)](https://github.com/panki27/Metronome) - Added [DTMF Dolphin (By litui)](https://github.com/litui/dtmf_dolphin) +- Added Clock.FAP Launching From Main Menu (It has a slight delay, working on it) [By RogueMaster]

TO DO
@@ -101,6 +103,7 @@ $ ./fbt plugin_dist FIRMWARE_APP_SET=ext_apps - BadUSB: Assets for Kiosk Evasion and Wifi Stealer - BadUSB: show script errors on screen [(By CromFr)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/200) - BadUSB: sk-SK maping keybord for BadUsb [(By jaroslavmraz)](https://github.com/flipperdevices/flipperzero-firmware/pull/1619) +- Clock.FAP Launching From Main Menu (It has a slight delay, working on it) [By RogueMaster](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/daee9db3667dd2bf3258efd985d9494b628255e3#diff-fc21e449837c4be79d47f76165f42a7faaa3e8a8b6c86bf7d57ab8324b06141a) - Development free space thanks to removal of unused debug tools and [thanks to ESurge](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/46/files) for removal of first start assets. - Dolphin: Assigned profile pic for levels 1-10 (Happy Lvl 1 Dolphin), 11-15 (Happy Lvl 2 Dolphin), 16-18 (Happy Lvl 3 Dolphin), 19-21 (Kid G0ku), 22-24 (Adult G0ku), 25-27 (SSJ G0ku) and 28-30 (SSJ3 G0ku) - Dolphin: Expanded max level from 3 to 30 using [Roll20](https://roll20.net/compendium/dnd5e/Monsters#h-Experience%20Points), Increased max deed XP per action type from 15 to 45 exp daily & updated animation manifest for max level 30 for all animations (By RogueMaster) From edd9713148b039b13a903271534ffee8681a0414 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Tue, 20 Sep 2022 18:06:20 -0400 Subject: [PATCH 11/30] Update CODEOWNERS --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 59ab7a1d8..e7a330d1f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @xMasterX \ No newline at end of file +* @RogueMaster \ No newline at end of file From 43f3f76776f0aaa6d50e08b960d22a20382dd6fd Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Tue, 20 Sep 2022 18:36:31 -0400 Subject: [PATCH 12/30] Added Fix and License/Readme --- applications/plugins/wifi_deauther/LICENSE | 674 ++++++++++++++++++ applications/plugins/wifi_deauther/README.md | 50 ++ .../scenes/wifi_deauther_scene_start.c | 2 +- .../plugins/wifi_deauther/wifi_deauther_app.c | 2 + 4 files changed, 727 insertions(+), 1 deletion(-) create mode 100644 applications/plugins/wifi_deauther/LICENSE create mode 100644 applications/plugins/wifi_deauther/README.md diff --git a/applications/plugins/wifi_deauther/LICENSE b/applications/plugins/wifi_deauther/LICENSE new file mode 100644 index 000000000..f288702d2 --- /dev/null +++ b/applications/plugins/wifi_deauther/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/applications/plugins/wifi_deauther/README.md b/applications/plugins/wifi_deauther/README.md new file mode 100644 index 000000000..87a419f90 --- /dev/null +++ b/applications/plugins/wifi_deauther/README.md @@ -0,0 +1,50 @@ +# flipperzero_esp8266_deautherv2 +Flipper Zero esp8266 deauther app. + + +Based off the WiFi Marauder App from 0xchocolate. + +https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion + +https://github.com/RogueMaster/flipperzero-firmware-wPlugins/tree/unleashed/applications/wifi_marauder_companion + +uses the Version 2 of the ESP8266 Deauther code. +https://github.com/SpacehuhnTech/esp8266_deauther/tree/v2/esp8266_deauther + +This is done so you can use the original deauther v2 firmware on the esp8266. +you can just flash the latest binary. + +also a shout out to https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module +This is already in the Roguemaster firmware and just needs to be enabled and compiled. unfortunatly I could not get this past the menu when I compiled his deauther source for the nodemcu. Nice menu though. + +I used a nodeMCU board. Wiring is simple. follow the wiring guide on https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module +On mine I connected one G to ground, VIN to 5V, RX to U_TX, TX to U_RX. + +NodeMCU---FlipperZero + +G---------GND + +VIN-------5V + +RX--------U_TX + +TX--------U_RX + + + +Video in action. +https://youtu.be/_RFzZyPkeR0 + +If you want to disable the built in WiFi access and web interface (only use flipper to serial send commands) then select "set webinterface false", "save settings" and "reboot". When it starts back up you wont see the pwned AP any more. + +I installed this into Roguemaster to test. + +git clone --recursive https://github.com/RogueMaster/flipperzero-firmware-wPlugins.git +cd flipperzero-firmware-wPlugins/ + +copy folder into applications. +add "APPS_wifi_deauther", to the meta/application.fam file. + +compile +./fbt resources icons +./fbt updater_package diff --git a/applications/plugins/wifi_deauther/scenes/wifi_deauther_scene_start.c b/applications/plugins/wifi_deauther/scenes/wifi_deauther_scene_start.c index eccfe1c14..6bcb913b0 100644 --- a/applications/plugins/wifi_deauther/scenes/wifi_deauther_scene_start.c +++ b/applications/plugins/wifi_deauther/scenes/wifi_deauther_scene_start.c @@ -37,7 +37,7 @@ const WifideautherItem MenuItems[NUM_MENU_ITEMS] = { { "Scan", {"All", "SSIDs", "Stations"}, 3, {"scan", "scan aps", "scan stations"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP }, { "Select", {"All", "SSIDs", "Stations"}, 3, {"select all", "select aps", "select stations"}, INPUT_ARGS, FOCUS_CONSOLE_END, NO_TIP }, { "Deselect", {"All", "SSIDs", "Stations"}, 3, {"deselect all", "deselect aps", "deselect stations"}, INPUT_ARGS, FOCUS_CONSOLE_END, NO_TIP }, - { "Show", {"All", "Selected"}, 2, {"show all", "show selected"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP }, + { "Show", {"SSIDs", "Stations", "All", "Selected"}, 4, {"show ap", "show station", "show all", "show selected"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP }, { "Attack", {"deauth", "deauthall", "beacon", "probe"}, 4, {"attack deauth", "attack deauthall", "attack beacon", "attack probe"}, NO_ARGS, FOCUS_CONSOLE_END, SHOW_STOPSCAN_TIP }, { "Settings", {"Get", "Remove AP", "Set SSID", "Set Pass", "Save"}, 5, {"get settings", "set webinterface false", "set ssid: pwned", "set password: deauther", "save settings"}, INPUT_ARGS, FOCUS_CONSOLE_END, NO_TIP }, { "Sysinfo", {""}, 1, {"sysinfo"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP }, diff --git a/applications/plugins/wifi_deauther/wifi_deauther_app.c b/applications/plugins/wifi_deauther/wifi_deauther_app.c index c98f2c6dc..7d17a2369 100644 --- a/applications/plugins/wifi_deauther/wifi_deauther_app.c +++ b/applications/plugins/wifi_deauther/wifi_deauther_app.c @@ -1,5 +1,6 @@ #include "wifi_deauther_app_i.h" +#include #include #include @@ -88,6 +89,7 @@ void wifi_deauther_app_free(WifideautherApp* app) { int32_t wifi_deauther_app(void* p) { furi_hal_power_enable_otg(); + furi_delay_ms(600); UNUSED(p); WifideautherApp* wifi_deauther_app = wifi_deauther_app_alloc(); From 150ff59b01f421d8d4c8d5754d2a7db47d243e84 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Tue, 20 Sep 2022 18:37:34 -0400 Subject: [PATCH 13/30] Update ReadMe.md --- ReadMe.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ReadMe.md b/ReadMe.md index 83bb2d2f5..72ddeacc2 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -17,6 +17,7 @@ - Updated [Metronome (By panki27)](https://github.com/panki27/Metronome) - Added [DTMF Dolphin (By litui)](https://github.com/litui/dtmf_dolphin) - Added Clock.FAP Launching From Main Menu (It has a slight delay, working on it) [By RogueMaster] +- Updated [WiFi (Deauther) (By Timmotools)](https://github.com/Timmotools/flipperzero_esp8266_deautherv2)
TO DO
@@ -223,7 +224,7 @@ $ ./fbt plugin_dist FIRMWARE_APP_SET=ext_apps - [Sub-GHz Playlist (By darmiel)](https://github.com/darmiel/flipper-playlist) - [UPC-A Generator (By McAzzaMan)](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator) - [WAV Player (By Zlo)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player) Updated by Atmanos & RogueMaster To Work -- [WiFi (Deauther) (By Timmotools)](https://github.com/Timmotools/flipperzero_esp8266_deautherv2) (Inspired by WiFi (Marauder) [(By 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion) +- [WiFi (Deauther) (By Timmotools)](https://github.com/Timmotools/flipperzero_esp8266_deautherv2) - [WiFi (Marauder) (By 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion) `REQUIRES ESP32 WITH MARAUDER FLASHED` - [WiFi Scanner v.0.4 (By SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module-ESP8266) `Req: ESP8266 or ESP32`
From d986ef410475de61f236bfd6364da859610b0e8a Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 21 Sep 2022 06:52:34 +0300 Subject: [PATCH 14/30] fix nice flor s crash, fix debug pack for debug builds --- applications/main/application.fam | 6 +++--- lib/subghz/protocols/came_atomo.c | 4 ++-- lib/subghz/protocols/nice_flor_s.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/applications/main/application.fam b/applications/main/application.fam index e03f70953..a3d310093 100644 --- a/applications/main/application.fam +++ b/applications/main/application.fam @@ -24,13 +24,13 @@ App( apptype=FlipperAppType.METAPACKAGE, provides=[ "gpio", - "ibutton", + #"ibutton", "infrared", "lfrfid", "nfc", "subghz", - "bad_usb", - "u2f", + #"bad_usb", + #"u2f", "fap_loader", "archive", ], diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index bb0cf24e1..727cef8ee 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -79,7 +79,7 @@ void* subghz_protocol_encoder_came_atomo_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->encoder.repeat = 10; - instance->encoder.size_upload = 1024; //approx max buffer size + instance->encoder.size_upload = 1024; //actual size about 760 instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; @@ -114,7 +114,7 @@ static LevelDuration break; default: - furi_crash("SubGhz: ManchesterEncoderResult is incorrect."); + FURI_LOG_E(TAG, "SubGhz: ManchesterEncoderResult is incorrect."); break; } return level_duration_make(data.level, data.duration); diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index d5c3cd665..ef2c73053 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -96,7 +96,7 @@ void* subghz_protocol_encoder_nice_flor_s_alloc(SubGhzEnvironment* environment) TAG, "Loading rainbow table from %s", instance->nice_flor_s_rainbow_table_file_name); } instance->encoder.repeat = 10; - instance->encoder.size_upload = 2976; //max upload 186*16 = 2976 + instance->encoder.size_upload = 1800; //wrong!! upload 186*16 = 2976 - actual size about 1716 instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; From 6000d47a0fd081cec6ff00894897e3f11bcaaf17 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 21 Sep 2022 07:12:09 +0300 Subject: [PATCH 15/30] allow saving only for protocols without encoder --- lib/subghz/protocols/ido.c | 3 ++- lib/subghz/protocols/scher_khan.c | 3 ++- lib/subghz/protocols/somfy_keytis.c | 2 +- lib/subghz/protocols/somfy_telis.c | 2 +- lib/subghz/protocols/star_line.c | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/subghz/protocols/ido.c b/lib/subghz/protocols/ido.c index 914468445..fca8fcd76 100644 --- a/lib/subghz/protocols/ido.c +++ b/lib/subghz/protocols/ido.c @@ -61,7 +61,8 @@ const SubGhzProtocolEncoder subghz_protocol_ido_encoder = { const SubGhzProtocol subghz_protocol_ido = { .name = SUBGHZ_PROTOCOL_IDO_NAME, .type = SubGhzProtocolTypeDynamic, - .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Save, .decoder = &subghz_protocol_ido_decoder, .encoder = &subghz_protocol_ido_encoder, diff --git a/lib/subghz/protocols/scher_khan.c b/lib/subghz/protocols/scher_khan.c index 1c044e9db..89f2937d8 100644 --- a/lib/subghz/protocols/scher_khan.c +++ b/lib/subghz/protocols/scher_khan.c @@ -69,7 +69,8 @@ const SubGhzProtocolEncoder subghz_protocol_scher_khan_encoder = { const SubGhzProtocol subghz_protocol_scher_khan = { .name = SUBGHZ_PROTOCOL_SCHER_KHAN_NAME, .type = SubGhzProtocolTypeDynamic, - .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Save, .decoder = &subghz_protocol_scher_khan_decoder, .encoder = &subghz_protocol_scher_khan_encoder, diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index 7a3b2186f..0307a78fa 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -68,7 +68,7 @@ const SubGhzProtocol subghz_protocol_somfy_keytis = { .name = SUBGHZ_PROTOCOL_SOMFY_KEYTIS_NAME, .type = SubGhzProtocolTypeDynamic, .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM | - SubGhzProtocolFlag_Decodable, + SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Save, .decoder = &subghz_protocol_somfy_keytis_decoder, .encoder = &subghz_protocol_somfy_keytis_encoder, diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index b9aac5777..d0b2f82a8 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -67,7 +67,7 @@ const SubGhzProtocol subghz_protocol_somfy_telis = { .name = SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME, .type = SubGhzProtocolTypeDynamic, .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM | - SubGhzProtocolFlag_Decodable, + SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Save, .decoder = &subghz_protocol_somfy_telis_decoder, .encoder = &subghz_protocol_somfy_telis_encoder, diff --git a/lib/subghz/protocols/star_line.c b/lib/subghz/protocols/star_line.c index 434cf81e3..3a09e40e7 100644 --- a/lib/subghz/protocols/star_line.c +++ b/lib/subghz/protocols/star_line.c @@ -74,7 +74,7 @@ const SubGhzProtocol subghz_protocol_star_line = { .name = SUBGHZ_PROTOCOL_STAR_LINE_NAME, .type = SubGhzProtocolTypeDynamic, .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | - SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save, .decoder = &subghz_protocol_star_line_decoder, .encoder = &subghz_protocol_star_line_encoder, From 87393a086c4fa7749eaf530586e54b5c8b8291d4 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 21 Sep 2022 08:43:07 +0300 Subject: [PATCH 16/30] fix rfid fuzzer crashes, some new random names --- CHANGELOG.md | 11 +++---- .../scene/flipfrid_scene_run_attack.c | 31 ++++--------------- lib/toolbox/random_name.c | 14 +++++++++ 3 files changed, 25 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16d072373..3adfcd008 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,9 @@ ### New changes -* PR: RFID Fuzzer - support for HIDProx, update for UI (PR #74 by mvanzanten) (xMasterX -> time between cards set to 6) -* Fix NFC User dict (list) crash, now it displays only first 200 elements for large lists -* Fix SubGHz transmitter GUI button -* Fix SubGHz Magellen protocol GUI -* Fix null pointer dereference crash in Archive -> Info in root folder (+ fix long path names display) -* OFW: SubGHz: Adding checks for get_upload functions +* Plugins: Fix RFID Fuzzer crashes +* SubGHz: Fix Nice Flor S crash +* SubGHz: Allow saving signals for subghz protocols without encoder (sending is not possible) +* Some random names added +* Fix `debug_pack` to allow building debug builds with extra parameter for `./fbt` (check previous releases for info) #### **DFU files no longer included in releases to avoid issues with wrong manual installation of assets - use .tgz file with qFlipper, or install automatically via web updater or use microSD update package** diff --git a/applications/plugins/flipfrid/scene/flipfrid_scene_run_attack.c b/applications/plugins/flipfrid/scene/flipfrid_scene_run_attack.c index f7776fb4d..9d30f4faa 100644 --- a/applications/plugins/flipfrid/scene/flipfrid_scene_run_attack.c +++ b/applications/plugins/flipfrid/scene/flipfrid_scene_run_attack.c @@ -44,6 +44,11 @@ void flipfrid_scene_run_attack_on_enter(FlipFridState* context) { context->attack_step = 0; context->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); context->worker = lfrfid_worker_alloc(context->dict); + if(context->proto == HIDProx) { + context->protocol = protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); + } else { + context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100"); + } } void flipfrid_scene_run_attack_on_exit(FlipFridState* context) { @@ -68,9 +73,6 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { switch(context->attack) { case FlipFridAttackDefaultValues: if(context->proto == EM4100) { - context->protocol = - protocol_dict_get_protocol_by_name(context->dict, "EM4100"); - context->payload[0] = id_list[context->attack_step][0]; context->payload[1] = id_list[context->attack_step][1]; context->payload[2] = id_list[context->attack_step][2]; @@ -88,9 +90,6 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { } break; } else { - context->protocol = - protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); - context->payload[0] = id_list_hid[context->attack_step][0]; context->payload[1] = id_list_hid[context->attack_step][1]; context->payload[2] = id_list_hid[context->attack_step][2]; @@ -113,9 +112,6 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { case FlipFridAttackBfCustomerId: if(context->proto == EM4100) { - context->protocol = - protocol_dict_get_protocol_by_name(context->dict, "EM4100"); - context->payload[0] = context->attack_step; context->payload[1] = 0x00; context->payload[2] = 0x00; @@ -133,9 +129,6 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { } break; } else { - context->protocol = - protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); - context->payload[0] = context->attack_step; context->payload[1] = 0x00; context->payload[2] = 0x00; @@ -157,9 +150,6 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { case FlipFridAttackLoadFile: if(context->proto == EM4100) { - context->protocol = - protocol_dict_get_protocol_by_name(context->dict, "EM4100"); - context->payload[0] = context->data[0]; context->payload[1] = context->data[1]; context->payload[2] = context->data[2]; @@ -180,9 +170,6 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { } break; } else { - context->protocol = - protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); - context->payload[0] = context->data[0]; context->payload[1] = context->data[1]; context->payload[2] = context->data[2]; @@ -207,9 +194,6 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { case FlipFridAttackLoadFileCustomUids: if(context->proto == EM4100) { - context->protocol = - protocol_dict_get_protocol_by_name(context->dict, "EM4100"); - while(true) { string_reset(context->data_str); if(!stream_read_line(context->uids_stream, context->data_str)) { @@ -236,9 +220,6 @@ void flipfrid_scene_run_attack_on_tick(FlipFridState* context) { } break; } else { - context->protocol = - protocol_dict_get_protocol_by_name(context->dict, "HIDProx"); - while(true) { string_reset(context->data_str); if(!stream_read_line(context->uids_stream, context->data_str)) { @@ -325,7 +306,7 @@ void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context) { canvas, 64, 8, AlignCenter, AlignTop, string_get_cstr(context->attack_name)); char uid[18]; - if(context->protocol == protocol_dict_get_protocol_by_name(context->dict, "HIDProx")) { + if(context->proto == HIDProx) { snprintf( uid, sizeof(uid), diff --git a/lib/toolbox/random_name.c b/lib/toolbox/random_name.c index 985906756..b5924c8db 100644 --- a/lib/toolbox/random_name.c +++ b/lib/toolbox/random_name.c @@ -21,6 +21,12 @@ void set_random_name(char* name, uint8_t max_name_size) { "thick", "great", "my", + "mini", + "ultra", + "haupt", + "small", + "random", + "strange", }; const char* suffix[] = { @@ -32,6 +38,14 @@ void set_random_name(char* name, uint8_t max_name_size) { "burer", "sidorovich", "habar", + "radar", + "borov", + "pda", + "konserva", + "aptechka", + "door", + "thing", + "stuff", }; // sus is not (sus)pect - this is about super sus uint8_t prefix_i = rand() % COUNT_OF(prefix); From 401406b7c4d11d23d6a016fabcedb4d64016cef2 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 01:46:49 -0400 Subject: [PATCH 17/30] less code less space... loader_start has its own errors + fix unirf link --- .../desktop/scenes/desktop_scene_main.c | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 68f712891..b8a03f650 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -112,7 +112,6 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { break; } case DesktopMainEventOpenClock: { - // it has its own error LoaderStatus status = loader_start(desktop->loader, "Applications", EXT_PATH("/apps/Main/Clock.fap")); consumed = true; break; @@ -172,59 +171,41 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { case DesktopMainEventOpenSnake: { LoaderStatus status = loader_start( desktop->loader, "Applications", EXT_PATH("/apps/Games/Snake.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } consumed = true; break; } case DesktopMainEventOpen2048: { LoaderStatus status = loader_start( desktop->loader, "Applications", EXT_PATH("/apps/Games/2048.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } consumed = true; break; } case DesktopMainEventOpenZombiez: { LoaderStatus status = loader_start( desktop->loader, "Applications", EXT_PATH("/apps/Games/Zombiez.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } consumed = true; break; } case DesktopMainEventOpenTetris: { LoaderStatus status = loader_start( desktop->loader, "Applications", EXT_PATH("/apps/Games/Tetris.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } consumed = true; break; } case DesktopMainEventOpenDOOM: { LoaderStatus status = loader_start( desktop->loader, "Applications", EXT_PATH("/apps/Games/DOOM.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } consumed = true; break; } case DesktopMainEventOpenDice: { LoaderStatus status = loader_start( desktop->loader, "Applications", EXT_PATH("/apps/Games/Dice.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } consumed = true; break; } case DesktopMainEventOpenSubRemote: { - loader_start(desktop->loader, FLIPPER_APPS[2].name, NULL); + loader_start(desktop->loader, FLIPPER_APPS[1].name, NULL); consumed = true; break; } From 6dd38fac0d392f8b7588475c6fa9875f1d364a86 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 01:47:13 -0400 Subject: [PATCH 18/30] Clock, iButton and u2f in Menu --- applications/services/loader/loader.c | 50 +++++++++++++++++++-------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index fbf5cb937..8afc853d5 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -58,13 +58,21 @@ static void loader_submenu_callback(void* context, uint32_t index) { } static void loader_clock_callback(void* context, uint32_t index) { + UNUSED(context); UNUSED(index); - Desktop* desktop = desktop_alloc(); - LoaderStatus status = loader_start( - desktop->loader, "Applications", EXT_PATH("/apps/Main/Clock.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + LoaderStatus status = loader_start(NULL, "Applications", EXT_PATH("/apps/Main/Clock.fap")); +} + +static void loader_ibutton_callback(void* context, uint32_t index) { + UNUSED(context); + UNUSED(index); + LoaderStatus status = loader_start(NULL, "Applications", EXT_PATH("/apps/Main/ibutton.fap")); +} + +static void loader_u2f_callback(void* context, uint32_t index) { + UNUSED(context); + UNUSED(index); + LoaderStatus status = loader_start(NULL, "Applications", EXT_PATH("/apps/Main/u2f.fap")); } static void loader_cli_print_usage() { @@ -384,14 +392,14 @@ static void loader_free(Loader* instance) { static void loader_build_menu() { FURI_LOG_I(TAG, "Building main menu"); size_t i; - menu_add_item( - loader_instance->primary_menu, - "Clock", - &A_Clock_14, - 0, - loader_clock_callback, - (void*)LoaderMenuViewPlugins); - for(i = 1; i < FLIPPER_APPS_COUNT; i++) { + menu_add_item( + loader_instance->primary_menu, + "Clock", + &A_Clock_14, + 0, + loader_clock_callback, + (void*)NULL); + for(i = 0; i < FLIPPER_APPS_COUNT; i++) { menu_add_item( loader_instance->primary_menu, FLIPPER_APPS[i].name, @@ -409,6 +417,20 @@ static void loader_build_menu() { loader_submenu_callback, (void*)LoaderMenuViewPlugins); } + menu_add_item( + loader_instance->primary_menu, + "iButton", + &A_iButton_14, + i++, + loader_ibutton_callback, + (void*)NULL); + menu_add_item( + loader_instance->primary_menu, + "U2F", + &A_U2F_14, + i++, + loader_u2f_callback, + (void*)NULL); // if(FLIPPER_GAMES_COUNT != 0) { // menu_add_item( // loader_instance->primary_menu, From ac86ab7995b8e8809604f4f61d21767dc51d3685 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 01:49:31 -0400 Subject: [PATCH 19/30] Update ReadMe.md --- ReadMe.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 72ddeacc2..74579e120 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -16,8 +16,11 @@ - Archive: FAPs are now launchable from Archive [By RogueMaster], thanks @xMasterX for the suggestion - Updated [Metronome (By panki27)](https://github.com/panki27/Metronome) - Added [DTMF Dolphin (By litui)](https://github.com/litui/dtmf_dolphin) -- Added Clock.FAP Launching From Main Menu (It has a slight delay, working on it) [By RogueMaster] - Updated [WiFi (Deauther) (By Timmotools)](https://github.com/Timmotools/flipperzero_esp8266_deautherv2) +- Fixed delay issue for launching FAP from Main Menu +- Added Clock.FAP Launching From Main Menu [By RogueMaster] +- Added ibutton.FAP Launching From Main Menu [By RogueMaster] +- Added u2f.FAP Launching From Main Menu [By RogueMaster]
TO DO
@@ -104,7 +107,9 @@ $ ./fbt plugin_dist FIRMWARE_APP_SET=ext_apps - BadUSB: Assets for Kiosk Evasion and Wifi Stealer - BadUSB: show script errors on screen [(By CromFr)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/200) - BadUSB: sk-SK maping keybord for BadUsb [(By jaroslavmraz)](https://github.com/flipperdevices/flipperzero-firmware/pull/1619) -- Clock.FAP Launching From Main Menu (It has a slight delay, working on it) [By RogueMaster](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/daee9db3667dd2bf3258efd985d9494b628255e3#diff-fc21e449837c4be79d47f76165f42a7faaa3e8a8b6c86bf7d57ab8324b06141a) +- Added Clock.FAP Launching From Main Menu [By RogueMaster](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/6dd38fac0d392f8b7588475c6fa9875f1d364a86) +- Added ibutton.FAP Launching From Main Menu [By RogueMaster](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/6dd38fac0d392f8b7588475c6fa9875f1d364a86) +- Added u2f.FAP Launching From Main Menu [By RogueMaster](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/6dd38fac0d392f8b7588475c6fa9875f1d364a86) - Development free space thanks to removal of unused debug tools and [thanks to ESurge](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/46/files) for removal of first start assets. - Dolphin: Assigned profile pic for levels 1-10 (Happy Lvl 1 Dolphin), 11-15 (Happy Lvl 2 Dolphin), 16-18 (Happy Lvl 3 Dolphin), 19-21 (Kid G0ku), 22-24 (Adult G0ku), 25-27 (SSJ G0ku) and 28-30 (SSJ3 G0ku) - Dolphin: Expanded max level from 3 to 30 using [Roll20](https://roll20.net/compendium/dnd5e/Monsters#h-Experience%20Points), Increased max deed XP per action type from 15 to 45 exp daily & updated animation manifest for max level 30 for all animations (By RogueMaster) From b435735f69d5b85c7651666baac27414a2c74c5a Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 01:50:11 -0400 Subject: [PATCH 20/30] Update ReadMe.md --- ReadMe.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 74579e120..ab8aff1de 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -17,10 +17,11 @@ - Updated [Metronome (By panki27)](https://github.com/panki27/Metronome) - Added [DTMF Dolphin (By litui)](https://github.com/litui/dtmf_dolphin) - Updated [WiFi (Deauther) (By Timmotools)](https://github.com/Timmotools/flipperzero_esp8266_deautherv2) -- Fixed delay issue for launching FAP from Main Menu -- Added Clock.FAP Launching From Main Menu [By RogueMaster] -- Added ibutton.FAP Launching From Main Menu [By RogueMaster] -- Added u2f.FAP Launching From Main Menu [By RogueMaster] +- Fixed delay issue for launching FAP from Main Menu +- Fixed SubGHz not showing +- Added Clock.FAP Launching From Main Menu [By RogueMaster](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/6dd38fac0d392f8b7588475c6fa9875f1d364a86) +- Added ibutton.FAP Launching From Main Menu [By RogueMaster](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/6dd38fac0d392f8b7588475c6fa9875f1d364a86) +- Added u2f.FAP Launching From Main Menu [By RogueMaster](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/6dd38fac0d392f8b7588475c6fa9875f1d364a86)
TO DO
From 725edb3b6d1d549a3a1a66453326cbc7d02c36d2 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 01:53:53 -0400 Subject: [PATCH 21/30] Update ReadMe.md --- ReadMe.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index ab8aff1de..ab0b7c432 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -10,8 +10,8 @@ Latest Updates: - Known Issues: `Chess`, `Tanks` & `Chip8` (No Controls) -- Last Synched changes from [Unleashed/xMasterX](https://github.com/Eng1n33r/flipperzero-firmware) in [changelog](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/CHANGELOG.md): `2022-09-20 22:55 GMT` -- Last Synched changes from [OFW](https://github.com/flipperdevices/flipperzero-firmware): `2022-09-20 22:55 GMT` +- Last Synched changes from [Unleashed/xMasterX](https://github.com/Eng1n33r/flipperzero-firmware) in [changelog](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/CHANGELOG.md): `2022-09-21 06:55 GMT` +- Last Synched changes from [OFW](https://github.com/flipperdevices/flipperzero-firmware): `2022-09-21 06:55 GMT` - To avoid Application errors and duplicates, delete /ext/apps before doing the RM firmware update - Archive: FAPs are now launchable from Archive [By RogueMaster], thanks @xMasterX for the suggestion - Updated [Metronome (By panki27)](https://github.com/panki27/Metronome) From 672af908f05807efea9bd3f39029c2de72638cc5 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 02:01:33 -0400 Subject: [PATCH 22/30] Loader Cleanup! --- applications/services/loader/loader.c | 31 +-------------------------- 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 8afc853d5..423185b26 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -1,9 +1,7 @@ #include "applications.h" #include -#include #include "loader/loader.h" #include "loader_i.h" -#include "applications/services/desktop/desktop_i.h" #define TAG "LoaderSrv" @@ -373,8 +371,6 @@ static void loader_free(Loader* instance) { menu_free(loader_instance->primary_menu); view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewPrimary); - // submenu_free(loader_instance->games_menu); - // view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewGames); submenu_free(loader_instance->plugins_menu); view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewPlugins); submenu_free(loader_instance->debug_menu); @@ -431,16 +427,7 @@ static void loader_build_menu() { i++, loader_u2f_callback, (void*)NULL); - // if(FLIPPER_GAMES_COUNT != 0) { - // menu_add_item( - // loader_instance->primary_menu, - // "Games", - // &A_Games_14, - // i++, - // loader_submenu_callback, - // (void*)LoaderMenuViewGames); - // } - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) && FLIPPER_DEBUG_APPS_COUNT != 0) { menu_add_item( loader_instance->primary_menu, "Debug Tools", @@ -459,16 +446,7 @@ static void loader_build_menu() { } static void loader_build_submenu() { - // FURI_LOG_I(TAG, "Building games menu"); size_t i; - // for(i = 0; i < FLIPPER_GAMES_COUNT; i++) { - // submenu_add_item( - // loader_instance->games_menu, - // FLIPPER_GAMES[i].name, - // i, - // loader_menu_callback, - // (void*)&FLIPPER_GAMES[i]); - // } FURI_LOG_I(TAG, "Building plugins menu"); for(i = 0; i < FLIPPER_PLUGINS_COUNT; i++) { @@ -506,13 +484,6 @@ void loader_show_menu() { furi_thread_flags_set(loader_instance->loader_thread, LOADER_THREAD_FLAG_SHOW_MENU); } -// void loader_show_game_menu() { - // furi_assert(loader_instance); - // menu_set_selected_item(loader_instance->primary_menu, 10); - // view_dispatcher_switch_to_view(loader_instance->view_dispatcher, LoaderMenuViewGames); - // view_dispatcher_run(loader_instance->view_dispatcher); -// } - void loader_update_menu() { menu_reset(loader_instance->primary_menu); loader_build_menu(); From 0bfa8768e1947249a55e81f2153ac371c5a8c157 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 02:07:21 -0400 Subject: [PATCH 23/30] More loader fixes --- applications/services/loader/loader.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 423185b26..4ab9bce80 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -2,6 +2,7 @@ #include #include "loader/loader.h" #include "loader_i.h" +#include "applications/services/desktop/desktop_i.h" #define TAG "LoaderSrv" @@ -160,6 +161,7 @@ void loader_cli_list(Cli* cli, string_t args, Loader* instance) { UNUSED(args); UNUSED(instance); printf("Applications:\r\n"); + printf("\t%s\r\n", "Clock"); for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { printf("\t%s\r\n", FLIPPER_APPS[i].name); } @@ -168,8 +170,10 @@ void loader_cli_list(Cli* cli, string_t args, Loader* instance) { for(size_t i = 0; i < FLIPPER_PLUGINS_COUNT; i++) { printf("\t%s\r\n", FLIPPER_PLUGINS[i].name); } + printf("\t%s\r\n", "iButton"); + printf("\t%s\r\n", "U2F"); - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) && FLIPPER_DEBUG_APPS_COUNT!=0) { printf("Debug:\r\n"); for(size_t i = 0; i < FLIPPER_DEBUG_APPS_COUNT; i++) { printf("\t%s\r\n", FLIPPER_DEBUG_APPS[i].name); From a7a1241e4428c1fcdc4741cdad306d2e32b90b54 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 02:26:06 -0400 Subject: [PATCH 24/30] Update manifest.txt --- assets/dolphin/external/manifest.txt | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/assets/dolphin/external/manifest.txt b/assets/dolphin/external/manifest.txt index dbc7c91e8..b20158b5d 100644 --- a/assets/dolphin/external/manifest.txt +++ b/assets/dolphin/external/manifest.txt @@ -5,117 +5,117 @@ Name: L1_Waves_128x50 Min butthurt: 0 Max butthurt: 5 Min level: 1 -Max level: 3 +Max level: 30 Weight: 3 Name: L1_Laptop_128x51 Min butthurt: 0 Max butthurt: 7 Min level: 1 -Max level: 1 +Max level: 30 Weight: 3 Name: L1_Sleep_128x64 Min butthurt: 0 Max butthurt: 10 Min level: 1 -Max level: 3 +Max level: 30 Weight: 3 Name: L1_Recording_128x51 Min butthurt: 0 Max butthurt: 8 Min level: 1 -Max level: 1 +Max level: 30 Weight: 3 Name: L1_Furippa1_128x64 Min butthurt: 0 Max butthurt: 6 Min level: 1 -Max level: 1 +Max level: 30 Weight: 3 Name: L2_Furippa2_128x64 Min butthurt: 0 Max butthurt: 6 Min level: 2 -Max level: 2 +Max level: 30 Weight: 3 Name: L3_Furippa3_128x64 Min butthurt: 0 Max butthurt: 6 Min level: 3 -Max level: 3 +Max level: 30 Weight: 3 Name: L1_Read_books_128x64 Min butthurt: 0 Max butthurt: 8 Min level: 1 -Max level: 1 +Max level: 30 Weight: 3 Name: L2_Hacking_pc_128x64 Min butthurt: 0 Max butthurt: 8 Min level: 2 -Max level: 2 +Max level: 30 Weight: 3 Name: L1_Cry_128x64 Min butthurt: 8 Max butthurt: 13 Min level: 1 -Max level: 3 +Max level: 30 Weight: 3 Name: L1_Boxing_128x64 Min butthurt: 10 Max butthurt: 13 Min level: 1 -Max level: 3 +Max level: 30 Weight: 3 Name: L1_Mad_fist_128x64 Min butthurt: 9 Max butthurt: 13 Min level: 1 -Max level: 3 +Max level: 30 Weight: 3 Name: L3_Hijack_radio_128x64 Min butthurt: 0 Max butthurt: 8 Min level: 3 -Max level: 3 +Max level: 30 Weight: 3 Name: L3_Lab_research_128x54 Min butthurt: 0 Max butthurt: 10 Min level: 3 -Max level: 3 +Max level: 30 Weight: 3 Name: L3_Fireplace_128x64 Min butthurt: 0 Max butthurt: 13 Min level: 2 -Max level: 3 +Max level: 30 Weight: 3 Name: L2_Soldering_128x64 Min butthurt: 0 Max butthurt: 10 Min level: 2 -Max level: 2 +Max level: 30 Weight: 3 Name: L1_Leaving_sad_128x64 Min butthurt: 14 Max butthurt: 14 Min level: 1 -Max level: 3 +Max level: 30 Weight: 3 From 1f4a259c58165ec5de2eac4c4a49819b25260583 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 02:26:34 -0400 Subject: [PATCH 25/30] Fixed crash without SD? --- assets/dolphin/internal/manifest.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/dolphin/internal/manifest.txt b/assets/dolphin/internal/manifest.txt index 8ae579de6..11b3a8a18 100644 --- a/assets/dolphin/internal/manifest.txt +++ b/assets/dolphin/internal/manifest.txt @@ -6,7 +6,7 @@ Name: L1_Tv_128x47 Min butthurt: 0 Max butthurt: 14 Min level: 1 -Max level: 3 +Max level: 30 Weight: 3 # Animation 2 @@ -14,7 +14,7 @@ Name: L1_BadBattery_128x47 Min butthurt: 0 Max butthurt: 14 Min level: 1 -Max level: 3 +Max level: 30 Weight: 3 # Animation 3 @@ -22,6 +22,6 @@ Name: L1_NoSd_128x49 Min butthurt: 0 Max butthurt: 14 Min level: 1 -Max level: 3 +Max level: 30 Weight: 6 From c7b4b7c9256b79ffd52b9617208a8fbea74f7959 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 02:27:08 -0400 Subject: [PATCH 26/30] Update ReadMe.md --- ReadMe.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index ab0b7c432..b68910b3d 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -13,15 +13,7 @@ - Last Synched changes from [Unleashed/xMasterX](https://github.com/Eng1n33r/flipperzero-firmware) in [changelog](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/CHANGELOG.md): `2022-09-21 06:55 GMT` - Last Synched changes from [OFW](https://github.com/flipperdevices/flipperzero-firmware): `2022-09-21 06:55 GMT` - To avoid Application errors and duplicates, delete /ext/apps before doing the RM firmware update -- Archive: FAPs are now launchable from Archive [By RogueMaster], thanks @xMasterX for the suggestion -- Updated [Metronome (By panki27)](https://github.com/panki27/Metronome) -- Added [DTMF Dolphin (By litui)](https://github.com/litui/dtmf_dolphin) -- Updated [WiFi (Deauther) (By Timmotools)](https://github.com/Timmotools/flipperzero_esp8266_deautherv2) -- Fixed delay issue for launching FAP from Main Menu -- Fixed SubGHz not showing -- Added Clock.FAP Launching From Main Menu [By RogueMaster](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/6dd38fac0d392f8b7588475c6fa9875f1d364a86) -- Added ibutton.FAP Launching From Main Menu [By RogueMaster](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/6dd38fac0d392f8b7588475c6fa9875f1d364a86) -- Added u2f.FAP Launching From Main Menu [By RogueMaster](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/6dd38fac0d392f8b7588475c6fa9875f1d364a86) +- Attempting fix for crash without SD
TO DO
From a3985e281927c3cf459954643bf9be21942b562a Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 02:44:05 -0400 Subject: [PATCH 27/30] Squashed commit of the following: commit 0b11b76df22abd1bbc18595e6472fe83acc65697 Author: Himura Kazuto Date: Sun Sep 18 17:25:38 2022 +0400 disable fran blink commit e9055f62b8131eca25c03dec9aab9e6a36548cb0 Author: Alexey 'Cluster' Avdyukhin Date: Wed Aug 10 23:31:45 2022 +0400 frequency analyzer - better RSSI level trigger commit 95a3bc1371addb4903fc17f5fa4dda2966cab96a Author: Alexey 'Cluster' Avdyukhin Date: Mon Aug 8 16:45:11 2022 +0400 Formatting commit 6062133170aac559fff037c8ff45d9e618030f12 Author: Alexey 'Cluster' Avdyukhin Date: Mon Aug 8 16:36:40 2022 +0400 New frequency analyzer --- .../subghz_frequency_analyzer_worker.h | 2 +- .../scenes/subghz_scene_frequency_analyzer.c | 14 +- .../subghz/views/subghz_frequency_analyzer.c | 314 ++++++++++++++++++ 3 files changed, 327 insertions(+), 3 deletions(-) create mode 100644 applications/subghz/views/subghz_frequency_analyzer.c diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h index 3b93f60ad..f1f5d21b8 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.h @@ -71,4 +71,4 @@ void subghz_frequency_analyzer_worker_set_trigger_level( * @param instance SubGhzFrequencyAnalyzerWorker instance * @return RSSI trigger level */ -float subghz_frequency_analyzer_worker_get_trigger_level(SubGhzFrequencyAnalyzerWorker* instance); \ No newline at end of file +float subghz_frequency_analyzer_worker_get_trigger_level(SubGhzFrequencyAnalyzerWorker* instance); diff --git a/applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c b/applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c index f067f9859..7e3965ac9 100644 --- a/applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c +++ b/applications/main/subghz/scenes/subghz_scene_frequency_analyzer.c @@ -17,8 +17,18 @@ void subghz_scene_frequency_analyzer_on_enter(void* context) { } bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); + SubGhz* subghz = context; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzCustomEventSceneAnalyzerLock) { + notification_message(subghz->notifications, &sequence_set_green_255); + notification_message(subghz->notifications, &sequence_set_vibro_on); + return true; + } else if(event.event == SubGhzCustomEventSceneAnalyzerUnlock) { + notification_message(subghz->notifications, &sequence_reset_rgb); + notification_message(subghz->notifications, &sequence_reset_vibro); + return true; + } + } return false; } diff --git a/applications/subghz/views/subghz_frequency_analyzer.c b/applications/subghz/views/subghz_frequency_analyzer.c new file mode 100644 index 000000000..b9360ea01 --- /dev/null +++ b/applications/subghz/views/subghz_frequency_analyzer.c @@ -0,0 +1,314 @@ +#include "subghz_frequency_analyzer.h" +#include "../subghz_i.h" + +#include +#include +#include +#include +#include +#include +#include "../helpers/subghz_frequency_analyzer_worker.h" + +#include + +#define TAG "frequency_analyzer" + +#define RSSI_MIN -97 +#define RSSI_MAX -60 +#define RSSI_SCALE 2 +#define TRIGGER_STEP 1 + +typedef enum { + SubGhzFrequencyAnalyzerStatusIDLE, +} SubGhzFrequencyAnalyzerStatus; + +struct SubGhzFrequencyAnalyzer { + View* view; + SubGhzFrequencyAnalyzerWorker* worker; + SubGhzFrequencyAnalyzerCallback callback; + void* context; + bool locked; + float rssi_last; + uint32_t frequency_last; + uint32_t frequency_last_vis; +}; + +typedef struct { + uint32_t frequency; + uint32_t frequency_last; + float rssi; + float rssi_last; + float trigger; +} SubGhzFrequencyAnalyzerModel; + +void subghz_frequency_analyzer_set_callback( + SubGhzFrequencyAnalyzer* subghz_frequency_analyzer, + SubGhzFrequencyAnalyzerCallback callback, + void* context) { + furi_assert(subghz_frequency_analyzer); + furi_assert(callback); + subghz_frequency_analyzer->callback = callback; + subghz_frequency_analyzer->context = context; +} + +void subghz_frequency_analyzer_draw_rssi( + Canvas* canvas, + float rssi, + float rssi_last, + float trigger, + uint8_t x, + uint8_t y) { + // Current RSSI + if(rssi) { + if(rssi > RSSI_MAX) rssi = RSSI_MAX; + rssi = (rssi - RSSI_MIN) / RSSI_SCALE; + uint8_t column_number = 0; + for(size_t i = 0; i <= (uint8_t)rssi; i++) { + if((i + 1) % 4) { + column_number++; + canvas_draw_box(canvas, x + 2 * i, y - column_number, 2, 4 + column_number); + } + } + } + + // Last RSSI + if(rssi_last) { + if(rssi_last > RSSI_MAX) rssi_last = RSSI_MAX; + int max_x = (int)((rssi_last - RSSI_MIN) / RSSI_SCALE) * 2; + //if(!(max_x % 8)) max_x -= 2; + int max_h = (int)((rssi_last - RSSI_MIN) / RSSI_SCALE) + 4; + max_h -= (max_h / 4) + 3; + canvas_draw_line(canvas, x + max_x + 1, y - max_h, x + max_x + 1, y + 3); + } + + // Trigger cursor + trigger = (trigger - RSSI_MIN) / RSSI_SCALE; + uint8_t tr_x = x + 2 * trigger; + canvas_draw_dot(canvas, tr_x, y + 4); + canvas_draw_line(canvas, tr_x - 1, y + 5, tr_x + 1, y + 5); + + canvas_draw_line(canvas, x, y + 3, x + (RSSI_MAX - RSSI_MIN) * 2 / RSSI_SCALE, y + 3); +} + +void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel* model) { + char buffer[64]; + + // Title + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 20, 8, "Frequency Analyzer"); + + // RSSI + canvas_draw_str(canvas, 33, 62, "RSSI"); + subghz_frequency_analyzer_draw_rssi( + canvas, model->rssi, model->rssi_last, model->trigger, 57, 58); + + // Frequency + canvas_set_font(canvas, FontBigNumbers); + snprintf( + buffer, + sizeof(buffer), + "%03ld.%03ld", + model->frequency / 1000000 % 1000, + model->frequency / 1000 % 1000); + canvas_draw_str(canvas, 8, 30, buffer); + canvas_draw_icon(canvas, 96, 19, &I_MHz_25x11); + + // Last detected frequency + canvas_set_font(canvas, FontSecondary); + if(model->frequency_last) { + snprintf( + buffer, + sizeof(buffer), + "Last: %03ld.%03ld MHz", + model->frequency_last / 1000000 % 1000, + model->frequency_last / 1000 % 1000); + } else { + strcpy(buffer, "Last: ---.--- MHz"); + } + canvas_draw_str(canvas, 9, 42, buffer); + + // Buttons hint + elements_button_left(canvas, "T-"); + elements_button_right(canvas, "T+"); +} + +bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { + furi_assert(context); + SubGhzFrequencyAnalyzer* instance = context; + + bool need_redraw = false; + + if(event->key == InputKeyBack) return false; + + if(((event->type == InputTypePress) || (event->type == InputTypeRepeat)) && + ((event->key == InputKeyLeft) || (event->key == InputKeyRight))) { + // Trigger setup + float trigger_level = subghz_frequency_analyzer_worker_get_trigger_level(instance->worker); + switch(event->key) { + case InputKeyLeft: + trigger_level -= TRIGGER_STEP; + if(trigger_level < RSSI_MIN) trigger_level = RSSI_MIN; + break; + default: + case InputKeyRight: + trigger_level += TRIGGER_STEP; + if(trigger_level > RSSI_MAX) trigger_level = RSSI_MAX; + break; + } + subghz_frequency_analyzer_worker_set_trigger_level(instance->worker, trigger_level); + FURI_LOG_I(TAG, "trigger = %.1f", (double)trigger_level); + need_redraw = true; + } + + if(need_redraw) { + SubGhzFrequencyAnalyzer* instance = context; + with_view_model( + instance->view, (SubGhzFrequencyAnalyzerModel * model) { + model->rssi_last = instance->rssi_last; + model->frequency_last = instance->frequency_last; + model->trigger = + subghz_frequency_analyzer_worker_get_trigger_level(instance->worker); + return true; + }); + } + + return true; +} + +uint32_t round_int(uint32_t value, uint8_t n) { + // Round value + uint8_t on = n; + while(n--) { + uint8_t i = value % 10; + value /= 10; + if(i >= 5) value++; + } + while(on--) value *= 10; + return value; +} + +void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency, float rssi) { + furi_assert(context); + SubGhzFrequencyAnalyzer* instance = context; + + if((rssi == 0.f) && (instance->locked)) { + if(instance->callback) { + instance->callback(SubGhzCustomEventSceneAnalyzerUnlock, instance->context); + } + instance->frequency_last_vis = instance->frequency_last; + } else if((rssi != 0.f) && (!instance->locked)) { + if(instance->callback) { + instance->callback(SubGhzCustomEventSceneAnalyzerLock, instance->context); + } + } + + if((rssi != 0.f) && (frequency != 0)) { + // Threre is some signal + FURI_LOG_I(TAG, "rssi = %.2f, frequency = %d Hz", (double)rssi, frequency); + frequency = round_int(frequency, 3); // Round 299999990Hz to 300000000Hz + if(!instance->locked) { + // Triggered! + instance->rssi_last = rssi; + FURI_LOG_D(TAG, "triggered"); + } + // Update values + if(rssi >= instance->rssi_last) { + instance->rssi_last = rssi; + instance->frequency_last = frequency; + } + } + + instance->locked = (rssi != 0.f); + with_view_model( + instance->view, (SubGhzFrequencyAnalyzerModel * model) { + model->rssi = rssi; + model->rssi_last = instance->rssi_last; + model->frequency = frequency; + model->frequency_last = instance->frequency_last_vis; + model->trigger = subghz_frequency_analyzer_worker_get_trigger_level(instance->worker); + return true; + }); +} + +void subghz_frequency_analyzer_enter(void* context) { + furi_assert(context); + SubGhzFrequencyAnalyzer* instance = context; + + //Start worker + instance->worker = subghz_frequency_analyzer_worker_alloc(instance->context); + + subghz_frequency_analyzer_worker_set_pair_callback( + instance->worker, + (SubGhzFrequencyAnalyzerWorkerPairCallback)subghz_frequency_analyzer_pair_callback, + instance); + + subghz_frequency_analyzer_worker_start(instance->worker); + + instance->rssi_last = 0; + instance->frequency_last = 0; + instance->frequency_last_vis = 0; + subghz_frequency_analyzer_worker_set_trigger_level(instance->worker, RSSI_MIN); + + with_view_model( + instance->view, (SubGhzFrequencyAnalyzerModel * model) { + model->rssi = 0; + model->rssi_last = 0; + model->frequency = 0; + model->frequency_last = 0; + model->trigger = RSSI_MIN; + return true; + }); +} + +void subghz_frequency_analyzer_exit(void* context) { + furi_assert(context); + SubGhzFrequencyAnalyzer* instance = context; + + //Stop worker + if(subghz_frequency_analyzer_worker_is_running(instance->worker)) { + subghz_frequency_analyzer_worker_stop(instance->worker); + } + subghz_frequency_analyzer_worker_free(instance->worker); + + with_view_model( + instance->view, (SubGhzFrequencyAnalyzerModel * model) { + model->rssi = 0; + return true; + }); +} + +SubGhzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() { + SubGhzFrequencyAnalyzer* instance = malloc(sizeof(SubGhzFrequencyAnalyzer)); + furi_assert(instance); + + // View allocation and configuration + instance->view = view_alloc(); + view_allocate_model( + instance->view, ViewModelTypeLocking, sizeof(SubGhzFrequencyAnalyzerModel)); + view_set_context(instance->view, instance); + view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_frequency_analyzer_draw); + view_set_input_callback(instance->view, subghz_frequency_analyzer_input); + view_set_enter_callback(instance->view, subghz_frequency_analyzer_enter); + view_set_exit_callback(instance->view, subghz_frequency_analyzer_exit); + + with_view_model( + instance->view, (SubGhzFrequencyAnalyzerModel * model) { + model->rssi = 0; + return true; + }); + + return instance; +} + +void subghz_frequency_analyzer_free(SubGhzFrequencyAnalyzer* instance) { + furi_assert(instance); + + view_free(instance->view); + free(instance); +} + +View* subghz_frequency_analyzer_get_view(SubGhzFrequencyAnalyzer* instance) { + furi_assert(instance); + return instance->view; +} From 27ba49ed88f7a3644ef6407d6bad3f1328d08964 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 02:51:26 -0400 Subject: [PATCH 28/30] Update ReadMe.md --- ReadMe.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ReadMe.md b/ReadMe.md index b68910b3d..a821e3514 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -14,6 +14,7 @@ - Last Synched changes from [OFW](https://github.com/flipperdevices/flipperzero-firmware): `2022-09-21 06:55 GMT` - To avoid Application errors and duplicates, delete /ext/apps before doing the RM firmware update - Attempting fix for crash without SD +- Updated to [Quiet Frequency Analyzer (By Himura2la)](https://github.com/ClusterM/flipperzero-firmware/pull/1)
TO DO
@@ -147,7 +148,7 @@ $ ./fbt plugin_dist FIRMWARE_APP_SET=ext_apps - SubGHz: [Add settings to subghz read functionality to allow setting RSSI threshold (raw only) (By PolymerPrints)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/184) - SubGHz: Extended ranges enabled through flag in /ext/subghz/assets/extend_range.txt [from tkerrby](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/116) - SubGHz: Moved setting_user file to setting_user.txt! This makes it changable from IOS app. (By RogueMaster) -- SubGHz: New frequency analyzer [(By ClusterM)](https://github.com/flipperdevices/flipperzero-firmware/pull/1501) [feedback mode (by darmiel)](https://github.com/darmiel/flipper-playlist/tree/feat/stealth-frequency-analyzer) +- SubGHz: New frequency analyzer [(By ClusterM)](https://github.com/flipperdevices/flipperzero-firmware/pull/1501) [feedback mode (by darmiel)](https://github.com/darmiel/flipper-playlist/tree/feat/stealth-frequency-analyzer) [Quiet Mode (by Himura2la)](https://github.com/ClusterM/flipperzero-firmware/pull/1) - SubGHz: Protocols An-Motors, BFT Mitto, Came Atomo, FAAC SLH (Spa), HCS101, Keeloq, Keeloq Common, Nice Flor S, SecPlus v1+v2 and Star Line updates from [Eng1n33r](https://github.com/Eng1n33r/flipperzero-firmware) - SubGHz: Unlock from SD flag from [(cloudbreakdaniel)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/97db0dc91ee3dff812b4dec0618e3f198de14405). Update `subghz/assets/extend_range.txt` with [this file](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/assets/resources/subghz/assets/extend_range.txt) on SD. **UPDATE IGNORE FLAG TO TRUE TO UNLEASH YOUR FLIPPER!!** From a7e3df67dca9fd83f6a1e52529903b0a980cd236 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 02:54:08 -0400 Subject: [PATCH 29/30] Update ReadMe.md --- ReadMe.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index a821e3514..f8f7f579f 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -10,8 +10,8 @@ Latest Updates: - Known Issues: `Chess`, `Tanks` & `Chip8` (No Controls) -- Last Synched changes from [Unleashed/xMasterX](https://github.com/Eng1n33r/flipperzero-firmware) in [changelog](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/CHANGELOG.md): `2022-09-21 06:55 GMT` -- Last Synched changes from [OFW](https://github.com/flipperdevices/flipperzero-firmware): `2022-09-21 06:55 GMT` +- Last Synched changes from [Unleashed/xMasterX](https://github.com/Eng1n33r/flipperzero-firmware) in [changelog](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/CHANGELOG.md): `2022-09-21 06:54 GMT` +- Last Synched changes from [OFW](https://github.com/flipperdevices/flipperzero-firmware): `2022-09-21 06:54 GMT` - To avoid Application errors and duplicates, delete /ext/apps before doing the RM firmware update - Attempting fix for crash without SD - Updated to [Quiet Frequency Analyzer (By Himura2la)](https://github.com/ClusterM/flipperzero-firmware/pull/1) From ba7292f4c3df157ae25d10fd3a244761791125cc Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Wed, 21 Sep 2022 02:56:24 -0400 Subject: [PATCH 30/30] Update ReadMe.md --- ReadMe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReadMe.md b/ReadMe.md index f8f7f579f..659285e44 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -13,7 +13,7 @@ - Last Synched changes from [Unleashed/xMasterX](https://github.com/Eng1n33r/flipperzero-firmware) in [changelog](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/CHANGELOG.md): `2022-09-21 06:54 GMT` - Last Synched changes from [OFW](https://github.com/flipperdevices/flipperzero-firmware): `2022-09-21 06:54 GMT` - To avoid Application errors and duplicates, delete /ext/apps before doing the RM firmware update -- Attempting fix for crash without SD +- Fixed crash without SD - Updated to [Quiet Frequency Analyzer (By Himura2la)](https://github.com/ClusterM/flipperzero-firmware/pull/1)